-
Notifications
You must be signed in to change notification settings - Fork 25
/
Copy pathStableSwapPriceHelper.vy
94 lines (79 loc) · 2.56 KB
/
StableSwapPriceHelper.vy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# @version 0.2.8
# The following code has been copied with minimal modifications from
# https://github.com/curvefi/curve-contract/blob/3fa3b6c/contracts/pools/steth/StableSwapSTETH.vy
N_COINS: constant(int128) = 2
FEE_DENOMINATOR: constant(uint256) = 10 ** 10
A_PRECISION: constant(uint256) = 100
@pure
@internal
def get_D(xp: uint256[N_COINS], amp: uint256) -> uint256:
S: uint256 = 0
Dprev: uint256 = 0
for _x in xp:
S += _x
if S == 0:
return 0
D: uint256 = S
Ann: uint256 = amp * N_COINS
for _i in range(255):
D_P: uint256 = D
for _x in xp:
D_P = D_P * D / (_x * N_COINS + 1) # +1 is to prevent /0
Dprev = D
D = (Ann * S / A_PRECISION + D_P * N_COINS) * D / ((Ann - A_PRECISION) * D / A_PRECISION + (N_COINS + 1) * D_P)
# Equality with the precision of 1
if D > Dprev:
if D - Dprev <= 1:
return D
else:
if Dprev - D <= 1:
return D
# convergence typically occurs in 4 rounds or less, this should be unreachable!
# if it does happen the pool is borked and LPs can withdraw via `remove_liquidity`
raise
@view
@internal
def get_y(i: int128, j: int128, x: uint256, xp: uint256[N_COINS], amp: uint256) -> uint256:
# x in the input is converted to the same price/precision
assert i != j # dev: same coin
assert j >= 0 # dev: j below zero
assert j < N_COINS # dev: j above N_COINS
# should be unreachable, but good for safety
assert i >= 0
assert i < N_COINS
D: uint256 = self.get_D(xp, amp)
Ann: uint256 = amp * N_COINS
c: uint256 = D
S_: uint256 = 0
_x: uint256 = 0
y_prev: uint256 = 0
for _i in range(N_COINS):
if _i == i:
_x = x
elif _i != j:
_x = xp[_i]
else:
continue
S_ += _x
c = c * D / (_x * N_COINS)
c = c * D * A_PRECISION / (Ann * N_COINS)
b: uint256 = S_ + D * A_PRECISION / Ann # - D
y: uint256 = D
for _i in range(255):
y_prev = y
y = (y*y + c) / (2 * y + b - D)
# Equality with the precision of 1
if y > y_prev:
if y - y_prev <= 1:
return y
else:
if y_prev - y <= 1:
return y
raise
@view
@external
def get_dy(i: int128, j: int128, dx: uint256, xp: uint256[N_COINS], A: uint256, fee: uint256) -> uint256:
x: uint256 = xp[i] + dx
y: uint256 = self.get_y(i, j, x, xp, A)
dy: uint256 = xp[j] - y - 1
return dy - fee * dy / FEE_DENOMINATOR