@pendle/core-v2 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/LICENSE +100 -0
  2. package/contracts/SuperComposableYield/ISuperComposableYield.sol +68 -0
  3. package/contracts/SuperComposableYield/SCYUtils.sol +14 -0
  4. package/contracts/SuperComposableYield/implementations/RewardManager.sol +117 -0
  5. package/contracts/SuperComposableYield/implementations/SCYBase.sol +126 -0
  6. package/contracts/SuperComposableYield/implementations/SCYBaseWithRewards.sol +79 -0
  7. package/contracts/core/PendleBaseToken.sol +39 -0
  8. package/contracts/core/PendleMarket.sol +248 -0
  9. package/contracts/core/PendleMarketFactory.sol +60 -0
  10. package/contracts/core/PendleOwnershipToken.sol +44 -0
  11. package/contracts/core/PendleSCYImpl/AaveV3/PendleAaveV3SCY.sol +139 -0
  12. package/contracts/core/PendleSCYImpl/AaveV3/WadRayMath.sol +126 -0
  13. package/contracts/core/PendleSCYImpl/PendleBenQiErc20SCY.sol +127 -0
  14. package/contracts/core/PendleSCYImpl/PendleBtrflySCY.sol +125 -0
  15. package/contracts/core/PendleSCYImpl/PendleYearnVaultSCY.sol +115 -0
  16. package/contracts/core/PendleYieldContractFactory.sol +109 -0
  17. package/contracts/core/PendleYieldToken.sol +240 -0
  18. package/contracts/core/misc/BoringOwnable.sol +62 -0
  19. package/contracts/core/misc/BoringOwnableUpg.sol +64 -0
  20. package/contracts/core/misc/PendleJoeSwapHelperUpg.sol +82 -0
  21. package/contracts/core/router/PendleRouterCoreUpg.sol +219 -0
  22. package/contracts/core/router/PendleRouterProxy.sol +64 -0
  23. package/contracts/core/router/PendleRouterYTUpg.sol +134 -0
  24. package/contracts/core/router/base/PendleRouterOTBaseUpg.sol +218 -0
  25. package/contracts/core/router/base/PendleRouterSCYAndForgeBaseUpg.sol +141 -0
  26. package/contracts/core/router/base/PendleRouterYTBaseUpg.sol +212 -0
  27. package/contracts/interfaces/IAToken.sol +34 -0
  28. package/contracts/interfaces/IAavePool.sol +41 -0
  29. package/contracts/interfaces/IAaveRewardsController.sol +32 -0
  30. package/contracts/interfaces/IBenQiComptroller.sol +33 -0
  31. package/contracts/interfaces/IJoePair.sol +98 -0
  32. package/contracts/interfaces/IJoeRouter01.sol +162 -0
  33. package/contracts/interfaces/IPBaseToken.sol +9 -0
  34. package/contracts/interfaces/IPFlashCallBack.sol +10 -0
  35. package/contracts/interfaces/IPGovernanceManager.sol +28 -0
  36. package/contracts/interfaces/IPMarket.sol +57 -0
  37. package/contracts/interfaces/IPMarketAddRemoveCallback.sol +18 -0
  38. package/contracts/interfaces/IPMarketFactory.sol +8 -0
  39. package/contracts/interfaces/IPMarketSwapCallback.sol +10 -0
  40. package/contracts/interfaces/IPOwnershipToken.sol +15 -0
  41. package/contracts/interfaces/IPPermissionsV2.sol +28 -0
  42. package/contracts/interfaces/IPRouterCore.sol +108 -0
  43. package/contracts/interfaces/IPRouterYT.sol +47 -0
  44. package/contracts/interfaces/IPYieldContractFactory.sol +36 -0
  45. package/contracts/interfaces/IPYieldToken.sol +19 -0
  46. package/contracts/interfaces/IQiErc20.sol +35 -0
  47. package/contracts/interfaces/IQiToken.sol +29 -0
  48. package/contracts/interfaces/IREDACTEDStaking.sol +35 -0
  49. package/contracts/interfaces/IWETH.sol +34 -0
  50. package/contracts/interfaces/IWXBTRFLY.sol +37 -0
  51. package/contracts/interfaces/IYearnVault.sol +32 -0
  52. package/contracts/libraries/JoeLibrary.sol +121 -0
  53. package/contracts/libraries/SCYIndex.sol +55 -0
  54. package/contracts/libraries/helpers/ExpiryUtilsLib.sol +166 -0
  55. package/contracts/libraries/math/FixedPoint.sol +208 -0
  56. package/contracts/libraries/math/LogExpMath.sol +515 -0
  57. package/contracts/libraries/math/MarketApproxLib.sol +140 -0
  58. package/contracts/libraries/math/MarketMathLib.sol +606 -0
  59. package/contracts/periphery/PendleGovernanceManager.sol +36 -0
  60. package/contracts/periphery/PermissionsV2.sol +23 -0
  61. package/package.json +76 -0
  62. package/typechain-types/BoringOwnable.ts +194 -0
  63. package/typechain-types/BoringOwnableData.ts +100 -0
  64. package/typechain-types/BoringOwnableUpg.ts +194 -0
  65. package/typechain-types/BoringOwnableUpgData.ts +100 -0
  66. package/typechain-types/ERC1967UpgradeUpgradeable.ts +97 -0
  67. package/typechain-types/ERC20.ts +417 -0
  68. package/typechain-types/IAToken.ts +331 -0
  69. package/typechain-types/IAavePool.ts +192 -0
  70. package/typechain-types/IAaveRewardsController.ts +148 -0
  71. package/typechain-types/IBeaconUpgradeable.ts +87 -0
  72. package/typechain-types/IBenQiComptroller.ts +125 -0
  73. package/typechain-types/IERC1822ProxiableUpgradeable.ts +87 -0
  74. package/typechain-types/IERC20.ts +300 -0
  75. package/typechain-types/IERC20Metadata.ts +339 -0
  76. package/typechain-types/IJoePair.ts +888 -0
  77. package/typechain-types/IJoeRouter01.ts +1107 -0
  78. package/typechain-types/IPBaseToken.ts +365 -0
  79. package/typechain-types/IPFlashCallback.ts +115 -0
  80. package/typechain-types/IPGovernanceManager.ts +84 -0
  81. package/typechain-types/IPMarket.ts +701 -0
  82. package/typechain-types/IPMarketAddRemoveCallback.ts +169 -0
  83. package/typechain-types/IPMarketFactory.ts +109 -0
  84. package/typechain-types/IPMarketSwapCallback.ts +115 -0
  85. package/typechain-types/IPOwnershipToken.ts +488 -0
  86. package/typechain-types/IPRouterCore.ts +759 -0
  87. package/typechain-types/IPRouterYT.ts +405 -0
  88. package/typechain-types/IPYieldContractFactory.ts +192 -0
  89. package/typechain-types/IPYieldToken.ts +525 -0
  90. package/typechain-types/IPermissionsV2.ts +87 -0
  91. package/typechain-types/IQiErc20.ts +402 -0
  92. package/typechain-types/IQiToken.ts +327 -0
  93. package/typechain-types/IREDACTEDStaking.ts +216 -0
  94. package/typechain-types/ISuperComposableYield.ts +652 -0
  95. package/typechain-types/IWETH.ts +380 -0
  96. package/typechain-types/IWXBTRFLY.ts +254 -0
  97. package/typechain-types/IYearnVault.ts +152 -0
  98. package/typechain-types/PendleAaveV3SCY.ts +901 -0
  99. package/typechain-types/PendleBaseToken.ts +505 -0
  100. package/typechain-types/PendleBenQiErc20SCY.ts +914 -0
  101. package/typechain-types/PendleBtrflyScy.ts +794 -0
  102. package/typechain-types/PendleGovernanceManager.ts +187 -0
  103. package/typechain-types/PendleJoeSwapHelperUpg.ts +97 -0
  104. package/typechain-types/PendleMarket.ts +1008 -0
  105. package/typechain-types/PendleMarketFactory.ts +246 -0
  106. package/typechain-types/PendleOwnershipToken.ts +628 -0
  107. package/typechain-types/PendleRouterCoreUpg.ts +780 -0
  108. package/typechain-types/PendleRouterProxy.ts +417 -0
  109. package/typechain-types/PendleRouterSCYAndForgeBaseUpg.ts +98 -0
  110. package/typechain-types/PendleRouterYTBaseUpg.ts +134 -0
  111. package/typechain-types/PendleRouterYTUpg.ts +453 -0
  112. package/typechain-types/PendleYearnVaultScy.ts +784 -0
  113. package/typechain-types/PendleYieldContractFactory.ts +479 -0
  114. package/typechain-types/PendleYieldToken.ts +1030 -0
  115. package/typechain-types/PermissionsV2.ts +87 -0
  116. package/typechain-types/Proxy.ts +57 -0
  117. package/typechain-types/RewardManager.ts +172 -0
  118. package/typechain-types/SCYBase.ts +734 -0
  119. package/typechain-types/SCYBaseWithRewards.ts +819 -0
  120. package/typechain-types/UUPSUpgradeable.ts +197 -0
  121. package/typechain-types/common.ts +44 -0
  122. package/typechain-types/factories/BoringOwnableData__factory.ts +90 -0
  123. package/typechain-types/factories/BoringOwnableUpgData__factory.ts +94 -0
  124. package/typechain-types/factories/BoringOwnableUpg__factory.ts +139 -0
  125. package/typechain-types/factories/BoringOwnable__factory.ts +149 -0
  126. package/typechain-types/factories/ERC1967UpgradeUpgradeable__factory.ts +75 -0
  127. package/typechain-types/factories/ERC20__factory.ts +348 -0
  128. package/typechain-types/factories/IAToken__factory.ts +225 -0
  129. package/typechain-types/factories/IAavePool__factory.ts +99 -0
  130. package/typechain-types/factories/IAaveRewardsController__factory.ts +78 -0
  131. package/typechain-types/factories/IBeaconUpgradeable__factory.ts +39 -0
  132. package/typechain-types/factories/IBenQiComptroller__factory.ts +59 -0
  133. package/typechain-types/factories/IERC1822ProxiableUpgradeable__factory.ts +43 -0
  134. package/typechain-types/factories/IERC20Metadata__factory.ts +248 -0
  135. package/typechain-types/factories/IERC20__factory.ts +203 -0
  136. package/typechain-types/factories/IJoePair__factory.ts +674 -0
  137. package/typechain-types/factories/IJoeRouter01__factory.ts +772 -0
  138. package/typechain-types/factories/IPBaseToken__factory.ts +271 -0
  139. package/typechain-types/factories/IPFlashCallback__factory.ts +49 -0
  140. package/typechain-types/factories/IPGovernanceManager__factory.ts +39 -0
  141. package/typechain-types/factories/IPMarketAddRemoveCallback__factory.ts +86 -0
  142. package/typechain-types/factories/IPMarketFactory__factory.ts +58 -0
  143. package/typechain-types/factories/IPMarketSwapCallback__factory.ts +53 -0
  144. package/typechain-types/factories/IPMarket__factory.ts +559 -0
  145. package/typechain-types/factories/IPOwnershipToken__factory.ts +349 -0
  146. package/typechain-types/factories/IPRouterCore__factory.ts +516 -0
  147. package/typechain-types/factories/IPRouterYT__factory.ts +246 -0
  148. package/typechain-types/factories/IPYieldContractFactory__factory.ts +117 -0
  149. package/typechain-types/factories/IPYieldToken__factory.ts +383 -0
  150. package/typechain-types/factories/IPermissionsV2__factory.ts +39 -0
  151. package/typechain-types/factories/IQiErc20__factory.ts +270 -0
  152. package/typechain-types/factories/IQiToken__factory.ts +219 -0
  153. package/typechain-types/factories/IREDACTEDStaking__factory.ts +107 -0
  154. package/typechain-types/factories/ISuperComposableYield__factory.ts +438 -0
  155. package/typechain-types/factories/IWETH__factory.ts +261 -0
  156. package/typechain-types/factories/IWXBTRFLY__factory.ts +131 -0
  157. package/typechain-types/factories/IYearnVault__factory.ts +74 -0
  158. package/typechain-types/factories/PendleAaveV3SCY__factory.ts +727 -0
  159. package/typechain-types/factories/PendleBaseToken__factory.ts +386 -0
  160. package/typechain-types/factories/PendleBenQiErc20SCY__factory.ts +753 -0
  161. package/typechain-types/factories/PendleBtrflyScy__factory.ts +652 -0
  162. package/typechain-types/factories/PendleGovernanceManager__factory.ts +149 -0
  163. package/typechain-types/factories/PendleJoeSwapHelperUpg__factory.ts +56 -0
  164. package/typechain-types/factories/PendleMarketFactory__factory.ts +207 -0
  165. package/typechain-types/factories/PendleMarket__factory.ts +891 -0
  166. package/typechain-types/factories/PendleOwnershipToken__factory.ts +565 -0
  167. package/typechain-types/factories/PendleRouterCoreUpg__factory.ts +620 -0
  168. package/typechain-types/factories/PendleRouterProxy__factory.ts +316 -0
  169. package/typechain-types/factories/PendleRouterSCYAndForgeBaseUpg__factory.ts +56 -0
  170. package/typechain-types/factories/PendleRouterYTBaseUpg__factory.ts +66 -0
  171. package/typechain-types/factories/PendleRouterYTUpg__factory.ts +363 -0
  172. package/typechain-types/factories/PendleYearnVaultScy__factory.ts +630 -0
  173. package/typechain-types/factories/PendleYieldContractFactory__factory.ts +368 -0
  174. package/typechain-types/factories/PendleYieldToken__factory.ts +814 -0
  175. package/typechain-types/factories/PermissionsV2__factory.ts +36 -0
  176. package/typechain-types/factories/Proxy__factory.ts +28 -0
  177. package/typechain-types/factories/RewardManager__factory.ts +89 -0
  178. package/typechain-types/factories/SCYBaseWithRewards__factory.ts +535 -0
  179. package/typechain-types/factories/SCYBase__factory.ts +479 -0
  180. package/typechain-types/factories/UUPSUpgradeable__factory.ts +115 -0
  181. package/typechain-types/hardhat.d.ts +564 -0
  182. package/typechain-types/index.ts +122 -0
