@@ -206,6 +206,7 @@ balances: public(uint256[N_COINS])
206206D: public (uint256 )
207207xcp_profit: public (uint256 )
208208xcp_profit_a: public (uint256 ) # <--- Full profit at last claim of admin fees.
209+ admin_claimed_profit: public (uint256 ) # Cumulative admin extraction from LP+DAO bucket, in vp units.
209210
210211virtual_price: public (uint256 ) # <------ Cached (fast to read) virtual price.
211212# The cached `virtual_price` is also used internally.
@@ -680,6 +681,7 @@ def add_liquidity(
680681 self .virtual_price = 10 ** 18
681682 self .xcp_profit = 10 ** 18
682683 self .xcp_profit_a = 10 ** 18
684+ self .admin_claimed_profit = 0
683685
684686 self .mint (receiver, d_token)
685687 assert d_token >= min_mint_amount, "slippage "
@@ -1152,9 +1154,21 @@ def tweak_price(
11521154 # 1. xcp_profit grows after virtual price, total growth since launch = (xcp_profit − 1)
11531155 # 2. We reserve lp_profit_fraction of the growth for LPs and admin, rest is used to rebalance the pool
11541156
1155- # Rebalancing condition transformation:
1156- # virtual_price > 1 + (xcp_profit - 1) * lp_profit_fraction
1157- threshold_vp: uint256 = PRECISION + (max (xcp_profit, PRECISION) - PRECISION) * self .lp_profit_fraction // FEE_PRECISION
1157+ # Rebalancing condition basis:
1158+ # virtual_price > 1 + (xcp_profit - 1) * lp_profit_fraction - admin_claimed_profit
1159+ # | pre_admin_threshold_vp |
1160+ # Interpretation:
1161+ # 1. xcp_profit - 1 is total gross profit growth above baseline.
1162+ # 2. Multiplying by lp_profit_fraction keeps only the LP+DAO retained share.
1163+ # 3. admin_claimed_profit subtracts what the admin has already extracted from that bucket.
1164+ # 4. The threshold is floored at PRECISION.
1165+ pre_admin_threshold_vp: uint256 = PRECISION + (
1166+ unsafe_sub (max (xcp_profit, PRECISION), PRECISION) * self .lp_profit_fraction // FEE_PRECISION
1167+ )
1168+ threshold_vp: uint256 = max (
1169+ PRECISION,
1170+ pre_admin_threshold_vp - min (self .admin_claimed_profit, pre_admin_threshold_vp),
1171+ )
11581172 # user_supply < total_supply => vp_boosted > virtual_price
11591173 # by not accounting for donation shares, virtual_price is boosted leading to rebalance trigger
11601174 # this is approximate condition that preliminary indicates readiness for rebalancing
@@ -1370,34 +1384,22 @@ def _claim_admin_fees():
13701384 )
13711385
13721386 if fees > 0 :
1373- # -------------------- Recalculate virtual price and xcp_profit --- -------
1387+ # ---------------- Recalculate virtual price and admin claim offset -------
13741388 # We withdraw token balances without touching LP shares, so virtual price goes down.
13751389 updated_vprice: uint256 = current_vprice - fees
13761390 # Do not claim fees if doing so causes virtual price to drop below 10**18.
13771391 if updated_vprice < 10 ** 18 :
13781392 return
1379- # To maintain rebalancing condition vp' > 1 + (xcp_profit' - 1)*lpf:
1380- # (i.e. not to affect rebalancing invariant)
1381- # at the boundary:
1382- # vp - f = 1 + (xcp_profit - 1)*lpf - f
1383- # vp - f = 1 + (xcp_profit - 1 - f/lpf)*lpf
1384- # => xcp_profit' := xcp_profit - f / lpf
1385- xcp_profit -= fees * FEE_PRECISION // lp_profit_fraction # (fees>0 => lpf>0)
1386-
1387- # Another way to see this is to track total_admin_claimed (sum_i(fees)), the cumulative amount
1388- # extracted from the LP+DAO bucket, and compare virtual_price against
1389- # 1 + (xcp_profit - 1) * lpf - total_admin_claimed instead.
1390- # This alternative model would keep xcp_profit strictly increasing.
1391- # Instead we fold claimed profit directly into xcp_profit here.
1392-
1393- # xcp_profit as raw value is thus shouldn't be used in integrations!
1393+ # Keep xcp_profit as the gross profit signal and track claimed admin
1394+ # extraction separately in the same virtual-price units as `fees`.
1395+ # Rebalancing thresholding then compares virtual_price against:
1396+ # 1 + (xcp_profit - 1) * lpf - admin_claimed_profit
1397+ self .admin_claimed_profit += fees
13941398
13951399 # ---------------------------- Update State ------------------------------
13961400 self .virtual_price = updated_vprice
1397- self .xcp_profit = xcp_profit
13981401 self .last_admin_fee_claim_timestamp = block .timestamp
1399- if xcp_profit > xcp_profit_a:
1400- self .xcp_profit_a = xcp_profit # <-------- Cache last claimed profit.
1402+ self .xcp_profit_a = xcp_profit # <-------- Cache last claimed gross profit.
14011403
14021404 # Adjust D after admin removes liquidity
14031405 # no _get_D() because we can't claim during ramping
0 commit comments