Skip to content

Commit

Permalink
support coins up to 8 (wip)
Browse files Browse the repository at this point in the history
  • Loading branch information
bout3fiddy committed Jun 30, 2023
1 parent f2d07ee commit ba84611
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 69 deletions.
18 changes: 9 additions & 9 deletions contracts/main/CurveStableSwap2NG.vy
Original file line number Diff line number Diff line change
Expand Up @@ -109,15 +109,15 @@ event ApplyNewFee:
fee: uint256


MAX_COINS: constant(uint256) = 8 # max coins is 8 in the factory

# ---------------------------- Pool Variables --------------------------------

WETH20: immutable(address)
MAX_POOL_COINS: constant(uint256) = 4

N_COINS: constant(uint256) = 2
N_COINS_128: constant(int128) = 2
PRECISION: constant(uint256) = 10 ** 18
IS_REBASING: immutable(bool[MAX_POOL_COINS])
IS_REBASING: immutable(bool[N_COINS])

factory: public(address)
coins: public(address[N_COINS])
Expand Down Expand Up @@ -187,15 +187,15 @@ CACHED_DOMAIN_SEPARATOR: immutable(bytes32)
def __init__(
_name: String[32],
_symbol: String[10],
_coins: address[MAX_POOL_COINS],
_rate_multipliers: uint256[MAX_POOL_COINS],
_coins: address[MAX_COINS],
_rate_multipliers: uint256[MAX_COINS],
_A: uint256,
_fee: uint256,
_weth: address,
_ma_exp_time: uint256,
_method_ids: bytes4[MAX_POOL_COINS],
_oracles: address[MAX_POOL_COINS],
_is_rebasing: bool[MAX_POOL_COINS]
_method_ids: bytes4[MAX_COINS],
_oracles: address[MAX_COINS],
_is_rebasing: bool[MAX_COINS]
):
"""
@notice Initialize the pool contract
Expand All @@ -222,7 +222,7 @@ def __init__(
"""

WETH20 = _weth
IS_REBASING = _is_rebasing
IS_REBASING = [_is_rebasing[0], _is_rebasing[1]]

name = _name
symbol = _symbol
Expand Down
110 changes: 60 additions & 50 deletions contracts/main/CurveStableSwapFactoryNG.vy
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ struct PoolArray:
base_pool: address
implementation: address
liquidity_gauge: address
coins: address[MAX_PLAIN_COINS]
decimals: uint256[MAX_PLAIN_COINS]
coins: address[MAX_COINS]
decimals: uint256[MAX_COINS]
n_coins: uint256
asset_type: uint256

Expand All @@ -20,20 +20,14 @@ struct BasePoolArray:
lp_token: address
fee_receiver: address
coins: address[MAX_COINS]
is_rebasing: bool[MAX_COINS]
decimals: uint256
n_coins: uint256
asset_type: uint256


interface AddressProvider:
def admin() -> address: view
def get_registry() -> address: view

interface Registry:
def get_lp_token(pool: address) -> address: view
def get_n_coins(pool: address) -> uint256: view
def get_coins(pool: address) -> address[MAX_COINS]: view
def get_pool_from_lp_token(lp_token: address) -> address: view

