-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSecondaryMonetaryPolicy.vy
153 lines (119 loc) · 5.02 KB
/
SecondaryMonetaryPolicy.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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# @version 0.3.10
"""
@title Secondary monetary policy
@notice Monetary policy to calculate borrow rates in lending markets
depending on "mint" borrow rate and utilization.
Calculated as:
rate = rate_from_amm * (r_minf + A / (u_inf - utilization))
Depending on target utilization (u0), rate ratio at 0 (alpha) and at max utilization (beta) one can calculate
coefficients for the hyperbolic dependency:
u_inf = (beta - 1) * u0 / ((beta - 1) * u0 - (1 - u0) * (1 - alpha))
A = (1 - alpha) * (u_inf - u0) * u_inf / u0
r_minf = alpha - A / u_inf
The function reaches rate_from_amm at u0 utilization, alpha*rate_from_amm at 0 utilization and
beta*rate_from_amm at 100% utilization.
code from here: https://github.com/curvefi/curve-stablecoin/blob/master/contracts/mpolicies/SecondaryMonetaryPolicy.vy
@author Curve.fi
@license Copyright (c) Curve.Fi, 2020-2024 - all rights reserved
"""
from vyper.interfaces import ERC20
interface Controller:
def total_debt() -> uint256: view
interface IAMM:
def rate() -> uint256: view
interface Factory:
def admin() -> address: view
event SetParameters:
u_inf: uint256
A: uint256
r_minf: uint256
shift: uint256
struct Parameters:
u_inf: uint256
A: uint256
r_minf: uint256
shift: uint256
MIN_UTIL: constant(uint256) = 10**16
MAX_UTIL: constant(uint256) = 99 * 10**16
MIN_LOW_RATIO: constant(uint256) = 10**16
MAX_HIGH_RATIO: constant(uint256) = 100 * 10**18
MAX_RATE_SHIFT: constant(uint256) = 100 * 10**18
BORROWED_TOKEN: public(immutable(ERC20))
FACTORY: public(immutable(Factory))
AMM: public(immutable(IAMM))
parameters: public(Parameters)
@external
def __init__(factory: Factory, amm: IAMM, borrowed_token: ERC20,
target_utilization: uint256, low_ratio: uint256, high_ratio: uint256, rate_shift: uint256):
"""
@param factory Factory contract
@param amm AMM to take borrow rate from as a basis
@param borrowed_token Borrowed token in the market (e.g. crvUSD)
@param target_utilization Utilization at which borrow rate is the same as in AMM
@param low_ratio Ratio rate/target_rate at 0% utilization
@param high_ratio Ratio rate/target_rate at 100% utilization
@param rate_shift Shift all the rate curve by this rate
"""
assert target_utilization >= MIN_UTIL
assert target_utilization <= MAX_UTIL
assert low_ratio >= MIN_LOW_RATIO
assert high_ratio <= MAX_HIGH_RATIO
assert low_ratio < high_ratio
assert rate_shift <= MAX_RATE_SHIFT
FACTORY = factory
AMM = amm
BORROWED_TOKEN = borrowed_token
p: Parameters = self.get_params(target_utilization, low_ratio, high_ratio, rate_shift)
self.parameters = p
log SetParameters(p.u_inf, p.A, p.r_minf, p.shift)
@internal
def get_params(u_0: uint256, alpha: uint256, beta: uint256, rate_shift: uint256) -> Parameters:
p: Parameters = empty(Parameters)
p.u_inf = (beta - 10**18) * u_0 / (((beta - 10**18) * u_0 - (10**18 - u_0) * (10**18 - alpha)) / 10**18)
p.A = (10**18 - alpha) * p.u_inf / 10**18 * (p.u_inf - u_0) / u_0
p.r_minf = alpha - p.A * 10**18 / p.u_inf
p.shift = rate_shift
return p
@internal
@view
def calculate_rate(_for: address, d_reserves: int256, d_debt: int256) -> uint256:
p: Parameters = self.parameters
total_debt: int256 = convert(Controller(_for).total_debt(), int256)
total_reserves: int256 = convert(BORROWED_TOKEN.balanceOf(_for), int256) + total_debt + d_reserves
total_debt += d_debt
assert total_debt >= 0, "Negative debt"
assert total_reserves >= total_debt, "Reserves too small"
u: uint256 = 0
if total_reserves > 0:
u = convert(total_debt * 10**18 / total_reserves, uint256)
r0: uint256 = AMM.rate()
return r0 * p.r_minf / 10**18 + p.A * r0 / (p.u_inf - u) + p.shift
@view
@external
def rate(_for: address = msg.sender) -> uint256:
return self.calculate_rate(_for, 0, 0)
@external
def rate_write(_for: address = msg.sender) -> uint256:
return self.calculate_rate(_for, 0, 0)
@external
def set_parameters(target_utilization: uint256, low_ratio: uint256, high_ratio: uint256, rate_shift: uint256):
"""
@param target_utilization Utilization at which borrow rate is the same as in AMM
@param low_ratio Ratio rate/target_rate at 0% utilization
@param high_ratio Ratio rate/target_rate at 100% utilization
@param rate_shift Shift all the rate curve by this rate
"""
assert msg.sender == FACTORY.admin()
assert target_utilization >= MIN_UTIL
assert target_utilization <= MAX_UTIL
assert low_ratio >= MIN_LOW_RATIO
assert high_ratio <= MAX_HIGH_RATIO
assert low_ratio < high_ratio
assert rate_shift <= MAX_RATE_SHIFT
p: Parameters = self.get_params(target_utilization, low_ratio, high_ratio, rate_shift)
self.parameters = p
log SetParameters(p.u_inf, p.A, p.r_minf, p.shift)
@view
@external
def future_rate(_for: address, d_reserves: int256, d_debt: int256) -> uint256:
return self.calculate_rate(_for, d_reserves, d_debt)