Skip to content

Commit

Permalink
Update CurveTwocryptoOptimized.vy
Browse files Browse the repository at this point in the history
  • Loading branch information
AlbertoCentonze committed Dec 6, 2024
1 parent 369aade commit 6aeac34
Showing 1 changed file with 53 additions and 7 deletions.
60 changes: 53 additions & 7 deletions contracts/main/CurveTwocryptoOptimized.vy
Original file line number Diff line number Diff line change
Expand Up @@ -808,13 +808,49 @@ def _exchange(

return [dy, fee, price_scale]

@external
@nonreentrant("lock")
def donate(amounts: uint256[N_COINS], expect_up: bool) -> uint256:
# TODO maybe add a donation timelock (one donation per block, every hour) and a donation cap (5% of the liquidity?)

amounts_received: uint256[N_COINS] = empty(uint256[N_COINS])
balances: uint256[N_COINS] = self.balances

for i in range(N_COINS):
if amounts[i] > 0:
amounts_received[i] = self._transfer_in(
i,
amounts[i],
msg.sender,
False,
)
balances[i] += amounts_received[i]

price_scale: uint256 = self.cached_price_scale
xp: uint256[N_COINS] = self.xp(balances, price_scale)

# tweak price here is in "donation mode".
new_price_scale: uint256 = self.tweak_price(self._A_gamma(), xp, 0, 0, True)

assert new_price_scale != price_scale, "Didn't rebalance"

This comment has been minimized.

Copy link
@bout3fiddy

bout3fiddy Dec 16, 2024

Collaborator

I'm wondering if this one would get triggered too frequently. Do you think it makes sense to have some sort of a 'def tweak_price_view' method that returns a new price scale but does not change state, so we can check if the price scale changes with the donated amounts (new xp) and only if it changes, we do _transfer_in and then commit the tweak_price changes?

This comment has been minimized.

Copy link
@AlbertoCentonze

AlbertoCentonze Dec 16, 2024

Author Contributor

I've been thinking about this for a while, strong opinion loosely held but I would rather avoid complexifying the AMM with something that is an edge case that can be checked offchain. You can just figure out the right amounts offchain by simulating txs till you find the right amount that doesn't revert (we can abstract this in the frontend).

Wdyt @bout3fiddy ?

# TODO extra safety checks, maybe remove in prod?
if expect_up:
assert price_scale > new_price_scale, "Didn't rebalance upwards"
else:
assert price_scale < new_price_scale, "Didn't rebalance downwards"
# TODO add event log
return new_price_scale
@internal
def tweak_price(
A_gamma: uint256[2],
_xp: uint256[N_COINS],
new_D: uint256,
K0_prev: uint256 = 0,
donation: bool = False,
) -> uint256:
"""
@notice Updates price_oracle, last_price and conditionally adjusts
Expand Down Expand Up @@ -949,11 +985,20 @@ def tweak_price(
# ------------------------------------- Calculate new price scale.
p_new: uint256 = unsafe_div(
price_scale * unsafe_sub(norm, adjustment_step) +
adjustment_step * price_oracle,
norm
) # <---- norm is non-zero and gt adjustment_step; unsafe = safe.
p_new: uint256 = 0
if donation:
# TODO this might be too expensive in some cases
# when donating we don't want to move at once to the oracle price
# setting the adjustement step to 0 in the formula above simplifies
# to this:
p_new = price_oracle
else:
p_new = unsafe_div(
price_scale * unsafe_sub(norm, adjustment_step) +
adjustment_step * price_oracle,
norm
) # <---- norm is non-zero and gt adjustment_step; unsafe = safe.
# ---------------- Update stale xp (using price_scale) with p_new.
Expand All @@ -980,9 +1025,10 @@ def tweak_price(
# ---------------------------- Proceed if we've got enough profit.
if (
old_virtual_price > 10**18 and
2 * old_virtual_price - 10**18 > xcp_profit
(2 * old_virtual_price - 10**18 > xcp_profit) or (
donation and old_virtual_price >= xcp_profit) # donation is fully used

This comment has been minimized.

Copy link
@michwill

michwill Dec 15, 2024

Contributor

Uhm. What if donation is really really small? Will it be forbidden?

This comment has been minimized.

Copy link
@AlbertoCentonze

AlbertoCentonze Dec 15, 2024

Author Contributor

The donation function is built under the assumption that rebalancing must occur otherwise the function will revert. This is to prevent donated funds from being stolen or wasted. This line in my head reads as "After a donation xcp_profit should not increase, because all donated funds should be consumed for rebalancing", the assertion just leaves some wiggle room so that you don't have to find a super precise amount to get the tx not to revert.

In case it wasn't clear the correct amount to donate must be computed offchain beforehand. Otherwise you want be able to get the donation to work.

This comment has been minimized.

Copy link
@AlbertoCentonze

AlbertoCentonze Dec 15, 2024

Author Contributor

What if donation is really really small?

If the donation is really small it will "just work" as the assertion will pass. Maybe I'm missing the point you were trying to make here?

):

assert xcp_profit - old_xcp_profit < 10**15, "donation shouldn't increase the profit"
self.D = D
self.virtual_price = old_virtual_price
self.cached_price_scale = p_new
Expand Down

0 comments on commit 6aeac34

Please sign in to comment.