interface ERC20:
def balanceOf(_addr: address) -> uint256: view
Expand All @@ -56,7 +50,7 @@ interface CurvePool:
_A: uint256,
_fee: uint256,
): nonpayable
def exchange(
def exchange( # TODO: change this!
i: int128,
j: int128,
dx: uint256,
Expand All @@ -68,18 +62,12 @@ interface CurveFactoryMetapool:
def coins(i :uint256) -> address: view
def decimals() -> uint256: view

interface OldFactory:
def get_coins(_pool: address) -> address[2]: view

interface LiquidityGauge:
def initialize(_lp_token: address): nonpayable


event BasePoolAdded:
base_pool: address

event PlainPoolDeployed:
coins: address[MAX_PLAIN_COINS]
coins: address[MAX_COINS]
A: uint256
fee: uint256
deployer: address
Expand All @@ -98,7 +86,6 @@ event LiquidityGaugeDeployed:
WETH20: public(immutable(address))

MAX_COINS: constant(uint256) = 8
MAX_PLAIN_COINS: constant(uint256) = 4 # max coins in a plain pool
ADDRESS_PROVIDER: constant(address) = 0x0000000022D53366457F9d5E68Ec105046FC4383
OLD_FACTORY: constant(address) = 0x0959158b6040D32d04c301A72CBFD6b39E21c9AE

Expand All @@ -111,7 +98,7 @@ pool_data: HashMap[address, PoolArray]

base_pool_list: public(address[4294967296]) # master list of pools
base_pool_count: public(uint256) # actual length of pool_list
base_pool_data: HashMap[address, BasePoolArray]
base_pool_data: public(HashMap[address, BasePoolArray])

# asset -> is used in a metapool?
base_pool_assets: public(HashMap[address, bool])
Expand Down Expand Up @@ -209,7 +196,7 @@ def get_meta_n_coins(_pool: address) -> (uint256, uint256):

@view
@external
def get_coins(_pool: address) -> address[MAX_PLAIN_COINS]:
def get_coins(_pool: address) -> address[MAX_COINS]:
"""
@notice Get the coins within a pool
@param _pool Pool address
Expand Down Expand Up @@ -241,14 +228,14 @@ def get_underlying_coins(_pool: address) -> address[MAX_COINS]:

@view
@external
def get_decimals(_pool: address) -> uint256[MAX_PLAIN_COINS]:
def get_decimals(_pool: address) -> uint256[MAX_COINS]:
"""
@notice Get decimal places for each coin within a pool
@param _pool Pool address
@return uint256 list of decimals
"""
if self.pool_data[_pool].base_pool != empty(address):
decimals: uint256[MAX_PLAIN_COINS] = empty(uint256[MAX_PLAIN_COINS])
decimals: uint256[MAX_COINS] = empty(uint256[MAX_COINS])
decimals = self.pool_data[_pool].decimals
decimals[1] = 18
return decimals
Expand All @@ -265,7 +252,7 @@ def get_underlying_decimals(_pool: address) -> uint256[MAX_COINS]:
"""
# decimals are tightly packed as a series of uint8 within a little-endian bytes32
# the packed value is stored as uint256 to simplify unpacking via shift and modulo
pool_decimals: uint256[MAX_PLAIN_COINS] = empty(uint256[MAX_PLAIN_COINS])
pool_decimals: uint256[MAX_COINS] = empty(uint256[MAX_COINS])
pool_decimals = self.pool_data[_pool].decimals
decimals: uint256[MAX_COINS] = empty(uint256[MAX_COINS])
decimals[0] = pool_decimals[0]
Expand Down Expand Up @@ -297,22 +284,27 @@ def get_metapool_rates(_pool: address) -> uint256[2]:

@view
@external
def get_balances(_pool: address) -> uint256[MAX_PLAIN_COINS]:
def get_balances(_pool: address) -> uint256[MAX_COINS]:
"""
@notice Get balances for each coin within a pool
@dev For pools using lending, these are the wrapped coin balances
@param _pool Pool address
@return uint256 list of balances
"""
balances: uint256[MAX_COINS] = empty(uint256[MAX_COINS])

if self.pool_data[_pool].base_pool != empty(address):
return [CurvePool(_pool).balances(0), CurvePool(_pool).balances(1), 0, 0]
balances[0] = CurvePool(_pool).balances(0)
balances[1] = CurvePool(_pool).balances(1)
return balances

n_coins: uint256 = self.pool_data[_pool].n_coins
balances: uint256[MAX_PLAIN_COINS] = empty(uint256[MAX_PLAIN_COINS])
for i in range(MAX_PLAIN_COINS):
for i in range(MAX_COINS):
if i < n_coins:
balances[i] = CurvePool(_pool).balances(i)
else:
balances[i] = 0

return balances


Expand Down Expand Up @@ -366,15 +358,15 @@ def get_fees(_pool: address) -> (uint256, uint256):

@view
@external
def get_admin_balances(_pool: address) -> uint256[MAX_PLAIN_COINS]:
def get_admin_balances(_pool: address) -> uint256[MAX_COINS]:
"""
@notice Get the current admin balances (uncollected fees) for a pool
@param _pool Pool address
@return List of uint256 admin balances
"""
n_coins: uint256 = self.pool_data[_pool].n_coins
admin_balances: uint256[MAX_PLAIN_COINS] = empty(uint256[MAX_PLAIN_COINS])
for i in range(MAX_PLAIN_COINS):
admin_balances: uint256[MAX_COINS] = empty(uint256[MAX_COINS])
for i in range(MAX_COINS):
if i == n_coins:
break
admin_balances[i] = CurvePool(_pool).admin_balances(i)
Expand Down Expand Up @@ -409,7 +401,7 @@ def get_coin_indices(
j: uint256 = 0
for x in range(MAX_COINS):
if base_pool == empty(address):
if x >= MAX_PLAIN_COINS:
if x >= MAX_COINS:
raise "No available market"
if x != 0:
coin = self.pool_data[_pool].coins[x]
Expand Down Expand Up @@ -499,12 +491,12 @@ def get_fee_receiver(_pool: address) -> address:
def deploy_plain_pool(
_name: String[32],
_symbol: String[10],
_coins: address[MAX_PLAIN_COINS],
_coins: address[MAX_COINS],
_A: uint256,
_fee: uint256,
_ma_exp_time: uint256,
_method_ids: bytes4[4] = empty(bytes4[4]),
_oracles: address[4] = empty(address[4]),
_method_ids: bytes4[MAX_COINS] = empty(bytes4[MAX_COINS]),
_oracles: address[MAX_COINS] = empty(address[MAX_COINS]),
_asset_type: uint256 = 0,
_implementation_idx: uint256 = 0,
_is_rebasing: bool = False
Expand Down Expand Up @@ -540,11 +532,11 @@ def deploy_plain_pool(
"""
assert _fee <= 100000000, "Invalid fee"

n_coins: uint256 = MAX_PLAIN_COINS
rate_multipliers: uint256[MAX_PLAIN_COINS] = empty(uint256[MAX_PLAIN_COINS])
decimals: uint256[MAX_PLAIN_COINS] = empty(uint256[MAX_PLAIN_COINS])
n_coins: uint256 = MAX_COINS
rate_multipliers: uint256[MAX_COINS] = empty(uint256[MAX_COINS])
decimals: uint256[MAX_COINS] = empty(uint256[MAX_COINS])

for i in range(MAX_PLAIN_COINS):
for i in range(MAX_COINS):

coin: address = _coins[i]

Expand All @@ -558,8 +550,8 @@ def deploy_plain_pool(

rate_multipliers[i] = 10 ** (36 - decimals[i])

for x in range(i, i+MAX_PLAIN_COINS):
if x+1 == MAX_PLAIN_COINS:
for x in range(i, i + MAX_COINS):
if x+1 == MAX_COINS:
break
if _coins[x+1] == empty(address):
break
Expand Down Expand Up @@ -593,7 +585,7 @@ def deploy_plain_pool(
if _asset_type != 0:
self.pool_data[pool].asset_type = _asset_type

for i in range(MAX_PLAIN_COINS):
for i in range(MAX_COINS):
coin: address = _coins[i]
if coin == empty(address):
break
Expand All @@ -606,7 +598,7 @@ def deploy_plain_pool(
convert(max_value(uint256), bytes32)
)
)
for j in range(MAX_PLAIN_COINS):
for j in range(MAX_COINS):
if i < j:
swappable_coin: address = _coins[j]
key: uint256 = (convert(coin, uint256) ^ convert(swappable_coin, uint256))
Expand Down Expand Up @@ -665,6 +657,17 @@ def deploy_metapool(
decimals: uint256 = ERC20(_coin).decimals()
assert decimals < 19, "Max 18 decimals for coins"
# combine _coins's _is_rebasing and basepool coins _is_rebasing:
base_pool_is_rebasing: bool[MAX_COINS] = self.base_pool_data[_base_pool].is_rebasing
is_rebasing: bool[MAX_COINS] = empty(bool[MAX_COINS])
is_rebasing[0] = _is_rebasing
for i in range(MAX_COINS):

if i+1 == MAX_COINS:
break

is_rebasing[i+1] = base_pool_is_rebasing[i]

pool: address = create_from_blueprint(
implementation,
_name,
Expand All @@ -677,6 +680,9 @@ def deploy_metapool(
_method_id,
_oracle,
_is_rebasing,
_base_pool,
self.base_pool_data[_base_pool].lp_token,
self.base_pool_data[_base_pool].coins,
code_offset=3
)

Expand All @@ -689,7 +695,7 @@ def deploy_metapool(

base_lp_token: address = self.base_pool_data[_base_pool].lp_token

self.pool_data[pool].decimals = [decimals, 0, 0, 0]
self.pool_data[pool].decimals = [decimals, 0, 0, 0, 0, 0, 0, 0]
self.pool_data[pool].n_coins = 2
self.pool_data[pool].base_pool = _base_pool
self.pool_data[pool].coins[0] = _coin
Expand Down Expand Up @@ -738,8 +744,12 @@ def deploy_gauge(_pool: address) -> address:
@external
def add_base_pool(
_base_pool: address,
_base_lp_token: address,
_fee_receiver: address,
_coins: address[MAX_COINS],
_asset_type: uint256,
_n_coins: uint256,
_is_rebasing: bool[MAX_COINS],
_implementations: address[10],
):
"""
Expand All @@ -748,20 +758,19 @@ def add_base_pool(
@param _base_pool Pool address to add
@param _fee_receiver Admin fee receiver address for metapools using this base pool
@param _asset_type Asset type for pool, as an integer 0 = USD, 1 = ETH, 2 = BTC, 3 = Other
@param _is_rebasing Array of booleans: _is_rebasing[i] is True if basepool coin[i] is rebasing
@param _implementations List of implementation addresses that can be used with this base pool
"""
assert msg.sender == self.admin # dev: admin-only function
assert self.base_pool_data[_base_pool].coins[0] == empty(address) # dev: pool exists
registry: address = AddressProvider(ADDRESS_PROVIDER).get_registry()
n_coins: uint256 = Registry(registry).get_n_coins(_base_pool)
assert _n_coins < MAX_COINS # dev: base pool can only have (MAX_COINS - 1) coins.

# add pool to pool_list
length: uint256 = self.base_pool_count
self.base_pool_list[length] = _base_pool
self.base_pool_count = length + 1
self.base_pool_data[_base_pool].lp_token = Registry(registry).get_lp_token(_base_pool)
self.base_pool_data[_base_pool].n_coins = n_coins
self.base_pool_data[_base_pool].lp_token = _base_lp_token
self.base_pool_data[_base_pool].n_coins = _n_coins
self.base_pool_data[_base_pool].fee_receiver = _fee_receiver
if _asset_type != 0:
self.base_pool_data[_base_pool].asset_type = _asset_type
Expand All @@ -773,12 +782,13 @@ def add_base_pool(
self.base_pool_data[_base_pool].implementations[i] = implementation

decimals: uint256 = 0
coins: address[MAX_COINS] = Registry(registry).get_coins(_base_pool)
coins: address[MAX_COINS] = _coins
for i in range(MAX_COINS):
if i == n_coins:
if i == _n_coins:
break
coin: address = coins[i]
self.base_pool_data[_base_pool].coins[i] = coin
self.base_pool_data[_base_pool].is_rebasing[i] = _is_rebasing[i]
self.base_pool_assets[coin] = True
decimals += (ERC20(coin).decimals() << i*8)
self.base_pool_data[_base_pool].decimals = decimals
Expand Down
Loading

0 comments on commit ba84611

Please sign in to comment.