@pendle/core-v2 0.4.0 → 0.5.1-beta

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 (97) hide show
  1. package/contracts/SuperComposableYield/implementations/IRewardManager.sol +16 -0
  2. package/contracts/SuperComposableYield/implementations/RewardManager.sol +24 -5
  3. package/contracts/core/PendleMarket.sol +10 -18
  4. package/contracts/core/PendleMarketFactory.sol +49 -22
  5. package/contracts/core/PendleRouter.sol +74 -0
  6. package/contracts/core/PendleYieldToken.sol +20 -12
  7. package/contracts/core/RouterStatic.sol +234 -0
  8. package/contracts/core/actions/ActionCallback.sol +101 -0
  9. package/contracts/core/{router/PendleRouterCoreUpg.sol → actions/ActionCore.sol} +6 -10
  10. package/contracts/core/{router/PendleRouterYTUpg.sol → actions/ActionYT.sol} +6 -11
  11. package/contracts/core/{router/base/PendleRouterOTBaseUpg.sol → actions/base/ActionSCYAndOTBase.sol} +1 -5
  12. package/contracts/core/{router/base/PendleRouterSCYAndForgeBaseUpg.sol → actions/base/ActionSCYAndYOBase.sol} +3 -5
  13. package/contracts/core/{router/base/PendleRouterYTBaseUpg.sol → actions/base/ActionSCYAndYTBase.sol} +7 -99
  14. package/contracts/core/actions/base/ActionType.sol +11 -0
  15. package/contracts/interfaces/{IPRouterCore.sol → IPActionCore.sol} +1 -1
  16. package/contracts/interfaces/{IPRouterYT.sol → IPActionYT.sol} +1 -3
  17. package/contracts/interfaces/IPAllAction.sol +9 -0
  18. package/contracts/interfaces/IPMarketFactory.sol +11 -0
  19. package/contracts/interfaces/IPRouterStatic.sol +27 -0
  20. package/contracts/interfaces/IPYieldToken.sol +21 -3
  21. package/contracts/libraries/math/MarketMathCore.sol +3 -2
  22. package/package.json +1 -1
  23. package/typechain-types/{PendleRouterYTBaseUpg.ts → ActionCallback.ts} +5 -5
  24. package/typechain-types/{PendleRouterCoreUpg.ts → ActionCore.ts} +5 -5
  25. package/typechain-types/{PendleRouterSCYAndForgeBaseUpg.ts → ActionSCYAndYOBase.ts} +5 -6
  26. package/typechain-types/{BoringOwnableData.ts → ActionSCYAndYTBase.ts} +21 -24
  27. package/typechain-types/{PendleRouterStaticUpg.ts → ActionStatic.ts} +5 -5
  28. package/typechain-types/{IPRouterYT.ts → ActionYT.ts} +27 -42
  29. package/typechain-types/IPActionAll.ts +1431 -0
  30. package/typechain-types/{IPRouterCore.ts → IPActionCore.ts} +5 -5
  31. package/typechain-types/{IPRouterView.ts → IPActionStatic.ts} +57 -5
  32. package/typechain-types/{PendleRouterYTUpg.ts → IPActionYT.ts} +5 -97
  33. package/typechain-types/IPAllAction.ts +1431 -0
  34. package/typechain-types/IPMarket.ts +3 -0
  35. package/typechain-types/IPMarketFactory.ts +46 -0
  36. package/typechain-types/IPYieldToken.ts +342 -14
  37. package/typechain-types/IRewardManager.ts +178 -0
  38. package/typechain-types/PendleAaveV3SCY.ts +70 -64
  39. package/typechain-types/PendleBenQiErc20SCY.ts +70 -64
  40. package/typechain-types/PendleMarket.ts +3 -59
  41. package/typechain-types/PendleMarketFactory.ts +150 -24
  42. package/typechain-types/{PendleRouterProxy.ts → PendleRouter.ts} +29 -39
  43. package/typechain-types/PendleYieldToken.ts +116 -101
  44. package/typechain-types/RewardManager.ts +48 -42
  45. package/typechain-types/{PendleRouterViewUpg.ts → RouterStatic.ts} +97 -5
  46. package/typechain-types/SCYBaseWithRewards.ts +70 -64
  47. package/typechain-types/factories/ActionCallback__factory.ts +116 -0
  48. package/typechain-types/factories/ActionCore__factory.ts +632 -0
  49. package/typechain-types/factories/{PendleRouterSCYAndForgeBaseUpg__factory.ts → ActionSCYAndYOBase__factory.ts} +8 -12
  50. package/typechain-types/factories/ActionSCYAndYTBase__factory.ts +52 -0
  51. package/typechain-types/factories/ActionStatic__factory.ts +308 -0
  52. package/typechain-types/factories/ActionYT__factory.ts +370 -0
  53. package/typechain-types/factories/IPActionAll__factory.ts +983 -0
  54. package/typechain-types/factories/{IPRouterCore__factory.ts → IPActionCore__factory.ts} +6 -6
  55. package/typechain-types/factories/{IPRouterView__factory.ts → IPActionStatic__factory.ts} +38 -6
  56. package/typechain-types/factories/{IPRouterYT__factory.ts → IPActionYT__factory.ts} +6 -29
  57. package/typechain-types/factories/IPAllAction__factory.ts +983 -0
  58. package/typechain-types/factories/IPMarketFactory__factory.ts +28 -0
  59. package/typechain-types/factories/IPMarket__factory.ts +7 -2
  60. package/typechain-types/factories/IPYieldToken__factory.ts +158 -1
  61. package/typechain-types/factories/IRewardManager__factory.ts +92 -0
  62. package/typechain-types/factories/PendleAaveV3SCY__factory.ts +34 -34
  63. package/typechain-types/factories/PendleBenQiErc20SCY__factory.ts +34 -34
  64. package/typechain-types/factories/PendleBtrflyScy__factory.ts +1 -1
  65. package/typechain-types/factories/PendleMarketFactory__factory.ts +112 -17
  66. package/typechain-types/factories/PendleMarket__factory.ts +8 -69
  67. package/typechain-types/factories/PendleRouter__factory.ts +282 -0
  68. package/typechain-types/factories/PendleYearnVaultScy__factory.ts +1 -1
  69. package/typechain-types/factories/PendleYieldContractFactory__factory.ts +1 -1
  70. package/typechain-types/factories/PendleYieldToken__factory.ts +58 -58
  71. package/typechain-types/factories/RewardManager__factory.ts +18 -18
  72. package/typechain-types/factories/RouterStatic__factory.ts +308 -0
  73. package/typechain-types/factories/SCYBaseWithRewards__factory.ts +33 -33
  74. package/typechain-types/hardhat.d.ts +93 -75
  75. package/typechain-types/index.ts +22 -18
  76. package/contracts/core/router/PendleRouterProxy.sol +0 -84
  77. package/contracts/core/router/PendleRouterStaticUpg.sol +0 -107
  78. package/contracts/interfaces/IPFlashCallBack.sol +0 -10
  79. package/typechain-types/BoringOwnable.ts +0 -194
  80. package/typechain-types/BoringOwnableUpg.ts +0 -194
  81. package/typechain-types/BoringOwnableUpgData.ts +0 -100
  82. package/typechain-types/IPFlashCallback.ts +0 -115
  83. package/typechain-types/IPermissionsV2.ts +0 -87
  84. package/typechain-types/PermissionsV2.ts +0 -87
  85. package/typechain-types/factories/BoringOwnableData__factory.ts +0 -90
  86. package/typechain-types/factories/BoringOwnableUpgData__factory.ts +0 -94
  87. package/typechain-types/factories/BoringOwnableUpg__factory.ts +0 -139
  88. package/typechain-types/factories/BoringOwnable__factory.ts +0 -149
  89. package/typechain-types/factories/IPFlashCallback__factory.ts +0 -49
  90. package/typechain-types/factories/IPermissionsV2__factory.ts +0 -39
  91. package/typechain-types/factories/PendleRouterCoreUpg__factory.ts +0 -635
  92. package/typechain-types/factories/PendleRouterProxy__factory.ts +0 -285
  93. package/typechain-types/factories/PendleRouterStaticUpg__factory.ts +0 -315
  94. package/typechain-types/factories/PendleRouterViewUpg__factory.ts +0 -265
  95. package/typechain-types/factories/PendleRouterYTBaseUpg__factory.ts +0 -66
  96. package/typechain-types/factories/PendleRouterYTUpg__factory.ts +0 -422
  97. package/typechain-types/factories/PermissionsV2__factory.ts +0 -36
