-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathInterestRateModel.py
More file actions
91 lines (79 loc) · 3.68 KB
/
InterestRateModel.py
File metadata and controls
91 lines (79 loc) · 3.68 KB
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
import smartpy as sp
IRMErrors = sp.io.import_script_from_url(
"file:contracts/errors/InterestRateModelErrors.py")
EC = IRMErrors.ErrorCodes
IRMInterface = sp.io.import_script_from_url(
"file:contracts/interfaces/InterestRateModelInterface.py")
class InterestRateModel(IRMInterface.InterestRateModelInterface):
def __init__(self,
baseRatePerBlock_,
multiplierPerBlock_,
jumpMultiplierPerBlock_,
kink_,
scale_,
**extra_storage):
self.init(
scale=scale_, # must match order of reserveFactorMantissa
# The multiplier of utilization rate that gives the slope of the interest rate
multiplierPerBlock=multiplierPerBlock_,
# The base interest rate which is the y-intercept when utilization rate is 0
baseRatePerBlock=baseRatePerBlock_,
# The multiplier per block after hitting the kink point
jumpMultiplierPerBlock=jumpMultiplierPerBlock_,
# The utilization point at which the jump multiplier is applied
kink=kink_,
**extra_storage
)
"""
Calculates the current borrow interest rate per block
params: TBorrowRateParams
return: The borrow rate per block (as a percentage)
"""
@sp.entry_point
def getBorrowRate(self, params):
sp.set_type(params, IRMInterface.TBorrowRateParams)
utRate = self.utilizationRate(sp.record(
cash=params.cash, borrows=params.borrows, reserves=params.reserves))
result = self.calculateBorrowRate(utRate)
sp.transfer(result, sp.mutez(0), params.cb)
"""
Calculates the current supply interest rate per block
params: TSupplyRateParams
return: The supply rate per block (as a percentage)
"""
@sp.entry_point
def getSupplyRate(self, params):
sp.set_type(params, IRMInterface.TSupplyRateParams)
oneMinusReserveFactor = sp.as_nat(
self.data.scale - params.reserveFactorMantissa)
utRate = self.utilizationRate(sp.record(
cash=params.cash, borrows=params.borrows, reserves=params.reserves))
borrowRate = self.calculateBorrowRate(utRate)
rateToPool = borrowRate * oneMinusReserveFactor // self.data.scale
result = utRate * rateToPool // self.data.scale
sp.transfer(result, sp.mutez(0), params.cb)
@sp.private_lambda(with_storage="read-only")
def utilizationRate(self, params):
sp.set_type(params, IRMInterface.TUtilizationParams)
ur = sp.local('ur', sp.nat(0))
sp.if params.borrows > sp.nat(0):
divisor = sp.compute(sp.as_nat(params.cash + params.borrows - params.reserves))
sp.verify(divisor > 0, EC.IRM_INSUFFICIENT_CASH)
ur.value = params.borrows * self.data.scale // divisor
sp.result(ur.value)
@sp.private_lambda(with_storage="read-only")
def calculateBorrowRate(self, utRate):
sp.if utRate <= self.data.kink:
sp.result(sp.compute(utRate * self.data.multiplierPerBlock // self.data.scale + self.data.baseRatePerBlock))
sp.else:
# Calculate the rate at the kink point
normalRate = sp.compute(
self.data.kink * self.data.multiplierPerBlock // self.data.scale + self.data.baseRatePerBlock
)
# Calculate excess utilization beyond kink
excessUtil = sp.as_nat(utRate - self.data.kink)
# Apply jump multiplier to excess utilization
rate = sp.compute(
excessUtil * self.data.jumpMultiplierPerBlock // self.data.scale + normalRate
)
sp.result(rate)