-
Notifications
You must be signed in to change notification settings - Fork 21
/
InterestRatesModel.sol
190 lines (168 loc) · 8.55 KB
/
InterestRatesModel.sol
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
// SPDX-License-Identifier: GNU AGPLv3
pragma solidity ^0.8.0;
import "@morpho-dao/morpho-utils/math/PercentageMath.sol";
import "@morpho-dao/morpho-utils/math/WadRayMath.sol";
import "@morpho-dao/morpho-utils/math/Math.sol";
import "./Types.sol";
library InterestRatesModel {
using PercentageMath for uint256;
using WadRayMath for uint256;
/// ERRORS ///
// Thrown when percentage is above 100%.
error PercentageTooHigh();
/// STRUCTS ///
struct GrowthFactors {
uint256 poolSupplyGrowthFactor; // The pool's supply index growth factor (in ray).
uint256 poolBorrowGrowthFactor; // The pool's borrow index growth factor (in ray).
uint256 p2pSupplyGrowthFactor; // Peer-to-peer supply index growth factor (in ray).
uint256 p2pBorrowGrowthFactor; // Peer-to-peer borrow index growth factor (in ray).
}
struct P2PIndexComputeParams {
uint256 poolGrowthFactor; // The pool's index growth factor (in ray).
uint256 p2pGrowthFactor; // Morpho peer-to-peer's median index growth factor (in ray).
uint256 lastPoolIndex; // The pool's last stored index (in ray).
uint256 lastP2PIndex; // Morpho's last stored peer-to-peer index (in ray).
uint256 p2pDelta; // The peer-to-peer delta for the given market (in pool unit).
uint256 p2pAmount; // The peer-to-peer amount for the given market (in peer-to-peer unit).
}
struct P2PRateComputeParams {
uint256 poolRate; // The pool's index growth factor (in wad).
uint256 p2pRate; // Morpho peer-to-peer's median index growth factor (in wad).
uint256 poolIndex; // The pool's last stored index (in ray).
uint256 p2pIndex; // Morpho's last stored peer-to-peer index (in ray).
uint256 p2pDelta; // The peer-to-peer delta for the given market (in pool unit).
uint256 p2pAmount; // The peer-to-peer amount for the given market (in peer-to-peer unit).
uint256 reserveFactor; // The reserve factor of the given market (in bps).
}
/// @notice Computes and returns the new growth factors associated to a given pool's supply/borrow index & Morpho's peer-to-peer index.
/// @param _newPoolSupplyIndex The pool's last current supply index.
/// @param _newPoolBorrowIndex The pool's last current borrow index.
/// @param _lastPoolIndexes The pool's last stored indexes.
/// @param _p2pIndexCursor The peer-to-peer index cursor for the given market.
/// @param _reserveFactor The reserve factor of the given market.
/// @return growthFactors The market's indexes growth factors (in ray).
function computeGrowthFactors(
uint256 _newPoolSupplyIndex,
uint256 _newPoolBorrowIndex,
Types.PoolIndexes memory _lastPoolIndexes,
uint256 _p2pIndexCursor,
uint256 _reserveFactor
) internal pure returns (GrowthFactors memory growthFactors) {
growthFactors.poolSupplyGrowthFactor = _newPoolSupplyIndex.rayDiv(
_lastPoolIndexes.poolSupplyIndex
);
growthFactors.poolBorrowGrowthFactor = _newPoolBorrowIndex.rayDiv(
_lastPoolIndexes.poolBorrowIndex
);
if (growthFactors.poolSupplyGrowthFactor <= growthFactors.poolBorrowGrowthFactor) {
uint256 p2pGrowthFactor = PercentageMath.weightedAvg(
growthFactors.poolSupplyGrowthFactor,
growthFactors.poolBorrowGrowthFactor,
_p2pIndexCursor
);
growthFactors.p2pSupplyGrowthFactor =
p2pGrowthFactor -
(p2pGrowthFactor - growthFactors.poolSupplyGrowthFactor).percentMul(_reserveFactor);
growthFactors.p2pBorrowGrowthFactor =
p2pGrowthFactor +
(growthFactors.poolBorrowGrowthFactor - p2pGrowthFactor).percentMul(_reserveFactor);
} else {
// The case poolSupplyGrowthFactor > poolBorrowGrowthFactor happens because someone has done a flashloan on Aave:
// the peer-to-peer growth factors are set to the pool borrow growth factor.
growthFactors.p2pSupplyGrowthFactor = growthFactors.poolBorrowGrowthFactor;
growthFactors.p2pBorrowGrowthFactor = growthFactors.poolBorrowGrowthFactor;
}
}
/// @notice Computes and returns the new peer-to-peer supply index of a market given its parameters.
/// @param _params The computation parameters.
/// @return newP2PSupplyIndex The updated peer-to-peer index (in ray).
function computeP2PSupplyIndex(P2PIndexComputeParams memory _params)
internal
pure
returns (uint256 newP2PSupplyIndex)
{
if (_params.p2pAmount == 0 || _params.p2pDelta == 0) {
newP2PSupplyIndex = _params.lastP2PIndex.rayMul(_params.p2pGrowthFactor);
} else {
uint256 shareOfTheDelta = Math.min(
_params.p2pDelta.wadToRay().rayMul(_params.lastPoolIndex).rayDiv(
_params.p2pAmount.wadToRay().rayMul(_params.lastP2PIndex)
),
WadRayMath.RAY // To avoid shareOfTheDelta > 1 with rounding errors.
); // In ray.
newP2PSupplyIndex = _params.lastP2PIndex.rayMul(
(WadRayMath.RAY - shareOfTheDelta).rayMul(_params.p2pGrowthFactor) +
shareOfTheDelta.rayMul(_params.poolGrowthFactor)
);
}
}
/// @notice Computes and returns the new peer-to-peer borrow index of a market given its parameters.
/// @param _params The computation parameters.
/// @return newP2PBorrowIndex The updated peer-to-peer index (in ray).
function computeP2PBorrowIndex(P2PIndexComputeParams memory _params)
internal
pure
returns (uint256 newP2PBorrowIndex)
{
if (_params.p2pAmount == 0 || _params.p2pDelta == 0) {
newP2PBorrowIndex = _params.lastP2PIndex.rayMul(_params.p2pGrowthFactor);
} else {
uint256 shareOfTheDelta = Math.min(
_params.p2pDelta.wadToRay().rayMul(_params.lastPoolIndex).rayDiv(
_params.p2pAmount.wadToRay().rayMul(_params.lastP2PIndex)
),
WadRayMath.RAY // To avoid shareOfTheDelta > 1 with rounding errors.
); // In ray.
newP2PBorrowIndex = _params.lastP2PIndex.rayMul(
(WadRayMath.RAY - shareOfTheDelta).rayMul(_params.p2pGrowthFactor) +
shareOfTheDelta.rayMul(_params.poolGrowthFactor)
);
}
}
/// @notice Computes and returns the peer-to-peer supply rate per year of a market given its parameters.
/// @param _params The computation parameters.
/// @return p2pSupplyRate The peer-to-peer supply rate per year (in ray).
function computeP2PSupplyRatePerYear(P2PRateComputeParams memory _params)
internal
pure
returns (uint256 p2pSupplyRate)
{
p2pSupplyRate =
_params.p2pRate -
(_params.p2pRate - _params.poolRate).percentMul(_params.reserveFactor);
if (_params.p2pDelta > 0 && _params.p2pAmount > 0) {
uint256 shareOfTheDelta = Math.min(
_params.p2pDelta.wadToRay().rayMul(_params.poolIndex).rayDiv(
_params.p2pAmount.wadToRay().rayMul(_params.p2pIndex)
),
WadRayMath.RAY // To avoid shareOfTheDelta > 1 with rounding errors.
); // In ray.
p2pSupplyRate =
p2pSupplyRate.rayMul(WadRayMath.RAY - shareOfTheDelta) +
_params.poolRate.rayMul(shareOfTheDelta);
}
}
/// @notice Computes and returns the peer-to-peer borrow rate per year of a market given its parameters.
/// @param _params The computation parameters.
/// @return p2pBorrowRate The peer-to-peer borrow rate per year (in ray).
function computeP2PBorrowRatePerYear(P2PRateComputeParams memory _params)
internal
pure
returns (uint256 p2pBorrowRate)
{
p2pBorrowRate =
_params.p2pRate +
(_params.poolRate - _params.p2pRate).percentMul(_params.reserveFactor);
if (_params.p2pDelta > 0 && _params.p2pAmount > 0) {
uint256 shareOfTheDelta = Math.min(
_params.p2pDelta.wadToRay().rayMul(_params.poolIndex).rayDiv(
_params.p2pAmount.wadToRay().rayMul(_params.p2pIndex)
),
WadRayMath.RAY // To avoid shareOfTheDelta > 1 with rounding errors.
); // In ray.
p2pBorrowRate =
p2pBorrowRate.rayMul(WadRayMath.RAY - shareOfTheDelta) +
_params.poolRate.rayMul(shareOfTheDelta);
}
}
}