@pendle/core-v2 0.5.1-beta-5 → 0.6.2

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 (54) hide show
  1. package/contracts/SuperComposableYield/ISuperComposableYield.sol +2 -0
  2. package/contracts/SuperComposableYield/implementations/RewardManager.sol +35 -20
  3. package/contracts/SuperComposableYield/implementations/SCYBase.sol +39 -19
  4. package/contracts/SuperComposableYield/implementations/SCYBaseWithRewards.sol +26 -14
  5. package/contracts/core/PendleBaseToken.sol +2 -2
  6. package/contracts/core/PendleMarket.sol +145 -61
  7. package/contracts/core/PendleMarketFactory.sol +30 -19
  8. package/contracts/core/{PendleOwnershipToken.sol → PendlePrincipalToken.sol} +14 -2
  9. package/contracts/core/PendleRouter.sol +23 -9
  10. package/contracts/core/PendleSCYImpl/AaveV3/PendleAaveV3SCY.sol +21 -20
  11. package/contracts/core/PendleSCYImpl/PendleBenQiErc20SCY.sol +22 -16
  12. package/contracts/core/PendleSCYImpl/PendleBtrflySCY.sol +13 -13
  13. package/contracts/core/PendleSCYImpl/PendleStETHSCY.sol +107 -0
  14. package/contracts/core/PendleSCYImpl/PendleYearnVaultSCY.sol +14 -15
  15. package/contracts/core/PendleYieldContractFactory.sol +29 -14
  16. package/contracts/core/PendleYieldToken.sol +130 -76
  17. package/contracts/core/RouterStatic.sol +51 -51
  18. package/contracts/core/actions/ActionCallback.sol +36 -18
  19. package/contracts/core/actions/ActionCore.sol +41 -88
  20. package/contracts/core/actions/ActionRedeem.sol +36 -0
  21. package/contracts/core/actions/ActionYT.sol +41 -59
  22. package/contracts/core/actions/base/{ActionSCYAndOTBase.sol → ActionSCYAndPTBase.sol} +59 -45
  23. package/contracts/core/actions/base/{ActionSCYAndYOBase.sol → ActionSCYAndPYBase.sol} +57 -19
  24. package/contracts/core/actions/base/ActionSCYAndYTBase.sol +31 -21
  25. package/contracts/interfaces/IPActionCore.sol +21 -28
  26. package/contracts/interfaces/IPActionRedeem.sol +17 -0
  27. package/contracts/interfaces/IPActionYT.sol +5 -12
  28. package/contracts/interfaces/IPAllAction.sol +2 -2
  29. package/contracts/interfaces/IPMarket.sol +33 -10
  30. package/contracts/interfaces/IPMarketAddRemoveCallback.sol +2 -2
  31. package/contracts/interfaces/IPMarketFactory.sol +3 -1
  32. package/contracts/interfaces/IPMarketSwapCallback.sol +1 -1
  33. package/contracts/interfaces/{IPOwnershipToken.sol → IPPrincipalToken.sol} +1 -1
  34. package/contracts/interfaces/IPRouterStatic.sol +19 -19
  35. package/contracts/interfaces/IPYieldContractFactory.sol +10 -2
  36. package/contracts/interfaces/IPYieldToken.sol +14 -5
  37. package/contracts/interfaces/IWstETH.sol +10 -0
  38. package/contracts/libraries/JoeLibrary.sol +1 -1
  39. package/contracts/libraries/math/LogExpMath.sol +1 -1
  40. package/contracts/libraries/math/MarketApproxLib.sol +128 -88
  41. package/contracts/libraries/math/MarketMathAux.sol +13 -13
  42. package/contracts/libraries/math/MarketMathCore.sol +62 -93
  43. package/contracts/libraries/math/Math.sol +14 -2
  44. package/contracts/periphery/PendleGovernanceManager.sol +5 -3
  45. package/package.json +3 -2
  46. package/typechain-types/IPRouterStatic.ts +480 -0
  47. package/typechain-types/RouterStatic.ts +484 -4
  48. package/typechain-types/factories/IPRouterStatic__factory.ts +616 -0
  49. package/typechain-types/factories/PendleRouter__factory.ts +1 -1
  50. package/typechain-types/factories/RouterStatic__factory.ts +619 -3
  51. package/typechain-types/ActionSCYAndYOBase.ts +0 -223
  52. package/typechain-types/PendleRouterRedeemUpg.ts +0 -125
  53. package/typechain-types/factories/ActionSCYAndYOBase__factory.ts +0 -200
  54. package/typechain-types/factories/PendleRouterRedeemUpg__factory.ts +0 -112
