token-swap: Remove stable-swap simulation tests (#3555)
This commit is contained in:
parent
8d1e57018a
commit
180d80be7d
|
@ -2100,29 +2100,6 @@ dependencies = [
|
||||||
"regex",
|
"regex",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "indoc"
|
|
||||||
version = "0.3.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "47741a8bc60fb26eb8d6e0238bbb26d8575ff623fdc97b1a2c00c050b9684ed8"
|
|
||||||
dependencies = [
|
|
||||||
"indoc-impl",
|
|
||||||
"proc-macro-hack",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "indoc-impl"
|
|
||||||
version = "0.3.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ce046d161f000fffde5f432a0d034d0341dc152643b2598ed5bfce44c4f3a8f0"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro-hack",
|
|
||||||
"proc-macro2 1.0.43",
|
|
||||||
"quote 1.0.21",
|
|
||||||
"syn 1.0.99",
|
|
||||||
"unindent",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "inout"
|
name = "inout"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
|
@ -3043,25 +3020,6 @@ dependencies = [
|
||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "paste"
|
|
||||||
version = "0.1.18"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "45ca20c77d80be666aef2b45486da86238fabe33e38306bd3118fe4af33fa880"
|
|
||||||
dependencies = [
|
|
||||||
"paste-impl",
|
|
||||||
"proc-macro-hack",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "paste-impl"
|
|
||||||
version = "0.1.18"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d95a7db200b97ef370c8e6de0088252f7e0dfff7d047a28528e47456c0fc98b6"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro-hack",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pbkdf2"
|
name = "pbkdf2"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
|
@ -3328,12 +3286,6 @@ dependencies = [
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro-hack"
|
|
||||||
version = "0.5.19"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "0.4.30"
|
version = "0.4.30"
|
||||||
|
@ -3487,54 +3439,6 @@ dependencies = [
|
||||||
"autotools",
|
"autotools",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pyo3"
|
|
||||||
version = "0.15.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7cf01dbf1c05af0a14c7779ed6f3aa9deac9c3419606ac9de537a2d649005720"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if 1.0.0",
|
|
||||||
"indoc",
|
|
||||||
"libc",
|
|
||||||
"parking_lot 0.11.2",
|
|
||||||
"paste",
|
|
||||||
"pyo3-build-config",
|
|
||||||
"pyo3-macros",
|
|
||||||
"unindent",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pyo3-build-config"
|
|
||||||
version = "0.15.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dbf9e4d128bfbddc898ad3409900080d8d5095c379632fbbfbb9c8cfb1fb852b"
|
|
||||||
dependencies = [
|
|
||||||
"once_cell",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pyo3-macros"
|
|
||||||
version = "0.15.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "67701eb32b1f9a9722b4bc54b548ff9d7ebfded011c12daece7b9063be1fd755"
|
|
||||||
dependencies = [
|
|
||||||
"pyo3-macros-backend",
|
|
||||||
"quote 1.0.21",
|
|
||||||
"syn 1.0.99",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pyo3-macros-backend"
|
|
||||||
version = "0.15.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f44f09e825ee49a105f2c7b23ebee50886a9aee0746f4dd5a704138a64b0218a"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2 1.0.43",
|
|
||||||
"pyo3-build-config",
|
|
||||||
"quote 1.0.21",
|
|
||||||
"syn 1.0.99",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "qstring"
|
name = "qstring"
|
||||||
version = "0.7.2"
|
version = "0.7.2"
|
||||||
|
@ -4398,13 +4302,6 @@ version = "1.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788"
|
checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sim"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"pyo3",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "simpl"
|
name = "simpl"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -6356,7 +6253,6 @@ dependencies = [
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"proptest",
|
"proptest",
|
||||||
"roots",
|
"roots",
|
||||||
"sim",
|
|
||||||
"solana-program",
|
"solana-program",
|
||||||
"solana-sdk",
|
"solana-sdk",
|
||||||
"spl-math",
|
"spl-math",
|
||||||
|
@ -7218,12 +7114,6 @@ version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unindent"
|
|
||||||
version = "0.1.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "universal-hash"
|
name = "universal-hash"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
|
|
|
@ -28,7 +28,6 @@ roots = { version = "0.0.7", optional = true }
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
proptest = "1.0"
|
proptest = "1.0"
|
||||||
roots = "0.0.7"
|
roots = "0.0.7"
|
||||||
sim = { path = "./sim" }
|
|
||||||
solana-sdk = "1.11.6"
|
solana-sdk = "1.11.6"
|
||||||
test-case = "2.2"
|
test-case = "2.2"
|
||||||
|
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "sim"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["michaelhly <michaelhly@gmail.com>"]
|
|
||||||
edition = "2018"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
pyo3 = { version = "0.15.1", features = ["auto-initialize"] }
|
|
|
@ -1,188 +0,0 @@
|
||||||
# Source from: https://github.com/curvefi/curve-contract/blob/master/tests/simulation.py
|
|
||||||
|
|
||||||
class Curve:
|
|
||||||
|
|
||||||
"""
|
|
||||||
Python model of Curve pool math.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, A, D, n, fee = 10 ** 7, p=None, tokens=None):
|
|
||||||
"""
|
|
||||||
A: Amplification coefficient
|
|
||||||
D: Total deposit size
|
|
||||||
n: number of currencies
|
|
||||||
p: target prices
|
|
||||||
"""
|
|
||||||
self.A = A # actually A * n ** (n - 1) because it's an invariant
|
|
||||||
self.n = n
|
|
||||||
self.fee = fee
|
|
||||||
if p:
|
|
||||||
self.p = p
|
|
||||||
else:
|
|
||||||
self.p = [10 ** 18] * n
|
|
||||||
if isinstance(D, list):
|
|
||||||
self.x = D
|
|
||||||
else:
|
|
||||||
self.x = [D // n * 10 ** 18 // _p for _p in self.p]
|
|
||||||
self.tokens = tokens
|
|
||||||
|
|
||||||
def xp(self):
|
|
||||||
return [x * p // 10 ** 18 for x, p in zip(self.x, self.p)]
|
|
||||||
|
|
||||||
def D(self):
|
|
||||||
"""
|
|
||||||
D invariant calculation in non-overflowing integer operations
|
|
||||||
iteratively
|
|
||||||
|
|
||||||
A * sum(x_i) * n**n + D = A * D * n**n + D**(n+1) / (n**n * prod(x_i))
|
|
||||||
|
|
||||||
Converging solution:
|
|
||||||
D[j+1] = (A * n**n * sum(x_i) - D[j]**(n+1) / (n**n prod(x_i))) / (A * n**n - 1)
|
|
||||||
"""
|
|
||||||
Dprev = 0
|
|
||||||
xp = self.xp()
|
|
||||||
S = sum(xp)
|
|
||||||
D = S
|
|
||||||
Ann = self.A * self.n
|
|
||||||
|
|
||||||
counter = 0
|
|
||||||
|
|
||||||
while abs(D - Dprev) > 1:
|
|
||||||
D_P = D
|
|
||||||
for x in xp:
|
|
||||||
D_P = D_P * D // (self.n * x + 1)
|
|
||||||
Dprev = D
|
|
||||||
D = (Ann * S + D_P * self.n) * D // ((Ann - 1) * D + (self.n + 1) * D_P)
|
|
||||||
|
|
||||||
counter += 1
|
|
||||||
if counter > 1000:
|
|
||||||
break
|
|
||||||
|
|
||||||
return D
|
|
||||||
|
|
||||||
def y(self, i, j, x):
|
|
||||||
"""
|
|
||||||
Calculate x[j] if one makes x[i] = x
|
|
||||||
|
|
||||||
Done by solving quadratic equation iteratively.
|
|
||||||
x_1**2 + x1 * (sum' - (A*n**n - 1) * D / (A * n**n)) = D ** (n + 1) / (n ** (2 * n) * prod' * A)
|
|
||||||
x_1**2 + b*x_1 = c
|
|
||||||
|
|
||||||
x_1 = (x_1**2 + c) / (2*x_1 + b)
|
|
||||||
"""
|
|
||||||
D = self.D()
|
|
||||||
xx = self.xp()
|
|
||||||
xx[i] = x # x is quantity of underlying asset brought to 1e18 precision
|
|
||||||
xx = [xx[k] for k in range(self.n) if k != j]
|
|
||||||
Ann = self.A * self.n
|
|
||||||
c = D
|
|
||||||
for y in xx:
|
|
||||||
c = c * D // (y * self.n)
|
|
||||||
c = c * D // (self.n * Ann)
|
|
||||||
b = sum(xx) + D // Ann - D
|
|
||||||
y_prev = 0
|
|
||||||
y = D
|
|
||||||
|
|
||||||
counter = 0
|
|
||||||
|
|
||||||
while abs(y - y_prev) > 1:
|
|
||||||
y_prev = y
|
|
||||||
y = (y ** 2 + c) // (2 * y + b)
|
|
||||||
|
|
||||||
counter += 1
|
|
||||||
if counter > 1000:
|
|
||||||
break
|
|
||||||
|
|
||||||
return y # the result is in underlying units too
|
|
||||||
|
|
||||||
def y_D(self, i, _D):
|
|
||||||
"""
|
|
||||||
Calculate x[j] if one makes x[i] = x
|
|
||||||
|
|
||||||
Done by solving quadratic equation iteratively.
|
|
||||||
x_1**2 + x1 * (sum' - (A*n**n - 1) * D / (A * n**n)) = D ** (n + 1) / (n ** (2 * n) * prod' * A)
|
|
||||||
x_1**2 + b*x_1 = c
|
|
||||||
|
|
||||||
x_1 = (x_1**2 + c) / (2*x_1 + b)
|
|
||||||
"""
|
|
||||||
xx = self.xp()
|
|
||||||
xx = [xx[k] for k in range(self.n) if k != i]
|
|
||||||
S = sum(xx)
|
|
||||||
Ann = self.A * self.n
|
|
||||||
c = _D
|
|
||||||
for y in xx:
|
|
||||||
c = c * _D // (y * self.n)
|
|
||||||
c = c * _D // (self.n * Ann)
|
|
||||||
b = S + _D // Ann
|
|
||||||
y_prev = 0
|
|
||||||
y = _D
|
|
||||||
|
|
||||||
counter = 0
|
|
||||||
|
|
||||||
while abs(y - y_prev) > 1:
|
|
||||||
y_prev = y
|
|
||||||
y = (y ** 2 + c) // (2 * y + b - _D)
|
|
||||||
|
|
||||||
counter += 1
|
|
||||||
if counter > 1000:
|
|
||||||
break
|
|
||||||
|
|
||||||
return y # the result is in underlying units too
|
|
||||||
|
|
||||||
def dy(self, i, j, dx):
|
|
||||||
# dx and dy are in underlying units
|
|
||||||
xp = self.xp()
|
|
||||||
return xp[j] - self.y(i, j, xp[i] + dx)
|
|
||||||
|
|
||||||
def exchange(self, i, j, dx):
|
|
||||||
xp = self.xp()
|
|
||||||
x = xp[i] + dx
|
|
||||||
y = self.y(i, j, x)
|
|
||||||
dy = xp[j] - y
|
|
||||||
fee = dy * self.fee // 10 ** 10
|
|
||||||
|
|
||||||
#assert dy > 0
|
|
||||||
if dy == 0:
|
|
||||||
return 0
|
|
||||||
|
|
||||||
self.x[i] = x * 10 ** 18 // self.p[i]
|
|
||||||
self.x[j] = (y + fee) * 10 ** 18 // self.p[j]
|
|
||||||
return dy - fee
|
|
||||||
|
|
||||||
def remove_liquidity_imbalance(self, amounts):
|
|
||||||
_fee = self.fee * self.n // (4 * (self.n - 1))
|
|
||||||
|
|
||||||
old_balances = self.x
|
|
||||||
new_balances = self.x[:]
|
|
||||||
D0 = self.D()
|
|
||||||
for i in range(self.n):
|
|
||||||
new_balances[i] -= amounts[i]
|
|
||||||
self.x = new_balances
|
|
||||||
D1 = self.D()
|
|
||||||
self.x = old_balances
|
|
||||||
fees = [0] * self.n
|
|
||||||
for i in range(self.n):
|
|
||||||
ideal_balance = D1 * old_balances[i] // D0
|
|
||||||
difference = abs(ideal_balance - new_balances[i])
|
|
||||||
fees[i] = _fee * difference // 10 ** 10
|
|
||||||
new_balances[i] -= fees[i]
|
|
||||||
self.x = new_balances
|
|
||||||
D2 = self.D()
|
|
||||||
self.x = old_balances
|
|
||||||
|
|
||||||
token_amount = (D0 - D2) * self.tokens // D0
|
|
||||||
|
|
||||||
return token_amount
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
D0 = self.D()
|
|
||||||
D1 = D0 - token_amount * D0 // self.tokens
|
|
||||||
dy = xp[i] - self.y_D(i, D1)
|
|
||||||
|
|
||||||
return dy - dy * fee // 10 ** 10
|
|
|
@ -1,193 +0,0 @@
|
||||||
use pyo3::prelude::*;
|
|
||||||
use pyo3::types::PyTuple;
|
|
||||||
use std::fs::File;
|
|
||||||
use std::io::prelude::*;
|
|
||||||
|
|
||||||
const FILE_NAME: &str = "simulation.py";
|
|
||||||
const FILE_PATH: &str = "sim/simulation.py";
|
|
||||||
const MODULE_NAME: &str = "simulation";
|
|
||||||
|
|
||||||
const DEFAULT_POOL_TOKENS: u128 = 0;
|
|
||||||
const DEFAULT_TARGET_PRICE: u128 = 1000000000000000000;
|
|
||||||
pub const MODEL_FEE_NUMERATOR: u128 = 1;
|
|
||||||
pub const MODEL_FEE_DENOMINATOR: u128 = 1000;
|
|
||||||
|
|
||||||
pub struct StableSwapModel {
|
|
||||||
py_src: String,
|
|
||||||
pub amp_factor: u128,
|
|
||||||
pub balances: Vec<u128>,
|
|
||||||
pub n_coins: u8,
|
|
||||||
pub fee: u128,
|
|
||||||
pub target_prices: Vec<u128>,
|
|
||||||
pub pool_tokens: u128,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StableSwapModel {
|
|
||||||
pub fn new(amp_factor: u128, balances: Vec<u128>, n_coins: u8) -> StableSwapModel {
|
|
||||||
let mut src_file = File::open(FILE_PATH).unwrap();
|
|
||||||
let mut src_content = String::new();
|
|
||||||
let _ = src_file.read_to_string(&mut src_content);
|
|
||||||
|
|
||||||
Self {
|
|
||||||
py_src: src_content,
|
|
||||||
amp_factor,
|
|
||||||
balances,
|
|
||||||
n_coins,
|
|
||||||
fee: 0,
|
|
||||||
target_prices: vec![DEFAULT_TARGET_PRICE, DEFAULT_TARGET_PRICE],
|
|
||||||
pool_tokens: DEFAULT_POOL_TOKENS,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_with_pool_tokens(
|
|
||||||
amp_factor: u128,
|
|
||||||
balances: Vec<u128>,
|
|
||||||
n_coins: u8,
|
|
||||||
pool_token_amount: u128,
|
|
||||||
) -> StableSwapModel {
|
|
||||||
let mut src_file = File::open(FILE_PATH).unwrap();
|
|
||||||
let mut src_content = String::new();
|
|
||||||
let _ = src_file.read_to_string(&mut src_content);
|
|
||||||
|
|
||||||
Self {
|
|
||||||
py_src: src_content,
|
|
||||||
amp_factor,
|
|
||||||
balances,
|
|
||||||
n_coins,
|
|
||||||
fee: 0,
|
|
||||||
target_prices: vec![DEFAULT_TARGET_PRICE, DEFAULT_TARGET_PRICE],
|
|
||||||
pool_tokens: pool_token_amount,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sim_d(&self) -> u128 {
|
|
||||||
let gil = Python::acquire_gil();
|
|
||||||
return self
|
|
||||||
.call0(gil.python(), "D")
|
|
||||||
.unwrap()
|
|
||||||
.extract(gil.python())
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sim_dy(&self, i: u128, j: u128, dx: u128) -> u128 {
|
|
||||||
let gil = Python::acquire_gil();
|
|
||||||
return self
|
|
||||||
.call1(gil.python(), "dy", (i, j, dx))
|
|
||||||
.unwrap()
|
|
||||||
.extract(gil.python())
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sim_exchange(&self, i: u128, j: u128, dx: u128) -> u128 {
|
|
||||||
let gil = Python::acquire_gil();
|
|
||||||
return self
|
|
||||||
.call1(gil.python(), "exchange", (i, j, dx))
|
|
||||||
.unwrap()
|
|
||||||
.extract(gil.python())
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sim_xp(&self) -> Vec<u128> {
|
|
||||||
let gil = Python::acquire_gil();
|
|
||||||
return self
|
|
||||||
.call0(gil.python(), "xp")
|
|
||||||
.unwrap()
|
|
||||||
.extract(gil.python())
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sim_y(&self, i: u128, j: u128, x: u128) -> u128 {
|
|
||||||
let gil = Python::acquire_gil();
|
|
||||||
return self
|
|
||||||
.call1(gil.python(), "y", (i, j, x))
|
|
||||||
.unwrap()
|
|
||||||
.extract(gil.python())
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sim_y_d(&self, i: u128, d: u128) -> u128 {
|
|
||||||
let gil = Python::acquire_gil();
|
|
||||||
return self
|
|
||||||
.call1(gil.python(), "y_D", (i, d))
|
|
||||||
.unwrap()
|
|
||||||
.extract(gil.python())
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sim_remove_liquidity_imbalance(&self, amounts: Vec<u128>) -> u128 {
|
|
||||||
let gil = Python::acquire_gil();
|
|
||||||
return self
|
|
||||||
.call1(
|
|
||||||
gil.python(),
|
|
||||||
"remove_liquidity_imbalance",
|
|
||||||
PyTuple::new(gil.python(), amounts.to_vec()),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.extract(gil.python())
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sim_calc_withdraw_one_coin(&self, token_amount: u128, i: u128) -> u128 {
|
|
||||||
let gil = Python::acquire_gil();
|
|
||||||
return self
|
|
||||||
.call1(gil.python(), "calc_withdraw_one_coin", (token_amount, i))
|
|
||||||
.unwrap()
|
|
||||||
.extract(gil.python())
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn call0(&self, py: Python, method_name: &str) -> Result<PyObject, PyErr> {
|
|
||||||
let sim = PyModule::from_code(py, &self.py_src, FILE_NAME, MODULE_NAME).unwrap();
|
|
||||||
let model = sim
|
|
||||||
.getattr("Curve")?
|
|
||||||
.call1((
|
|
||||||
self.amp_factor,
|
|
||||||
self.balances.to_vec(),
|
|
||||||
self.n_coins,
|
|
||||||
self.fee,
|
|
||||||
self.target_prices.to_vec(),
|
|
||||||
self.pool_tokens,
|
|
||||||
))
|
|
||||||
.unwrap()
|
|
||||||
.to_object(py);
|
|
||||||
let py_ret = model.as_ref(py).call_method0(method_name);
|
|
||||||
self.extract_py_ret(py, py_ret)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn call1(
|
|
||||||
&self,
|
|
||||||
py: Python,
|
|
||||||
method_name: &str,
|
|
||||||
args: impl IntoPy<Py<PyTuple>>,
|
|
||||||
) -> Result<PyObject, PyErr> {
|
|
||||||
let sim = PyModule::from_code(py, &self.py_src, FILE_NAME, MODULE_NAME).unwrap();
|
|
||||||
let model = sim
|
|
||||||
.getattr("Curve")?
|
|
||||||
.call1((
|
|
||||||
self.amp_factor,
|
|
||||||
self.balances.to_vec(),
|
|
||||||
self.n_coins,
|
|
||||||
self.fee,
|
|
||||||
self.target_prices.to_vec(),
|
|
||||||
self.pool_tokens,
|
|
||||||
))
|
|
||||||
.unwrap()
|
|
||||||
.to_object(py);
|
|
||||||
let py_ret = model.as_ref(py).call_method1(method_name, args);
|
|
||||||
self.extract_py_ret(py, py_ret)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extract_py_ret(&self, py: Python, ret: PyResult<&PyAny>) -> Result<PyObject, PyErr> {
|
|
||||||
match ret {
|
|
||||||
Ok(v) => v.extract(),
|
|
||||||
Err(e) => {
|
|
||||||
e.print_and_set_sys_last_vars(py);
|
|
||||||
panic!("Python execution failed.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn print_src(&self) {
|
|
||||||
println!("{}", self.py_src);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -388,7 +388,6 @@ mod tests {
|
||||||
RoundDirection, INITIAL_SWAP_POOL_AMOUNT,
|
RoundDirection, INITIAL_SWAP_POOL_AMOUNT,
|
||||||
};
|
};
|
||||||
use proptest::prelude::*;
|
use proptest::prelude::*;
|
||||||
use sim::StableSwapModel;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn initial_pool_amount() {
|
fn initial_pool_amount() {
|
||||||
|
@ -437,54 +436,6 @@ mod tests {
|
||||||
assert_eq!(result.destination_amount_swapped, 0);
|
assert_eq!(result.destination_amount_swapped, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
proptest! {
|
|
||||||
#[test]
|
|
||||||
fn swap_no_fee(
|
|
||||||
swap_source_amount in 100..1_000_000_000_000_000_000u128,
|
|
||||||
swap_destination_amount in 100..1_000_000_000_000_000_000u128,
|
|
||||||
source_amount in 100..100_000_000_000u128,
|
|
||||||
amp in 1..150u64
|
|
||||||
) {
|
|
||||||
prop_assume!(source_amount < swap_source_amount);
|
|
||||||
|
|
||||||
let curve = StableCurve { amp };
|
|
||||||
|
|
||||||
let model: StableSwapModel = StableSwapModel::new(
|
|
||||||
curve.amp.into(),
|
|
||||||
vec![swap_source_amount, swap_destination_amount],
|
|
||||||
N_COINS,
|
|
||||||
);
|
|
||||||
|
|
||||||
let result = curve.swap_without_fees(
|
|
||||||
source_amount,
|
|
||||||
swap_source_amount,
|
|
||||||
swap_destination_amount,
|
|
||||||
TradeDirection::AtoB,
|
|
||||||
);
|
|
||||||
|
|
||||||
let result = result.unwrap();
|
|
||||||
let sim_result = model.sim_exchange(0, 1, source_amount);
|
|
||||||
|
|
||||||
let diff =
|
|
||||||
(sim_result as i128 - result.destination_amount_swapped as i128).abs();
|
|
||||||
|
|
||||||
// tolerate a difference of 2 because of the ceiling during calculation
|
|
||||||
let tolerance = std::cmp::max(2, sim_result as i128 / 1_000_000_000);
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
diff <= tolerance,
|
|
||||||
"result={}, sim_result={}, amp={}, source_amount={}, swap_source_amount={}, swap_destination_amount={}, diff={}",
|
|
||||||
result.destination_amount_swapped,
|
|
||||||
sim_result,
|
|
||||||
amp,
|
|
||||||
source_amount,
|
|
||||||
swap_source_amount,
|
|
||||||
swap_destination_amount,
|
|
||||||
diff
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn pack_curve() {
|
fn pack_curve() {
|
||||||
let amp = 1;
|
let amp = 1;
|
||||||
|
|
Loading…
Reference in New Issue