-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
AlbertoCentonze
Author
Contributor
|
||
# 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 | ||
|
@@ -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. | ||
|
@@ -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.
Sorry, something went wrong.
michwill
Contributor
|
||
): | ||
|
||
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 | ||
|
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?