@pendle/core-v2 0.17.6-testnet → 0.17.7-testnet

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.
@@ -1,22 +1,13 @@
1
1
  // SPDX-License-Identifier: GPL-3.0-or-later
2
2
  pragma solidity 0.8.17;
3
- import "../../interfaces/IStandardizedYield.sol";
4
3
 
4
+ import "../../interfaces/IStandardizedYield.sol";
5
5
  import "../erc20/PendleERC20Permit.sol";
6
-
7
6
  import "../libraries/math/Math.sol";
8
7
  import "../libraries/TokenHelper.sol";
9
8
  import "../libraries/Errors.sol";
10
- import "../libraries/BoringOwnableUpgradeable.sol";
11
- import "@openzeppelin/contracts/security/Pausable.sol";
12
-
13
- abstract contract SYBase is
14
- IStandardizedYield,
15
- PendleERC20Permit,
16
- TokenHelper,
17
- BoringOwnableUpgradeable,
18
- Pausable
19
- {
9
+
10
+ abstract contract SYBase is IStandardizedYield, PendleERC20Permit, TokenHelper {
20
11
  using Math for uint256;
21
12
 
22
13
  address public immutable yieldToken;
@@ -25,9 +16,8 @@ abstract contract SYBase is
25
16
  string memory _name,
26
17
  string memory _symbol,
27
18
  address _yieldToken
28
- ) PendleERC20Permit(_name, _symbol, IERC20Metadata(_yieldToken).decimals()) initializer {
19
+ ) PendleERC20Permit(_name, _symbol, IERC20Metadata(_yieldToken).decimals()) {
29
20
  yieldToken = _yieldToken;
30
- __BoringOwnable_init();
31
21
  }
32
22
 
33
23
  // solhint-disable no-empty-blocks
@@ -189,19 +179,11 @@ abstract contract SYBase is
189
179
  return _previewRedeem(tokenOut, amountSharesToRedeem);
190
180
  }
191
181
 
192
- function pause() external onlyOwner {
193
- _pause();
194
- }
195
-
196
- function unpause() external onlyOwner {
197
- _unpause();
198
- }
199
-
200
182
  function _beforeTokenTransfer(
201
183
  address,
202
184
  address,
203
185
  uint256
204
- ) internal virtual override whenNotPaused {}
186
+ ) internal virtual override {}
205
187
 
206
188
  function _previewDeposit(address tokenIn, uint256 amountTokenToDeposit)
207
189
  internal
