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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) 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 +16 -157
  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 +7 -82
  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
@@ -75,4 +75,6 @@ interface ISuperComposableYield is IERC20Metadata {
75
75
  function getRewardTokens() external view returns (address[] memory);
76
76
 
77
77
  function assetDecimals() external view returns (uint8);
78
+
79
+ function assetId() external view returns (bytes32);
78
80
  }
@@ -19,6 +19,8 @@ abstract contract RewardManager is IRewardManager {
19
19
  uint256 accruedReward;
20
20
  }
21
21
 
22
+ uint256 public lastRewardUpdateBlock;
23
+
22
24
  uint256 internal constant INITIAL_REWARD_INDEX = 1;
23
25
 
24
26
  mapping(address => GlobalReward) internal globalReward;
@@ -66,22 +68,18 @@ abstract contract RewardManager is IRewardManager {
66
68
  }
67
69
  }
68
70
 
69
- function _updateUserReward(
70
- address user,
71
- uint256 balanceOfUser,
72
- uint256 totalSupply
73
- ) internal virtual {
74
- address[] memory rewardTokens = getRewardTokens();
75
- _updateGlobalReward(rewardTokens, totalSupply);
76
- _updateUserRewardSkipGlobal(rewardTokens, user, balanceOfUser);
71
+ function _updateUserReward(address user) internal virtual {
72
+ _updateGlobalReward();
73
+ _updateUserRewardSkipGlobal(user);
77
74
  }
78
75
 
79
- function _updateGlobalReward(address[] memory rewardTokens, uint256 totalSupply)
80
- internal
81
- virtual
82
- {
76
+ function _updateGlobalReward() internal virtual {
77
+ if (!_shouldUpdateGlobalReward()) return;
83
78
  _redeemExternalReward();
84
79
 
80
+ uint256 totalShares = _rewardSharesTotal();
81
+
82
+ address[] memory rewardTokens = getRewardTokens();
85
83
  _initGlobalReward(rewardTokens);
86
84
 
87
85
  for (uint256 i = 0; i < rewardTokens.length; ++i) {
@@ -89,20 +87,20 @@ abstract contract RewardManager is IRewardManager {
89
87
 
90
88
  uint256 currentRewardBalance = IERC20(token).balanceOf(address(this));
91
89
 
92
- if (totalSupply != 0) {
90
+ if (totalShares != 0) {
93
91
  globalReward[token].index += (currentRewardBalance -
94
- globalReward[token].lastBalance).divDown(totalSupply);
92
+ globalReward[token].lastBalance).divDown(totalShares);
95
93
  }
96
94
 
97
95
  globalReward[token].lastBalance = currentRewardBalance;
98
96
  }
99
97
  }
100
98
 
101
- function _updateUserRewardSkipGlobal(
102
- address[] memory rewardTokens,
103
- address user,
104
- uint256 balanceOfUser
105
- ) internal virtual {
99
+ function _updateUserRewardSkipGlobal(address user) internal virtual {
100
+ address[] memory rewardTokens = getRewardTokens();
101
+
102
+ uint256 userShares = _rewardSharesUser(user);
103
+
106
104
  for (uint256 i = 0; i < rewardTokens.length; ++i) {
107
105
  address token = rewardTokens[i];
108
106
 
@@ -117,7 +115,7 @@ abstract contract RewardManager is IRewardManager {
117
115
  }
118
116
 
119
117
  uint256 rewardAmountPerUnit = globalReward[token].index - userLastIndex;
120
- uint256 rewardFromUnit = balanceOfUser.mulDown(rewardAmountPerUnit);
118
+ uint256 rewardFromUnit = userShares.mulDown(rewardAmountPerUnit);
121
119
 
122
120
  userReward[user][token].accruedReward += rewardFromUnit;
123
121
  userReward[user][token].lastIndex = globalReward[token].index;
@@ -132,5 +130,22 @@ abstract contract RewardManager is IRewardManager {
132
130
  }
133
131
  }
134
132
 
133
+ function _shouldUpdateGlobalReward() internal virtual returns (bool) {
134
+ if (lastRewardUpdateBlock == block.number) {
135
+ return false;
136
+ }
137
+ lastRewardUpdateBlock = block.number;
138
+ return true;
139
+ }
140
+
141
+ /// @dev to be overriden if there is rewards
135
142
  function _redeemExternalReward() internal virtual;
143
+
144
+ /// @dev to be overriden if there is rewards
145
+ function _rewardSharesTotal() internal virtual returns (uint256);
146
+
147
+ /// @dev to be overriden if there is rewards
148
+ function _rewardSharesUser(
149
+ address /*user*/
150
+ ) internal virtual returns (uint256);
136
151
  }
@@ -4,21 +4,19 @@ import "../ISuperComposableYield.sol";
4
4
  import "./RewardManager.sol";
5
5
  import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
6
6
  import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
7
+ import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
7
8
  import "../../libraries/math/Math.sol";
8
9
  import "../SCYUtils.sol";
9
10
 
10
- /**
11
- # CONDITIONS TO USE THIS PRESET:
12
- - the token's balance must be static (i.e not increase on its own). Some examples of tokens don't
13
- satisfy this restriction is AaveV2's aToken
14
-
15
- */
16
- abstract contract SCYBase is ERC20, ISuperComposableYield {
11
+ abstract contract SCYBase is ERC20, ISuperComposableYield, ReentrancyGuard {
17
12
  using SafeERC20 for IERC20;
18
13
  using Math for uint256;
19
14
 
15
+ event UpdateScyIndex(uint256 scyIndex);
16
+
20
17
  uint8 private immutable _scyDecimals;
21
18
  uint8 private immutable _assetDecimals;
19
+ bytes32 private immutable _assetId;
22
20
 
23
21
  mapping(address => uint256) internal lastBalanceOf;
24
22
 
@@ -26,10 +24,12 @@ abstract contract SCYBase is ERC20, ISuperComposableYield {
26
24
  string memory _name,
27
25
  string memory _symbol,
28
26
  uint8 __scyDecimals,
29
- uint8 __assetDecimals
27
+ uint8 __assetDecimals,
28
+ bytes32 __assetId
30
29
  ) ERC20(_name, _symbol) {
31
30
  _scyDecimals = __scyDecimals;
32
31
  _assetDecimals = __assetDecimals;
32
+ _assetId = __assetId;
33
33
  }
34
34
 
35
35
  /*///////////////////////////////////////////////////////////////
@@ -41,9 +41,9 @@ abstract contract SCYBase is ERC20, ISuperComposableYield {
41
41
  address baseTokenIn,
42
42
  uint256 amountBaseToPull,
43
43
  uint256 minAmountScyOut
44
- ) external returns (uint256 amountScyOut) {
44
+ ) external nonReentrant returns (uint256 amountScyOut) {
45
45
  IERC20(baseTokenIn).safeTransferFrom(msg.sender, address(this), amountBaseToPull);
46
- amountScyOut = mintNoPull(receiver, baseTokenIn, minAmountScyOut);
46
+ amountScyOut = _mintFresh(receiver, baseTokenIn, minAmountScyOut);
47
47
  }
48
48
 
49
49
  function redeem(
@@ -51,16 +51,32 @@ abstract contract SCYBase is ERC20, ISuperComposableYield {
51
51
  address baseTokenOut,
52
52
  uint256 amountScyToPull,
53
53
  uint256 minAmountBaseOut
54
- ) external returns (uint256 amountBaseOut) {
54
+ ) external nonReentrant returns (uint256 amountBaseOut) {
55
55
  transferFrom(msg.sender, address(this), amountScyToPull);
56
- amountBaseOut = redeemNoPull(receiver, baseTokenOut, minAmountBaseOut);
56
+ amountBaseOut = _redeemFresh(receiver, baseTokenOut, minAmountBaseOut);
57
57
  }
58
58
 
59
59
  function mintNoPull(
60
60
  address receiver,
61
61
  address baseTokenIn,
62
62
  uint256 minAmountScyOut
63
- ) public virtual override returns (uint256 amountScyOut) {
63
+ ) external virtual override nonReentrant returns (uint256) {
64
+ return _mintFresh(receiver, baseTokenIn, minAmountScyOut);
65
+ }
66
+
67
+ function redeemNoPull(
68
+ address receiver,
69
+ address baseTokenOut,
70
+ uint256 minAmountBaseOut
71
+ ) external virtual override nonReentrant returns (uint256) {
72
+ return _redeemFresh(receiver, baseTokenOut, minAmountBaseOut);
73
+ }
74
+
75
+ function _mintFresh(
76
+ address receiver,
77
+ address baseTokenIn,
78
+ uint256 minAmountScyOut
79
+ ) internal virtual returns (uint256 amountScyOut) {
64
80
  require(isValidBaseToken(baseTokenIn), "invalid base token");
65
81
 
66
82
  uint256 amountBaseIn = _afterReceiveToken(baseTokenIn);
@@ -72,11 +88,11 @@ abstract contract SCYBase is ERC20, ISuperComposableYield {
72
88
  _mint(receiver, amountScyOut);
73
89
  }
74
90
 
75
- function redeemNoPull(
91
+ function _redeemFresh(
76
92
  address receiver,
77
93
  address baseTokenOut,
78
94
  uint256 minAmountBaseOut
79
- ) public virtual override returns (uint256 amountBaseOut) {
95
+ ) internal virtual returns (uint256 amountBaseOut) {
80
96
  require(isValidBaseToken(baseTokenOut), "invalid base token");
81
97
 
82
98
  uint256 amountScyRedeem = balanceOf(address(this));
@@ -105,9 +121,9 @@ abstract contract SCYBase is ERC20, ISuperComposableYield {
105
121
  SCY-INDEX
106
122
  //////////////////////////////////////////////////////////////*/
107
123
 
108
- function scyIndexCurrent() public virtual override returns (uint256 res);
124
+ function scyIndexCurrent() external virtual override returns (uint256 res);
109
125
 
110
- function scyIndexStored() public view virtual override returns (uint256 res);
126
+ function scyIndexStored() external view virtual override returns (uint256 res);
111
127
 
112
128
  /*///////////////////////////////////////////////////////////////
113
129
  MISC METADATA FUNCTIONS
@@ -117,11 +133,15 @@ abstract contract SCYBase is ERC20, ISuperComposableYield {
117
133
  return _scyDecimals;
118
134
  }
119
135
 
120
- function assetDecimals() public view virtual returns (uint8) {
136
+ function assetDecimals() external view virtual returns (uint8) {
121
137
  return _assetDecimals;
122
138
  }
123
139
 
124
- function getBaseTokens() public view virtual override returns (address[] memory res);
140
+ function assetId() external view returns (bytes32) {
141
+ return _assetId;
142
+ }
143
+
144
+ function getBaseTokens() external view virtual override returns (address[] memory res);
125
145
 
126
146
  function isValidBaseToken(address token) public view virtual override returns (bool);
127
147
 
@@ -17,14 +17,16 @@ abstract contract SCYBaseWithRewards is SCYBase, RewardManager {
17
17
  using SafeERC20 for IERC20;
18
18
  using Math for uint256;
19
19
 
20
+ event RedeemReward(address indexed user, uint256[] rewardsOut);
21
+
20
22
  constructor(
21
23
  string memory _name,
22
24
  string memory _symbol,
23
25
  uint8 __scydecimals,
24
- uint8 __assetDecimals
26
+ uint8 __assetDecimals,
27
+ bytes32 __assetId
25
28
  )
26
- SCYBase(_name, _symbol, __scydecimals, __assetDecimals)
27
- RewardManager()
29
+ SCYBase(_name, _symbol, __scydecimals, __assetDecimals, __assetId)
28
30
  // solhint-disable-next-line no-empty-blocks
29
31
  {
30
32
 
@@ -35,22 +37,23 @@ abstract contract SCYBaseWithRewards is SCYBase, RewardManager {
35
37
  //////////////////////////////////////////////////////////////*/
36
38
 
37
39
  function redeemReward(address user)
38
- public
40
+ external
39
41
  virtual
40
42
  override
43
+ nonReentrant
41
44
  returns (uint256[] memory outAmounts)
42
45
  {
43
- _updateUserReward(user, balanceOf(user), totalSupply());
46
+ _updateUserReward(user);
44
47
  outAmounts = _doTransferOutRewardsForUser(user, user);
48
+ emit RedeemReward(user, outAmounts);
45
49
  }
46
50
 
47
- function updateGlobalReward() public virtual override {
48
- address[] memory rewardTokens = getRewardTokens();
49
- _updateGlobalReward(rewardTokens, totalSupply());
51
+ function updateGlobalReward() external virtual override nonReentrant {
52
+ _updateGlobalReward();
50
53
  }
51
54
 
52
- function updateUserReward(address user) public virtual override {
53
- _updateUserReward(user, balanceOf(user), totalSupply());
55
+ function updateUserReward(address user) external virtual override nonReentrant {
56
+ _updateUserReward(user);
54
57
  }
55
58
 
56
59
  function getRewardTokens()
@@ -68,9 +71,18 @@ abstract contract SCYBaseWithRewards is SCYBase, RewardManager {
68
71
  address to,
69
72
  uint256 /*amount*/
70
73
  ) internal virtual override {
71
- address[] memory rewardTokens = getRewardTokens();
72
- _updateGlobalReward(rewardTokens, totalSupply());
73
- if (from != address(0)) _updateUserRewardSkipGlobal(rewardTokens, from, balanceOf(from));
74
- if (to != address(0)) _updateUserRewardSkipGlobal(rewardTokens, to, balanceOf(to));
74
+ _updateGlobalReward();
75
+ if (from != address(0)) _updateUserRewardSkipGlobal(from);
76
+ if (to != address(0)) _updateUserRewardSkipGlobal(to);
77
+ }
78
+
79
+ /// @dev to be overriden if there is rewards
80
+ function _rewardSharesTotal() internal virtual override returns (uint256) {
81
+ return totalSupply();
82
+ }
83
+
84
+ /// @dev to be overriden if there is rewards
85
+ function _rewardSharesUser(address user) internal virtual override returns (uint256) {
86
+ return balanceOf(user);
75
87
  }
76
88
  }
@@ -29,7 +29,7 @@ abstract contract PendleBaseToken is ERC20, IPBaseToken {
29
29
  return _decimals;
30
30
  }
31
31
 
32
- function isExpired() public view virtual returns (bool res) {
33
- res = (block.timestamp >= expiry);
32
+ function isExpired() public view virtual returns (bool) {
33
+ return block.timestamp >= expiry;
34
34
  }
35
35
  }