diff --git a/contracts/CryptoPoolProxy.vy b/contracts/CryptoPoolProxy.vy index 73f1c47e..5d6a2f9e 100644 --- a/contracts/CryptoPoolProxy.vy +++ b/contracts/CryptoPoolProxy.vy @@ -1,18 +1,22 @@ -# @version 0.2.12 +# @version 0.3.10 """ @title Curve Crypto Pool Proxy @author Curve Finance @license MIT +@notice Used to control Custom Cryptoswap Pools """ +from vyper.interfaces import ERC20 + interface Burner: - def burn(_coin: address) -> bool: payable + def burn(_coin: ERC20) -> bool: payable interface Curve: + def claim_admin_fees(): nonpayable + def commit_transfer_ownership(_owner: address): nonpayable def accept_transfer_ownership(): nonpayable - def apply_new_parameters(): nonpayable def apply_transfer_ownership(): nonpayable - def claim_admin_fees(): nonpayable + def revert_transfer_ownership(): nonpayable def commit_new_parameters( _new_mid_fee: uint256, _new_out_fee: uint256, @@ -22,37 +26,18 @@ interface Curve: _new_adjustment_step: uint256, _new_ma_half_time: uint256 ): nonpayable - def commit_transfer_ownership(_owner: address): nonpayable - def donate_admin_fees(): nonpayable - def kill_me(): nonpayable - def price_oracle(k: uint256) -> uint256: view - def ramp_A_gamma(future_A: uint256, future_gamma: uint256, future_time: uint256): nonpayable def revert_new_parameters(): nonpayable - def revert_transfer_ownership(): nonpayable + def apply_new_parameters(): nonpayable + def ramp_A_gamma(future_A: uint256, future_gamma: uint256, future_time: uint256): nonpayable + def stop_ramp_A_gamma(): nonpayable def set_admin_fee_receiver(_admin_fee_receiver: address): nonpayable def set_aave_referral(referral_code: uint256): nonpayable - def stop_ramp_A_gamma(): nonpayable + def donate_admin_fees(): nonpayable + def kill_me(): nonpayable def unkill_me(): nonpayable -interface AddressProvider: - def get_registry() -> address: view - -interface Registry: - def get_decimals(_pool: address) -> uint256[8]: view - def get_underlying_balances(_pool: address) -> uint256[8]: view - MAX_COINS: constant(int128) = 8 -ADDRESS_PROVIDER: constant(address) = 0x0000000022D53366457F9d5E68Ec105046FC4383 - -struct PoolInfo: - balances: uint256[MAX_COINS] - underlying_balances: uint256[MAX_COINS] - decimals: uint256[MAX_COINS] - underlying_decimals: uint256[MAX_COINS] - lp_token: address - A: uint256 - fee: uint256 event CommitAdmins: ownership_admin: address @@ -64,9 +49,12 @@ event ApplyAdmins: parameter_admin: address emergency_admin: address -event AddBurner: - burner: address +event SetBurner: + coin: ERC20 + burner: Burner + +ETH_ADDRESS: constant(address) = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE ownership_admin: public(address) parameter_admin: public(address) @@ -76,11 +64,10 @@ future_ownership_admin: public(address) future_parameter_admin: public(address) future_emergency_admin: public(address) -burners: public(HashMap[address, address]) -burner_kill: public(bool) +burner: public(Burner) # pool -> caller -> can call `donate_admin_fees` -donate_approval: public(HashMap[address, HashMap[address, bool]]) +donate_approval: public(HashMap[Curve, HashMap[address, bool]]) @external def __init__( @@ -134,134 +121,72 @@ def apply_set_admins(): log ApplyAdmins(_o_admin, _p_admin, _e_admin) -@internal -def _set_burner(_coin: address, _burner: address): - old_burner: address = self.burners[_coin] - if _coin != 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE: - if old_burner != ZERO_ADDRESS: - # revoke approval on previous burner - response: Bytes[32] = raw_call( - _coin, - concat( - method_id("approve(address,uint256)"), - convert(old_burner, bytes32), - convert(0, bytes32), - ), - max_outsize=32, - ) - if len(response) != 0: - assert convert(response, bool) - - if _burner != ZERO_ADDRESS: - # infinite approval for current burner - response: Bytes[32] = raw_call( - _coin, - concat( - method_id("approve(address,uint256)"), - convert(_burner, bytes32), - convert(MAX_UINT256, bytes32), - ), - max_outsize=32, - ) - if len(response) != 0: - assert convert(response, bool) - - self.burners[_coin] = _burner - - log AddBurner(_burner) - - @external @nonreentrant('lock') -def set_burner(_coin: address, _burner: address): +def set_burner(_burner: Burner): """ - @notice Set burner of `_coin` to `_burner` address - @param _coin Token address @param _burner Burner contract address """ assert msg.sender == self.ownership_admin, "Access denied" - - self._set_burner(_coin, _burner) - - -@external -@nonreentrant('lock') -def set_many_burners(_coins: address[20], _burners: address[20]): - """ - @notice Set burner of `_coin` to `_burner` address - @param _coins Token address - @param _burners Burner contract address - """ - assert msg.sender == self.ownership_admin, "Access denied" - - for i in range(20): - coin: address = _coins[i] - if coin == ZERO_ADDRESS: - break - self._set_burner(coin, _burners[i]) + self.burner = _burner @external @nonreentrant('lock') -def withdraw_admin_fees(_pool: address): +def withdraw_admin_fees(_pool: Curve): """ @notice Withdraw admin fees from `_pool` @param _pool Pool address to withdraw admin fees from """ - Curve(_pool).claim_admin_fees() + _pool.claim_admin_fees() @external @nonreentrant('lock') -def withdraw_many(_pools: address[20]): +def withdraw_many(_pools: Curve[20]): """ @notice Withdraw admin fees from multiple pools @param _pools List of pool address to withdraw admin fees from """ for pool in _pools: - if pool == ZERO_ADDRESS: + if pool == empty(Curve): break - Curve(pool).claim_admin_fees() + pool.claim_admin_fees() + + +@internal +def _burn(_coin: ERC20): + burner: Burner = self.burner + value: uint256 = 0 + if _coin.address == ETH_ADDRESS: + value = self.balance + elif _coin.allowance(self, burner.address) < max_value(uint256) / 2: + assert _coin.approve(burner.address, max_value(uint256), default_return_value=True) + + burner.burn(_coin, value=value) # dev: should implement burn() @external @nonreentrant('burn') -def burn(_coin: address): +def burn(_coin: ERC20): """ @notice Burn accrued `_coin` via a preset burner - @dev Only callable by an EOA to prevent flashloan exploits @param _coin Coin address """ - assert tx.origin == msg.sender - assert not self.burner_kill - - _value: uint256 = 0 - if _coin == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE: - _value = self.balance - - Burner(self.burners[_coin]).burn(_coin, value=_value) # dev: should implement burn() + self._burn(_coin) @external @nonreentrant('burn') -def burn_many(_coins: address[20]): +def burn_many(_coins: ERC20[20]): """ @notice Burn accrued admin fees from multiple coins - @dev Only callable by an EOA to prevent flashloan exploits @param _coins List of coin addresses """ - assert tx.origin == msg.sender - assert not self.burner_kill - for coin in _coins: - if coin == ZERO_ADDRESS: + if coin == empty(ERC20): break - - _value: uint256 = 0 - if coin == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE: - _value = self.balance - - Burner(self.burners[coin]).burn(coin, value=_value) # dev: should implement burn() + self._burn(coin) @external @@ -286,68 +211,58 @@ def unkill_me(_pool: address): Curve(_pool).unkill_me() -@external -def set_burner_kill(_is_killed: bool): - """ - @notice Kill or unkill `burn` functionality - @param _is_killed Burner kill status - """ - assert msg.sender == self.emergency_admin or msg.sender == self.ownership_admin, "Access denied" - self.burner_kill = _is_killed - - @external @nonreentrant('lock') -def commit_transfer_ownership(_pool: address, new_owner: address): +def commit_transfer_ownership(_pool: Curve, new_owner: address): """ @notice Transfer ownership for `_pool` pool to `new_owner` address @param _pool Pool which ownership is to be transferred @param new_owner New pool owner address """ assert msg.sender == self.ownership_admin, "Access denied" - Curve(_pool).commit_transfer_ownership(new_owner) + _pool.commit_transfer_ownership(new_owner) @external @nonreentrant('lock') -def apply_transfer_ownership(_pool: address): +def apply_transfer_ownership(_pool: Curve): """ @notice Apply transferring ownership of `_pool` @param _pool Pool address """ - Curve(_pool).apply_transfer_ownership() + _pool.apply_transfer_ownership() @external @nonreentrant('lock') -def accept_transfer_ownership(_pool: address): +def accept_transfer_ownership(_pool: Curve): """ @notice Apply transferring ownership of `_pool` @param _pool Pool address """ - Curve(_pool).accept_transfer_ownership() + _pool.accept_transfer_ownership() @external @nonreentrant('lock') -def revert_transfer_ownership(_pool: address): +def revert_transfer_ownership(_pool: Curve): """ @notice Revert commited transferring ownership for `_pool` @param _pool Pool address """ assert msg.sender in [self.ownership_admin, self.emergency_admin], "Access denied" - Curve(_pool).revert_transfer_ownership() + _pool.revert_transfer_ownership() @external @nonreentrant('lock') def commit_new_parameters( - _pool: address, + _pool: Curve, _new_mid_fee: uint256, _new_out_fee: uint256, _new_admin_fee: uint256, _new_fee_gamma: uint256, - _new_price_threshold: uint256, + _new_allowed_extra_profit: uint256, _new_adjustment_step: uint256, _new_ma_half_time: uint256, ): @@ -358,17 +273,17 @@ def commit_new_parameters( @param _new_out_fee New out fee, greater than MIN_FEE and less than MAX_FEE @param _new_admin_fee New admin fee, less than MAX_ADMIN_FEE @param _new_fee_gamma New fee gamma, within the bounds of [1, 2**100] - @param _new_price_threshold New price threshold, greater than `_new_mid_fee` - @param _new_adjustment_step New adjustment step, less than `_new_price_threshold` + @param _new_allowed_extra_profit New allowed extra profit + @param _new_adjustment_step New adjustment step @param _new_ma_half_time New MA half time, less than 7 days """ assert msg.sender == self.parameter_admin, "Access denied" - Curve(_pool).commit_new_parameters( + _pool.commit_new_parameters( _new_mid_fee, _new_out_fee, _new_admin_fee, _new_fee_gamma, - _new_price_threshold, + _new_allowed_extra_profit, _new_adjustment_step, _new_ma_half_time ) # dev: if implemented by the pool @@ -376,30 +291,30 @@ def commit_new_parameters( @external @nonreentrant('lock') -def apply_new_parameters(_pool: address): +def apply_new_parameters(_pool: Curve): """ @notice Apply new parameters for `_pool` pool @dev Only callable by an EOA @param _pool Pool address """ assert msg.sender == tx.origin - Curve(_pool).apply_new_parameters() # dev: if implemented by the pool + _pool.apply_new_parameters() # dev: if implemented by the pool @external @nonreentrant('lock') -def revert_new_parameters(_pool: address): +def revert_new_parameters(_pool: Curve): """ - @notice Revert comitted new parameters for `_pool` pool + @notice Revert committed new parameters for `_pool` pool @param _pool Pool address """ assert msg.sender in [self.ownership_admin, self.parameter_admin, self.emergency_admin], "Access denied" - Curve(_pool).revert_new_parameters() # dev: if implemented by the pool + _pool.revert_new_parameters() # dev: if implemented by the pool @external @nonreentrant('lock') -def ramp_A_gamma(_pool: address, _future_A: uint256, _future_gamma: uint256, _future_time: uint256): +def ramp_A_gamma(_pool: Curve, _future_A: uint256, _future_gamma: uint256, _future_time: uint256): """ @notice Start gradually increasing A and gamma of `_pool` reaching `_future_A` and `_future_gamma` at `_future_time` time @param _pool Pool address @@ -407,38 +322,48 @@ def ramp_A_gamma(_pool: address, _future_A: uint256, _future_gamma: uint256, _fu @param _future_time Future time """ assert msg.sender == self.parameter_admin, "Access denied" - Curve(_pool).ramp_A_gamma(_future_A, _future_gamma, _future_time) + _pool.ramp_A_gamma(_future_A, _future_gamma, _future_time) @external @nonreentrant('lock') -def stop_ramp_A_gamma(_pool: address): +def stop_ramp_A_gamma(_pool: Curve): """ @notice Stop gradually increasing A and gamma of `_pool` @param _pool Pool address """ assert msg.sender in [self.parameter_admin, self.emergency_admin], "Access denied" - Curve(_pool).stop_ramp_A_gamma() + _pool.stop_ramp_A_gamma() + + +@external +def set_admin_fee_receiver(_pool: Curve, _admin_fee_receiver: address): + """ + @param _pool Pool address + @param _admin_fee_receiver Contract receiving admin fees + """ + assert msg.sender == self.ownership_admin, "Access denied" + _pool.set_admin_fee_receiver(_admin_fee_receiver) @external @nonreentrant('lock') -def set_aave_referral(_pool: address, referral_code: uint256): +def set_aave_referral(_pool: Curve, referral_code: uint256): """ - @notice Set Aave referral for undelying tokens of `_pool` to `referral_code` + @notice Set Aave referral for underlying tokens of `_pool` to `referral_code` @param _pool Pool address @param referral_code Aave referral code """ assert msg.sender == self.ownership_admin, "Access denied" - Curve(_pool).set_aave_referral(referral_code) # dev: if implemented by the pool + _pool.set_aave_referral(referral_code) # dev: if implemented by the pool @external -def set_donate_approval(_pool: address, _caller: address, _is_approved: bool): +def set_donate_approval(_pool: Curve, _caller: address, _is_approved: bool): """ @notice Set approval of `_caller` to donate admin fees for `_pool` @param _pool Pool address - @param _caller Adddress to set approval for + @param _caller Address to set approval for @param _is_approved Approval status """ assert msg.sender == self.ownership_admin, "Access denied" @@ -448,7 +373,7 @@ def set_donate_approval(_pool: address, _caller: address, _is_approved: bool): @external @nonreentrant('lock') -def donate_admin_fees(_pool: address): +def donate_admin_fees(_pool: Curve): """ @notice Donate admin fees of `_pool` pool @param _pool Pool address @@ -456,4 +381,4 @@ def donate_admin_fees(_pool: address): if msg.sender != self.ownership_admin: assert self.donate_approval[_pool][msg.sender], "Access denied" - Curve(_pool).donate_admin_fees() # dev: if implemented by the pool + _pool.donate_admin_fees() # dev: if implemented by the pool