Skip to content

Commit

Permalink
LpSugar: _safe_symbol handles large string values (#95)
Browse files Browse the repository at this point in the history
* fix: symbol string size

* feat: truncate symbols

* simplify string conversion.

* LpSugar: refactor `_safe_symbol()`

* LpSugar: cleanups and tests.

* env: base release

* env: new optimism lp sugar release.

---------

Co-authored-by: Stas SUȘCOV <[email protected]>
  • Loading branch information
ethzoomer and stas authored Dec 14, 2024
1 parent 928ed4c commit ffc81d4
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 37 deletions.
53 changes: 20 additions & 33 deletions contracts/LpSugar.vy
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ struct Position:

struct Token:
token_address: address
symbol: String[100]
symbol: String[30]
decimals: uint8
account_balance: uint256
listed: bool
Expand All @@ -83,7 +83,7 @@ struct SwapLp:

struct Lp:
lp: address
symbol: String[100]
symbol: String[30]
decimals: uint8
liquidity: uint256

Expand Down Expand Up @@ -131,11 +131,6 @@ struct AlmManagedPositionInfo:

# Our contracts / Interfaces

interface IERC20:
def decimals() -> uint8: view
def symbol() -> String[100]: view
def balanceOf(_account: address) -> uint256: view

interface IPool:
def token0() -> address: view
def token1() -> address: view
Expand All @@ -148,7 +143,6 @@ interface IPool:
def index0() -> uint256: view
def index1() -> uint256: view
def totalSupply() -> uint256: view
def symbol() -> String[100]: view
def decimals() -> uint8: view
def stable() -> bool: view
def balanceOf(_account: address) -> uint256: view
Expand Down Expand Up @@ -348,7 +342,6 @@ def tokens(_limit: uint256, _offset: uint256, _account: address, \
@internal
@view
def _token(_address: address, _account: address) -> Token:
token: IERC20 = IERC20(_address)
bal: uint256 = empty(uint256)

if _account != empty(address):
Expand Down Expand Up @@ -433,8 +426,6 @@ def _v2_lp(_data: address[4], _token0: address, _token1: address) -> Lp:
is_stable: bool = staticcall pool.stable()
pool_fee: uint256 = staticcall lp_shared.IPoolFactory(_data[0]).getFee(pool.address, is_stable)
pool_fees: address = staticcall pool.poolFees()
token0: IERC20 = IERC20(_token0)
token1: IERC20 = IERC20(_token1)
token0_fees: uint256 = self._safe_balance_of(_token0, pool_fees)
token1_fees: uint256 = self._safe_balance_of(_token1, pool_fees)
gauge_alive: bool = staticcall lp_shared.voter.isAlive(gauge.address)
Expand Down Expand Up @@ -465,19 +456,19 @@ def _v2_lp(_data: address[4], _token0: address, _token1: address) -> Lp:

return Lp({
lp: _data[1],
symbol: staticcall pool.symbol(),
symbol: self._safe_symbol(pool.address),
decimals: decimals,
liquidity: pool_liquidity,

type: type,
tick: 0,
sqrt_ratio: 0,

token0: token0.address,
token0: _token0,
reserve0: reserve0,
staked0: staked0,

token1: token1.address,
token1: _token1,
reserve1: reserve1,
staked1: staked1,

Expand All @@ -500,9 +491,7 @@ def _v2_lp(_data: address[4], _token0: address, _token1: address) -> Lp:
nfpm: empty(address),
alm: empty(address),

root: lp_shared._root_lp_address(
_data[0], token0.address, token1.address, type
)
root: lp_shared._root_lp_address(_data[0], _token0, _token1, type)
})

@external
Expand Down Expand Up @@ -958,8 +947,6 @@ def _cl_lp(_data: address[4], _token0: address, _token1: address) -> Lp:
fee_voting_reward: address = empty(address)
emissions: uint256 = 0
emissions_token: address = empty(address)
token0: IERC20 = IERC20(_token0)
token1: IERC20 = IERC20(_token1)
staked0: uint256 = 0
staked1: uint256 = 0
tick_spacing: int24 = staticcall pool.tickSpacing()
Expand Down Expand Up @@ -1006,11 +993,11 @@ def _cl_lp(_data: address[4], _token0: address, _token1: address) -> Lp:
tick: slot.tick,
sqrt_ratio: slot.sqrtPriceX96,

token0: token0.address,
token0: _token0,
reserve0: self._safe_balance_of(_token0, pool.address),
staked0: staked0,

token1: token1.address,
token1: _token1,
reserve1: self._safe_balance_of(_token1, pool.address),
staked1: staked1,

Expand All @@ -1033,9 +1020,7 @@ def _cl_lp(_data: address[4], _token0: address, _token1: address) -> Lp:
nfpm: _data[3],
alm: alm_addresses[1],

root: lp_shared._root_lp_address(
_data[0], token0.address, token1.address, tick_spacing
),
root: lp_shared._root_lp_address(_data[0], _token0, _token1, tick_spacing),
})

@internal
Expand Down Expand Up @@ -1088,28 +1073,30 @@ def _safe_decimals(_token: address) -> uint8:

