Skip to content

Commit

Permalink
remove xcp_oracle
Browse files Browse the repository at this point in the history
  • Loading branch information
bout3fiddy committed May 22, 2024
1 parent 340d947 commit 911dd18
Show file tree
Hide file tree
Showing 2 changed files with 7 additions and 174 deletions.
129 changes: 7 additions & 122 deletions contracts/main/CurveTwocryptoOptimized.vy
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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


Expand Down Expand Up @@ -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
Expand All @@ -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,
Expand All @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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.
Expand All @@ -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

Expand Down Expand Up @@ -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(
Expand All @@ -2032,5 +1918,4 @@ def apply_new_parameters(
new_allowed_extra_profit,
new_adjustment_step,
new_ma_time,
_new_xcp_ma_time,
)
52 changes: 0 additions & 52 deletions tests/unitary/pool/test_oracles.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down

0 comments on commit 911dd18

Please sign in to comment.