@@ -0,0 +1,606 @@
1
+ // SPDX-License-Identifier: GPL-3.0-or-later
2
+ pragma solidity 0.8.9;
3
+
4
+ import "../../interfaces/IPOwnershipToken.sol";
5
+ import "../../interfaces/IPYieldToken.sol";
6
+ import "../../SuperComposableYield/ISuperComposableYield.sol";
7
+ import "../../interfaces/IPMarket.sol";
8
+ import "./FixedPoint.sol";
9
+ import "./LogExpMath.sol";
10
+ import "../SCYIndex.sol";
11
+
12
+ // if this is changed, change deepCloneMarket as well
13
+ struct MarketParameters {
14
+ int256 totalOt;
15
+ int256 totalScy;
16
+ int256 totalLp;
17
+ uint256 oracleRate;
18
+ /// immutable variables ///
19
+ int256 scalarRoot;
20
+ uint256 feeRateRoot;
21
+ uint256 rateOracleTimeWindow;
22
+ uint256 expiry;
23
+ int256 reserveFeePercent; // base 100
24
+ /// last trade data ///
25
+ uint256 lastImpliedRate;
26
+ uint256 lastTradeTime;
27
+ }
28
+
29
+ struct MarketStorage {
30
+ int128 totalOt;
31
+ int128 totalScy;
32
+ uint112 lastImpliedRate;
33
+ uint112 oracleRate;
34
+ uint32 lastTradeTime;
35
+ }
36
+
37
+ // solhint-disable reason-string, ordering
38
+ library MarketMathLib {
39
+ using FixedPoint for uint256;
40
+ using FixedPoint for int256;
41
+ using LogExpMath for int256;
42
+ using SCYIndexLib for SCYIndex;
43
+
44
+ struct NetTo {
45
+ int256 toAccount;
46
+ int256 toMarket;
47
+ int256 toReserve;
48
+ }
49
+
50
+ struct ExecuteTradeSlot {
51
+ uint256 timeToExpiry;
52
+ int256 rateScalar;
53
+ int256 totalAsset;
54
+ int256 rateAnchor;
55
+ int256 preFeeExchangeRate;
56
+ }
57
+
58
+ int256 internal constant MINIMUM_LIQUIDITY = 10**3;
59
+ int256 internal constant PERCENTAGE_DECIMALS = 100;
60
+ uint256 internal constant DAY = 86400;
61
+ uint256 internal constant IMPLIED_RATE_TIME = 360 * DAY;
62
+
63
+ int256 internal constant MAX_MARKET_PROPORTION = (1e18 * 96) / 100;
64
+
65
+ function addLiquidity(
66
+ MarketParameters memory market,
67
+ SCYIndex index,
68
+ uint256 scyDesired,
69
+ uint256 otDesired
70
+ )
71
+ internal
72
+ pure
73
+ returns (
74
+ uint256 lpToReserve,
75
+ uint256 lpToAccount,
76
+ uint256 scyUsed,
77
+ uint256 otUsed
78
+ )
79
+ {
80
+ (
81
+ int256 _lpToReserve,
82
+ int256 _lpToAccount,
83
+ int256 _scyUsed,
84
+ int256 _otUsed
85
+ ) = _addLiquidity(market, index, scyDesired.Int(), otDesired.Int());
86
+
87
+ lpToReserve = _lpToReserve.Uint();
88
+ lpToAccount = _lpToAccount.Uint();
89
+ scyUsed = _scyUsed.Uint();
90
+ otUsed = _otUsed.Uint();
91
+ }
92
+
93
+ function removeLiquidity(MarketParameters memory market, uint256 lpToRemove)
94
+ internal
95
+ pure
96
+ returns (uint256 scyToAccount, uint256 otToAccount)
97
+ {
98
+ (int256 _scyToAccount, int256 _otToAccount) = _removeLiquidity(market, lpToRemove.Int());
99
+
100
+ scyToAccount = _scyToAccount.Uint();
101
+ otToAccount = _otToAccount.Uint();
102
+ }
103
+
104
+ function swapExactOtForScy(
105
+ MarketParameters memory market,
106
+ SCYIndex index,
107
+ uint256 exactOtToMarket,
108
+ uint256 blockTime
109
+ ) internal pure returns (uint256 netScyToAccount, uint256 netScyToReserve) {
110
+ (int256 _netScyToAccount, int256 _netScyToReserve) = _executeTrade(
111
+ market,
112
+ index,
113
+ exactOtToMarket.neg(),
114
+ blockTime
115
+ );
116
+
117
+ netScyToAccount = _netScyToAccount.Uint();
118
+ netScyToReserve = _netScyToReserve.Uint();
119
+ }
120
+
121
+ function swapScyForExactOt(
122
+ MarketParameters memory market,
123
+ SCYIndex index,
124
+ uint256 exactOtToAccount,
125
+ uint256 blockTime
126
+ ) internal pure returns (uint256 netScyToMarket, uint256 netScyToReserve) {
127
+ (int256 _netScyToAccount, int256 _netScyToReserve) = _executeTrade(
128
+ market,
129
+ index,
130
+ exactOtToAccount.Int(),
131
+ blockTime
132
+ );
133
+
134
+ netScyToMarket = _netScyToAccount.neg().Uint();
135
+ netScyToReserve = _netScyToReserve.Uint();
136
+ }
137
+
138
+ function setInitialImpliedRate(
139
+ MarketParameters memory market,
140
+ SCYIndex index,
141
+ int256 anchorRoot,
142
+ uint256 blockTime
143
+ ) internal pure {
144
+ int256 totalAsset = index.scyToAsset(market.totalScy);
145
+ market.lastImpliedRate = _getImpliedRate(
146
+ market.totalOt,
147
+ totalAsset,
148
+ market.scalarRoot,
149
+ anchorRoot,
150
+ market.expiry - blockTime
151
+ );
152
+ }
153
+
154
+ function updateNewRateOracle(MarketParameters memory market, uint256 blockTime)
155
+ internal
156
+ pure
157
+ returns (uint256)
158
+ {
159
+ // require(rateOracleTimeWindow > 0); // dev: update rate oracle, time window zero
160
+
161
+ // This can occur when using a view function get to a market state in the past
162
+ if (market.lastTradeTime > blockTime) {
163
+ market.oracleRate = market.lastImpliedRate;
164
+ return market.oracleRate;
165
+ }
166
+
167
+ uint256 timeDiff = blockTime - market.lastTradeTime;
168
+ if (timeDiff > market.rateOracleTimeWindow) {
169
+ // If past the time window just return the market.lastImpliedRate
170
+ market.oracleRate = market.lastImpliedRate;
171
+ return market.oracleRate;
172
+ }
173
+
174
+ // (currentTs - previousTs) / timeWindow
175
+ uint256 lastTradeWeight = timeDiff.divDown(market.rateOracleTimeWindow);
176
+
177
+ // 1 - (currentTs - previousTs) / timeWindow
178
+ uint256 oracleWeight = FixedPoint.ONE - lastTradeWeight;
179
+
180
+ uint256 newOracleRate = market.lastTradeTime.mulDown(lastTradeWeight) +
181
+ market.oracleRate.mulDown(oracleWeight);
182
+
183
+ market.oracleRate = newOracleRate;
184
+ return market.oracleRate;
185
+ }
186
+
187
+ /*///////////////////////////////////////////////////////////////
188
+ END OF HIGH LEVEL FUNCTIONS
189
+ //////////////////////////////////////////////////////////////*/
190
+
191
+ function _addLiquidity(
192
+ MarketParameters memory market,
193
+ SCYIndex index,
194
+ int256 scyDesired,
195
+ int256 otDesired
196
+ )
197
+ private
198
+ pure
199
+ returns (
200
+ int256 lpToReserve,
201
+ int256 lpToAccount,
202
+ int256 scyUsed,
203
+ int256 otUsed
204
+ )
205
+ {
206
+ require(scyDesired > 0 && otDesired > 0, "ZERO_AMOUNTS");
207
+
208
+ if (market.totalLp == 0) {
209
+ lpToAccount = index.scyToAsset(scyDesired).subNoNeg(MINIMUM_LIQUIDITY);
210
+ lpToReserve = MINIMUM_LIQUIDITY;
211
+ scyUsed = scyDesired;
212
+ otUsed = otDesired;
213
+ } else {
214
+ lpToAccount = FixedPoint.min(
215
+ (otDesired * market.totalLp) / market.totalOt,
216
+ (scyDesired * market.totalLp) / market.totalScy
217
+ );
218
+ scyUsed = (market.totalScy * lpToAccount) / market.totalLp;
219
+ otUsed = (market.totalOt * lpToAccount) / market.totalLp;
220
+ }
221
+
222
+ market.totalScy += scyUsed;
223
+ market.totalOt += otUsed;
224
+ market.totalLp += lpToAccount + lpToReserve;
225
+
226
+ require(lpToAccount > 0, "INSUFFICIENT_LIQUIDITY_MINTED");
227
+ }
228
+
229
+ function _removeLiquidity(MarketParameters memory market, int256 lpToRemove)
230
+ private
231
+ pure
232
+ returns (int256 scyToAccount, int256 otToAccount)
233
+ {
234
+ require(lpToRemove > 0, "invalid lp amount");
235
+
236
+ scyToAccount = (lpToRemove * market.totalScy) / market.totalLp;
237
+ otToAccount = (lpToRemove * market.totalOt) / market.totalLp;
238
+
239
+ market.totalLp = market.totalLp.subNoNeg(lpToRemove);
240
+ market.totalOt = market.totalOt.subNoNeg(otToAccount);
241
+ market.totalScy = market.totalScy.subNoNeg(scyToAccount);
242
+ }
243
+
244
+ /// @notice Calculates the asset amount the results from trading otToAccount with the market. A positive
245
+ /// otToAccount is equivalent of swapping OT into the market, a negative is taking OT out.
246
+ /// Updates the market state in memory.
247
+ /// @param market the current market state
248
+ /// @param otToAccount the OT amount that will be deposited into the user's portfolio. The net change
249
+ /// to the market is in the opposite direction.
250
+ /// @return netScyToAccount netScyToReserve
251
+ function _executeTrade(
252
+ MarketParameters memory market,
253
+ SCYIndex index,
254
+ int256 otToAccount,
255
+ uint256 blockTime
256
+ ) private pure returns (int256 netScyToAccount, int256 netScyToReserve) {
257
+ require(blockTime < market.expiry, "MARKET_EXPIRED");
258
+
259
+ ExecuteTradeSlot memory slot;
260
+ slot.timeToExpiry = market.expiry - blockTime;
261
+
262
+ // We return false if there is not enough Ot to support this trade.
263
+ // if otToAccount > 0 and totalOt - otToAccount <= 0 then the trade will fail
264
+ // if otToAccount < 0 and totalOt > 0 then this will always pass
265
+ require(market.totalOt > otToAccount, "insufficient liquidity");
266
+
267
+ // Calculates initial rate factors for the trade
268
+ (slot.rateScalar, slot.totalAsset, slot.rateAnchor) = _getExchangeRateFactors(
269
+ market,
270
+ index,
271
+ slot.timeToExpiry
272
+ );
273
+
274
+ // Calculates the exchange rate from Asset to OT before any liquidity fees
275
+ // are applied
276
+ slot.preFeeExchangeRate = _getExchangeRate(
277
+ market.totalOt,
278
+ slot.totalAsset,
279
+ slot.rateScalar,
280
+ slot.rateAnchor,
281
+ otToAccount
282
+ );
283
+
284
+ NetTo memory netAsset;
285
+ // Given the exchange rate, returns the netAsset amounts to apply to each of the
286
+ // three relevant balances.
287
+ (
288
+ netAsset.toAccount,
289
+ netAsset.toMarket,
290
+ netAsset.toReserve
291
+ ) = _getNetAssetAmountsToAddresses(
292
+ market.feeRateRoot,
293
+ slot.preFeeExchangeRate,
294
+ otToAccount,
295
+ slot.timeToExpiry,
296
+ market.reserveFeePercent
297
+ );
298
+
299
+ //////////////////////////////////
300
+ /// Update params in the market///
301
+ ///////////////////////////////x///
302
+ // Set the new implied interest rate after the trade has taken effect, this
303
+ // will be used to calculate the next trader's interest rate.
304
+ market.totalOt = market.totalOt.subNoNeg(otToAccount);
305
+ market.lastImpliedRate = _getImpliedRate(
306
+ market.totalOt,
307
+ slot.totalAsset + netAsset.toMarket,
308
+ slot.rateScalar,
309
+ slot.rateAnchor,
310
+ slot.timeToExpiry
311
+ );
312
+
313
+ // It's technically possible that the implied rate is actually exactly zero (or
314
+ // more accurately the natural log rounds down to zero) but we will still fail
315
+ // in this case. If this does happen we may assume that markets are not initialized.
316
+ require(market.lastImpliedRate != 0);
317
+
318
+ (netScyToAccount, netScyToReserve) = _setNewMarketState(
319
+ market,
320
+ index,
321
+ netAsset.toAccount,
322
+ netAsset.toMarket,
323
+ netAsset.toReserve,
324
+ blockTime
325
+ );
326
+ }
327
+
328
+ /// @notice Returns factors for calculating exchange rates
329
+ /// @return rateScalar a value in rate precision that defines the slope of the line
330
+ /// @return totalAsset the converted SCY to Asset for calculatin the exchange rates for the trade
331
+ /// @return rateAnchor an offset from the x axis to maintain interest rate continuity over time
332
+ function _getExchangeRateFactors(
333
+ MarketParameters memory market,
334
+ SCYIndex index,
335
+ uint256 timeToExpiry
336
+ )
337
+ private
338
+ pure
339
+ returns (
340
+ int256 rateScalar,
341
+ int256 totalAsset,
342
+ int256 rateAnchor
343
+ )
344
+ {
345
+ rateScalar = _getRateScalar(market, timeToExpiry);
346
+ totalAsset = index.scyToAsset(market.totalScy);
347
+
348
+ require(market.totalOt != 0 && totalAsset != 0);
349
+
350
+ // Get the rateAnchor given the market state, this will establish the baseline for where
351
+ // the exchange rate is set.
352
+ {
353
+ rateAnchor = _getRateAnchor(
354
+ market.totalOt,
355
+ market.lastImpliedRate,
356
+ totalAsset,
357
+ rateScalar,
358
+ timeToExpiry
359
+ );
360
+ }
361
+ }
362
+
363
+ /// @dev Returns net Asset amounts to the account, the market and the reserve. netAssetToReserve
364
+ /// is actually the fee portion of the trade
365
+ /// @return netAssetToAccount this is a positive or negative amount of Asset change to the account
366
+ /// @return netAssetToMarket this is a positive or negative amount of Asset change in the market
367
+ /// @return netAssetToReserve this is always a positive amount of Asset accrued to the reserve
368
+ function _getNetAssetAmountsToAddresses(
369
+ uint256 feeRateRoot,
370
+ int256 preFeeExchangeRate,
371
+ int256 otToAccount,
372
+ uint256 timeToExpiry,
373
+ int256 reserveFeePercent
374
+ )
375
+ private
376
+ pure
377
+ returns (
378
+ int256 netAssetToAccount,
379
+ int256 netAssetToMarket,
380
+ int256 netAssetToReserve
381
+ )
382
+ {
383
+ // Fees are specified in basis points which is an rate precision denomination. We convert this to
384
+ // an exchange rate denomination for the given time to expiry. (i.e. get e^(fee * t) and multiply
385
+ // or divide depending on the side of the trade).
386
+ // tradeExchangeRate = exp((tradeInterestRateNoFee +/- fee) * timeToExpiry)
387
+ // tradeExchangeRate = tradeExchangeRateNoFee (* or /) exp(fee * timeToExpiry)
388
+ // Asset = OT / exchangeRate, exchangeRate > 1
389
+ int256 preFeeAssetToAccount = otToAccount.divDown(preFeeExchangeRate).neg();
390
+ int256 fee = _getExchangeRateFromImpliedRate(feeRateRoot, timeToExpiry);
391
+
392
+ if (otToAccount > 0) {
393
+ // swapping SCY for OT
394
+
395
+ // Dividing reduces exchange rate, swapping SCY to OT means account should receive less OT
396
+ int256 postFeeExchangeRate = preFeeExchangeRate.divDown(fee);
397
+ // It's possible that the fee pushes exchange rates into negative territory. This is not possible
398
+ // when swapping OT to SCY. If this happens then the trade has failed.
399
+ require(postFeeExchangeRate >= FixedPoint.ONE_INT, "exchange rate below 1");
400
+
401
+ // assetToAccount = -(otToAccount / exchangeRate)
402
+ // postFeeExchangeRate = preFeeExchangeRate / feeExchangeRate
403
+ // preFeeAssetToAccount = -(otToAccount / preFeeExchangeRate)
404
+ // postFeeAssetToAccount = -(otToAccount / postFeeExchangeRate)
405
+ // netFee = preFeeAssetToAccount - postFeeAssetToAccount
406
+ // netFee = (otToAccount / postFeeExchangeRate) - (otToAccount / preFeeExchangeRate)
407
+ // netFee = ((otToAccount * feeExchangeRate) / preFeeExchangeRate) - (otToAccount / preFeeExchangeRate)
408
+ // netFee = (otToAccount / preFeeExchangeRate) * (feeExchangeRate - 1)
409
+ // netFee = -(preFeeAssetToAccount) * (feeExchangeRate - 1)
410
+ // netFee = preFeeAssetToAccount * (1 - feeExchangeRate)
411
+ // RATE_PRECISION - fee will be negative here, preFeeAssetToAccount < 0, fee > 0
412
+ fee = preFeeAssetToAccount.mulDown(FixedPoint.ONE_INT - fee);
413
+ } else {
414
+ // swapping OT for SCY
415
+
416
+ // assetToAccount = -(otToAccount / exchangeRate)
417
+ // postFeeExchangeRate = preFeeExchangeRate * feeExchangeRate
418
+
419
+ // netFee = preFeeAssetToAccount - postFeeAssetToAccount
420
+ // netFee = (otToAccount / postFeeExchangeRate) - (otToAccount / preFeeExchangeRate)
421
+ // netFee = ((otToAccount / (feeExchangeRate * preFeeExchangeRate)) - (otToAccount / preFeeExchangeRate)
422
+ // netFee = (otToAccount / preFeeExchangeRate) * (1 / feeExchangeRate - 1)
423
+ // netFee = preFeeAssetToAccount * ((1 - feeExchangeRate) / feeExchangeRate)
424
+ // NOTE: preFeeAssetToAccount is negative in this branch so we negate it to ensure that fee is a positive number
425
+ // preFee * (1 - fee) / fee will be negative, use neg() to flip to positive
426
+ // RATE_PRECISION - fee will be negative
427
+ fee = ((preFeeAssetToAccount * (FixedPoint.ONE_INT - fee)) / fee).neg();
428
+ }
429
+
430
+ netAssetToReserve = (fee * reserveFeePercent) / PERCENTAGE_DECIMALS;
431
+
432
+ // postFeeAssetToAccount = preFeeAssetToAccount - fee
433
+ netAssetToAccount = preFeeAssetToAccount - fee;
434
+ netAssetToMarket = (preFeeAssetToAccount - fee + netAssetToReserve).neg();
435
+ }
436
+
437
+ /// @notice Sets the new market state
438
+ /// @return netScyToAccount the positive or negative change in asset scy to the account
439
+ /// @return netScyToReserve the positive amount of scy that accrues to the reserve
440
+ function _setNewMarketState(
441
+ MarketParameters memory market,
442
+ SCYIndex index,
443
+ int256 netAssetToAccount,
444
+ int256 netAssetToMarket,
445
+ int256 netAssetToReserve,
446
+ uint256 blockTime
447
+ ) private pure returns (int256 netScyToAccount, int256 netScyToReserve) {
448
+ int256 netScyToMarket = index.assetToScy(netAssetToMarket);
449
+ // Set storage checks that total asset scy is above zero
450
+ market.totalScy = market.totalScy + netScyToMarket;
451
+
452
+ market.lastTradeTime = blockTime;
453
+ netScyToReserve = index.assetToScy(netAssetToReserve);
454
+ netScyToAccount = index.assetToScy(netAssetToAccount);
455
+ }
456
+
457
+ /// @notice Rate anchors update as the market gets closer to expiry. Rate anchors are not comparable
458
+ /// across time or markets but implied rates are. The goal here is to ensure that the implied rate
459
+ /// before and after the rate anchor update is the same. Therefore, the market will trade at the same implied
460
+ /// rate that it last traded at. If these anchors do not update then it opens up the opportunity for arbitrage
461
+ /// which will hurt the liquidity providers.
462
+ ///
463
+ /// The rate anchor will update as the market rolls down to expiry. The calculation is:
464
+ /// newExchangeRate = e^(lastImpliedRate * timeToExpiry / Constants.IMPLIED_RATE_TIME)
465
+ /// newAnchor = newExchangeRate - ln((proportion / (1 - proportion)) / rateScalar
466
+ ///
467
+ /// where:
468
+ /// lastImpliedRate = ln(exchangeRate') * (Constants.IMPLIED_RATE_TIME / timeToExpiry')
469
+ /// (calculated when the last trade in the market was made)
470
+ /// @return rateAnchor the new rateAnchor
471
+ function _getRateAnchor(
472
+ int256 totalOt,
473
+ uint256 lastImpliedRate,
474
+ int256 totalAsset,
475
+ int256 rateScalar,
476
+ uint256 timeToExpiry
477
+ ) private pure returns (int256 rateAnchor) {
478
+ // This is the exchange rate at the new time to expiry
479
+ int256 newExchangeRate = _getExchangeRateFromImpliedRate(lastImpliedRate, timeToExpiry);
480
+
481
+ require(newExchangeRate >= FixedPoint.ONE_INT, "exchange rate below 1");
482
+
483
+ {
484
+ // totalOt / (totalOt + totalAsset)
485
+ int256 proportion = totalOt.divDown(totalOt + totalAsset);
486
+
487
+ int256 lnProportion = _logProportion(proportion);
488
+
489
+ // newExchangeRate - ln(proportion / (1 - proportion)) / rateScalar
490
+ rateAnchor = newExchangeRate - lnProportion.divDown(rateScalar);
491
+ }
492
+ }
493
+
494
+ /// @notice Calculates the current market implied rate.
495
+ /// @return impliedRate the implied rate
496
+ function _getImpliedRate(
497
+ int256 totalOt,
498
+ int256 totalAsset,
499
+ int256 rateScalar,
500
+ int256 rateAnchor,
501
+ uint256 timeToExpiry
502
+ ) private pure returns (uint256 impliedRate) {
503
+ // This will check for exchange rates < FixedPoint.ONE_INT
504
+ int256 exchangeRate = _getExchangeRate(totalOt, totalAsset, rateScalar, rateAnchor, 0);
505
+
506
+ // exchangeRate >= 1 so its ln >= 0
507
+ uint256 lnRate = exchangeRate.ln().Uint();
508
+
509
+ impliedRate = (lnRate * IMPLIED_RATE_TIME) / timeToExpiry;
510
+ }
511
+
512
+ /// @notice Converts an implied rate to an exchange rate given a time to expiry. The
513
+ /// formula is E = e^rt
514
+ function _getExchangeRateFromImpliedRate(uint256 impliedRate, uint256 timeToExpiry)
515
+ private
516
+ pure
517
+ returns (int256 exchangeRate)
518
+ {
519
+ uint256 rt = (impliedRate * timeToExpiry) / IMPLIED_RATE_TIME;
520
+
521
+ exchangeRate = LogExpMath.exp(rt.Int());
522
+ }
523
+
524
+ /// @notice Returns the exchange rate between OT and Asset for the given market
525
+ /// Calculates the following exchange rate:
526
+ /// (1 / rateScalar) * ln(proportion / (1 - proportion)) + rateAnchor
527
+ /// where:
528
+ /// proportion = totalOt / (totalOt + totalUnderlyingAsset)
529
+ function _getExchangeRate(
530
+ int256 totalOt,
531
+ int256 totalAsset,
532
+ int256 rateScalar,
533
+ int256 rateAnchor,
534
+ int256 otToAccount
535
+ ) private pure returns (int256 exchangeRate) {
536
+ int256 numerator = totalOt.subNoNeg(otToAccount);
537
+
538
+ // This is the proportion scaled by FixedPoint.ONE_INT
539
+ // (totalOt + otToMarket) / (totalOt + totalAsset)
540
+ int256 proportion = (numerator.divDown(totalOt + totalAsset));
541
+
542
+ // This limit is here to prevent the market from reaching extremely high interest rates via an
543
+ // excessively large proportion (high amounts of OT relative to Asset).
544
+ // Market proportion can only increase via swapping OT to SCY (OT is added to the market and SCY is
545
+ // removed). Over time, the yield from SCY will slightly decrease the proportion (the
546
+ // amount of Asset in the market must be monotonically increasing). Therefore it is not
547
+ // possible for the proportion to go over max market proportion unless borrowing occurs.
548
+ require(proportion <= MAX_MARKET_PROPORTION); // TODO: probably not applicable to Pendle
549
+
550
+ int256 lnProportion = _logProportion(proportion);
551
+
552
+ // lnProportion / rateScalar + rateAnchor
553
+ exchangeRate = lnProportion.divDown(rateScalar) + rateAnchor;
554
+
555
+ // Do not succeed if interest rates fall below 1
556
+ require(exchangeRate >= FixedPoint.ONE_INT, "exchange rate below 1");
557
+ }
558
+
559
+ function _logProportion(int256 proportion) private pure returns (int256 res) {
560
+ // This will result in divide by zero, short circuit
561
+ require(proportion != FixedPoint.ONE_INT);
562
+
563
+ // Convert proportion to what is used inside the logit function (p / (1-p))
564
+ int256 logitP = proportion.divDown(FixedPoint.ONE_INT - proportion);
565
+
566
+ res = logitP.ln();
567
+ }
568
+
569
+ function _getRateScalar(MarketParameters memory market, uint256 timeToExpiry)
570
+ private
571
+ pure
572
+ returns (int256 rateScalar)
573
+ {
574
+ rateScalar = (market.scalarRoot * IMPLIED_RATE_TIME.Int()) / timeToExpiry.Int();
575
+ require(rateScalar > 0, "rateScalar underflow");
576
+ }
577
+
578
+ ////////////////////////////////////////////////////////////////////////////////////////////////
579
+ /// Utility functions ////
580
+ ////////////////////////////////////////////////////////////////////////////////////////////////
581
+
582
+ // function timeToExpiry(MarketParameters memory market) internal view returns (uint256) {
583
+ // unchecked {
584
+ // require(block.timestamp <= market.expiry, "market expired");
585
+ // return market.expiry - block.timestamp;
586
+ // }
587
+ // }
588
+
589
+ function deepCloneMarket(MarketParameters memory marketImmutable)
590
+ internal
591
+ pure
592
+ returns (MarketParameters memory market)
593
+ {
594
+ market.totalOt = marketImmutable.totalOt;
595
+ market.totalScy = marketImmutable.totalScy;
596
+ market.totalLp = marketImmutable.totalLp;
597
+ market.oracleRate = marketImmutable.oracleRate;
598
+ market.scalarRoot = marketImmutable.scalarRoot;
599
+ market.feeRateRoot = marketImmutable.feeRateRoot;
600
+ market.rateOracleTimeWindow = marketImmutable.rateOracleTimeWindow;
601
+ market.expiry = marketImmutable.expiry;
602
+ market.reserveFeePercent = marketImmutable.reserveFeePercent;
603
+ market.lastImpliedRate = marketImmutable.lastImpliedRate;
604
+ market.lastTradeTime = marketImmutable.lastTradeTime;
605
+ }
606
+ }
@@ -0,0 +1,36 @@
1
+ // SPDX-License-Identifier: GPL-3.0-or-later
2
+ pragma solidity 0.8.9;
3
+
4
+ contract PendleGovernanceManager {
5
+ address public governance;
6
+ address public pendingGovernance;
7
+
8
+ event GovernanceTransferred(address newGovernance, address previousGovernance);
9
+
10
+ modifier onlyGovernance() {
11
+ require(msg.sender == governance, "ONLY_GOVERNANCE");
12
+ _;
13
+ }
14
+
15
+ constructor(address _governance) {
16
+ governance = _governance;
17
+ }
18
+
19
+ /**
20
+ * @dev Allows the pendingGovernance address to finalize the change governance process.
21
+ */
22
+ function claimGovernance() external {
23
+ require(pendingGovernance == msg.sender, "FORBIDDEN");
24
+ emit GovernanceTransferred(pendingGovernance, governance);
25
+ governance = pendingGovernance;
26
+ pendingGovernance = address(0);
27
+ }
28
+
29
+ /**
30
+ * @dev Allows the current governance to set the pendingGovernance address.
31
+ * @param _governance The address to transfer ownership to.
32
+ */
33
+ function transferGovernance(address _governance) external onlyGovernance {
34
+ pendingGovernance = _governance;
35
+ }
36
+ }
@@ -0,0 +1,23 @@
1
+ // SPDX-License-Identifier: GPL-3.0-or-later
2
+ pragma solidity 0.8.9;
3
+
4
+ import "../interfaces/IPGovernanceManager.sol";
5
+ import "../interfaces/IPPermissionsV2.sol";
6
+
7
+ abstract contract PermissionsV2 is IPermissionsV2 {
8
+ address public immutable governanceManager;
9
+
10
+ modifier onlyGovernance() {
11
+ require(msg.sender == _governance(), "ONLY_GOVERNANCE");
12
+ _;
13
+ }
14
+
15
+ constructor(address _governanceManager) {
16
+ require(_governanceManager != address(0), "ZERO_ADDRESS");
17
+ governanceManager = _governanceManager;
18
+ }
19
+
20
+ function _governance() internal view returns (address) {
21
+ return IPGovernanceManager(governanceManager).governance();
22
+ }
23
+ }