diff --git a/contracts/main/CurveTwocryptoOptimized.vy b/contracts/main/CurveTwocryptoOptimized.vy index 149cbdf6..1cba540e 100644 --- a/contracts/main/CurveTwocryptoOptimized.vy +++ b/contracts/main/CurveTwocryptoOptimized.vy @@ -100,7 +100,6 @@ event NewParameters: allowed_extra_profit: uint256 adjustment_step: uint256 ma_time: uint256 - xcp_ma_time: uint256 event RampAgamma: initial_A: uint256 @@ -132,12 +131,9 @@ factory: public(immutable(Factory)) cached_price_scale: uint256 # <------------------------ Internal price scale. cached_price_oracle: uint256 # <------- Price target given by moving average. -cached_xcp_oracle: uint256 # <----------- EMA of totalSupply * virtual_price. last_prices: public(uint256) last_timestamp: public(uint256) # idx 0 is for prices, idx 1 is for xcp. -last_xcp: public(uint256) -xcp_ma_time: public(uint256) initial_A_gamma: public(uint256) initial_A_gamma_time: public(uint256) @@ -258,9 +254,8 @@ def __init__( self.cached_price_scale = initial_price self.cached_price_oracle = initial_price self.last_prices = initial_price - self.last_timestamp = self._pack_2(block.timestamp, block.timestamp) + self.last_timestamp = block.timestamp self.xcp_profit_a = 10**18 - self.xcp_ma_time = 62324 # <--------- 12 hours default on contract start. # Cache DOMAIN_SEPARATOR. If chain.id is not CACHED_CHAIN_ID, then # DOMAIN_SEPARATOR will be re-calculated each time `permit` is called. @@ -558,9 +553,6 @@ def add_liquidity( self.xcp_profit = 10**18 self.xcp_profit_a = 10**18 - # Initialise xcp oracle here: - self.cached_xcp_oracle = d_token # <--- virtual_price * totalSupply / 10**18 - self.mint(receiver, d_token) assert d_token >= min_mint_amount, "Slippage" @@ -641,38 +633,6 @@ def remove_liquidity( log RemoveLiquidity(msg.sender, withdraw_amounts, total_supply - _amount) - # --------------------------- Upkeep xcp oracle -------------------------- - - # Update xcp since liquidity was removed: - xp: uint256[N_COINS] = self.xp(self.balances, self.cached_price_scale) - last_xcp: uint256 = isqrt(xp[0] * xp[1]) # <----------- Cache it for now. - - last_timestamp: uint256[2] = self._unpack_2(self.last_timestamp) - if last_timestamp[1] < block.timestamp: - - cached_xcp_oracle: uint256 = self.cached_xcp_oracle - alpha: uint256 = MATH.wad_exp( - -convert( - unsafe_div( - unsafe_sub(block.timestamp, last_timestamp[1]) * 10**18, - self.xcp_ma_time # <---------- xcp ma time has is longer. - ), - int256, - ) - ) - - self.cached_xcp_oracle = unsafe_div( - last_xcp * (10**18 - alpha) + cached_xcp_oracle * alpha, - 10**18 - ) - last_timestamp[1] = block.timestamp - - # Pack and store timestamps: - self.last_timestamp = self._pack_2(last_timestamp[0], last_timestamp[1]) - - # Store last xcp - self.last_xcp = last_xcp - return withdraw_amounts @@ -880,11 +840,11 @@ def tweak_price( old_xcp_profit: uint256 = self.xcp_profit old_virtual_price: uint256 = self.virtual_price - # ----------------------- Update Oracles if needed ----------------------- + # ------------------ Update Price Oracle if needed ----------------------- - last_timestamp: uint256[2] = self._unpack_2(self.last_timestamp) + last_timestamp: uint256 = self.last_timestamp alpha: uint256 = 0 - if last_timestamp[0] < block.timestamp: # 0th index is for price_oracle. + if last_timestamp < block.timestamp: # 0th index is for price_oracle. # The moving average price oracle is calculated using the last_price # of the trade at the previous block, and the price oracle logged @@ -895,7 +855,7 @@ def tweak_price( alpha = MATH.wad_exp( -convert( unsafe_div( - unsafe_sub(block.timestamp, last_timestamp[0]) * 10**18, + unsafe_sub(block.timestamp, last_timestamp) * 10**18, rebalancing_params[2] # <----------------------- ma_time. ), int256, @@ -913,32 +873,7 @@ def tweak_price( ) self.cached_price_oracle = price_oracle - last_timestamp[0] = block.timestamp - - # ----------------------------------------------------- Update xcp oracle. - - if last_timestamp[1] < block.timestamp: - - cached_xcp_oracle: uint256 = self.cached_xcp_oracle - alpha = MATH.wad_exp( - -convert( - unsafe_div( - unsafe_sub(block.timestamp, last_timestamp[1]) * 10**18, - self.xcp_ma_time # <---------- xcp ma time has is longer. - ), - int256, - ) - ) - - self.cached_xcp_oracle = unsafe_div( - self.last_xcp * (10**18 - alpha) + cached_xcp_oracle * alpha, - 10**18 - ) - - # Pack and store timestamps: - last_timestamp[1] = block.timestamp - - self.last_timestamp = self._pack_2(last_timestamp[0], last_timestamp[1]) + self.last_timestamp = block.timestamp # `price_oracle` is used further on to calculate its vector distance from # price_scale. This distance is used to calculate the amount of adjustment @@ -985,10 +920,6 @@ def tweak_price( # this usually reverts when withdrawing a very small amount of LP tokens assert virtual_price > old_virtual_price # dev: virtual price decreased - # -------------------------- Cache last_xcp -------------------------- - - self.last_xcp = xcp # geometric_mean(D * price_scale) - self.xcp_profit = xcp_profit # ------------ Rebalance liquidity if there's enough profits to adjust it: @@ -1532,7 +1463,7 @@ def internal_price_oracle() -> uint256: """ price_oracle: uint256 = self.cached_price_oracle price_scale: uint256 = self.cached_price_scale - last_prices_timestamp: uint256 = self._unpack_2(self.last_timestamp)[0] + last_prices_timestamp: uint256 = self.last_timestamp if last_prices_timestamp < block.timestamp: # <------------ Update moving # average if needed. @@ -1663,41 +1594,6 @@ def price_oracle() -> uint256: return self.internal_price_oracle() -@external -@view -@nonreentrant("lock") -def xcp_oracle() -> uint256: - """ - @notice Returns the oracle value for xcp. - @dev The oracle is an exponential moving average, with a periodicity - determined by `self.xcp_ma_time`. - `TVL` is xcp, calculated as either: - 1. virtual_price * total_supply, OR - 2. self.get_xcp(...), OR - 3. MATH.geometric_mean(xp) - @return uint256 Oracle value of xcp. - """ - - last_prices_timestamp: uint256 = self._unpack_2(self.last_timestamp)[1] - cached_xcp_oracle: uint256 = self.cached_xcp_oracle - - if last_prices_timestamp < block.timestamp: - - alpha: uint256 = MATH.wad_exp( - -convert( - unsafe_div( - unsafe_sub(block.timestamp, last_prices_timestamp) * 10**18, - self.xcp_ma_time - ), - int256, - ) - ) - - return (self.last_xcp * (10**18 - alpha) + cached_xcp_oracle * alpha) / 10**18 - - return cached_xcp_oracle - - @external @view @nonreentrant("lock") @@ -1953,7 +1849,6 @@ def apply_new_parameters( _new_allowed_extra_profit: uint256, _new_adjustment_step: uint256, _new_ma_time: uint256, - _new_xcp_ma_time: uint256, ): """ @notice Commit new parameters. @@ -1964,7 +1859,6 @@ def apply_new_parameters( @param _new_allowed_extra_profit The new allowed extra profit. @param _new_adjustment_step The new adjustment step. @param _new_ma_time The new ma time. ma_time is time_in_seconds/ln(2). - @param _new_xcp_ma_time The new ma time for xcp oracle. """ assert msg.sender == factory.admin() # dev: only owner @@ -2015,14 +1909,6 @@ def apply_new_parameters( [new_allowed_extra_profit, new_adjustment_step, new_ma_time] ) - # Set xcp oracle moving average window time: - new_xcp_ma_time: uint256 = _new_xcp_ma_time - if new_xcp_ma_time < 872542: - assert new_xcp_ma_time > 86 # dev: xcp MA time should be longer than 60/ln(2) - else: - new_xcp_ma_time = self.xcp_ma_time - self.xcp_ma_time = new_xcp_ma_time - # ---------------------------------- LOG --------------------------------- log NewParameters( @@ -2032,5 +1918,4 @@ def apply_new_parameters( new_allowed_extra_profit, new_adjustment_step, new_ma_time, - _new_xcp_ma_time, ) diff --git a/tests/unitary/pool/test_oracles.py b/tests/unitary/pool/test_oracles.py index 672694af..53485552 100644 --- a/tests/unitary/pool/test_oracles.py +++ b/tests/unitary/pool/test_oracles.py @@ -85,58 +85,6 @@ def test_ma(swap_with_deposit, coins, user, amount, i, t): assert abs(log2(theory / prices3)) < 0.001 -@given( - amount=strategy( - "uint256", min_value=10**10, max_value=2 * 10**6 * 10**18 - ), # Can be more than we have - i=strategy("uint8", min_value=0, max_value=1), - t=strategy("uint256", min_value=10, max_value=10 * UNIX_DAY), -) -@settings(**SETTINGS) -def test_xcp_ma(swap_with_deposit, coins, user, amount, i, t): - - price_scale = swap_with_deposit.price_scale() - D0 = swap_with_deposit.D() - xp = [0, 0] - xp[0] = D0 // 2 # N_COINS = 2 - xp[1] = D0 * 10**18 // (2 * price_scale) - - xcp0 = boa.eval(f"isqrt({xp[0]*xp[1]})") - - # after first deposit anf before any swaps: - # xcp oracle is equal to totalSupply - assert xcp0 == swap_with_deposit.totalSupply() - - amount = amount * 10**18 // INITIAL_PRICES[i] - mint_for_testing(coins[i], user, amount) - - ma_time = swap_with_deposit.xcp_ma_time() - - # swap to populate - with boa.env.prank(user): - swap_with_deposit.exchange(i, 1 - i, amount, 0) - - xcp1 = swap_with_deposit.last_xcp() - tvl = ( - swap_with_deposit.virtual_price() - * swap_with_deposit.totalSupply() - // 10**18 - ) - assert approx(xcp1, tvl, 1e-10) - - boa.env.time_travel(t) - - with boa.env.prank(user): - swap_with_deposit.remove_liquidity_one_coin(10**15, 0, 0) - - xcp2 = swap_with_deposit.xcp_oracle() - - alpha = exp(-1 * t / ma_time) - theory = xcp0 * alpha + xcp1 * (1 - alpha) - - assert approx(theory, xcp2, 1e-10) - - # Sanity check for price scale @given( amount=strategy(