@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.
- package/contracts/SuperComposableYield/implementations/IRewardManager.sol +16 -0
- package/contracts/SuperComposableYield/implementations/RewardManager.sol +24 -5
- package/contracts/core/PendleMarket.sol +10 -18
- package/contracts/core/PendleMarketFactory.sol +49 -22
- package/contracts/core/PendleRouter.sol +74 -0
- package/contracts/core/PendleYieldToken.sol +20 -12
- package/contracts/core/RouterStatic.sol +234 -0
- package/contracts/core/actions/ActionCallback.sol +101 -0
- package/contracts/core/{router/PendleRouterCoreUpg.sol → actions/ActionCore.sol} +6 -10
- package/contracts/core/{router/PendleRouterYTUpg.sol → actions/ActionYT.sol} +6 -11
- package/contracts/core/{router/base/PendleRouterOTBaseUpg.sol → actions/base/ActionSCYAndOTBase.sol} +1 -5
- package/contracts/core/{router/base/PendleRouterSCYAndForgeBaseUpg.sol → actions/base/ActionSCYAndYOBase.sol} +3 -5
- package/contracts/core/{router/base/PendleRouterYTBaseUpg.sol → actions/base/ActionSCYAndYTBase.sol} +7 -99
- package/contracts/core/actions/base/ActionType.sol +11 -0
- package/contracts/interfaces/{IPRouterCore.sol → IPActionCore.sol} +1 -1
- package/contracts/interfaces/{IPRouterYT.sol → IPActionYT.sol} +1 -3
- package/contracts/interfaces/IPAllAction.sol +9 -0
- package/contracts/interfaces/IPMarketFactory.sol +11 -0
- package/contracts/interfaces/IPRouterStatic.sol +27 -0
- package/contracts/interfaces/IPYieldToken.sol +21 -3
- package/contracts/libraries/math/MarketMathCore.sol +3 -2
- package/package.json +1 -1
- package/typechain-types/{PendleRouterYTBaseUpg.ts → ActionCallback.ts} +5 -5
- package/typechain-types/{PendleRouterCoreUpg.ts → ActionCore.ts} +5 -5
- package/typechain-types/{PendleRouterSCYAndForgeBaseUpg.ts → ActionSCYAndYOBase.ts} +5 -6
- package/typechain-types/{BoringOwnableData.ts → ActionSCYAndYTBase.ts} +21 -24
- package/typechain-types/{PendleRouterStaticUpg.ts → ActionStatic.ts} +5 -5
- package/typechain-types/{IPRouterYT.ts → ActionYT.ts} +27 -42
- package/typechain-types/IPActionAll.ts +1431 -0
- package/typechain-types/{IPRouterCore.ts → IPActionCore.ts} +5 -5
- package/typechain-types/{IPRouterView.ts → IPActionStatic.ts} +57 -5
- package/typechain-types/{PendleRouterYTUpg.ts → IPActionYT.ts} +5 -97
- package/typechain-types/IPAllAction.ts +1431 -0
- package/typechain-types/IPMarket.ts +3 -0
- package/typechain-types/IPMarketFactory.ts +46 -0
- package/typechain-types/IPYieldToken.ts +342 -14
- package/typechain-types/IRewardManager.ts +178 -0
- package/typechain-types/PendleAaveV3SCY.ts +70 -64
- package/typechain-types/PendleBenQiErc20SCY.ts +70 -64
- package/typechain-types/PendleMarket.ts +3 -59
- package/typechain-types/PendleMarketFactory.ts +150 -24
- package/typechain-types/{PendleRouterProxy.ts → PendleRouter.ts} +29 -39
- package/typechain-types/PendleYieldToken.ts +116 -101
- package/typechain-types/RewardManager.ts +48 -42
- package/typechain-types/{PendleRouterViewUpg.ts → RouterStatic.ts} +97 -5
- package/typechain-types/SCYBaseWithRewards.ts +70 -64
- package/typechain-types/factories/ActionCallback__factory.ts +116 -0
- package/typechain-types/factories/ActionCore__factory.ts +632 -0
- package/typechain-types/factories/{PendleRouterSCYAndForgeBaseUpg__factory.ts → ActionSCYAndYOBase__factory.ts} +8 -12
- package/typechain-types/factories/ActionSCYAndYTBase__factory.ts +52 -0
- package/typechain-types/factories/ActionStatic__factory.ts +308 -0
- package/typechain-types/factories/ActionYT__factory.ts +370 -0
- package/typechain-types/factories/IPActionAll__factory.ts +983 -0
- package/typechain-types/factories/{IPRouterCore__factory.ts → IPActionCore__factory.ts} +6 -6
- package/typechain-types/factories/{IPRouterView__factory.ts → IPActionStatic__factory.ts} +38 -6
- package/typechain-types/factories/{IPRouterYT__factory.ts → IPActionYT__factory.ts} +6 -29
- package/typechain-types/factories/IPAllAction__factory.ts +983 -0
- package/typechain-types/factories/IPMarketFactory__factory.ts +28 -0
- package/typechain-types/factories/IPMarket__factory.ts +7 -2
- package/typechain-types/factories/IPYieldToken__factory.ts +158 -1
- package/typechain-types/factories/IRewardManager__factory.ts +92 -0
- package/typechain-types/factories/PendleAaveV3SCY__factory.ts +34 -34
- package/typechain-types/factories/PendleBenQiErc20SCY__factory.ts +34 -34
- package/typechain-types/factories/PendleBtrflyScy__factory.ts +1 -1
- package/typechain-types/factories/PendleMarketFactory__factory.ts +112 -17
- package/typechain-types/factories/PendleMarket__factory.ts +8 -69
- package/typechain-types/factories/PendleRouter__factory.ts +282 -0
- package/typechain-types/factories/PendleYearnVaultScy__factory.ts +1 -1
- package/typechain-types/factories/PendleYieldContractFactory__factory.ts +1 -1
- package/typechain-types/factories/PendleYieldToken__factory.ts +58 -58
- package/typechain-types/factories/RewardManager__factory.ts +18 -18
- package/typechain-types/factories/RouterStatic__factory.ts +308 -0
- package/typechain-types/factories/SCYBaseWithRewards__factory.ts +33 -33
- package/typechain-types/hardhat.d.ts +93 -75
- package/typechain-types/index.ts +22 -18
- package/contracts/core/router/PendleRouterProxy.sol +0 -84
- package/contracts/core/router/PendleRouterStaticUpg.sol +0 -107
- package/contracts/interfaces/IPFlashCallBack.sol +0 -10
- package/typechain-types/BoringOwnable.ts +0 -194
- package/typechain-types/BoringOwnableUpg.ts +0 -194
- package/typechain-types/BoringOwnableUpgData.ts +0 -100
- package/typechain-types/IPFlashCallback.ts +0 -115
- package/typechain-types/IPermissionsV2.ts +0 -87
- package/typechain-types/PermissionsV2.ts +0 -87
- package/typechain-types/factories/BoringOwnableData__factory.ts +0 -90
- package/typechain-types/factories/BoringOwnableUpgData__factory.ts +0 -94
- package/typechain-types/factories/BoringOwnableUpg__factory.ts +0 -139
- package/typechain-types/factories/BoringOwnable__factory.ts +0 -149
- package/typechain-types/factories/IPFlashCallback__factory.ts +0 -49
- package/typechain-types/factories/IPermissionsV2__factory.ts +0 -39
- package/typechain-types/factories/PendleRouterCoreUpg__factory.ts +0 -635
- package/typechain-types/factories/PendleRouterProxy__factory.ts +0 -285
- package/typechain-types/factories/PendleRouterStaticUpg__factory.ts +0 -315
- package/typechain-types/factories/PendleRouterViewUpg__factory.ts +0 -265
- package/typechain-types/factories/PendleRouterYTBaseUpg__factory.ts +0 -66
- package/typechain-types/factories/PendleRouterYTUpg__factory.ts +0 -422
- 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)
|
|
24
|
-
mapping(address => mapping(address => 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(
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
19
|
-
|
|
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,
|
|
22
|
+
contract PendleYieldToken is PendleBaseToken, RewardManager, IPYieldToken {
|
|
23
23
|
using Math for uint256;
|
|
24
24
|
using SafeERC20 for IERC20;
|
|
25
25
|
|
|
26
|
-
struct
|
|
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 =>
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
138
|
-
|
|
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 =
|
|
169
|
-
|
|
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 =
|
|
258
|
+
uint256 scyIndex = interestData[user].lastScyIndex;
|
|
251
259
|
if (scyIndex == 0) return 0;
|
|
252
|
-
return SCYUtils.assetToScy(scyIndex, balanceOf(user)) +
|
|
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
|
+
}
|