@@ -29,7 +29,6 @@ abstract contract SYBaseWithRewards is SYBase, RewardManager {
29
29
  virtual
30
30
  override
31
31
  nonReentrant
32
- whenNotPaused
33
32
  returns (uint256[] memory rewardAmounts)
34
33
  {
35
34
  _updateAndDistributeRewards(user);
@@ -74,7 +73,6 @@ abstract contract SYBaseWithRewards is SYBase, RewardManager {
74
73
  function rewardIndexesCurrent()
75
74
  external
76
75
  override
77
- whenNotPaused
78
76
  nonReentrant
79
77
  returns (uint256[] memory indexes)
80
78
  {
@@ -122,7 +120,7 @@ abstract contract SYBaseWithRewards is SYBase, RewardManager {
122
120
  address from,
123
121
  address to,
124
122
  uint256
125
- ) internal virtual override whenNotPaused {
123
+ ) internal virtual override {
126
124
  _updateAndDistributeRewardsForTwo(from, to);
127
125
  }
128
126
  }
@@ -0,0 +1,184 @@
1
+ // SPDX-License-Identifier: GPL-3.0-or-later
2
+ pragma solidity 0.8.17;
3
+
4
+ import "../../SYBase.sol";
5
+ import "../../../../interfaces/IApeStaking.sol";
6
+
7
+ contract PendleApeStakingSY is SYBase {
8
+ using Math for uint256;
9
+
10
+ uint256 public constant APE_COIN_POOL_ID = 0;
11
+ uint256 public constant MIN_APE_DEPOSIT = 10**18;
12
+ uint256 public constant EPOCH_LENGTH = 1 hours;
13
+
14
+ address public immutable apeStaking;
15
+ address public immutable apeCoin;
16
+
17
+ uint256 private lastRewardClaimedEpoch;
18
+
19
+ constructor(
20
+ string memory _name,
21
+ string memory _symbol,
22
+ address _apeCoin,
23
+ address _apeStaking
24
+ )
25
+ SYBase(_name, _symbol, _apeCoin)
26
+ {
27
+ apeStaking = _apeStaking;
28
+ apeCoin = _apeCoin;
29
+ lastRewardClaimedEpoch = _getCurrentEpochId();
30
+ _safeApproveInf(apeCoin, apeStaking);
31
+ }
32
+
33
+ function _deposit(address, uint256 amountDeposited)
34
+ internal
35
+ virtual
36
+ override
37
+ returns (uint256 amountSharesOut)
38
+ {
39
+ // Respecting APE's deposit invariant & prevent frontrunning on deployment
40
+ if (amountDeposited < MIN_APE_DEPOSIT) {
41
+ revert Errors.SYApeDepositAmountTooSmall(amountDeposited);
42
+ }
43
+
44
+ _harvestAndCompound();
45
+
46
+ // As SY Base is pulling the tokenIn first, the totalAsset should exclude user's deposit
47
+ uint256 priorTotalAssetOwned = getTotalAssetOwned() - amountDeposited;
48
+
49
+ if (totalSupply() == 0) {
50
+ amountSharesOut = amountDeposited;
51
+ } else {
52
+ // The upcoming calculation can be reduced to amountDeposited.divDown(exchangeRate())
53
+ // The following calculation is choosen instead to minimize precision error
54
+ amountSharesOut = (amountDeposited * totalSupply()) / priorTotalAssetOwned;
55
+ }
56
+ }
57
+
58
+ function _redeem(
59
+ address receiver,
60
+ address,
61
+ uint256 amountSharesToRedeem
62
+ ) internal virtual override returns (uint256 amountTokenOut) {
63
+ _harvestAndCompound();
64
+
65
+ // As SY is burned before calling _redeem(), we should account for priorSupply
66
+ uint256 priorTotalSupply = totalSupply() + amountSharesToRedeem;
67
+
68
+ if (amountSharesToRedeem == priorTotalSupply) {
69
+ amountTokenOut = getTotalAssetOwned();
70
+ } else {
71
+ // The upcoming calculation can be reduced to amountSharesToRedeem.mulDown(exchangeRate())
72
+ // The following calculation is choosen instead to minimize precision error
73
+ amountTokenOut = (amountSharesToRedeem * getTotalAssetOwned()) / priorTotalSupply;
74
+ }
75
+
76
+ // There might be case when the contract is holding < 1 APE reward and user is withdrawing everything out of it
77
+ if (amountTokenOut > _selfBalance(apeCoin)) {
78
+ IApeStaking(apeStaking).withdrawApeCoin(
79
+ amountTokenOut - _selfBalance(apeCoin),
80
+ address(this)
81
+ );
82
+ }
83
+ _transferOut(apeCoin, receiver, amountTokenOut);
84
+ }
85
+
86
+ function exchangeRate() public view virtual override returns (uint256) {
87
+ return getTotalAssetOwned().divDown(totalSupply());
88
+ }
89
+
90
+ /*///////////////////////////////////////////////////////////////
91
+ AUTOCOMPOUND FEATURE
92
+ //////////////////////////////////////////////////////////////*/
93
+
94
+ function harvestAndCompound() external {
95
+ _harvestAndCompound();
96
+ }
97
+
98
+ function getTotalAssetOwned() public view returns (uint256 totalAssetOwned) {
99
+ (uint256 stakedAmount, ) = IApeStaking(apeStaking).addressPosition(address(this));
100
+ uint256 unclaimedAmount = IApeStaking(apeStaking).pendingRewards(
101
+ APE_COIN_POOL_ID,
102
+ address(this),
103
+ 0
104
+ );
105
+ uint256 floatingAmount = _selfBalance(apeCoin);
106
+ totalAssetOwned = stakedAmount + unclaimedAmount + floatingAmount;
107
+ }
108
+
109
+ function _harvestAndCompound() internal {
110
+ // Claim reward
111
+ uint256 currentEpochId = _getCurrentEpochId();
112
+ if (currentEpochId != lastRewardClaimedEpoch) {
113
+ IApeStaking(apeStaking).claimSelfApeCoin();
114
+ lastRewardClaimedEpoch = currentEpochId;
115
+ }
116
+
117
+ // Deposit APE
118
+ uint256 amountAssetToCompound = _selfBalance(apeCoin);
119
+ if (amountAssetToCompound >= MIN_APE_DEPOSIT) {
120
+ IApeStaking(apeStaking).depositSelfApeCoin(amountAssetToCompound);
121
+ }
122
+ }
123
+
124
+ /*///////////////////////////////////////////////////////////////
125
+ MISC FUNCTIONS FOR METADATA
126
+ //////////////////////////////////////////////////////////////*/
127
+
128
+ function _previewDeposit(address, uint256 amountTokenToDeposit)
129
+ internal
130
+ view
131
+ override
132
+ returns (uint256 amountSharesOut)
133
+ {
134
+ if (totalSupply() == 0) {
135
+ amountSharesOut = amountTokenToDeposit;
136
+ } else {
137
+ amountSharesOut = (amountTokenToDeposit * totalSupply()) / getTotalAssetOwned();
138
+ }
139
+ }
140
+
141
+ function _previewRedeem(address, uint256 amountSharesToRedeem)
142
+ internal
143
+ view
144
+ override
145
+ returns (uint256 amountTokenOut)
146
+ {
147
+ amountTokenOut = (amountSharesToRedeem * getTotalAssetOwned()) / totalSupply();
148
+ }
149
+
150
+
151
+ function _getCurrentEpochId() private view returns (uint256) {
152
+ return block.timestamp / EPOCH_LENGTH;
153
+ }
154
+
155
+ function getTokensIn() public view virtual override returns (address[] memory res) {
156
+ res = new address[](1);
157
+ res[0] = apeCoin;
158
+ }
159
+
160
+ function getTokensOut() public view virtual override returns (address[] memory res) {
161
+ res = new address[](1);
162
+ res[0] = apeCoin;
163
+ }
164
+
165
+ function isValidTokenIn(address token) public view virtual override returns (bool) {
166
+ return token == apeCoin;
167
+ }
168
+
169
+ function isValidTokenOut(address token) public view virtual override returns (bool) {
170
+ return token == apeCoin;
171
+ }
172
+
173
+ function assetInfo()
174
+ external
175
+ view
176
+ returns (
177
+ AssetType assetType,
178
+ address assetAddress,
179
+ uint8 assetDecimals
180
+ )
181
+ {
182
+ return (AssetType.TOKEN, apeCoin, IERC20Metadata(apeCoin).decimals());
183
+ }
184
+ }
@@ -111,6 +111,8 @@ library Errors {
111
111
  error SYCurveInvalidPid();
112
112
  error SYCurve3crvPoolNotFound();
113
113
 
114
+ error SYApeDepositAmountTooSmall(uint256 amountDeposited);
115
+
114
116
  // Liquidity Mining
115
117
  error VCInactivePool(address pool);
116
118
  error VCPoolAlreadyActive(address pool);
@@ -0,0 +1,27 @@
1
+ // SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+ pragma solidity 0.8.17;
4
+
5
+ interface IApeStaking {
6
+ function apeCoin() external view returns (address);
7
+
8
+ function depositSelfApeCoin(uint256 _amount) external;
9
+
10
+ function withdrawApeCoin(uint256 _amount, address _recipient) external;
11
+
12
+ function claimSelfApeCoin() external;
13
+
14
+ /**
15
+ * @notice when poolId is set to 0, tokenId's value does not matter
16
+ */
17
+ function pendingRewards(
18
+ uint256 _poolId,
19
+ address _address,
20
+ uint256 _tokenId
21
+ ) external view returns (uint256);
22
+
23
+ function addressPosition(address addr)
24
+ external
25
+ view
26
+ returns (uint256 stakedAmount, int256 rewardsDebt);
27
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "sAPE",
3
+ "SY": "0xDE080bEeB90e62F61936C113Fb46E62aa766cF1f",
4
+ "YT": "0x6537939Ec3e9da193D234A36bC5664B3cA570bc8",
5
+ "PT": "0x1432364a6a56d30810087fbD2ed197e609451299",
6
+ "market": "0x94B81B4cF70849E994f17b872C0e8E448443aE9b",
7
+ "expiry": 1680134400,
8
+ "scalarRoot": "2200000000000000000",
9
+ "initAnchor": "1151500000000000000"
10
+ }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@pendle/core-v2",
3
3
  "description": "Core smart contracts of Pendle Protocol.",
4
4
  "license": "BUSL-1.1",
5
- "version": "0.17.6-testnet",
5
+ "version": "0.17.7-testnet",
6
6
  "homepage": "https://pendle.finance",
7
7
  "keywords": [
8
8
  "pendle",