From c45b3603297b7d453df03d0444077cf1cdb0b455 Mon Sep 17 00:00:00 2001 From: michaelhly Date: Fri, 20 Nov 2020 22:59:39 -0600 Subject: [PATCH 1/5] Make calc_withdraw_one_coin consistent with _calc_withdraw_one_coin --- tests/simulation.py | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/tests/simulation.py b/tests/simulation.py index 5559b320..aff3f451 100644 --- a/tests/simulation.py +++ b/tests/simulation.py @@ -148,13 +148,24 @@ def remove_liquidity_imbalance(self, amounts): def calc_withdraw_one_coin(self, token_amount, i): xp = self.xp() - if self.fee: - fee = self.fee - self.fee * xp[i] // sum(xp) + 5 * 10 ** 5 - else: - fee = 0 + xp_reduced = xp D0 = self.D() D1 = D0 - token_amount * D0 // self.tokens - dy = xp[i] - self.y_D(i, D1) - - return dy - dy * fee // 10 ** 10 + new_y = self.y_D(i, D1) + + fee = self.fee * self.n // (4 * (self.n - 1)) + for j in range(self.n): + dx_expected = 0 + if j == i: + dx_expected = xp[j] * D1 // D0 - new_y + else: + dx_expected = xp[j] - xp[j] * D1 // D0 + xp_reduced[j] -= fee * dx_expected // 10 ** 10 + + self.x = [x // (p // 10 ** 18) for x, p in zip(xp_reduced, self.p)] + dy = xp_reduced[i] - self.y_D(i, D1) + self.x = [x // (p // 10 ** 18) for x, p in zip(xp, self.p)] + dy_0 = (xp[i] - new_y) + + return dy, dy_0 - dy From d110681a48fd7859184f2b1e8487456fac61d72a Mon Sep 17 00:00:00 2001 From: michaelhly Date: Fri, 20 Nov 2020 23:21:15 -0600 Subject: [PATCH 2/5] Fix --- tests/simulation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/simulation.py b/tests/simulation.py index aff3f451..067a3701 100644 --- a/tests/simulation.py +++ b/tests/simulation.py @@ -148,7 +148,7 @@ def remove_liquidity_imbalance(self, amounts): def calc_withdraw_one_coin(self, token_amount, i): xp = self.xp() - xp_reduced = xp + xp_reduced = list(xp) D0 = self.D() D1 = D0 - token_amount * D0 // self.tokens @@ -166,6 +166,6 @@ def calc_withdraw_one_coin(self, token_amount, i): self.x = [x // (p // 10 ** 18) for x, p in zip(xp_reduced, self.p)] dy = xp_reduced[i] - self.y_D(i, D1) self.x = [x // (p // 10 ** 18) for x, p in zip(xp, self.p)] - dy_0 = (xp[i] - new_y) + dy_0 = xp[i] - new_y return dy, dy_0 - dy From 36191e2543900423b193d83e234cd8c09cbe75e3 Mon Sep 17 00:00:00 2001 From: michaelhly Date: Sat, 21 Nov 2020 01:34:45 -0600 Subject: [PATCH 3/5] Add test --- .../common/unitary/test_remove_liquidity_one_coin.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/pools/common/unitary/test_remove_liquidity_one_coin.py b/tests/pools/common/unitary/test_remove_liquidity_one_coin.py index 3a37d6ac..590682d9 100644 --- a/tests/pools/common/unitary/test_remove_liquidity_one_coin.py +++ b/tests/pools/common/unitary/test_remove_liquidity_one_coin.py @@ -1,5 +1,6 @@ import brownie import pytest +from simulation import Curve pytestmark = [ pytest.mark.skip_pool("busd", "compound", "pax", "susd", "usdt", "y"), @@ -81,3 +82,13 @@ def test_below_zero(alice, swap): def test_above_n_coins(alice, swap, wrapped_coins, n_coins): with brownie.reverts(): swap.remove_liquidity_one_coin(1, n_coins, 0, {'from': alice}) + +@pytest.mark.itercoins("idx") +def test_against_simulation(alice, swap, n_coins, pool_token, idx): + amount = pool_token.balanceOf(alice) + + balances = [swap.balances(i) for i in range(n_coins)] + curve_model = Curve(swap.A(), balances, n_coins, tokens=pool_token.totalSupply()) + expected, _ = curve_model.calc_withdraw_one_coin(amount, idx) + + assert swap.swap.calc_withdraw_one_coin(amount, idx) == expected From a5d0083b8a2678b7caf69a5795aa3325a0a0f365 Mon Sep 17 00:00:00 2001 From: michaelhly Date: Sat, 21 Nov 2020 09:51:14 -0600 Subject: [PATCH 4/5] Fix --- tests/pools/common/unitary/test_remove_liquidity_one_coin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/pools/common/unitary/test_remove_liquidity_one_coin.py b/tests/pools/common/unitary/test_remove_liquidity_one_coin.py index 590682d9..83dbfb6d 100644 --- a/tests/pools/common/unitary/test_remove_liquidity_one_coin.py +++ b/tests/pools/common/unitary/test_remove_liquidity_one_coin.py @@ -91,4 +91,4 @@ def test_against_simulation(alice, swap, n_coins, pool_token, idx): curve_model = Curve(swap.A(), balances, n_coins, tokens=pool_token.totalSupply()) expected, _ = curve_model.calc_withdraw_one_coin(amount, idx) - assert swap.swap.calc_withdraw_one_coin(amount, idx) == expected + assert swap.calc_withdraw_one_coin(amount, idx) == expected From a3d1d566cb58d511b941fa7d20969da1f4764a23 Mon Sep 17 00:00:00 2001 From: michaelhly Date: Sat, 21 Nov 2020 10:18:46 -0600 Subject: [PATCH 5/5] -1 to account for rounding errors --- tests/simulation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/simulation.py b/tests/simulation.py index 067a3701..9fa1bddf 100644 --- a/tests/simulation.py +++ b/tests/simulation.py @@ -164,7 +164,7 @@ def calc_withdraw_one_coin(self, token_amount, i): xp_reduced[j] -= fee * dx_expected // 10 ** 10 self.x = [x // (p // 10 ** 18) for x, p in zip(xp_reduced, self.p)] - dy = xp_reduced[i] - self.y_D(i, D1) + dy = xp_reduced[i] - self.y_D(i, D1) - 1 # Withdraw less to account for rounding errors self.x = [x // (p // 10 ** 18) for x, p in zip(xp, self.p)] dy_0 = xp[i] - new_y