@@ -0,0 +1,16 @@
1
+ // SPDX-License-Identifier: GPL-3.0-or-later
2
+ pragma solidity 0.8.9;
3
+
4
+ interface IRewardManager {
5
+ function getGlobalReward(address rewardToken)
6
+ external
7
+ view
8
+ returns (uint256 index, uint256 lastBalance);
9
+
10
+ function getUserReward(address user, address rewardToken)
11
+ external
12
+ view
13
+ returns (uint256 lastIndex, uint256 accruedReward);
14
+
15
+ function getRewardTokens() external view returns (address[] memory);
16
+ }
@@ -1,10 +1,11 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-or-later
2
2
  pragma solidity 0.8.9;
3
3
  import "../ISuperComposableYield.sol";
4
+ import "./IRewardManager.sol";
4
5
  import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
5
6
  import "../../libraries/math/Math.sol";
6
7
 
7
- abstract contract RewardManager {
8
+ abstract contract RewardManager is IRewardManager {
8
9
  using SafeERC20 for IERC20;
9
10
  using Math for uint256;
10
11
 
@@ -20,8 +21,28 @@ abstract contract RewardManager {
20
21
 
21
22
  uint256 internal constant INITIAL_REWARD_INDEX = 1;
22
23
 
23
- mapping(address => GlobalReward) public globalReward;
24
- mapping(address => mapping(address => UserReward)) public userReward;
24
+ mapping(address => GlobalReward) internal globalReward;
25
+ mapping(address => mapping(address => UserReward)) internal userReward;
26
+
27
+ function getGlobalReward(address rewardToken)
28
+ external
29
+ view
30
+ returns (uint256 index, uint256 lastBalance)
31
+ {
32
+ GlobalReward memory reward = globalReward[rewardToken];
33
+ return (reward.index, reward.lastBalance);
34
+ }
35
+
36
+ function getUserReward(address user, address rewardToken)
37
+ external
38
+ view
39
+ returns (uint256 lastIndex, uint256 accruedReward)
40
+ {
41
+ UserReward memory reward = userReward[user][rewardToken];
42
+ return (reward.lastIndex, reward.accruedReward);
43
+ }
44
+
45
+ function getRewardTokens() public view virtual override returns (address[] memory);
25
46
 
26
47
  function _doTransferOutRewardsForUser(address user, address receiver)
27
48
  internal
@@ -111,7 +132,5 @@ abstract contract RewardManager {
111
132
  }
112
133
  }
113
134
 
114
- function getRewardTokens() public view virtual returns (address[] memory);
115
-
116
135
  function _redeemExternalReward() internal virtual;
117
136
  }
@@ -34,31 +34,19 @@ contract PendleMarket is PendleBaseToken, IPMarket, ReentrancyGuard {
34
34
  address public immutable YT;
35
35
 
36
36
  int256 public immutable scalarRoot;
37
- uint256 public immutable feeRateRoot; // allow fee to be changable?
38
37
  int256 public immutable initialAnchor;
39
38
 
40
- uint256 public immutable rateOracleTimeWindow;
41
- int8 public immutable reserveFeePercent;
42
-
43
39
  MarketStorage public marketStorage;
44
40
 
45
41
  constructor(
46
42
  address _OT,
47
- uint256 _rateOracleTimeWindow,
48
- uint256 _feeRateRoot,
49
43
  int256 _scalarRoot,
50
- int256 _initialAnchor,
51
- uint8 _reserveFeePercent
44
+ int256 _initialAnchor
52
45
  ) PendleBaseToken(NAME, SYMBOL, 18, IPOwnershipToken(_OT).expiry()) {
53
46
  OT = _OT;
54
47
  SCY = IPOwnershipToken(_OT).SCY();
55
48
  YT = IPOwnershipToken(_OT).YT();
56
- feeRateRoot = _feeRateRoot;
57
49
  scalarRoot = _scalarRoot;
58
- rateOracleTimeWindow = _rateOracleTimeWindow;
59
-
60
- require(_reserveFeePercent <= 100, "invalid fee rate");
61
- reserveFeePercent = int8(_reserveFeePercent);
62
50
  initialAnchor = _initialAnchor;
63
51
  }
64
52
 
@@ -154,7 +142,7 @@ contract PendleMarket is PendleBaseToken, IPMarket, ReentrancyGuard {
154
142
  );
155
143
  require(netScyOut >= minScyOut, "insufficient scy out");
156
144
  IERC20(SCY).safeTransfer(receiver, netScyOut);
157
- IERC20(SCY).safeTransfer(IPMarketFactory(factory).treasury(), netScyToReserve);
145
+ IERC20(SCY).safeTransfer(market.treasury, netScyToReserve);
158
146
 
159
147
  if (data.length > 0) {
160
148
  IPMarketSwapCallback(msg.sender).swapCallback(exactOtIn.neg(), netScyOut.Int(), data);
@@ -183,7 +171,7 @@ contract PendleMarket is PendleBaseToken, IPMarket, ReentrancyGuard {
183
171
  );
184
172
  require(netScyIn <= maxScyIn, "scy in exceed limit");
185
173
  IERC20(OT).safeTransfer(receiver, exactOtOut);
186
- IERC20(SCY).safeTransfer(IPMarketFactory(factory).treasury(), netScyToReserve);
174
+ IERC20(SCY).safeTransfer(market.treasury, netScyToReserve);
187
175
 
188
176
  if (data.length > 0) {
189
177
  IPMarketSwapCallback(msg.sender).swapCallback(exactOtOut.Int(), netScyIn.neg(), data);
@@ -206,11 +194,15 @@ contract PendleMarket is PendleBaseToken, IPMarket, ReentrancyGuard {
206
194
  market.totalScy = store.totalScy;
207
195
  market.totalLp = totalSupply().Int();
208
196
  market.oracleRate = store.oracleRate;
209
- market.reserveFeePercent = reserveFeePercent;
197
+
198
+ (
199
+ market.treasury,
200
+ market.feeRateRoot,
201
+ market.rateOracleTimeWindow,
202
+ market.reserveFeePercent
203
+ ) = IPMarketFactory(factory).marketConfig();
210
204
 
211
205
  market.scalarRoot = scalarRoot;
212
- market.feeRateRoot = feeRateRoot;
213
- market.rateOracleTimeWindow = rateOracleTimeWindow;
214
206
  market.expiry = expiry;
215
207
 
216
208
  market.lastImpliedRate = store.lastImpliedRate;
@@ -10,24 +10,40 @@ import "./PendleMarket.sol";
10
10
  contract PendleMarketFactory is PermissionsV2Upg, IPMarketFactory {
11
11
  using EnumerableSet for EnumerableSet.AddressSet;
12
12
 
13
+ struct MarketConfig {
14
+ address treasury; // 160 bit
15
+ uint96 feeRateRoot; // 96 bit
16
+ // 1 SLOT
17
+ uint32 rateOracleTimeWindow;
18
+ uint8 reserveFeePercent;
19
+ }
20
+
13
21
  mapping(address => EnumerableSet.AddressSet) internal markets;
14
22
 
15
23
  address public immutable yieldContractFactory;
16
- address public treasury;
17
24
 
18
- constructor(address _governanceManager, address _yieldContractFactory)
19
- PermissionsV2Upg(_governanceManager)
20
- {
25
+ MarketConfig public marketConfig;
26
+
27
+ constructor(
28
+ address _governanceManager,
29
+ address _yieldContractFactory,
30
+ address _treasury,
31
+ uint96 _feeRateRoot,
32
+ uint32 _rateOracleTimeWindow,
33
+ uint8 _reserveFeePercent
34
+ ) PermissionsV2Upg(_governanceManager) {
21
35
  yieldContractFactory = _yieldContractFactory;
36
+
37
+ setTreasury(_treasury);
38
+ setFeeRateRoot(_feeRateRoot);
39
+ setRateOracleTimeWindow(_rateOracleTimeWindow);
40
+ setReserveFeePercent(_reserveFeePercent);
22
41
  }
23
42
 
24
43
  function createNewMarket(
25
44
  address OT,
26
- uint256 feeRateRoot,
27
45
  int256 scalarRoot,
28
- int256 initialAnchor,
29
- uint8 reserveFeePercent,
30
- uint256 rateOracleTimeWindow
46
+ int256 initialAnchor
31
47
  ) external returns (address market) {
32
48
  address SCY = IPOwnershipToken(OT).SCY();
33
49
  uint256 expiry = IPOwnershipToken(OT).expiry();
@@ -37,25 +53,36 @@ contract PendleMarketFactory is PermissionsV2Upg, IPMarketFactory {
37
53
  "INVALID_OT"
38
54
  );
39
55
 
40
- market = address(
41
- new PendleMarket(
42
- OT,
43
- rateOracleTimeWindow,
44
- feeRateRoot,
45
- scalarRoot,
46
- initialAnchor,
47
- reserveFeePercent
48
- )
49
- );
56
+ market = address(new PendleMarket(OT, scalarRoot, initialAnchor));
50
57
  markets[OT].add(market);
51
58
  }
52
59
 
53
- function setTreasury(address newTreasury) external onlyGovernance {
54
- treasury = newTreasury;
55
- }
56
-
57
60
  function isValidMarket(address market) external view returns (bool) {
58
61
  address OT = IPMarket(market).OT();
59
62
  return markets[OT].contains(market);
60
63
  }
64
+
65
+ function treasury() external view returns (address) {
66
+ return marketConfig.treasury;
67
+ }
68
+
69
+ function setTreasury(address newTreasury) public onlyGovernance {
70
+ require(newTreasury != address(0), "zero address");
71
+ marketConfig.treasury = newTreasury;
72
+ }
73
+
74
+ function setFeeRateRoot(uint96 newFeeRateRoot) public onlyGovernance {
75
+ // TODO: hard cap on the fee
76
+ marketConfig.feeRateRoot = newFeeRateRoot;
77
+ }
78
+
79
+ function setRateOracleTimeWindow(uint32 newRateOracleTimeWindow) public onlyGovernance {
80
+ // TODO: hard min for the time window
81
+ marketConfig.rateOracleTimeWindow = newRateOracleTimeWindow;
82
+ }
83
+
84
+ function setReserveFeePercent(uint8 newReserveFeePercent) public onlyGovernance {
85
+ require(newReserveFeePercent <= 100, "invalid fee rate");
86
+ marketConfig.reserveFeePercent = newReserveFeePercent;
87
+ }
61
88
  }
@@ -0,0 +1,74 @@
1
+ // SPDX-License-Identifier: GPL-3.0-or-later
2
+ pragma solidity 0.8.9;
3
+
4
+ import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
5
+ import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
6
+ import "@openzeppelin/contracts/proxy/Proxy.sol";
7
+ import "../interfaces/IPActionCore.sol";
8
+ import "../interfaces/IPActionYT.sol";
9
+ import "../interfaces/IPRouterStatic.sol";
10
+ import "../interfaces/IPMarketSwapCallback.sol";
11
+ import "../periphery/PermissionsV2Upg.sol";
12
+
13
+ /// @dev this contract will be deployed behind an ERC1967 proxy
14
+ /// calls to the ERC1967 proxy will be resolved at this contract, and proxied again to the
15
+ /// corresponding implementation contracts
16
+
17
+ // solhint-disable no-empty-blocks
18
+ contract PendleRouter is Proxy, Initializable, UUPSUpgradeable, PermissionsV2Upg {
19
+ address public immutable ACTION_CORE;
20
+ address public immutable ACTION_YT;
21
+ address public immutable ACTION_CALLBACK;
22
+
23
+ constructor(
24
+ address _ACTION_CORE,
25
+ address _ACTION_YT,
26
+ address _ACTION_CALLBACK,
27
+ address _governanceManager
28
+ ) PermissionsV2Upg(_governanceManager) initializer {
29
+ ACTION_CORE = _ACTION_CORE;
30
+ ACTION_YT = _ACTION_YT;
31
+ ACTION_CALLBACK = _ACTION_CALLBACK;
32
+ }
33
+
34
+ function initialize() external initializer {
35
+ __UUPSUpgradeable_init();
36
+ // no need to initialize PermissionsV2Upg
37
+ }
38
+
39
+ function getRouterImplementation(bytes4 sig) public view returns (address) {
40
+ if (
41
+ sig == IPActionCore.mintScyFromRawToken.selector ||
42
+ sig == IPActionCore.redeemScyToRawToken.selector ||
43
+ sig == IPActionCore.mintYoFromRawToken.selector ||
44
+ sig == IPActionCore.redeemYoToRawToken.selector ||
45
+ sig == IPActionCore.addLiquidity.selector ||
46
+ sig == IPActionCore.removeLiquidity.selector ||
47
+ sig == IPActionCore.swapExactOtForScy.selector ||
48
+ sig == IPActionCore.swapOtForExactScy.selector ||
49
+ sig == IPActionCore.swapScyForExactOt.selector ||
50
+ sig == IPActionCore.swapExactScyForOt.selector ||
51
+ sig == IPActionCore.swapExactRawTokenForOt.selector ||
52
+ sig == IPActionCore.swapExactOtForRawToken.selector
53
+ ) {
54
+ return ACTION_CORE;
55
+ } else if (
56
+ sig == IPActionYT.swapExactYtForScy.selector ||
57
+ sig == IPActionYT.swapScyForExactYt.selector ||
58
+ sig == IPActionYT.swapExactScyForYt.selector ||
59
+ sig == IPActionYT.swapExactRawTokenForYt.selector ||
60
+ sig == IPActionYT.swapExactYtForRawToken.selector
61
+ ) {
62
+ return ACTION_YT;
63
+ } else if (sig == IPMarketSwapCallback.swapCallback.selector) {
64
+ return ACTION_CALLBACK;
65
+ }
66
+ require(false, "invalid market sig");
67
+ }
68
+
69
+ function _implementation() internal view override returns (address) {
70
+ return getRouterImplementation(msg.sig);
71
+ }
72
+
73
+ function _authorizeUpgrade(address newImplementation) internal override onlyGovernance {}
74
+ }
@@ -19,11 +19,11 @@ It has been proven and tested that impliedScyBalance will not change over time,
19
19
 
20
20
  Due to this, it is required to update users' accruedReward STRICTLY BEFORE redeeming their interest.
21
21
  */
22
- contract PendleYieldToken is PendleBaseToken, IPYieldToken, RewardManager {
22
+ contract PendleYieldToken is PendleBaseToken, RewardManager, IPYieldToken {
23
23
  using Math for uint256;
24
24
  using SafeERC20 for IERC20;
25
25
 
26
- struct UserData {
26
+ struct InterestData {
27
27
  uint256 lastScyIndex;
28
28
  uint256 dueInterest;
29
29
  }
@@ -40,7 +40,7 @@ contract PendleYieldToken is PendleBaseToken, IPYieldToken, RewardManager {
40
40
  mapping(address => uint256) public totalRewardsPostExpiry;
41
41
  uint256 public totalProtocolFee;
42
42
 
43
- mapping(address => UserData) public data;
43
+ mapping(address => InterestData) internal interestData;
44
44
 
45
45
  constructor(
46
46
  address _SCY,
@@ -118,13 +118,13 @@ contract PendleYieldToken is PendleBaseToken, IPYieldToken, RewardManager {
118
118
  }
119
119
 
120
120
  function updateUserInterest(address user) public {
121
- uint256 prevIndex = data[user].lastScyIndex;
121
+ uint256 prevIndex = interestData[user].lastScyIndex;
122
122
 
123
123
  uint256 currentIndex = getScyIndexBeforeExpiry();
124
124
 
125
125
  if (prevIndex == currentIndex) return;
126
126
  if (prevIndex == 0) {
127
- data[user].lastScyIndex = currentIndex;
127
+ interestData[user].lastScyIndex = currentIndex;
128
128
  return;
129
129
  }
130
130
 
@@ -134,8 +134,16 @@ contract PendleYieldToken is PendleBaseToken, IPYieldToken, RewardManager {
134
134
  prevIndex * currentIndex
135
135
  );
136
136
 
137
- data[user].dueInterest += interestFromYT;
138
- data[user].lastScyIndex = currentIndex;
137
+ interestData[user].dueInterest += interestFromYT;
138
+ interestData[user].lastScyIndex = currentIndex;
139
+ }
140
+
141
+ function getInterestData(address user)
142
+ external
143
+ view
144
+ returns (uint256 lastScyIndex, uint256 dueInterest)
145
+ {
146
+ return (interestData[user].lastScyIndex, interestData[user].dueInterest);
139
147
  }
140
148
 
141
149
  function _updateGlobalReward(address[] memory rewardTokens, uint256 totalSupply)
@@ -165,8 +173,8 @@ contract PendleYieldToken is PendleBaseToken, IPYieldToken, RewardManager {
165
173
  }
166
174
 
167
175
  function _doTransferOutDueInterest(address user) internal returns (uint256 interestOut) {
168
- uint256 interestPreFee = data[user].dueInterest;
169
- data[user].dueInterest = 0;
176
+ uint256 interestPreFee = interestData[user].dueInterest;
177
+ interestData[user].dueInterest = 0;
170
178
 
171
179
  uint256 feeRate = IPYieldContractFactory(factory).interestFeeRate();
172
180
  uint256 feeAmount = interestPreFee.mulDown(feeRate);
@@ -185,7 +193,7 @@ contract PendleYieldToken is PendleBaseToken, IPYieldToken, RewardManager {
185
193
  public
186
194
  view
187
195
  virtual
188
- override(RewardManager)
196
+ override(RewardManager, IRewardManager)
189
197
  returns (address[] memory)
190
198
  {
191
199
  return ISuperComposableYield(SCY).getRewardTokens();
@@ -247,9 +255,9 @@ contract PendleYieldToken is PendleBaseToken, IPYieldToken, RewardManager {
247
255
  }
248
256
 
249
257
  function getImpliedScyBalance(address user) public view returns (uint256) {
250
- uint256 scyIndex = data[user].lastScyIndex;
258
+ uint256 scyIndex = interestData[user].lastScyIndex;
251
259
  if (scyIndex == 0) return 0;
252
- return SCYUtils.assetToScy(scyIndex, balanceOf(user)) + data[user].dueInterest;
260
+ return SCYUtils.assetToScy(scyIndex, balanceOf(user)) + interestData[user].dueInterest;
253
261
  }
254
262
 
255
263
  function _beforeTokenTransfer(
@@ -0,0 +1,234 @@
1
+ // SPDX-License-Identifier: GPL-3.0-or-later
2
+ pragma solidity 0.8.9;
3
+
4
+ import "../interfaces/IPRouterStatic.sol";
5
+ import "../interfaces/IPMarket.sol";
6
+ import "../interfaces/IPYieldContractFactory.sol";
7
+ import "../interfaces/IPMarketFactory.sol";
8
+ import "../libraries/math/MarketMathAux.sol";
9
+ import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
10
+ import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
11
+
12
+ contract RouterStatic is IPRouterStatic {
13
+ using MarketMathCore for MarketState;
14
+ using MarketMathAux for MarketState;
15
+ using Math for uint256;
16
+ using Math for int256;
17
+ using LogExpMath for int256;
18
+
19
+ IPYieldContractFactory public immutable yieldContractFactory;
20
+ IPMarketFactory public immutable marketFactory;
21
+
22
+ constructor(IPYieldContractFactory _yieldContractFactory, IPMarketFactory _marketFactory) {
23
+ yieldContractFactory = _yieldContractFactory;
24
+ marketFactory = _marketFactory;
25
+ }
26
+
27
+ function addLiquidityStatic(
28
+ address market,
29
+ uint256 scyDesired,
30
+ uint256 otDesired
31
+ )
32
+ external
33
+ returns (
34
+ uint256 netLpOut,
35
+ uint256 scyUsed,
36
+ uint256 otUsed
37
+ )
38
+ {
39
+ MarketState memory state = IPMarket(market).readState(false);
40
+ (, netLpOut, scyUsed, otUsed) = state.addLiquidity(
41
+ scyIndex(market),
42
+ scyDesired,
43
+ otDesired,
44
+ false
45
+ );
46
+ }
47
+
48
+ function removeLiquidityStatic(address market, uint256 lpToRemove)
49
+ external
50
+ view
51
+ returns (uint256 netScyOut, uint256 netOtOut)
52
+ {
53
+ MarketState memory state = IPMarket(market).readState(false);
54
+ (netScyOut, netOtOut) = state.removeLiquidity(lpToRemove, false);
55
+ }
56
+
57
+ function swapOtForScyStatic(address market, uint256 exactOtIn)
58
+ external
59
+ returns (uint256 netScyOut, uint256 netScyFee)
60
+ {
61
+ MarketState memory state = IPMarket(market).readState(false);
62
+ (netScyOut, netScyFee) = state.swapExactOtForScy(
63
+ scyIndex(market),
64
+ exactOtIn,
65
+ block.timestamp,
66
+ false
67
+ );
68
+ }
69
+
70
+ function swapScyForOtStatic(address market, uint256 exactOtOut)
71
+ external
72
+ returns (uint256 netScyIn, uint256 netScyFee)
73
+ {
74
+ MarketState memory state = IPMarket(market).readState(false);
75
+ (netScyIn, netScyFee) = state.swapScyForExactOt(
76
+ scyIndex(market),
77
+ exactOtOut,
78
+ block.timestamp,
79
+ false
80
+ );
81
+ }
82
+
83
+ function scyIndex(address market) public returns (SCYIndex index) {
84
+ return SCYIndexLib.newIndex(IPMarket(market).SCY());
85
+ }
86
+
87
+ function getOtImpliedYield(address market) public view returns (int256) {
88
+ MarketState memory state = IPMarket(market).readState(false);
89
+
90
+ int256 lnImpliedRate = (state.lastImpliedRate).Int();
91
+ return lnImpliedRate.exp();
92
+ }
93
+
94
+ function getPendleTokenType(address token)
95
+ external
96
+ view
97
+ returns (
98
+ bool isOT,
99
+ bool isYT,
100
+ bool isMarket
101
+ )
102
+ {
103
+ if (yieldContractFactory.isOT(token)) isOT = true;
104
+ else if (yieldContractFactory.isYT(token)) isYT = true;
105
+ else if (marketFactory.isValidMarket(token)) isMarket = true;
106
+ }
107
+
108
+ function getUserYOInfo(address token, address user)
109
+ public
110
+ view
111
+ returns (UserYOInfo memory userYOInfo)
112
+ {
113
+ (userYOInfo.yt, userYOInfo.ot) = getYO(token);
114
+ IPYieldToken YT = IPYieldToken(userYOInfo.yt);
115
+ userYOInfo.ytBalance = YT.balanceOf(user);
116
+ userYOInfo.otBalance = IPOwnershipToken(userYOInfo.ot).balanceOf(user);
117
+ userYOInfo.unclaimedInterest.token = YT.SCY();
118
+ (, userYOInfo.unclaimedInterest.amount) = YT.getInterestData(user);
119
+ address[] memory rewardTokens = YT.getRewardTokens();
120
+ TokenAmount[] memory unclaimedRewards = new TokenAmount[](rewardTokens.length);
121
+ uint256 length = 0;
122
+ for (uint256 i = 0; i < rewardTokens.length; ++i) {
123
+ address rewardToken = rewardTokens[i];
124
+ (, uint256 amount) = YT.getUserReward(user, rewardToken);
125
+ if (amount > 0) {
126
+ unclaimedRewards[length].token = rewardToken;
127
+ unclaimedRewards[length].amount = amount;
128
+ ++length;
129
+ }
130
+ }
131
+ userYOInfo.unclaimedRewards = new TokenAmount[](length);
132
+ for (uint256 i = 0; i < length; ++i) {
133
+ userYOInfo.unclaimedRewards[i] = unclaimedRewards[i];
134
+ }
135
+ }
136
+
137
+ function getYOInfo(address token)
138
+ external
139
+ returns (
140
+ uint256 exchangeRate,
141
+ uint256 totalSupply,
142
+ RewardIndex[] memory rewardIndexes
143
+ )
144
+ {
145
+ (address yt, ) = getYO(token);
146
+ IPYieldToken YT = IPYieldToken(yt);
147
+ exchangeRate = YT.getScyIndexBeforeExpiry();
148
+ totalSupply = YT.totalSupply();
149
+ address[] memory rewardTokens = YT.getRewardTokens();
150
+ rewardIndexes = new RewardIndex[](rewardTokens.length);
151
+ for (uint256 i = 0; i < rewardTokens.length; ++i) {
152
+ address rewardToken = rewardTokens[i];
153
+ rewardIndexes[i].rewardToken = rewardToken;
154
+ (, rewardIndexes[i].index) = YT.getGlobalReward(rewardToken);
155
+ }
156
+ }
157
+
158
+ function getYO(address token) public view returns (address ot, address yt) {
159
+ if (yieldContractFactory.isOT(token)) {
160
+ yt = IPOwnershipToken(token).YT();
161
+ ot = token;
162
+ } else if (yieldContractFactory.isYT(token)) {
163
+ yt = token;
164
+ ot = IPYieldToken(token).OT();
165
+ } else if (marketFactory.isValidMarket(token)) {
166
+ yt = IPMarket(token).YT();
167
+ ot = IPMarket(token).OT();
168
+ }
169
+ }
170
+
171
+ function getMarketInfo(address market)
172
+ external
173
+ view
174
+ returns (
175
+ address ot,
176
+ address scy,
177
+ MarketState memory state,
178
+ int256 impliedYield,
179
+ uint256 exchangeRate
180
+ )
181
+ {
182
+ IPMarket _market = IPMarket(market);
183
+ ot = _market.OT();
184
+ scy = _market.SCY();
185
+ state = _market.readState(true);
186
+ impliedYield = getOtImpliedYield(market);
187
+ exchangeRate = 0; // TODO: get the actual exchange rate
188
+ }
189
+
190
+ function getUserMarketInfo(address market, address user)
191
+ public
192
+ view
193
+ returns (UserMarketInfo memory userMarketInfo)
194
+ {
195
+ IPMarket _market = IPMarket(market);
196
+ userMarketInfo.market = market;
197
+ // TODO: What will this return if the user's balance is staked?
198
+ userMarketInfo.lpBalance = _market.balanceOf(user);
199
+ // TODO: Is there a way to convert LP to OT and SCY?
200
+ userMarketInfo.otBalance = TokenAmount(_market.OT(), 0);
201
+ userMarketInfo.scyBalance = TokenAmount(_market.SCY(), 0);
202
+ // TODO: Get this from SCY once it is in the interface
203
+ userMarketInfo.assetBalance = TokenAmount(address(0), 0);
204
+ }
205
+
206
+ function getUserYOPositionsByTokens(address user, address[] calldata tokens)
207
+ external
208
+ view
209
+ returns (UserYOInfo[] memory userYOPositions)
210
+ {
211
+ userYOPositions = new UserYOInfo[](tokens.length);
212
+ for (uint256 i = 0; i < tokens.length; ++i) {
213
+ userYOPositions[i] = getUserYOInfo(tokens[i], user);
214
+ }
215
+ }
216
+
217
+ function getUserMarketPositions(address user, address[] calldata markets)
218
+ external
219
+ view
220
+ returns (UserMarketInfo[] memory userMarketPositions)
221
+ {
222
+ userMarketPositions = new UserMarketInfo[](markets.length);
223
+ for (uint256 i = 0; i < markets.length; ++i) {
224
+ userMarketPositions[i] = getUserMarketInfo(markets[i], user);
225
+ }
226
+ }
227
+
228
+ function hasYOPosition(UserYOInfo memory userYOInfo) public pure returns (bool hasPosition) {
229
+ hasPosition = (userYOInfo.ytBalance > 0 ||
230
+ userYOInfo.otBalance > 0 ||
231
+ userYOInfo.unclaimedInterest.amount > 0 ||
232
+ userYOInfo.unclaimedRewards.length > 0);
233
+ }
234
+ }