Skip to content

Commit

Permalink
refactor: rebalance logic to helper function
Browse files Browse the repository at this point in the history
This commit moves the logic that was previously applied whenever `can_rebalance` was set to `True` to a separate helper function to improve code readability and maintainability.

Also `rebalance_reserves` was renamed to `D_rebalance` to reduce cognitive complexity.
  • Loading branch information
AlbertoCentonze committed Jun 19, 2024
1 parent 5776987 commit 317ea87
Showing 1 changed file with 59 additions and 52 deletions.
111 changes: 59 additions & 52 deletions contracts/main/CurveTwocrypto.vy
Original file line number Diff line number Diff line change
Expand Up @@ -869,7 +869,7 @@ def tweak_price(
A_gamma: uint256[2],
_xp: uint256[N_COINS],
D_before_rebalance: uint256,
D_rebalance_fee: uint256 = 0
dD_rebalance: uint256 = 0
) -> uint256:
"""
@notice Updates price_oracle, last_price and conditionally adjusts
Expand All @@ -879,8 +879,9 @@ def tweak_price(
@dev Contains main liquidity rebalancing logic, by tweaking `price_scale`.
@param A_gamma Array of A and gamma parameters.
@param _xp Array of current balances.
@param D_before_rebalance Value of D computed by the caller method, without
taking into account whether the pool should be rebalanced.
@param D_before_rebalance New value of D computed by the caller method, without
taking into account future pool rebalances (if any).
@param dD_rebalance Variation of D allocated to the rebalance operation.
"""

# ---------------------------- Read storage ------------------------------
Expand All @@ -896,13 +897,13 @@ def tweak_price(
old_virtual_price: uint256 = self.virtual_price

# We cache the rebalancing reserves to avoid recalculating them. We add
# D_rebalance_fee to D_rebalance to account for fees that the pool earned
# dD_rebalance to D_rebalance to account for fees that the pool earned
# while saving an SSTORE instead of increasing self.D_rebalance directly.
rebalance_reserves: uint256 = self.D_rebalance + D_rebalance_fee
D_rebalance: uint256 = self.D_rebalance + dD_rebalance

# This will be used later to compute whether the ratio between donations and
# total D is big enough to allow for a rebalance.
D_total_before_rebalance: uint256 = D_before_rebalance + rebalance_reserves
D_total_before_rebalance: uint256 = D_before_rebalance + D_rebalance

# ------------------ Update Price Oracle if needed -----------------------

Expand Down Expand Up @@ -984,7 +985,7 @@ def tweak_price(
self.profit = profit

# We check whether D / (D + D_rebalance) is big enough to attempt a rebalance.
if (rebalance_reserves * 10**18 / D_total_before_rebalance) > 10**15:
if (D_rebalance * 10**18 / D_total_before_rebalance) > 10**15:

# ------------------- Get adjustment step ----------------------------

Expand Down Expand Up @@ -1046,12 +1047,18 @@ def tweak_price(
# We compute the loss "delta D" made by the rebalance.
dD = D_total_before_rebalance - D_total

# if the rebalancing reserves can cover the loss, we use them.
# Otherwise, we don't rebalance.
if (rebalance_reserves >= dD):
rebalance_reserves -= dD
# if the rebalancing reserves can cover the loss, we use them
# and we update the liquidity.
if (D_rebalance >= dD):
self._update_liquidity(
D_total,
# We decrease the rebalancing reserves with the loss.
D_rebalance - dD,
new_price_scale,
total_supply
)

can_rebalance = True
return new_price_scale

# if the old D_total is less than the new D_total, it means that
# the pool has gained value. This can happen when the oracle price goes
Expand All @@ -1062,46 +1069,19 @@ def tweak_price(
# We compute the profit "delta D" made by the rebalance.
dD = D_total - D_total_before_rebalance

# We increase the rebalancing reserves with the profit to be
# used for future rebalances.
rebalance_reserves += dD

# If rebalancing leads to profit, doing it is a no brainer
# as it improves the pool competitiveness.
can_rebalance = True

# TODO handle case where D_total == old_D_total

if can_rebalance:

# Just `D` represents the value of the user deposits.
D: uint256 = D_total - rebalance_reserves

# We store the new D value in the pool. This updates liquidity
# if there was any withdrawal or deposit and locks in the profit
# made by LPs (if any).
self.D = D

# We update D_rebalance with the new rebalancing reserves.
# This takes into account both dD change due to rebalance and
# any fee that was token because of `exchange`, `add_liquidity`
# or `remove_liquidity_one_coin`.
self.D_rebalance = rebalance_reserves

# This is the key to the rebalancing mechanism. We store the
# new price scale effectively changing the slope of the curve.
self.cached_price_scale = new_price_scale

# Virtual price is calculated taking into account **only** the
# user deposits. This way donations can't be used to inflate
# the virtual price.
self.virtual_price = unsafe_div(
10**18 * self.get_xcp(D, new_price_scale), total_supply
# If rebalancing leads to profit, updating liquidity is a
# no brainer as it improves the pool competitiveness.
self._update_liquidity(
D_total,
# We increase the rebalancing reserves with the profit to be
# used for future rebalances.
D_rebalance + dD,
new_price_scale,
total_supply
)

return new_price_scale


# If we end up not rebalancing because the pool doesn't have enough
# funds in D_rebalance, we still need to update the state to reflect
# the changes in the pool because of `exchange`, `add_liquidity` or
Expand All @@ -1112,13 +1092,40 @@ def tweak_price(
self.D = D_before_rebalance
self.virtual_price = virtual_price

# * We update the rebalancing reserves to reflect the fees allocated for
# rebalancing that were collected by the pool (rebalancing_reserves =
# self.D_rebalance + D_rebalance_fee).
self.D_rebalance = rebalance_reserves
# * We increase the rebalancing reserves to reflect the fees allocated for
# rebalancing that were collected by the pool because D_rebalance =
# self.D_rebalance + dD_rebalance.
self.D_rebalance = D_rebalance

return price_scale

@internal
def _update_liquidity(D_total: uint256, D_rebalance: uint256, price_scale: uint256, total_supply: uint256):
# Just `D` represents the value of the user deposits.
D: uint256 = D_total - D_rebalance

# We store the new D value in the pool. This updates liquidity
# if there was any withdrawal or deposit and locks in the profit
# made by LPs (if any).
self.D = D

# We update D_rebalance with the new rebalancing reserves.
# This takes into account both dD change due to rebalance and
# any fee that was token because of `exchange`, `add_liquidity`
# or `remove_liquidity_one_coin`.
self.D_rebalance = D_rebalance

# This is the key to the rebalancing mechanism. We store the
# new price scale effectively changing the slope of the curve.
self.cached_price_scale = price_scale

# Virtual price is calculated taking into account **only** the
# user deposits. This way donations can't be used to inflate
# the virtual price.
self.virtual_price = unsafe_div(
10**18 * self.get_xcp(D, price_scale), total_supply
)


@internal
def _claim_admin_fees():
Expand Down

0 comments on commit 317ea87

Please sign in to comment.