@pendle/core-v2 0.1.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.
- package/LICENSE +100 -0
- package/contracts/SuperComposableYield/ISuperComposableYield.sol +68 -0
- package/contracts/SuperComposableYield/SCYUtils.sol +14 -0
- package/contracts/SuperComposableYield/implementations/RewardManager.sol +117 -0
- package/contracts/SuperComposableYield/implementations/SCYBase.sol +126 -0
- package/contracts/SuperComposableYield/implementations/SCYBaseWithRewards.sol +79 -0
- package/contracts/core/PendleBaseToken.sol +39 -0
- package/contracts/core/PendleMarket.sol +248 -0
- package/contracts/core/PendleMarketFactory.sol +60 -0
- package/contracts/core/PendleOwnershipToken.sol +44 -0
- package/contracts/core/PendleSCYImpl/AaveV3/PendleAaveV3SCY.sol +139 -0
- package/contracts/core/PendleSCYImpl/AaveV3/WadRayMath.sol +126 -0
- package/contracts/core/PendleSCYImpl/PendleBenQiErc20SCY.sol +127 -0
- package/contracts/core/PendleSCYImpl/PendleBtrflySCY.sol +125 -0
- package/contracts/core/PendleSCYImpl/PendleYearnVaultSCY.sol +115 -0
- package/contracts/core/PendleYieldContractFactory.sol +109 -0
- package/contracts/core/PendleYieldToken.sol +240 -0
- package/contracts/core/misc/BoringOwnable.sol +62 -0
- package/contracts/core/misc/BoringOwnableUpg.sol +64 -0
- package/contracts/core/misc/PendleJoeSwapHelperUpg.sol +82 -0
- package/contracts/core/router/PendleRouterCoreUpg.sol +219 -0
- package/contracts/core/router/PendleRouterProxy.sol +64 -0
- package/contracts/core/router/PendleRouterYTUpg.sol +134 -0
- package/contracts/core/router/base/PendleRouterOTBaseUpg.sol +218 -0
- package/contracts/core/router/base/PendleRouterSCYAndForgeBaseUpg.sol +141 -0
- package/contracts/core/router/base/PendleRouterYTBaseUpg.sol +212 -0
- package/contracts/interfaces/IAToken.sol +34 -0
- package/contracts/interfaces/IAavePool.sol +41 -0
- package/contracts/interfaces/IAaveRewardsController.sol +32 -0
- package/contracts/interfaces/IBenQiComptroller.sol +33 -0
- package/contracts/interfaces/IJoePair.sol +98 -0
- package/contracts/interfaces/IJoeRouter01.sol +162 -0
- package/contracts/interfaces/IPBaseToken.sol +9 -0
- package/contracts/interfaces/IPFlashCallBack.sol +10 -0
- package/contracts/interfaces/IPGovernanceManager.sol +28 -0
- package/contracts/interfaces/IPMarket.sol +57 -0
- package/contracts/interfaces/IPMarketAddRemoveCallback.sol +18 -0
- package/contracts/interfaces/IPMarketFactory.sol +8 -0
- package/contracts/interfaces/IPMarketSwapCallback.sol +10 -0
- package/contracts/interfaces/IPOwnershipToken.sol +15 -0
- package/contracts/interfaces/IPPermissionsV2.sol +28 -0
- package/contracts/interfaces/IPRouterCore.sol +108 -0
- package/contracts/interfaces/IPRouterYT.sol +47 -0
- package/contracts/interfaces/IPYieldContractFactory.sol +36 -0
- package/contracts/interfaces/IPYieldToken.sol +19 -0
- package/contracts/interfaces/IQiErc20.sol +35 -0
- package/contracts/interfaces/IQiToken.sol +29 -0
- package/contracts/interfaces/IREDACTEDStaking.sol +35 -0
- package/contracts/interfaces/IWETH.sol +34 -0
- package/contracts/interfaces/IWXBTRFLY.sol +37 -0
- package/contracts/interfaces/IYearnVault.sol +32 -0
- package/contracts/libraries/JoeLibrary.sol +121 -0
- package/contracts/libraries/SCYIndex.sol +55 -0
- package/contracts/libraries/helpers/ExpiryUtilsLib.sol +166 -0
- package/contracts/libraries/math/FixedPoint.sol +208 -0
- package/contracts/libraries/math/LogExpMath.sol +515 -0
- package/contracts/libraries/math/MarketApproxLib.sol +140 -0
- package/contracts/libraries/math/MarketMathLib.sol +606 -0
- package/contracts/periphery/PendleGovernanceManager.sol +36 -0
- package/contracts/periphery/PermissionsV2.sol +23 -0
- package/package.json +76 -0
- package/typechain-types/BoringOwnable.ts +194 -0
- package/typechain-types/BoringOwnableData.ts +100 -0
- package/typechain-types/BoringOwnableUpg.ts +194 -0
- package/typechain-types/BoringOwnableUpgData.ts +100 -0
- package/typechain-types/ERC1967UpgradeUpgradeable.ts +97 -0
- package/typechain-types/ERC20.ts +417 -0
- package/typechain-types/IAToken.ts +331 -0
- package/typechain-types/IAavePool.ts +192 -0
- package/typechain-types/IAaveRewardsController.ts +148 -0
- package/typechain-types/IBeaconUpgradeable.ts +87 -0
- package/typechain-types/IBenQiComptroller.ts +125 -0
- package/typechain-types/IERC1822ProxiableUpgradeable.ts +87 -0
- package/typechain-types/IERC20.ts +300 -0
- package/typechain-types/IERC20Metadata.ts +339 -0
- package/typechain-types/IJoePair.ts +888 -0
- package/typechain-types/IJoeRouter01.ts +1107 -0
- package/typechain-types/IPBaseToken.ts +365 -0
- package/typechain-types/IPFlashCallback.ts +115 -0
- package/typechain-types/IPGovernanceManager.ts +84 -0
- package/typechain-types/IPMarket.ts +701 -0
- package/typechain-types/IPMarketAddRemoveCallback.ts +169 -0
- package/typechain-types/IPMarketFactory.ts +109 -0
- package/typechain-types/IPMarketSwapCallback.ts +115 -0
- package/typechain-types/IPOwnershipToken.ts +488 -0
- package/typechain-types/IPRouterCore.ts +759 -0
- package/typechain-types/IPRouterYT.ts +405 -0
- package/typechain-types/IPYieldContractFactory.ts +192 -0
- package/typechain-types/IPYieldToken.ts +525 -0
- package/typechain-types/IPermissionsV2.ts +87 -0
- package/typechain-types/IQiErc20.ts +402 -0
- package/typechain-types/IQiToken.ts +327 -0
- package/typechain-types/IREDACTEDStaking.ts +216 -0
- package/typechain-types/ISuperComposableYield.ts +652 -0
- package/typechain-types/IWETH.ts +380 -0
- package/typechain-types/IWXBTRFLY.ts +254 -0
- package/typechain-types/IYearnVault.ts +152 -0
- package/typechain-types/PendleAaveV3SCY.ts +901 -0
- package/typechain-types/PendleBaseToken.ts +505 -0
- package/typechain-types/PendleBenQiErc20SCY.ts +914 -0
- package/typechain-types/PendleBtrflyScy.ts +794 -0
- package/typechain-types/PendleGovernanceManager.ts +187 -0
- package/typechain-types/PendleJoeSwapHelperUpg.ts +97 -0
- package/typechain-types/PendleMarket.ts +1008 -0
- package/typechain-types/PendleMarketFactory.ts +246 -0
- package/typechain-types/PendleOwnershipToken.ts +628 -0
- package/typechain-types/PendleRouterCoreUpg.ts +780 -0
- package/typechain-types/PendleRouterProxy.ts +417 -0
- package/typechain-types/PendleRouterSCYAndForgeBaseUpg.ts +98 -0
- package/typechain-types/PendleRouterYTBaseUpg.ts +134 -0
- package/typechain-types/PendleRouterYTUpg.ts +453 -0
- package/typechain-types/PendleYearnVaultScy.ts +784 -0
- package/typechain-types/PendleYieldContractFactory.ts +479 -0
- package/typechain-types/PendleYieldToken.ts +1030 -0
- package/typechain-types/PermissionsV2.ts +87 -0
- package/typechain-types/Proxy.ts +57 -0
- package/typechain-types/RewardManager.ts +172 -0
- package/typechain-types/SCYBase.ts +734 -0
- package/typechain-types/SCYBaseWithRewards.ts +819 -0
- package/typechain-types/UUPSUpgradeable.ts +197 -0
- package/typechain-types/common.ts +44 -0
- package/typechain-types/factories/BoringOwnableData__factory.ts +90 -0
- package/typechain-types/factories/BoringOwnableUpgData__factory.ts +94 -0
- package/typechain-types/factories/BoringOwnableUpg__factory.ts +139 -0
- package/typechain-types/factories/BoringOwnable__factory.ts +149 -0
- package/typechain-types/factories/ERC1967UpgradeUpgradeable__factory.ts +75 -0
- package/typechain-types/factories/ERC20__factory.ts +348 -0
- package/typechain-types/factories/IAToken__factory.ts +225 -0
- package/typechain-types/factories/IAavePool__factory.ts +99 -0
- package/typechain-types/factories/IAaveRewardsController__factory.ts +78 -0
- package/typechain-types/factories/IBeaconUpgradeable__factory.ts +39 -0
- package/typechain-types/factories/IBenQiComptroller__factory.ts +59 -0
- package/typechain-types/factories/IERC1822ProxiableUpgradeable__factory.ts +43 -0
- package/typechain-types/factories/IERC20Metadata__factory.ts +248 -0
- package/typechain-types/factories/IERC20__factory.ts +203 -0
- package/typechain-types/factories/IJoePair__factory.ts +674 -0
- package/typechain-types/factories/IJoeRouter01__factory.ts +772 -0
- package/typechain-types/factories/IPBaseToken__factory.ts +271 -0
- package/typechain-types/factories/IPFlashCallback__factory.ts +49 -0
- package/typechain-types/factories/IPGovernanceManager__factory.ts +39 -0
- package/typechain-types/factories/IPMarketAddRemoveCallback__factory.ts +86 -0
- package/typechain-types/factories/IPMarketFactory__factory.ts +58 -0
- package/typechain-types/factories/IPMarketSwapCallback__factory.ts +53 -0
- package/typechain-types/factories/IPMarket__factory.ts +559 -0
- package/typechain-types/factories/IPOwnershipToken__factory.ts +349 -0
- package/typechain-types/factories/IPRouterCore__factory.ts +516 -0
- package/typechain-types/factories/IPRouterYT__factory.ts +246 -0
- package/typechain-types/factories/IPYieldContractFactory__factory.ts +117 -0
- package/typechain-types/factories/IPYieldToken__factory.ts +383 -0
- package/typechain-types/factories/IPermissionsV2__factory.ts +39 -0
- package/typechain-types/factories/IQiErc20__factory.ts +270 -0
- package/typechain-types/factories/IQiToken__factory.ts +219 -0
- package/typechain-types/factories/IREDACTEDStaking__factory.ts +107 -0
- package/typechain-types/factories/ISuperComposableYield__factory.ts +438 -0
- package/typechain-types/factories/IWETH__factory.ts +261 -0
- package/typechain-types/factories/IWXBTRFLY__factory.ts +131 -0
- package/typechain-types/factories/IYearnVault__factory.ts +74 -0
- package/typechain-types/factories/PendleAaveV3SCY__factory.ts +727 -0
- package/typechain-types/factories/PendleBaseToken__factory.ts +386 -0
- package/typechain-types/factories/PendleBenQiErc20SCY__factory.ts +753 -0
- package/typechain-types/factories/PendleBtrflyScy__factory.ts +652 -0
- package/typechain-types/factories/PendleGovernanceManager__factory.ts +149 -0
- package/typechain-types/factories/PendleJoeSwapHelperUpg__factory.ts +56 -0
- package/typechain-types/factories/PendleMarketFactory__factory.ts +207 -0
- package/typechain-types/factories/PendleMarket__factory.ts +891 -0
- package/typechain-types/factories/PendleOwnershipToken__factory.ts +565 -0
- package/typechain-types/factories/PendleRouterCoreUpg__factory.ts +620 -0
- package/typechain-types/factories/PendleRouterProxy__factory.ts +316 -0
- package/typechain-types/factories/PendleRouterSCYAndForgeBaseUpg__factory.ts +56 -0
- package/typechain-types/factories/PendleRouterYTBaseUpg__factory.ts +66 -0
- package/typechain-types/factories/PendleRouterYTUpg__factory.ts +363 -0
- package/typechain-types/factories/PendleYearnVaultScy__factory.ts +630 -0
- package/typechain-types/factories/PendleYieldContractFactory__factory.ts +368 -0
- package/typechain-types/factories/PendleYieldToken__factory.ts +814 -0
- package/typechain-types/factories/PermissionsV2__factory.ts +36 -0
- package/typechain-types/factories/Proxy__factory.ts +28 -0
- package/typechain-types/factories/RewardManager__factory.ts +89 -0
- package/typechain-types/factories/SCYBaseWithRewards__factory.ts +535 -0
- package/typechain-types/factories/SCYBase__factory.ts +479 -0
- package/typechain-types/factories/UUPSUpgradeable__factory.ts +115 -0
- package/typechain-types/hardhat.d.ts +564 -0
- package/typechain-types/index.ts +122 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
+
pragma solidity 0.8.9;
|
|
3
|
+
|
|
4
|
+
import "./PendleBaseToken.sol";
|
|
5
|
+
import "../SuperComposableYield/ISuperComposableYield.sol";
|
|
6
|
+
import "../interfaces/IPYieldToken.sol";
|
|
7
|
+
import "../interfaces/IPOwnershipToken.sol";
|
|
8
|
+
import "../libraries/math/FixedPoint.sol";
|
|
9
|
+
import "../interfaces/IPYieldContractFactory.sol";
|
|
10
|
+
import "openzeppelin-solidity/contracts/utils/math/Math.sol";
|
|
11
|
+
import "openzeppelin-solidity/contracts/token/ERC20/utils/SafeERC20.sol";
|
|
12
|
+
import "../SuperComposableYield/SCYUtils.sol";
|
|
13
|
+
import "../SuperComposableYield/implementations/RewardManager.sol";
|
|
14
|
+
|
|
15
|
+
contract PendleYieldToken is PendleBaseToken, IPYieldToken, RewardManager {
|
|
16
|
+
using FixedPoint for uint256;
|
|
17
|
+
using SafeERC20 for IERC20;
|
|
18
|
+
|
|
19
|
+
struct UserData {
|
|
20
|
+
uint256 lastScyIndex;
|
|
21
|
+
uint256 dueInterest;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
address public immutable SCY;
|
|
25
|
+
address public immutable OT;
|
|
26
|
+
|
|
27
|
+
/// params to do interests & rewards accounting
|
|
28
|
+
uint256 public lastScyBalance;
|
|
29
|
+
uint256 public lastScyIndexBeforeExpiry;
|
|
30
|
+
uint256[] public paramL;
|
|
31
|
+
|
|
32
|
+
/// params to do fee accounting
|
|
33
|
+
mapping(address => uint256) public totalRewardsPostExpiry;
|
|
34
|
+
uint256 public totalProtocolFee;
|
|
35
|
+
|
|
36
|
+
mapping(address => UserData) public data;
|
|
37
|
+
|
|
38
|
+
constructor(
|
|
39
|
+
address _SCY,
|
|
40
|
+
address _OT,
|
|
41
|
+
string memory _name,
|
|
42
|
+
string memory _symbol,
|
|
43
|
+
uint8 __decimals,
|
|
44
|
+
uint256 _expiry
|
|
45
|
+
) PendleBaseToken(_name, _symbol, __decimals, _expiry) {
|
|
46
|
+
SCY = _SCY;
|
|
47
|
+
OT = _OT;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @notice this function splits scy into OT + YT of equal qty
|
|
52
|
+
* @dev the scy to tokenize has to be pre-transferred to this contract prior to the function call
|
|
53
|
+
*/
|
|
54
|
+
function mintYO(address receiverOT, address receiverYT) public returns (uint256 amountYOOut) {
|
|
55
|
+
uint256 amountToTokenize = _receiveSCY();
|
|
56
|
+
|
|
57
|
+
amountYOOut = _calcAmountToMint(amountToTokenize);
|
|
58
|
+
|
|
59
|
+
_mint(receiverYT, amountYOOut);
|
|
60
|
+
|
|
61
|
+
IPOwnershipToken(OT).mintByYT(receiverOT, amountYOOut);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/// this function converts YO tokens into scy, but interests & rewards are not included
|
|
65
|
+
function redeemYO(address receiver) public returns (uint256 amountScyOut) {
|
|
66
|
+
// minimum of OT & YT balance
|
|
67
|
+
uint256 amountYOToRedeem = IERC20(OT).balanceOf(address(this));
|
|
68
|
+
if (!isExpired()) {
|
|
69
|
+
amountYOToRedeem = Math.min(amountYOToRedeem, balanceOf(address(this)));
|
|
70
|
+
_burn(address(this), amountYOToRedeem);
|
|
71
|
+
}
|
|
72
|
+
IPOwnershipToken(OT).burnByYT(address(this), amountYOToRedeem);
|
|
73
|
+
|
|
74
|
+
amountScyOut = _calcAmountRedeemable(amountYOToRedeem);
|
|
75
|
+
|
|
76
|
+
IERC20(SCY).safeTransfer(receiver, amountScyOut);
|
|
77
|
+
_afterTransferOutSCY();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function redeemDueInterest(address user) public returns (uint256 interestOut) {
|
|
81
|
+
_updateDueInterest(user);
|
|
82
|
+
|
|
83
|
+
uint256 interestPreFee = data[user].dueInterest;
|
|
84
|
+
data[user].dueInterest = 0;
|
|
85
|
+
|
|
86
|
+
uint256 feeRate = IPYieldContractFactory(factory).interestFeeRate();
|
|
87
|
+
uint256 feeAmount = interestPreFee.mulDown(feeRate);
|
|
88
|
+
totalProtocolFee += feeAmount;
|
|
89
|
+
|
|
90
|
+
interestOut = interestPreFee - feeAmount;
|
|
91
|
+
IERC20(SCY).safeTransfer(user, interestOut);
|
|
92
|
+
_afterTransferOutSCY();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function redeemDueRewards(address user, address receiver)
|
|
96
|
+
public
|
|
97
|
+
returns (uint256[] memory rewardsOut)
|
|
98
|
+
{
|
|
99
|
+
if (user != msg.sender) require(receiver == user, "invalid receiver");
|
|
100
|
+
else require(receiver != address(0), "zero address");
|
|
101
|
+
|
|
102
|
+
_updateUserReward(user, balanceOf(user), totalSupply());
|
|
103
|
+
rewardsOut = _doTransferOutRewardsForUser(user, receiver);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function updateGlobalReward() public virtual {
|
|
107
|
+
address[] memory rewardTokens = getRewardTokens();
|
|
108
|
+
_updateGlobalReward(rewardTokens, totalSupply());
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function updateUserReward(address user) public virtual {
|
|
112
|
+
_updateUserReward(user, balanceOf(user), totalSupply());
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function _updateGlobalReward(address[] memory rewardTokens, uint256 totalSupply)
|
|
116
|
+
internal
|
|
117
|
+
virtual
|
|
118
|
+
override
|
|
119
|
+
{
|
|
120
|
+
_redeemExternalReward();
|
|
121
|
+
|
|
122
|
+
_initGlobalReward(rewardTokens);
|
|
123
|
+
|
|
124
|
+
bool _isExpired = isExpired();
|
|
125
|
+
for (uint256 i = 0; i < rewardTokens.length; ++i) {
|
|
126
|
+
address token = rewardTokens[i];
|
|
127
|
+
|
|
128
|
+
uint256 currentRewardBalance = IERC20(token).balanceOf(address(this));
|
|
129
|
+
uint256 totalIncomeReward = currentRewardBalance - globalReward[token].lastBalance;
|
|
130
|
+
|
|
131
|
+
if (_isExpired) {
|
|
132
|
+
totalRewardsPostExpiry[token] += totalIncomeReward;
|
|
133
|
+
} else if (totalSupply != 0) {
|
|
134
|
+
globalReward[token].index += totalIncomeReward.divDown(totalSupply);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
globalReward[token].lastBalance = currentRewardBalance;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function _redeemExternalReward() internal virtual override {
|
|
142
|
+
ISuperComposableYield(SCY).redeemReward(address(this), address(this));
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function getRewardTokens()
|
|
146
|
+
public
|
|
147
|
+
view
|
|
148
|
+
virtual
|
|
149
|
+
override(RewardManager)
|
|
150
|
+
returns (address[] memory)
|
|
151
|
+
{
|
|
152
|
+
return ISuperComposableYield(SCY).getRewardTokens();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function getScyIndexBeforeExpiry() public returns (uint256 res) {
|
|
156
|
+
if (isExpired()) return res = lastScyIndexBeforeExpiry;
|
|
157
|
+
res = ISuperComposableYield(SCY).scyIndexCurrent();
|
|
158
|
+
lastScyIndexBeforeExpiry = res;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function withdrawFeeToTreasury() public {
|
|
162
|
+
address[] memory rewardTokens = ISuperComposableYield(SCY).getRewardTokens();
|
|
163
|
+
uint256 length = rewardTokens.length;
|
|
164
|
+
address treasury = IPYieldContractFactory(factory).treasury();
|
|
165
|
+
|
|
166
|
+
for (uint256 i = 0; i < length; i++) {
|
|
167
|
+
address token = rewardTokens[i];
|
|
168
|
+
uint256 outAmount = totalRewardsPostExpiry[token];
|
|
169
|
+
if (outAmount > 0) IERC20(rewardTokens[i]).safeTransfer(treasury, outAmount);
|
|
170
|
+
totalRewardsPostExpiry[token] = 0;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (totalProtocolFee > 0) {
|
|
174
|
+
IERC20(SCY).safeTransfer(treasury, totalProtocolFee);
|
|
175
|
+
_afterTransferOutSCY();
|
|
176
|
+
totalProtocolFee = 0;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function _updateDueInterest(address user) internal {
|
|
181
|
+
uint256 prevIndex = data[user].lastScyIndex;
|
|
182
|
+
|
|
183
|
+
uint256 currentIndex = getScyIndexBeforeExpiry();
|
|
184
|
+
|
|
185
|
+
if (prevIndex == currentIndex) return;
|
|
186
|
+
if (prevIndex == 0) {
|
|
187
|
+
data[user].lastScyIndex = currentIndex;
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
uint256 principal = balanceOf(user);
|
|
192
|
+
|
|
193
|
+
uint256 interestFromYT = (principal * (currentIndex - prevIndex)).divDown(
|
|
194
|
+
prevIndex * currentIndex
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
data[user].dueInterest += interestFromYT;
|
|
198
|
+
data[user].lastScyIndex = currentIndex;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function _calcAmountToMint(uint256 amount) internal returns (uint256) {
|
|
202
|
+
return SCYUtils.scyToAsset(getScyIndexBeforeExpiry(), amount);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function _calcAmountRedeemable(uint256 amount) internal returns (uint256) {
|
|
206
|
+
return SCYUtils.assetToScy(getScyIndexBeforeExpiry(), amount);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function _receiveSCY() internal returns (uint256 amount) {
|
|
210
|
+
uint256 balanceScy = IERC20(SCY).balanceOf(address(this));
|
|
211
|
+
amount = balanceScy - lastScyBalance;
|
|
212
|
+
require(amount > 0, "RECEIVE_ZERO");
|
|
213
|
+
lastScyBalance = balanceScy;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function _afterTransferOutSCY() internal {
|
|
217
|
+
lastScyBalance = IERC20(SCY).balanceOf(address(this));
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function _beforeTokenTransfer(
|
|
221
|
+
address from,
|
|
222
|
+
address to,
|
|
223
|
+
uint256
|
|
224
|
+
) internal override {
|
|
225
|
+
address[] memory rewardTokens = getRewardTokens();
|
|
226
|
+
_updateGlobalReward(rewardTokens, totalSupply());
|
|
227
|
+
if (from != address(0) && from != address(this)) {
|
|
228
|
+
_updateDueInterest(from);
|
|
229
|
+
_updateUserRewardSkipGlobal(rewardTokens, from, balanceOf(from));
|
|
230
|
+
}
|
|
231
|
+
if (to != address(0) && to != address(this)) {
|
|
232
|
+
_updateDueInterest(to);
|
|
233
|
+
_updateUserRewardSkipGlobal(rewardTokens, to, balanceOf(to));
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
/*INVARIANTS TO CHECK
|
|
238
|
+
- supply OT == supply YT
|
|
239
|
+
- reentrancy check
|
|
240
|
+
*/
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity 0.8.9;
|
|
3
|
+
|
|
4
|
+
// Audit on 5-Jan-2021 by Keno and BoringCrypto
|
|
5
|
+
// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol + Claimable.sol
|
|
6
|
+
// Edited by BoringCrypto
|
|
7
|
+
|
|
8
|
+
contract BoringOwnableData {
|
|
9
|
+
address public owner;
|
|
10
|
+
address public pendingOwner;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
contract BoringOwnable is BoringOwnableData {
|
|
14
|
+
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
|
|
15
|
+
|
|
16
|
+
/// @notice Only allows the `owner` to execute the function.
|
|
17
|
+
modifier onlyOwner() {
|
|
18
|
+
require(msg.sender == owner, "Ownable: caller is not the owner");
|
|
19
|
+
_;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
constructor(address _owner) {
|
|
23
|
+
owner = _owner;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/// @notice Transfers ownership to `newOwner`. Either directly or claimable by the new pending owner.
|
|
27
|
+
/// Can only be invoked by the current `owner`.
|
|
28
|
+
/// @param newOwner Address of the new owner.
|
|
29
|
+
/// @param direct True if `newOwner` should be set immediately. False if `newOwner` needs to use `claimOwnership`.
|
|
30
|
+
/// @param renounce Allows the `newOwner` to be `address(0)` if `direct` and `renounce` is True. Has no effect otherwise.
|
|
31
|
+
function transferOwnership(
|
|
32
|
+
address newOwner,
|
|
33
|
+
bool direct,
|
|
34
|
+
bool renounce
|
|
35
|
+
) public onlyOwner {
|
|
36
|
+
if (direct) {
|
|
37
|
+
// Checks
|
|
38
|
+
require(newOwner != address(0) || renounce, "Ownable: zero address");
|
|
39
|
+
|
|
40
|
+
// Effects
|
|
41
|
+
emit OwnershipTransferred(owner, newOwner);
|
|
42
|
+
owner = newOwner;
|
|
43
|
+
pendingOwner = address(0);
|
|
44
|
+
} else {
|
|
45
|
+
// Effects
|
|
46
|
+
pendingOwner = newOwner;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/// @notice Needs to be called by `pendingOwner` to claim ownership.
|
|
51
|
+
function claimOwnership() public {
|
|
52
|
+
address _pendingOwner = pendingOwner;
|
|
53
|
+
|
|
54
|
+
// Checks
|
|
55
|
+
require(msg.sender == _pendingOwner, "Ownable: caller != pending owner");
|
|
56
|
+
|
|
57
|
+
// Effects
|
|
58
|
+
emit OwnershipTransferred(owner, _pendingOwner);
|
|
59
|
+
owner = _pendingOwner;
|
|
60
|
+
pendingOwner = address(0);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity 0.8.9;
|
|
3
|
+
|
|
4
|
+
import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol";
|
|
5
|
+
|
|
6
|
+
/// Modified by the Pendle team, needs to audit
|
|
7
|
+
|
|
8
|
+
contract BoringOwnableUpgData {
|
|
9
|
+
address public owner;
|
|
10
|
+
address public pendingOwner;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
contract BoringOwnableUpg is BoringOwnableUpgData, Initializable {
|
|
14
|
+
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
|
|
15
|
+
|
|
16
|
+
function __BoringOwnable_init() internal onlyInitializing {
|
|
17
|
+
owner = msg.sender;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/// @notice Transfers ownership to `newOwner`. Either directly or claimable by the new pending owner.
|
|
21
|
+
/// Can only be invoked by the current `owner`.
|
|
22
|
+
/// @param newOwner Address of the new owner.
|
|
23
|
+
/// @param direct True if `newOwner` should be set immediately. False if `newOwner` needs to use `claimOwnership`.
|
|
24
|
+
/// @param renounce Allows the `newOwner` to be `address(0)` if `direct` and `renounce` is True. Has no effect otherwise.
|
|
25
|
+
function transferOwnership(
|
|
26
|
+
address newOwner,
|
|
27
|
+
bool direct,
|
|
28
|
+
bool renounce
|
|
29
|
+
) public onlyOwner {
|
|
30
|
+
if (direct) {
|
|
31
|
+
// Checks
|
|
32
|
+
require(newOwner != address(0) || renounce, "Ownable: zero address");
|
|
33
|
+
|
|
34
|
+
// Effects
|
|
35
|
+
emit OwnershipTransferred(owner, newOwner);
|
|
36
|
+
owner = newOwner;
|
|
37
|
+
pendingOwner = address(0);
|
|
38
|
+
} else {
|
|
39
|
+
// Effects
|
|
40
|
+
pendingOwner = newOwner;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/// @notice Needs to be called by `pendingOwner` to claim ownership.
|
|
45
|
+
function claimOwnership() public {
|
|
46
|
+
address _pendingOwner = pendingOwner;
|
|
47
|
+
|
|
48
|
+
// Checks
|
|
49
|
+
require(msg.sender == _pendingOwner, "Ownable: caller != pending owner");
|
|
50
|
+
|
|
51
|
+
// Effects
|
|
52
|
+
emit OwnershipTransferred(owner, _pendingOwner);
|
|
53
|
+
owner = _pendingOwner;
|
|
54
|
+
pendingOwner = address(0);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/// @notice Only allows the `owner` to execute the function.
|
|
58
|
+
modifier onlyOwner() {
|
|
59
|
+
require(msg.sender == owner, "Ownable: caller is not the owner");
|
|
60
|
+
_;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
uint256[48] private __gap;
|
|
64
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
+
/*
|
|
3
|
+
* MIT License
|
|
4
|
+
* ===========
|
|
5
|
+
*
|
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
* in the Software without restriction, including without limitation the rights
|
|
9
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
* furnished to do so, subject to the following conditions:
|
|
12
|
+
*
|
|
13
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
* copies or substantial portions of the Software.
|
|
15
|
+
*
|
|
16
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
pragma solidity 0.8.9;
|
|
25
|
+
import "../../interfaces/IJoeRouter01.sol";
|
|
26
|
+
import "../../libraries/JoeLibrary.sol";
|
|
27
|
+
import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";
|
|
28
|
+
import "openzeppelin-solidity/contracts/token/ERC20/utils/SafeERC20.sol";
|
|
29
|
+
|
|
30
|
+
abstract contract PendleJoeSwapHelperUpg {
|
|
31
|
+
using SafeERC20 for IERC20;
|
|
32
|
+
address public immutable joeRouter;
|
|
33
|
+
address public immutable joeFactory;
|
|
34
|
+
|
|
35
|
+
/// @dev since this contract will be proxied, it must not contains non-immutable variables
|
|
36
|
+
constructor(address _joeRouter, address _joeFactory) {
|
|
37
|
+
joeRouter = _joeRouter;
|
|
38
|
+
joeFactory = _joeFactory;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function _getFirstPair(address[] memory path) internal view returns (address pair) {
|
|
42
|
+
return JoeLibrary.pairFor(joeFactory, path[0], path[1]);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @notice swap tokens with no limit on amountOut. Tokens must have been transferred to the first pair
|
|
47
|
+
*/
|
|
48
|
+
function _swapExactIn(
|
|
49
|
+
address[] memory path,
|
|
50
|
+
uint256 amountIn,
|
|
51
|
+
address receiver
|
|
52
|
+
) internal virtual returns (uint256 amountOut) {
|
|
53
|
+
uint256[] memory amounts = JoeLibrary.getAmountsOut(joeFactory, amountIn, path);
|
|
54
|
+
_low_level_swap(amounts, path, receiver);
|
|
55
|
+
amountOut = amounts[amounts.length - 1];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/// function from TraderJoe
|
|
59
|
+
function _low_level_swap(
|
|
60
|
+
uint256[] memory amounts,
|
|
61
|
+
address[] memory path,
|
|
62
|
+
address _to
|
|
63
|
+
) internal virtual {
|
|
64
|
+
for (uint256 i; i < path.length - 1; i++) {
|
|
65
|
+
(address input, address output) = (path[i], path[i + 1]);
|
|
66
|
+
(address token0, ) = JoeLibrary.sortTokens(input, output);
|
|
67
|
+
uint256 amountOut = amounts[i + 1];
|
|
68
|
+
(uint256 amount0Out, uint256 amount1Out) = input == token0
|
|
69
|
+
? (uint256(0), amountOut)
|
|
70
|
+
: (amountOut, uint256(0));
|
|
71
|
+
address to = i < path.length - 2
|
|
72
|
+
? JoeLibrary.pairFor(joeFactory, output, path[i + 2])
|
|
73
|
+
: _to;
|
|
74
|
+
IJoePair(JoeLibrary.pairFor(joeFactory, input, output)).swap(
|
|
75
|
+
amount0Out,
|
|
76
|
+
amount1Out,
|
|
77
|
+
to,
|
|
78
|
+
new bytes(0)
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
+
pragma solidity 0.8.9;
|
|
3
|
+
|
|
4
|
+
import "./base/PendleRouterSCYAndForgeBaseUpg.sol";
|
|
5
|
+
import "./base/PendleRouterOTBaseUpg.sol";
|
|
6
|
+
import "../../interfaces/IPOwnershipToken.sol";
|
|
7
|
+
import "../../interfaces/IPYieldToken.sol";
|
|
8
|
+
import "../../interfaces/IPRouterCore.sol";
|
|
9
|
+
|
|
10
|
+
contract PendleRouterCoreUpg is
|
|
11
|
+
IPRouterCore,
|
|
12
|
+
PendleRouterSCYAndForgeBaseUpg,
|
|
13
|
+
PendleRouterOTBaseUpg
|
|
14
|
+
{
|
|
15
|
+
using MarketMathLib for MarketParameters;
|
|
16
|
+
using FixedPoint for uint256;
|
|
17
|
+
using FixedPoint for int256;
|
|
18
|
+
|
|
19
|
+
/// @dev since this contract will be proxied, it must not contains non-immutable variabless
|
|
20
|
+
constructor(
|
|
21
|
+
address _joeRouter,
|
|
22
|
+
address _joeFactory,
|
|
23
|
+
address _marketFactory
|
|
24
|
+
)
|
|
25
|
+
PendleRouterSCYAndForgeBaseUpg(_joeRouter, _joeFactory)
|
|
26
|
+
PendleRouterOTBaseUpg()
|
|
27
|
+
//solhint-disable-next-line no-empty-blocks
|
|
28
|
+
{
|
|
29
|
+
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/// @dev docs can be found in the internal function
|
|
33
|
+
function addLiquidity(
|
|
34
|
+
address receiver,
|
|
35
|
+
address market,
|
|
36
|
+
uint256 scyDesired,
|
|
37
|
+
uint256 otDesired,
|
|
38
|
+
uint256 minLpOut
|
|
39
|
+
)
|
|
40
|
+
external
|
|
41
|
+
returns (
|
|
42
|
+
uint256,
|
|
43
|
+
uint256,
|
|
44
|
+
uint256
|
|
45
|
+
)
|
|
46
|
+
{
|
|
47
|
+
return _addLiquidity(receiver, market, scyDesired, otDesired, minLpOut, true);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/// @dev docs can be found in the internal function
|
|
51
|
+
function removeLiquidity(
|
|
52
|
+
address receiver,
|
|
53
|
+
address market,
|
|
54
|
+
uint256 lpToRemove,
|
|
55
|
+
uint256 scyOutMin,
|
|
56
|
+
uint256 otOutMin
|
|
57
|
+
) external returns (uint256, uint256) {
|
|
58
|
+
return _removeLiquidity(receiver, market, lpToRemove, scyOutMin, otOutMin, true);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/// @dev docs can be found in the internal function
|
|
62
|
+
function swapExactOtForScy(
|
|
63
|
+
address receiver,
|
|
64
|
+
address market,
|
|
65
|
+
uint256 exactOtIn,
|
|
66
|
+
uint256 minScyOut
|
|
67
|
+
) external returns (uint256) {
|
|
68
|
+
return _swapExactOtForScy(receiver, market, exactOtIn, minScyOut, true);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/// @dev docs can be found in the internal function
|
|
72
|
+
function swapOtForExactScy(
|
|
73
|
+
address receiver,
|
|
74
|
+
address market,
|
|
75
|
+
uint256 maxOtIn,
|
|
76
|
+
uint256 exactScyOut,
|
|
77
|
+
uint256 netOtInGuessMin,
|
|
78
|
+
uint256 netOtInGuessMax
|
|
79
|
+
) external returns (uint256) {
|
|
80
|
+
return
|
|
81
|
+
_swapOtForExactScy(
|
|
82
|
+
receiver,
|
|
83
|
+
market,
|
|
84
|
+
maxOtIn,
|
|
85
|
+
exactScyOut,
|
|
86
|
+
netOtInGuessMin,
|
|
87
|
+
netOtInGuessMax,
|
|
88
|
+
true
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/// @dev docs can be found in the internal function
|
|
93
|
+
function swapScyForExactOt(
|
|
94
|
+
address receiver,
|
|
95
|
+
address market,
|
|
96
|
+
uint256 exactOtOut,
|
|
97
|
+
uint256 maxScyIn
|
|
98
|
+
) external returns (uint256) {
|
|
99
|
+
return _swapScyForExactOt(receiver, market, exactOtOut, maxScyIn, true);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/// @dev docs can be found in the internal function
|
|
103
|
+
function swapExactScyForOt(
|
|
104
|
+
address receiver,
|
|
105
|
+
address market,
|
|
106
|
+
uint256 exactScyIn,
|
|
107
|
+
uint256 minOtOut,
|
|
108
|
+
uint256 netOtOutGuessMin,
|
|
109
|
+
uint256 netOtOutGuessMax
|
|
110
|
+
) external returns (uint256) {
|
|
111
|
+
return
|
|
112
|
+
_swapExactScyForOt(
|
|
113
|
+
receiver,
|
|
114
|
+
market,
|
|
115
|
+
exactScyIn,
|
|
116
|
+
minOtOut,
|
|
117
|
+
netOtOutGuessMin,
|
|
118
|
+
netOtOutGuessMax,
|
|
119
|
+
true
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/// @dev docs can be found in the internal function
|
|
124
|
+
function mintScyFromRawToken(
|
|
125
|
+
uint256 netRawTokenIn,
|
|
126
|
+
address SCY,
|
|
127
|
+
uint256 minScyOut,
|
|
128
|
+
address receiver,
|
|
129
|
+
address[] calldata path
|
|
130
|
+
) external returns (uint256) {
|
|
131
|
+
return _mintScyFromRawToken(netRawTokenIn, SCY, minScyOut, receiver, path, true);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/// @dev docs can be found in the internal function
|
|
135
|
+
function redeemScyToRawToken(
|
|
136
|
+
address SCY,
|
|
137
|
+
uint256 netScyIn,
|
|
138
|
+
uint256 minRawTokenOut,
|
|
139
|
+
address receiver,
|
|
140
|
+
address[] memory path
|
|
141
|
+
) external returns (uint256) {
|
|
142
|
+
return _redeemScyToRawToken(SCY, netScyIn, minRawTokenOut, receiver, path, true);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/// @dev docs can be found in the internal function
|
|
146
|
+
function mintYoFromRawToken(
|
|
147
|
+
uint256 netRawTokenIn,
|
|
148
|
+
address YT,
|
|
149
|
+
uint256 minYoOut,
|
|
150
|
+
address receiver,
|
|
151
|
+
address[] calldata path
|
|
152
|
+
) external returns (uint256) {
|
|
153
|
+
return _mintYoFromRawToken(netRawTokenIn, YT, minYoOut, receiver, path, true);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/// @dev docs can be found in the internal function
|
|
157
|
+
function redeemYoToRawToken(
|
|
158
|
+
address YT,
|
|
159
|
+
uint256 netYoIn,
|
|
160
|
+
uint256 minRawTokenOut,
|
|
161
|
+
address receiver,
|
|
162
|
+
address[] memory path
|
|
163
|
+
) external returns (uint256) {
|
|
164
|
+
return _redeemYoToRawToken(YT, netYoIn, minRawTokenOut, receiver, path, true);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* @dev netOtOutGuessMin & netOtOutGuessMax the minimum & maximum possible guess for the netOtOut
|
|
169
|
+
the correct otOut must lie between this range, else the function will revert.
|
|
170
|
+
* @dev the smaller the range, the fewer iterations it will take (hence less gas). The expected way
|
|
171
|
+
to create the guess is to run this function with min = 0, max = type(uint256.max) to trigger the widest
|
|
172
|
+
guess range. After getting the result, min = result * (100-slippage) & max = result * (100+slippage)
|
|
173
|
+
* @param path the path to swap from rawToken to baseToken. path = [baseToken] if no swap is needed
|
|
174
|
+
*/
|
|
175
|
+
function swapExactRawTokenForOt(
|
|
176
|
+
uint256 exactRawTokenIn,
|
|
177
|
+
address receiver,
|
|
178
|
+
address[] calldata path,
|
|
179
|
+
address market,
|
|
180
|
+
uint256 minOtOut,
|
|
181
|
+
uint256 netOtOutGuessMin,
|
|
182
|
+
uint256 netOtOutGuessMax
|
|
183
|
+
) external returns (uint256 netOtOut) {
|
|
184
|
+
address SCY = IPMarket(market).SCY();
|
|
185
|
+
uint256 netScyUseToBuyOt = _mintScyFromRawToken(
|
|
186
|
+
exactRawTokenIn,
|
|
187
|
+
SCY,
|
|
188
|
+
1,
|
|
189
|
+
market,
|
|
190
|
+
path,
|
|
191
|
+
true
|
|
192
|
+
);
|
|
193
|
+
netOtOut = _swapExactScyForOt(
|
|
194
|
+
receiver,
|
|
195
|
+
market,
|
|
196
|
+
netScyUseToBuyOt,
|
|
197
|
+
minOtOut,
|
|
198
|
+
netOtOutGuessMin,
|
|
199
|
+
netOtOutGuessMax,
|
|
200
|
+
false
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* @notice sell all Ot for RawToken
|
|
206
|
+
* @param path the path to swap from rawToken to baseToken. path = [baseToken] if no swap is needed
|
|
207
|
+
*/
|
|
208
|
+
function swapExactOtForRawToken(
|
|
209
|
+
uint256 exactOtIn,
|
|
210
|
+
address receiver,
|
|
211
|
+
address[] calldata path,
|
|
212
|
+
address market,
|
|
213
|
+
uint256 minRawTokenOut
|
|
214
|
+
) external returns (uint256 netRawTokenOut) {
|
|
215
|
+
address SCY = IPMarket(market).SCY();
|
|
216
|
+
_swapExactOtForScy(SCY, market, exactOtIn, 1, true);
|
|
217
|
+
netRawTokenOut = _redeemScyToRawToken(SCY, 0, minRawTokenOut, receiver, path, false);
|
|
218
|
+
}
|
|
219
|
+
}
|