-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathDynamicCurve.py
96 lines (80 loc) · 4.31 KB
/
DynamicCurve.py
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
95
96
from .common.BuiltIn import *
from . import AdvancedMath
from . import FractionMath
MAX_WEIGHT = 1000000;
# Abstract:
# Consider a pool which implements the bonding-curve model over a primary reserve token and a secondary reserve token.
# Let 'on-chain price' denote the conversion rate between these tokens inside the pool (i.e., as determined by the pool).
# Let 'off-chain price' denote the conversion rate between these tokens outside the pool (i.e., as determined by the market).
# The arbitrage incentive is always to convert to the point where the on-chain price is equal to the off-chain price.
# We want this operation to also impact the primary reserve balance becoming equal to the primary reserve staked balance.
# In other words, we want the arbitrager to convert the difference between the reserve balance and the reserve staked balance.
# Hence we adjust the weights in order to create an arbitrage incentive which, when realized, will subsequently equalize the pool.
#
# Input:
# - Let t denote the primary reserve token staked balance
# - Let s denote the primary reserve token balance
# - Let r denote the secondary reserve token balance
# - Let q denote the numerator of the off-chain price
# - Let p denote the denominator of the off-chain price
# Where p primary tokens are equal to q secondary tokens
#
# Output:
# - Solve the equation x * (s // t) ^ x = (t // r) * (q // p)
# - Return x // (x + 1) as the weight of the primary reserve token
# - Return 1 // (x + 1) as the weight of the secondary reserve token
#
# If the rate-provider provides the rates for a common unit, for example:
# - P = 2 ==> 2 primary reserve tokens = 1 ether
# - Q = 3 ==> 3 secondary reserve tokens = 1 ether
# Then you can simply use p = P and q = Q
#
# If the rate-provider provides the rates for a single unit, for example:
# - P = 2 ==> 1 primary reserve token = 2 ethers
# - Q = 3 ==> 1 secondary reserve token = 3 ethers
# Then you can simply use p = Q and q = P
'''
@dev Equalize the weights of a given pool while opting for accuracy over performance
@param t The primary reserve token staked balance
@param s The primary reserve token balance
@param r The secondary reserve token balance
@param q The numerator of the off-chain price
@param p The denominator of the off-chain price
Note that `numerator / denominator` should represent the amount of secondary tokens equal to one primary token
@return The weight of the primary reserve token and the weight of the secondary reserve token, both in ppm units
'''
def equalizeExact(t, s, r, q, p):
return equalize(t, s, r, q, p, AdvancedMath.solveExact);
'''
@dev Equalize the weights of a given pool while opting for performance over accuracy
@param t The primary reserve token staked balance
@param s The primary reserve token balance
@param r The secondary reserve token balance
@param q The numerator of the off-chain price
@param p The denominator of the off-chain price
Note that `numerator / denominator` should represent the amount of secondary tokens equal to one primary token
@return The weight of the primary reserve token and the weight of the secondary reserve token, both in ppm units
'''
def equalizeQuick(t, s, r, q, p):
return equalize(t, s, r, q, p, AdvancedMath.solveQuick);
'''
@dev Equalize the weights of a given pool
@param t The primary reserve token staked balance
@param s The primary reserve token balance
@param r The secondary reserve token balance
@param q The numerator of the off-chain price
@param p The denominator of the off-chain price
@param AdvancedMath_solveFunction An equation solver
Note that `numerator / denominator` should represent the amount of secondary tokens equal to one primary token
@return The weight of the primary reserve token and the weight of the secondary reserve token, both in ppm units
'''
def equalize(t, s, r, q, p, AdvancedMath_solveFunction):
if (t == s):
require(t > 0 or r > 0, "invalid balance");
else:
require(t > 0 and s > 0 and r > 0, "invalid balance");
require(q > 0 and p > 0, "invalid rate");
(tq, rp) = FractionMath.productRatio(t, q, r, p);
(xn, xd) = AdvancedMath_solveFunction(s, t, tq, rp);
(w1, w2) = FractionMath.normalizedRatio(xn, xd, MAX_WEIGHT);
return (w1, w2);