Skip to content

Commit

Permalink
claim admin virtual balances as well
Browse files Browse the repository at this point in the history
  • Loading branch information
bout3fiddy committed Nov 1, 2023
1 parent 3c3e29a commit 4d76e11
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 34 deletions.
12 changes: 10 additions & 2 deletions contracts/main/CurveTwocryptoOptimized.vy
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ NOISE_FEE: constant(uint256) = 10**5 # <---------------------------- 0.1 BPS.
# ----------------------- Admin params ---------------------------------------

last_admin_fee_claim_timestamp: uint256
admin_lp_virtual_balance: uint256

MIN_RAMP_TIME: constant(uint256) = 86400
MIN_ADMIN_FEE_CLAIM_INTERVAL: constant(uint256) = 86400
Expand Down Expand Up @@ -698,6 +699,7 @@ def add_liquidity(
d_token -= d_token_fee
token_supply += d_token
self.mint(receiver, d_token)
self.admin_lp_virtual_balance += d_token_fee

price_scale = self.tweak_price(A_gamma, xp, D, 0)

Expand Down Expand Up @@ -1269,13 +1271,16 @@ def _claim_admin_fees():

# ------------------------------ Claim admin fees by minting admin's share
# of the pool in LP tokens.
admin_share: uint256 = 0

# This is the admin fee tokens claimed in self.add_liquidity. We add it to
# the LP token share that the admin needs to claim:
admin_share: uint256 = self.admin_lp_virtual_balance
frac: uint256 = 0
if fee_receiver != empty(address) and fees > 0:

# -------------------------------- Calculate admin share to be minted.
frac = vprice * 10**18 / (vprice - fees) - 10**18
admin_share = current_lp_token_supply * frac / 10**18
admin_share += current_lp_token_supply * frac / 10**18

# ------ Subtract fees from profits that will be used for rebalancing.
xcp_profit -= fees * 2
Expand All @@ -1295,6 +1300,9 @@ def _claim_admin_fees():

# ---------------------------- Update State ------------------------------

# Set admin virtual LP balances to zero because we claimed:
self.admin_lp_virtual_balance = 0

self.xcp_profit = xcp_profit
self.last_admin_fee_claim_timestamp = block.timestamp

Expand Down
2 changes: 1 addition & 1 deletion contracts/mocks/ERC20Mock.vy
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,4 @@ def _mint_for_testing(_target: address, _value: uint256) -> bool:
self.balanceOf[_target] += _value
log Transfer(ZERO_ADDRESS, _target, _value)

return True
return True
82 changes: 51 additions & 31 deletions tests/unitary/pool/stateful/stateful_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
from boa.test import strategy

MAX_SAMPLES = 20
MAX_D = 10 ** 12 * 10 ** 18 # $1T is hopefully a reasonable cap for tests
MAX_D = 10**12 * 10**18 # $1T is hopefully a reasonable cap for tests
INITIAL_PRICES = [10**18, 1500 * 10**18] # price relative to coin_id = 0


class StatefulBase:
exchange_amount_in = strategy("uint256", max_value=10 ** 9 * 10 ** 18)
exchange_amount_in = strategy("uint256", max_value=10**9 * 10**18)
exchange_i = strategy("uint8", max_value=1)
sleep_time = strategy("uint256", max_value=86400 * 7)
user = strategy("address")
Expand All @@ -23,61 +23,69 @@ def setup(self, user_id=0):
self.decimals = [int(c.decimals()) for c in self.coins]
self.user_balances = {u: [0] * 2 for u in self.accounts}
self.initial_deposit = [
10 ** 4 * 10 ** (18 + d) // p
for p, d in zip([10 ** 18] + INITIAL_PRICES, self.decimals)
10**4 * 10 ** (18 + d) // p
for p, d in zip([10**18] + INITIAL_PRICES, self.decimals)
] # $10k * 2
self.initial_prices = [10 ** 18] + INITIAL_PRICES
self.initial_prices = [10**18] + INITIAL_PRICES
user = self.accounts[user_id]

for coin, q in zip(self.coins, self.initial_deposit):
coin._mint_for_testing(user, q)
coin.approve(self.swap, 2 ** 256 - 1, {"from": user})
coin.approve(self.swap, 2**256 - 1, {"from": user})

# Inf approve all, too. Not always that's the best way though
for u in self.accounts:
if u != user:
for coin in self.coins:
coin.approve(self.swap, 2 ** 256 - 1, {"from": u})
coin.approve(self.swap, 2**256 - 1, {"from": u})

# Very first deposit
self.swap.add_liquidity(self.initial_deposit, 0, {"from": user})

self.balances = self.initial_deposit[:]
self.total_supply = self.token.balanceOf(user)
self.xcp_profit = 10 ** 18
self.xcp_profit = 10**18
print(" \n ----------- INIT ----------------- ")

def convert_amounts(self, amounts):
prices = [10 ** 18] + [self.swap.price_scale()]
return [p * a // 10 ** (36 - d) for p, a, d in zip(prices, amounts, self.decimals)]
prices = [10**18] + [self.swap.price_scale()]
return [
p * a // 10 ** (36 - d)
for p, a, d in zip(prices, amounts, self.decimals)
]

def check_limits(self, amounts, D=True, y=True):
"""
Should be good if within limits, but if outside - can be either
"""
_D = self.swap.D()
prices = [10 ** 18] + [self.swap.price_scale()]
prices = [10**18] + [self.swap.price_scale()]
xp_0 = [self.swap.balances(i) for i in range(2)]
xp = xp_0
xp_0 = [x * p // 10 ** d for x, p, d in zip(xp_0, prices, self.decimals)]
xp = [(x + a) * p // 10 ** d for a, x, p, d in zip(amounts, xp, prices, self.decimals)]
xp_0 = [
x * p // 10**d for x, p, d in zip(xp_0, prices, self.decimals)
]
xp = [
(x + a) * p // 10**d
for a, x, p, d in zip(amounts, xp, prices, self.decimals)
]

if D:
for _xp in [xp_0, xp]:
if (
(min(_xp) * 10 ** 18 // max(_xp) < 10 ** 14)
or (max(_xp) < 10 ** 9 * 10 ** 18)
or (max(_xp) > 10 ** 15 * 10 ** 18)
(min(_xp) * 10**18 // max(_xp) < 10**14)
or (max(_xp) < 10**9 * 10**18)
or (max(_xp) > 10**15 * 10**18)
):
return False

if y:
for _xp in [xp_0, xp]:
if (
(_D < 10 ** 17)
or (_D > 10 ** 15 * 10 ** 18)
or (min(_xp) * 10 ** 18 // _D < 10 ** 16)
or (max(_xp) * 10 ** 18 // _D > 10 ** 20)
(_D < 10**17)
or (_D > 10**15 * 10**18)
or (min(_xp) * 10**18 // _D < 10**16)
or (max(_xp) * 10**18 // _D > 10**20)
):
return False

Expand All @@ -86,10 +94,14 @@ def check_limits(self, amounts, D=True, y=True):
def rule_exchange(self, exchange_amount_in, exchange_i, user):
return self._rule_exchange(exchange_amount_in, exchange_i, user)

def _rule_exchange(self, exchange_amount_in, exchange_i, user, check_out_amount=True):
def _rule_exchange(
self, exchange_amount_in, exchange_i, user, check_out_amount=True
):
exchange_j = 1 - exchange_i
try:
calc_amount = self.swap.get_dy(exchange_i, exchange_j, exchange_amount_in)
calc_amount = self.swap.get_dy(
exchange_i, exchange_j, exchange_amount_in
)
except Exception:
_amounts = [0] * 2
_amounts[exchange_i] = exchange_amount_in
Expand All @@ -101,7 +113,9 @@ def _rule_exchange(self, exchange_amount_in, exchange_i, user, check_out_amount=
d_balance_i = self.coins[exchange_i].balanceOf(user)
d_balance_j = self.coins[exchange_j].balanceOf(user)
try:
self.swap.exchange(exchange_i, exchange_j, exchange_amount_in, 0, {"from": user})
self.swap.exchange(
exchange_i, exchange_j, exchange_amount_in, 0, {"from": user}
)
except Exception:
# Small amounts may fail with rounding errors
if (
Expand All @@ -118,7 +132,9 @@ def _rule_exchange(self, exchange_amount_in, exchange_i, user, check_out_amount=
self.swap.get_dy(
exchange_j,
exchange_i,
10 ** 16 * 10 ** self.decimals[exchange_j] // ([10 ** 18] + INITIAL_PRICES)[exchange_j],
10**16
* 10 ** self.decimals[exchange_j]
// ([10**18] + INITIAL_PRICES)[exchange_j],
)

d_balance_i -= self.coins[exchange_i].balanceOf(user)
Expand All @@ -127,7 +143,9 @@ def _rule_exchange(self, exchange_amount_in, exchange_i, user, check_out_amount=
assert d_balance_i == exchange_amount_in
if check_out_amount:
if check_out_amount is True:
assert -d_balance_j == calc_amount, f"{-d_balance_j} vs {calc_amount}"
assert (
-d_balance_j == calc_amount
), f"{-d_balance_j} vs {calc_amount}"
else:
assert abs(d_balance_j + calc_amount) < max(
check_out_amount * calc_amount, 3
Expand Down Expand Up @@ -156,13 +174,15 @@ def invariant_virtual_price(self):
xcp_profit = self.swap.xcp_profit()
get_virtual_price = self.swap.get_virtual_price()

assert xcp_profit >= 10 ** 18 - 10
assert virtual_price >= 10 ** 18 - 10
assert get_virtual_price >= 10 ** 18 - 10
assert xcp_profit >= 10**18 - 10
assert virtual_price >= 10**18 - 10
assert get_virtual_price >= 10**18 - 10

assert xcp_profit - self.xcp_profit > -3, f"{xcp_profit} vs {self.xcp_profit}"
assert (virtual_price - 10 ** 18) * 2 - (
xcp_profit - 10 ** 18
assert (
xcp_profit - self.xcp_profit > -3
), f"{xcp_profit} vs {self.xcp_profit}"
assert (virtual_price - 10**18) * 2 - (
xcp_profit - 10**18
) >= -5, f"vprice={virtual_price}, xcp_profit={xcp_profit}"
assert abs(log(virtual_price / get_virtual_price)) < 1e-10

Expand Down
2 changes: 2 additions & 0 deletions tests/unitary/pool/stateful/test_add_liquidity.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# flake8: noqa

import math

import boa
Expand Down

0 comments on commit 4d76e11

Please sign in to comment.