@@ -4,22 +4,23 @@ pragma solidity 0.8.9;
4
4
  import "./PendleBaseToken.sol";
5
5
  import "../SuperComposableYield/ISuperComposableYield.sol";
6
6
  import "../interfaces/IPYieldToken.sol";
7
- import "../interfaces/IPOwnershipToken.sol";
7
+ import "../interfaces/IPPrincipalToken.sol";
8
8
  import "../libraries/math/Math.sol";
9
9
  import "../interfaces/IPYieldContractFactory.sol";
10
- import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
11
10
  import "../SuperComposableYield/SCYUtils.sol";
12
11
  import "../SuperComposableYield/implementations/RewardManager.sol";
12
+ import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
13
+ import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
13
14
 
14
15
  /*
15
16
  With YT yielding more SCYs overtime, which is allowed to be redeemed by users, the reward distribution should
16
17
  be based on the amount of SCYs that their YT currently represent, plus with their dueInterest.
17
18
 
18
- It has been proven and tested that impliedScyBalance will not change over time, unless users redeem their interest or redeemYO.
19
+ It has been proven and tested that impliedScyBalance will not change over time, unless users redeem their interest or redeemPY.
19
20
 
20
21
  Due to this, it is required to update users' accruedReward STRICTLY BEFORE redeeming their interest.
21
22
  */