@internal
@view
def _safe_symbol(_token: address) -> String[100]:
def _safe_symbol(_token: address) -> String[30]:
"""
@notice Returns the `ERC20.symbol()` result safely
@notice Returns the `ERC20.symbol()` safely (max 30 chars)
@param _token The token to call
"""
# >=192 input size is required by Vyper's _abi_decode()
response: Bytes[192] = b""
response = raw_call(
response: Bytes[100] = raw_call(
_token,
method_id("symbol()"),
max_outsize=192,
# Min bytes to use abi_decode()
max_outsize=100,
gas=50000,
is_delegate_call=False,
is_static_call=True,
revert_on_failure=False
)[1]

resp_len: uint256 = len(response)

# Check response as revert_on_failure is set to False
if len(response) > 0:
return abi_decode(response, String[100])
# And that the symbol size is not more than 10 chars (96 bytes)
if resp_len > 0 and resp_len <= 96:
return abi_decode(response, String[30])

return "-NA-"
return "-???-"

@internal
@view
Expand Down
24 changes: 24 additions & 0 deletions contracts/test.vy
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# To test on OP Mainnet, pass these token addresses:
# * 0x4200000000000000000000000000000000000006 (weth)
# * 0x045D841ba37E180bC9b9D4da718E14b9ED7925d6 (garbaged unicode)

@external
@view
def safe_symbol(_token: address) -> String[10]:
response: Bytes[100] = raw_call(
_token,
method_id("symbol()"),
max_outsize=100,
gas=50000,
is_delegate_call=False,
is_static_call=True,
revert_on_failure=False,
)[1]

response_len: uint256 = len(response)

# Min bytes to use abi_decode()
if response_len > 0 and response_len <= 96:
return abi_decode(response, String[10])

return "-???-"
4 changes: 2 additions & 2 deletions env.base
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ TEST_FACTORY_ADDRESS_8453=0x5e7BB104d84c7CB9B682AaC2F3d509f5F406809A
TEST_ADDRESS_8453=0x892Ff98a46e5bd141E2D12618f4B2Fe6284debac
TEST_ALM_ADDRESS_8453=0x892Ff98a46e5bd141E2D12618f4B2Fe6284debac

LP_SUGAR_ADDRESS_8453=0x25546d006fD79b6910Cb30e96a32B5ce296663bb
REWARDS_SUGAR_ADDRESS_8453=0xEbfD2d983340e0bA6109a387928ADAe9FEE47D4b
LP_SUGAR_ADDRESS_8453=0x82dA79111A0C79639B7a4c6dc149283D103f1860
REWARDS_SUGAR_ADDRESS_8453=0xA44600F4DBA6683d8BD99270B1A6a143fB9F1C3B
VE_SUGAR_ADDRESS_8453=0x4c5d3925fe65DFeB5A079485136e4De09cb664A5
RELAY_SUGAR_ADDRESS_8453=0x8932B5FE23C07Df06533F8f09E43e7cca6a24143
2 changes: 1 addition & 1 deletion env.optimism
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ GOVERNOR_10=0x1F82e10D58aEf03DeA2e478029fB0387A1cbE989
TEST_ADDRESS_10=0x892ff98a46e5bd141e2d12618f4b2fe6284debac
TEST_ALM_ADDRESS_10=0x892ff98a46e5bd141e2d12618f4b2fe6284debac

LP_SUGAR_ADDRESS_10=0x5B3B370C85c8816cBB4BCE5f647dCa3e06c421d7
LP_SUGAR_ADDRESS_10=0xf01d04b0963a175Ac43D31C515A4397356cF74D8
REWARDS_SUGAR_ADDRESS_10=0x62CCFB2496f49A80B0184AD720379B529E9152fB
VE_SUGAR_ADDRESS_10=0x94f913362b232e31daB49a1aFB775cfd25DaA6a1
RELAY_SUGAR_ADDRESS_10=0xb8307e5842B9aeE75C704183F0355076aa74b4e2
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Below is the list of datasets we support.

> [!NOTE]
> `LpSugar.vy` is deployed on:
> Optimism - `0x35F233BE126d7D08aB2D65E647E8c379b1FACF39`
> Optimism - `0x54F8968CC76ECB17018E44049FdcC14ff833fa67`
> Base - `0x63a73829C74e936C1D2EEbE64164694f16700138`
It allows fetching on-chain pools data.
Expand Down
32 changes: 32 additions & 0 deletions tests/test_lp_sugar.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,38 @@ def test_tokens(sugar_contract, TokenStruct, LpStruct):
assert token1.token_address == first_lp.token1


@pytest.mark.skipif(int(CHAIN_ID) not in [10], reason="Only OP")
def test_tokens_long_symbol(sugar_contract, TokenStruct):
tokens = list(map(
lambda _p: TokenStruct(*_p),
sugar_contract.tokens(1, 995, ADDRESS_ZERO, [])
))

assert tokens is not None
assert len(tokens) > 1

token = tokens[0]

assert token.symbol is not None
assert token.symbol == '-???-'


@pytest.mark.skipif(int(CHAIN_ID) not in [10], reason="Only OP")
def test_all_long_symbol(sugar_contract, LpStruct):
pools = list(map(
lambda _p: LpStruct(*_p),
sugar_contract.all(1, 995)
))

assert pools is not None
assert len(pools) == 1

pool = pools[0]

assert pool.symbol is not None
assert pool.symbol == '-???-'


def test_all(sugar_contract, LpStruct):
first_lp = LpStruct(*sugar_contract.byIndex(0))
second_lp = LpStruct(*sugar_contract.byIndex(1))
Expand Down

0 comments on commit ffc81d4

Please sign in to comment.