22
- contract PendleYieldToken is PendleBaseToken, RewardManager, IPYieldToken {
23
+ contract PendleYieldToken is PendleBaseToken, RewardManager, IPYieldToken, ReentrancyGuard {
23
24
  using Math for uint256;
24
25
  using SafeERC20 for IERC20;
25
26
 
@@ -29,113 +30,145 @@ contract PendleYieldToken is PendleBaseToken, RewardManager, IPYieldToken {
29
30
  }
30
31
 
31
32
  address public immutable SCY;
32
- address public immutable OT;
33
+ address public immutable PT;
33
34
 
34
35
  /// params to do interests & rewards accounting
35
36
  uint256 public lastScyBalance;
36
37
  uint256 public lastScyIndexBeforeExpiry;
37
- uint256[] public paramL;
38
38
 
39
39
  /// params to do fee accounting
40
40
  mapping(address => uint256) public totalRewardsPostExpiry;
41
+ uint256 public totalInterestPostExpiry;
41
42
  uint256 public totalProtocolFee;
42
43
 
43
44
  mapping(address => InterestData) internal interestData;
44
45
 
45
46
  constructor(
46
47
  address _SCY,
47
- address _OT,
48
+ address _PT,
48
49
  string memory _name,
49
50
  string memory _symbol,
50
51
  uint8 __decimals,
51
52
  uint256 _expiry
52
53
  ) PendleBaseToken(_name, _symbol, __decimals, _expiry) {
54
+ require(_SCY != address(0) && _PT != address(0), "zero address");
53
55
  SCY = _SCY;
54
- OT = _OT;
56
+ PT = _PT;
55
57
  }
56
58
 
57
59
  /**
58
- * @notice this function splits scy into OT + YT of equal qty
60
+ * @notice this function splits scy into PT + YT of equal qty
59
61
  * @dev the scy to tokenize has to be pre-transferred to this contract prior to the function call
60
62
  */
61
- function mintYO(address receiverOT, address receiverYT) public returns (uint256 amountYOOut) {
63
+ function mintPY(address receiverPT, address receiverYT)
64
+ external
65
+ nonReentrant
66
+ returns (uint256 amountPYOut)
67
+ {
62
68
  uint256 amountToTokenize = _receiveSCY();
63
69
 
64
- amountYOOut = _calcAmountToMint(amountToTokenize);
70
+ amountPYOut = _calcAmountToMint(amountToTokenize);
65
71
 
66
- _mint(receiverYT, amountYOOut);
72
+ _mint(receiverYT, amountPYOut);
67
73
 
68
- IPOwnershipToken(OT).mintByYT(receiverOT, amountYOOut);
74
+ IPPrincipalToken(PT).mintByYT(receiverPT, amountPYOut);
69
75
  }
70
76
 
71
- /// this function converts YO tokens into scy, but interests & rewards are not included
72
- function redeemYO(address receiver) public returns (uint256 amountScyOut) {
73
- // minimum of OT & YT balance
74
- uint256 amountYOToRedeem = IERC20(OT).balanceOf(address(this));
77
+ /// @dev this function converts PY tokens into scy, but interests & rewards are not redeemed at the same time
78
+ function redeemPY(address receiver) external nonReentrant returns (uint256 amountScyOut) {
79
+ // minimum of PT & YT balance
80
+ uint256 amountPYToRedeem = IERC20(PT).balanceOf(address(this));
75
81
  if (!isExpired()) {
76
- amountYOToRedeem = Math.min(amountYOToRedeem, balanceOf(address(this)));
77
- _burn(address(this), amountYOToRedeem);
82
+ amountPYToRedeem = Math.min(amountPYToRedeem, balanceOf(address(this)));
83
+ _burn(address(this), amountPYToRedeem);
78
84
  }
79
- IPOwnershipToken(OT).burnByYT(address(this), amountYOToRedeem);
80
85
 
81
- amountScyOut = _calcAmountRedeemable(amountYOToRedeem);
86
+ IPPrincipalToken(PT).burnByYT(address(this), amountPYToRedeem);
87
+
88
+ uint256 amountScyToTreasury;
89
+ (amountScyOut, amountScyToTreasury) = _calcAmountToRedeem(amountPYToRedeem);
90
+
91
+ totalInterestPostExpiry += amountScyToTreasury;
82
92
 
83
93
  IERC20(SCY).safeTransfer(receiver, amountScyOut);
84
94
  _afterTransferOutSCY();
85
95
  }
86
96
 
97
+ /**
98
+ * @dev as mentioned in doc, updateDueReward should be placed strictly before every redeemDueInterest
99
+ */
87
100
  function redeemDueInterestAndRewards(address user)
88
- public
101
+ external
102
+ nonReentrant
89
103
  returns (uint256 interestOut, uint256[] memory rewardsOut)
90
104
  {
91
105
  // redeemDueRewards before redeemDueInterest
92
- updateUserReward(user);
93
- updateUserInterest(user);
106
+ _updateUserReward(user);
107
+ _updateUserInterest(user);
94
108
  rewardsOut = _doTransferOutRewardsForUser(user, user);
95
109
  interestOut = _doTransferOutDueInterest(user);
110
+
111
+ emit RedeemReward(user, rewardsOut);
112
+ emit RedeemInterest(user, interestOut);
96
113
  }
97
114
 
98
- function redeemDueInterest(address user) public returns (uint256 interestOut) {
99
- updateUserReward(user); /// strictly required, see above for explanation
100
- updateUserInterest(user);
115
+ /**
116
+ * @dev as mentioned in doc, updateDueReward should be placed strictly before every redeemDueInterest
117
+ */
118
+ function redeemDueInterest(address user) external nonReentrant returns (uint256 interestOut) {
119
+ _updateUserReward(user); /// strictly required, see above for explanation
120
+
121
+ _updateUserInterest(user);
101
122
  interestOut = _doTransferOutDueInterest(user);
123
+ emit RedeemInterest(user, interestOut);
102
124
  }
103
125
 
104
- function redeemDueRewards(address user) public returns (uint256[] memory rewardsOut) {
105
- updateUserReward(user);
126
+ function redeemDueRewards(address user)
127
+ external
128
+ nonReentrant
129
+ returns (uint256[] memory rewardsOut)
130
+ {
131
+ _updateUserReward(user);
132
+
106
133
  rewardsOut = _doTransferOutRewardsForUser(user, user);
134
+ emit RedeemReward(user, rewardsOut);
107
135
  }
108
136
 
109
- function updateGlobalReward() external {
110
- address[] memory rewardTokens = getRewardTokens();
111
- _updateGlobalReward(rewardTokens, IERC20(SCY).balanceOf(address(this)));
137
+ /**
138
+ * @dev updateGlobalReward does not need reentrancy modifier since the rewards
139
+ * will be transfered directly from SCY to YT, without triggering any callbacks
140
+ */
141
+ function updateGlobalReward() external nonReentrant {
142
+ _updateGlobalReward();
143
+ }
144
+
145
+ function updateUserReward(address user) external nonReentrant {
146
+ _updateUserReward(user);
112
147
  }
113
148
 
114
- function updateUserReward(address user) public {
115
- uint256 impliedScyBalance = getImpliedScyBalance(user);
116
- uint256 totalScy = IERC20(SCY).balanceOf(address(this));
117
- _updateUserReward(user, impliedScyBalance, totalScy);
149
+ function updateUserInterest(address user) external nonReentrant {
150
+ _updateUserInterest(user);
118
151
  }
119
152
 
120
- function updateUserInterest(address user) public {
153
+ function _updateUserInterest(address user) internal {
121
154
  uint256 prevIndex = interestData[user].lastScyIndex;
122
155
 
123
- uint256 currentIndex = getScyIndexBeforeExpiry();
156
+ (, uint256 currentIndexBeforeExpiry) = getScyIndex();
124
157
 
125
- if (prevIndex == currentIndex) return;
158
+ if (prevIndex == currentIndexBeforeExpiry) return;
126
159
  if (prevIndex == 0) {
127
- interestData[user].lastScyIndex = currentIndex;
160
+ interestData[user].lastScyIndex = currentIndexBeforeExpiry;
128
161
  return;
129
162
  }
130
163
 
131
164
  uint256 principal = balanceOf(user);
132
165
 
133
- uint256 interestFromYT = (principal * (currentIndex - prevIndex)).divDown(
134
- prevIndex * currentIndex
166
+ uint256 interestFromYT = (principal * (currentIndexBeforeExpiry - prevIndex)).divDown(
167
+ prevIndex * currentIndexBeforeExpiry
135
168
  );
136
169
 
137
170
  interestData[user].dueInterest += interestFromYT;
138
- interestData[user].lastScyIndex = currentIndex;
171
+ interestData[user].lastScyIndex = currentIndexBeforeExpiry;
139
172
  }
140
173
 
141
174
  function getInterestData(address user)
@@ -146,13 +179,15 @@ contract PendleYieldToken is PendleBaseToken, RewardManager, IPYieldToken {
146
179
  return (interestData[user].lastScyIndex, interestData[user].dueInterest);
147
180
  }
148
181
 
149
- function _updateGlobalReward(address[] memory rewardTokens, uint256 totalSupply)
150
- internal
151
- virtual
152
- override
153
- {
182
+ /// @dev override the default updateGlobalReward to avoid distributing the rewards after
183
+ /// YT has expired. Instead, these funds will go to the treasury
184
+ function _updateGlobalReward() internal virtual override {
185
+ if (!_shouldUpdateGlobalReward()) return;
154
186
  _redeemExternalReward();
155
187
 
188
+ uint256 totalShares = _rewardSharesTotal();
189
+
190
+ address[] memory rewardTokens = getRewardTokens();
156
191
  _initGlobalReward(rewardTokens);
157
192
 
158
193
  bool _isExpired = isExpired();
@@ -164,8 +199,8 @@ contract PendleYieldToken is PendleBaseToken, RewardManager, IPYieldToken {
164
199
 
165
200
  if (_isExpired) {
166
201
  totalRewardsPostExpiry[token] += totalIncomeReward;
167
- } else if (totalSupply != 0) {
168
- globalReward[token].index += totalIncomeReward.divDown(totalSupply);
202
+ } else if (totalShares != 0) {
203
+ globalReward[token].index += totalIncomeReward.divDown(totalShares);
169
204
  }
170
205
 
171
206
  globalReward[token].lastBalance = currentRewardBalance;
@@ -186,7 +221,17 @@ contract PendleYieldToken is PendleBaseToken, RewardManager, IPYieldToken {
186
221
  }
187
222
 
188
223
  function _redeemExternalReward() internal virtual override {
189
- ISuperComposableYield(SCY).redeemReward(address(this));
224
+ ISuperComposableYield(SCY).redeemReward(address(this)); // ignore return
225
+ }
226
+
227
+ /// @dev to be overriden if there is rewards
228
+ function _rewardSharesTotal() internal virtual override returns (uint256) {
229
+ return IERC20(SCY).balanceOf(address(this));
230
+ }
231
+
232
+ /// @dev to be overriden if there is rewards
233
+ function _rewardSharesUser(address user) internal virtual override returns (uint256) {
234
+ return getImpliedScyBalance(user);
190
235
  }
191
236
 
192
237
  function getRewardTokens()
@@ -199,48 +244,63 @@ contract PendleYieldToken is PendleBaseToken, RewardManager, IPYieldToken {
199
244
  return ISuperComposableYield(SCY).getRewardTokens();
200
245
  }
201
246
 
202
- function getScyIndexBeforeExpiry() public returns (uint256 res) {
203
- if (isExpired()) return res = lastScyIndexBeforeExpiry;
204
- res = ISuperComposableYield(SCY).scyIndexCurrent();
205
- lastScyIndexBeforeExpiry = res;
247
+ function getScyIndex() public returns (uint256 currentIndex, uint256 lastIndexBeforeExpiry) {
248
+ currentIndex = ISuperComposableYield(SCY).scyIndexCurrent();
249
+ if (isExpired()) {
250
+ lastIndexBeforeExpiry = lastScyIndexBeforeExpiry;
251
+ } else {
252
+ lastScyIndexBeforeExpiry = lastIndexBeforeExpiry = currentIndex;
253
+ }
206
254
  }
207
255
 
208
256
  /**
209
- * In case the pool is expired and there is left some SCY not yet redeemed from the contract, the rewards should
257
+ * @dev In case the pool is expired and there is left some SCY not yet redeemed from the contract, the rewards should
210
258
  * be claimed before withdrawing to treasury.
211
259
  *
212
- * And since the reward distribution (which based on users' dueInterest) stopped at the scyIndexBeforeExpiry, it is not
213
- * necessary to updateDueInterest along with reward here.
260
+ * @dev And since the reward distribution (which based on users' dueInterest) stopped at the scyIndexBeforeExpiry, it is not
261
+ * necessary to updateUserInterest along with reward here.
214
262
  */
215
263
  function withdrawFeeToTreasury() public {
216
264
  address[] memory rewardTokens = getRewardTokens();
217
265
  if (isExpired()) {
218
- _updateGlobalReward(rewardTokens, IERC20(SCY).balanceOf(address(this))); // as refered to the doc above
266
+ _updateGlobalReward(); // as refered to the doc above
219
267
  }
220
268
 
221
269
  uint256 length = rewardTokens.length;
222
270
  address treasury = IPYieldContractFactory(factory).treasury();
271
+ uint256[] memory amountRewardsOut = new uint256[](length);
223
272
 
224
273
  for (uint256 i = 0; i < length; i++) {
225
274
  address token = rewardTokens[i];
226
275
  uint256 outAmount = totalRewardsPostExpiry[token];
227
276
  if (outAmount > 0) IERC20(rewardTokens[i]).safeTransfer(treasury, outAmount);
228
277
  totalRewardsPostExpiry[token] = 0;
278
+ amountRewardsOut[i] = outAmount;
229
279
  }
230
280
 
231
- if (totalProtocolFee > 0) {
232
- IERC20(SCY).safeTransfer(treasury, totalProtocolFee);
281
+ uint256 totalScyFee = totalProtocolFee + totalInterestPostExpiry;
282
+ totalProtocolFee = totalInterestPostExpiry = 0;
283
+
284
+ if (totalScyFee > 0) {
285
+ IERC20(SCY).safeTransfer(treasury, totalScyFee);
233
286
  _afterTransferOutSCY();
234
- totalProtocolFee = 0;
235
287
  }
288
+ emit WithdrawFeeToTreasury(amountRewardsOut, totalScyFee);
236
289
  }
237
290
 
238
291
  function _calcAmountToMint(uint256 amount) internal returns (uint256) {
239
- return SCYUtils.scyToAsset(getScyIndexBeforeExpiry(), amount);
292
+ (, uint256 lastIndexBeforeExpiry) = getScyIndex();
293
+ return SCYUtils.scyToAsset(lastIndexBeforeExpiry, amount);
240
294
  }
241
295
 
242
- function _calcAmountRedeemable(uint256 amount) internal returns (uint256) {
243
- return SCYUtils.assetToScy(getScyIndexBeforeExpiry(), amount);
296
+ function _calcAmountToRedeem(uint256 amount)
297
+ internal
298
+ returns (uint256 amountToUser, uint256 amountToTreasury)
299
+ {
300
+ (uint256 currentIndex, uint256 lastIndexBeforeExpiry) = getScyIndex();
301
+ uint256 totalRedeemable = SCYUtils.assetToScy(lastIndexBeforeExpiry, amount);
302
+ amountToUser = SCYUtils.assetToScy(currentIndex, amount);
303
+ amountToTreasury = totalRedeemable - amountToUser;
244
304
  }
245
305
 
246
306
  function _receiveSCY() internal returns (uint256 amount) {
@@ -256,7 +316,6 @@ contract PendleYieldToken is PendleBaseToken, RewardManager, IPYieldToken {
256
316
 
257
317
  function getImpliedScyBalance(address user) public view returns (uint256) {
258
318
  uint256 scyIndex = interestData[user].lastScyIndex;
259
- if (scyIndex == 0) return 0;
260
319
  return SCYUtils.assetToScy(scyIndex, balanceOf(user)) + interestData[user].dueInterest;
261
320
  }
262
321
 
@@ -265,22 +324,17 @@ contract PendleYieldToken is PendleBaseToken, RewardManager, IPYieldToken {
265
324
  address to,
266
325
  uint256
267
326
  ) internal override {
268
- address[] memory rewardTokens = getRewardTokens();
269
- _updateGlobalReward(rewardTokens, IERC20(SCY).balanceOf(address(this)));
327
+ _updateGlobalReward();
270
328
 
271
329
  // Before the change in YT balance, users' impliedScyBalance is kept unchanged from last time
272
330
  // Therefore, both updating due interest before or after due reward work the same.
273
331
  if (from != address(0) && from != address(this)) {
274
- updateUserInterest(from);
275
- _updateUserRewardSkipGlobal(rewardTokens, from, getImpliedScyBalance(from));
332
+ _updateUserInterest(from);
333
+ _updateUserRewardSkipGlobal(from);
276
334
  }
277
335
  if (to != address(0) && to != address(this)) {
278
- updateUserInterest(to);
279
- _updateUserRewardSkipGlobal(rewardTokens, to, getImpliedScyBalance(to));
336
+ _updateUserInterest(to);
337
+ _updateUserRewardSkipGlobal(to);
280
338
  }
281
339
  }
282
340
  }
283
- /*INVARIANTS TO CHECK
284
- - supply OT == supply YT
285
- - reentrancy check
286
- */
@@ -29,20 +29,20 @@ contract RouterStatic is IPRouterStatic {
29
29
  function addLiquidityStatic(
30
30
  address market,
31
31
  uint256 scyDesired,
32
- uint256 otDesired
32
+ uint256 ptDesired
33
33
  )
34
34
  external
35
35
  returns (
36
36
  uint256 netLpOut,
37
37
  uint256 scyUsed,
38
- uint256 otUsed
38
+ uint256 ptUsed
39
39
  )
40
40
  {
41
41
  MarketState memory state = IPMarket(market).readState(false);
42
- (, netLpOut, scyUsed, otUsed) = state.addLiquidity(
42
+ (, netLpOut, scyUsed, ptUsed) = state.addLiquidity(
43
43
  scyIndex(market),
44
44
  scyDesired,
45
- otDesired,
45
+ ptDesired,
46
46
  false
47
47
  );
48
48
  }
@@ -50,33 +50,33 @@ contract RouterStatic is IPRouterStatic {
50
50
  function removeLiquidityStatic(address market, uint256 lpToRemove)
51
51
  external
52
52
  view
53
- returns (uint256 netScyOut, uint256 netOtOut)
53
+ returns (uint256 netScpyut, uint256 netPtOut)
54
54
  {
55
55
  MarketState memory state = IPMarket(market).readState(false);
56
- (netScyOut, netOtOut) = state.removeLiquidity(lpToRemove, false);
56
+ (netScpyut, netPtOut) = state.removeLiquidity(lpToRemove, false);
57
57
  }
58
58
 
59
- function swapOtForScyStatic(address market, uint256 exactOtIn)
59
+ function swapPtForScyStatic(address market, uint256 exactPtIn)
60
60
  external
61
- returns (uint256 netScyOut, uint256 netScyFee)
61
+ returns (uint256 netScpyut, uint256 netScyFee)
62
62
  {
63
63
  MarketState memory state = IPMarket(market).readState(false);
64
- (netScyOut, netScyFee) = state.swapExactOtForScy(
64
+ (netScpyut, netScyFee) = state.swapExactPtForScy(
65
65
  scyIndex(market),
66
- exactOtIn,
66
+ exactPtIn,
67
67
  block.timestamp,
68
68
  false
69
69
  );
70
70
  }
71
71
 
72
- function swapScyForOtStatic(address market, uint256 exactOtOut)
72
+ function swapScyForPtStatic(address market, uint256 exactPtOut)
73
73
  external
74
74
  returns (uint256 netScyIn, uint256 netScyFee)
75
75
  {
76
76
  MarketState memory state = IPMarket(market).readState(false);
77
- (netScyIn, netScyFee) = state.swapScyForExactOt(
77
+ (netScyIn, netScyFee) = state.swapScyForExactPt(
78
78
  scyIndex(market),
79
- exactOtOut,
79
+ exactPtOut,
80
80
  block.timestamp,
81
81
  false
82
82
  );
@@ -86,10 +86,10 @@ contract RouterStatic is IPRouterStatic {
86
86
  return SCYIndexLib.newIndex(IPMarket(market).SCY());
87
87
  }
88
88
 
89
- function getOtImpliedYield(address market) public view returns (int256) {
89
+ function getPtImpliedYield(address market) public view returns (int256) {
90
90
  MarketState memory state = IPMarket(market).readState(false);
91
91
 
92
- int256 lnImpliedRate = (state.lastImpliedRate).Int();
92
+ int256 lnImpliedRate = (state.lastLnImpliedRate).Int();
93
93
  return lnImpliedRate.exp();
94
94
  }
95
95
 
@@ -97,27 +97,27 @@ contract RouterStatic is IPRouterStatic {
97
97
  external
98
98
  view
99
99
  returns (
100
- bool isOT,
100
+ bool isPT,
101
101
  bool isYT,
102
102
  bool isMarket
103
103
  )
104
104
  {
105
- if (yieldContractFactory.isOT(token)) isOT = true;
105
+ if (yieldContractFactory.isPT(token)) isPT = true;
106
106
  else if (yieldContractFactory.isYT(token)) isYT = true;
107
107
  else if (marketFactory.isValidMarket(token)) isMarket = true;
108
108
  }
109
109
 
110
- function getUserYOInfo(address yo, address user)
110
+ function getUserPYInfo(address py, address user)
111
111
  public
112
112
  view
113
- returns (UserYOInfo memory userYOInfo)
113
+ returns (UserPYInfo memory userPYInfo)
114
114
  {
115
- (userYOInfo.yt, userYOInfo.ot) = getYO(yo);
116
- IPYieldToken YT = IPYieldToken(userYOInfo.yt);
117
- userYOInfo.ytBalance = YT.balanceOf(user);
118
- userYOInfo.otBalance = IPOwnershipToken(userYOInfo.ot).balanceOf(user);
119
- userYOInfo.unclaimedInterest.token = YT.SCY();
120
- (, userYOInfo.unclaimedInterest.amount) = YT.getInterestData(user);
115
+ (userPYInfo.yt, userPYInfo.pt) = getPY(py);
116
+ IPYieldToken YT = IPYieldToken(userPYInfo.yt);
117
+ userPYInfo.ytBalance = YT.balanceOf(user);
118
+ userPYInfo.ptBalance = IPPrincipalToken(userPYInfo.pt).balanceOf(user);
119
+ userPYInfo.unclaimedInterest.token = YT.SCY();
120
+ (, userPYInfo.unclaimedInterest.amount) = YT.getInterestData(user);
121
121
  address[] memory rewardTokens = YT.getRewardTokens();
122
122
  TokenAmount[] memory unclaimedRewards = new TokenAmount[](rewardTokens.length);
123
123
  uint256 length = 0;
@@ -130,13 +130,13 @@ contract RouterStatic is IPRouterStatic {
130
130
  ++length;
131
131
  }
132
132
  }
133
- userYOInfo.unclaimedRewards = new TokenAmount[](length);
133
+ userPYInfo.unclaimedRewards = new TokenAmount[](length);
134
134
  for (uint256 i = 0; i < length; ++i) {
135
- userYOInfo.unclaimedRewards[i] = unclaimedRewards[i];
135
+ userPYInfo.unclaimedRewards[i] = unclaimedRewards[i];
136
136
  }
137
137
  }
138
138
 
139
- function getYOInfo(address yo)
139
+ function getPYInfo(address py)
140
140
  external
141
141
  returns (
142
142
  uint256 exchangeRate,
@@ -144,9 +144,9 @@ contract RouterStatic is IPRouterStatic {
144
144
  RewardIndex[] memory rewardIndexes
145
145
  )
146
146
  {
147
- (address yt, ) = getYO(yo);
147
+ (address yt, ) = getPY(py);
148
148
  IPYieldToken YT = IPYieldToken(yt);
149
- exchangeRate = YT.getScyIndexBeforeExpiry();
149
+ (, exchangeRate) = YT.getScyIndex();
150
150
  totalSupply = YT.totalSupply();
151
151
  address[] memory rewardTokens = YT.getRewardTokens();
152
152
  rewardIndexes = new RewardIndex[](rewardTokens.length);
@@ -157,13 +157,13 @@ contract RouterStatic is IPRouterStatic {
157
157
  }
158
158
  }
159
159
 
160
- function getYO(address yo) public view returns (address ot, address yt) {
161
- if (yieldContractFactory.isYT(yo)) {
162
- yt = yo;
163
- ot = IPYieldToken(yo).OT();
160
+ function getPY(address py) public view returns (address pt, address yt) {
161
+ if (yieldContractFactory.isYT(py)) {
162
+ yt = py;
163
+ pt = IPYieldToken(py).PT();
164
164
  } else {
165
- yt = IPOwnershipToken(yo).YT();
166
- ot = yo;
165
+ yt = IPPrincipalToken(py).YT();
166
+ pt = py;
167
167
  }
168
168
  }
169
169
 
@@ -171,7 +171,7 @@ contract RouterStatic is IPRouterStatic {
171
171
  external
172
172
  view
173
173
  returns (
174
- address ot,
174
+ address pt,
175
175
  address scy,
176
176
  MarketState memory state,
177
177
  int256 impliedYield,
@@ -179,10 +179,10 @@ contract RouterStatic is IPRouterStatic {
179
179
  )
180
180
  {
181
181
  IPMarket _market = IPMarket(market);
182
- ot = _market.OT();
182
+ pt = _market.PT();
183
183
  scy = _market.SCY();
184
184
  state = _market.readState(true);
185
- impliedYield = getOtImpliedYield(market);
185
+ impliedYield = getPtImpliedYield(market);
186
186
  exchangeRate = 0; // TODO: get the actual exchange rate
187
187
  }
188
188
 
@@ -194,21 +194,21 @@ contract RouterStatic is IPRouterStatic {
194
194
  IPMarket _market = IPMarket(market);
195
195
  userMarketInfo.market = market;
196
196
  userMarketInfo.lpBalance = _market.balanceOf(user);
197
- // TODO: Is there a way to convert LP to OT and SCY?
198
- userMarketInfo.otBalance = TokenAmount(_market.OT(), 0);
197
+ // TODO: Is there a way to convert LP to PT and SCY?
198
+ userMarketInfo.ptBalance = TokenAmount(_market.PT(), 0);
199
199
  userMarketInfo.scyBalance = TokenAmount(_market.SCY(), 0);
200
200
  // TODO: Get this from SCY once it is in the interface
201
201
  userMarketInfo.assetBalance = TokenAmount(address(0), 0);
202
202
  }
203
203
 
204
- function getUserYOPositionsByYOs(address user, address[] calldata yos)
204
+ function getUserPYPositionsByPYs(address user, address[] calldata pys)
205
205
  external
206
206
  view
207
- returns (UserYOInfo[] memory userYOPositions)
207
+ returns (UserPYInfo[] memory userPYPositions)
208
208
  {
209
- userYOPositions = new UserYOInfo[](yos.length);
210
- for (uint256 i = 0; i < yos.length; ++i) {
211
- userYOPositions[i] = getUserYOInfo(yos[i], user);
209
+ userPYPositions = new UserPYInfo[](pys.length);
210
+ for (uint256 i = 0; i < pys.length; ++i) {
211
+ userPYPositions[i] = getUserPYInfo(pys[i], user);
212
212
  }
213
213
  }
214
214
 
@@ -223,11 +223,11 @@ contract RouterStatic is IPRouterStatic {
223
223
  }
224
224
  }
225
225
 
226
- function hasYOPosition(UserYOInfo memory userYOInfo) public pure returns (bool hasPosition) {
227
- hasPosition = (userYOInfo.ytBalance > 0 ||
228
- userYOInfo.otBalance > 0 ||
229
- userYOInfo.unclaimedInterest.amount > 0 ||
230
- userYOInfo.unclaimedRewards.length > 0);
226
+ function hasPYPosition(UserPYInfo memory userPYInfo) public pure returns (bool hasPosition) {
227
+ hasPosition = (userPYInfo.ytBalance > 0 ||
228
+ userPYInfo.ptBalance > 0 ||
229
+ userPYInfo.unclaimedInterest.amount > 0 ||
230
+ userPYInfo.unclaimedRewards.length > 0);
231
231
  }
232
232
 
233
233
  function getUserSCYInfo(address scy, address user)