// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2 <0.8.0;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
uint256 size;
// solhint-disable-next-line no-inline-assembly
assembly { size := extcodesize(account) }
return size > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
// solhint-disable-next-line avoid-low-level-calls, avoid-call-value
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain`call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.call{ value: value }(data);
return _verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.staticcall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.delegatecall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
// solhint-disable-next-line no-inline-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.7.6;
pragma abicoder v2;
import "@openzeppelin/contracts/math/SafeMath.sol";
library ExpiryUtils {
struct Date {
uint16 year;
uint8 month;
uint8 day;
}
uint256 private constant DAY_IN_SECONDS = 86400;
uint256 private constant YEAR_IN_SECONDS = 31536000;
uint256 private constant LEAP_YEAR_IN_SECONDS = 31622400;
uint16 private constant ORIGIN_YEAR = 1970;
/**
* @notice Concatenates a Pendle token name/symbol, a yield token name/symbol,
* and an expiry, using a delimiter (usually "-" or " ").
* @param _bt The Pendle token name/symbol.
* @param _yt The yield token name/symbol.
* @param _expiry The expiry in epoch time.
* @param _delimiter Can be any delimiter, but usually "-" or " ".
* @return result Returns the concatenated string.
**/
function concat(
string memory _bt,
string memory _yt,
uint256 _expiry,
string memory _delimiter
) internal pure returns (string memory result) {
result = string(
abi.encodePacked(_bt, _delimiter, _yt, _delimiter, toRFC2822String(_expiry))
);
}
function toRFC2822String(uint256 _timestamp) internal pure returns (string memory s) {
Date memory d = parseTimestamp(_timestamp);
string memory day = uintToString(d.day);
string memory month = monthName(d);
string memory year = uintToString(d.year);
s = string(abi.encodePacked(day, month, year));
}
function getDaysInMonth(uint8 _month, uint16 _year) private pure returns (uint8) {
if (
_month == 1 ||
_month == 3 ||
_month == 5 ||
_month == 7 ||
_month == 8 ||
_month == 10 ||
_month == 12
) {
return 31;
} else if (_month == 4 || _month == 6 || _month == 9 || _month == 11) {
return 30;
} else if (isLeapYear(_year)) {
return 29;
} else {
return 28;
}
}
function getYear(uint256 _timestamp) private pure returns (uint16) {
uint256 secondsAccountedFor = 0;
uint16 year;
uint256 numLeapYears;
// Year
year = uint16(ORIGIN_YEAR + _timestamp / YEAR_IN_SECONDS);
numLeapYears = leapYearsBefore(year) - leapYearsBefore(ORIGIN_YEAR);
secondsAccountedFor += LEAP_YEAR_IN_SECONDS * numLeapYears;
secondsAccountedFor += YEAR_IN_SECONDS * (year - ORIGIN_YEAR - numLeapYears);
while (secondsAccountedFor > _timestamp) {
if (isLeapYear(uint16(year - 1))) {
secondsAccountedFor -= LEAP_YEAR_IN_SECONDS;
} else {
secondsAccountedFor -= YEAR_IN_SECONDS;
}
year -= 1;
}
return year;
}
function isLeapYear(uint16 _year) private pure returns (bool) {
return ((_year % 4 == 0) && (_year % 100 != 0)) || (_year % 400 == 0);
}
function leapYearsBefore(uint256 _year) private pure returns (uint256) {
_year -= 1;
return _year / 4 - _year / 100 + _year / 400;
}
function monthName(Date memory d) private pure returns (string memory) {
string[12] memory months = [
"JAN",
"FEB",
"MAR",
"APR",
"MAY",
"JUN",
"JUL",
"AUG",
"SEP",
"OCT",
"NOV",
"DEC"
];
return months[d.month - 1];
}
function parseTimestamp(uint256 _timestamp) private pure returns (Date memory d) {
uint256 secondsAccountedFor = 0;
uint256 buf;
uint8 i;
// Year
d.year = getYear(_timestamp);
buf = leapYearsBefore(d.year) - leapYearsBefore(ORIGIN_YEAR);
secondsAccountedFor += LEAP_YEAR_IN_SECONDS * buf;
secondsAccountedFor += YEAR_IN_SECONDS * (d.year - ORIGIN_YEAR - buf);
// Month
uint256 secondsInMonth;
for (i = 1; i <= 12; i++) {
secondsInMonth = DAY_IN_SECONDS * getDaysInMonth(i, d.year);
if (secondsInMonth + secondsAccountedFor > _timestamp) {
d.month = i;
break;
}
secondsAccountedFor += secondsInMonth;
}
// Day
for (i = 1; i <= getDaysInMonth(d.month, d.year); i++) {
if (DAY_IN_SECONDS + secondsAccountedFor > _timestamp) {
d.day = i;
break;
}
secondsAccountedFor += DAY_IN_SECONDS;
}
}
function uintToString(uint256 _i) private pure returns (string memory) {
if (_i == 0) {
return "0";
}
uint256 j = _i;
uint256 len;
while (j != 0) {
len++;
j /= 10;
}
bytes memory bstr = new bytes(len);
uint256 k = len - 1;
while (_i != 0) {
bstr[k--] = bytes1(uint8(48 + (_i % 10)));
_i /= 10;
}
return string(bstr);
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}
// SPDX-License-Identifier: MIT
/*
* MIT License
* ===========
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*/
pragma solidity 0.7.6;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IPendleBaseToken is IERC20 {
/**
* @notice Decreases the allowance granted to spender by the caller.
* @param spender The address to reduce the allowance from.
* @param subtractedValue The amount allowance to subtract.
* @return Returns true if allowance has decreased, otherwise false.
**/
function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);
/**
* @notice The yield contract start in epoch time.
* @return Returns the yield start date.
**/
function start() external view returns (uint256);
/**
* @notice The yield contract expiry in epoch time.
* @return Returns the yield expiry date.
**/
function expiry() external view returns (uint256);
/**
* @notice Increases the allowance granted to spender by the caller.
* @param spender The address to increase the allowance from.
* @param addedValue The amount allowance to add.
* @return Returns true if allowance has increased, otherwise false
**/
function increaseAllowance(address spender, uint256 addedValue) external returns (bool);
/**
* @notice Returns the number of decimals the token uses.
* @return Returns the token's decimals.
**/
function decimals() external view returns (uint8);
/**
* @notice Returns the name of the token.
* @return Returns the token's name.
**/
function name() external view returns (string memory);
/**
* @notice Returns the symbol of the token.
* @return Returns the token's symbol.
**/
function symbol() external view returns (string memory);
/**
* @notice approve using the owner's signature
**/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
}
// SPDX-License-Identifier: MIT
/*
* MIT License
* ===========
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*/
pragma solidity 0.7.6;
import "./IPendleForge.sol";
interface IPendleCompoundForge is IPendleForge {
/**
@dev directly get the exchangeRate from Compound
*/
function getExchangeRate(address _underlyingAsset) external returns (uint256);
}
// SPDX-License-Identifier: MIT
/*
* MIT License
* ===========
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*/
pragma solidity 0.7.6;
import "./IPendleRouter.sol";
import "./IPendleYieldToken.sol";
import "./IPendlePausingManager.sol";
import "./IPendleMarket.sol";
interface IPendleData {
/**
* @notice Emitted when validity of a forge-factory pair is updated
* @param _forgeId the forge id
* @param _marketFactoryId the market factory id
* @param _valid valid or not
**/
event ForgeFactoryValiditySet(bytes32 _forgeId, bytes32 _marketFactoryId, bool _valid);
/**
* @notice Emitted when Pendle and PendleFactory addresses have been updated.
* @param treasury The address of the new treasury contract.
**/
event TreasurySet(address treasury);
/**
* @notice Emitted when LockParams is changed
**/
event LockParamsSet(uint256 lockNumerator, uint256 lockDenominator);
/**
* @notice Emitted when ExpiryDivisor is changed
**/
event ExpiryDivisorSet(uint256 expiryDivisor);
/**
* @notice Emitted when forge fee is changed
**/
event ForgeFeeSet(uint256 forgeFee);
/**
* @notice Emitted when interestUpdateRateDeltaForMarket is changed
* @param interestUpdateRateDeltaForMarket new interestUpdateRateDeltaForMarket setting
**/
event InterestUpdateRateDeltaForMarketSet(uint256 interestUpdateRateDeltaForMarket);
/**
* @notice Emitted when market fees are changed
* @param _swapFee new swapFee setting
* @param _protocolSwapFee new protocolSwapFee setting
**/
event MarketFeesSet(uint256 _swapFee, uint256 _protocolSwapFee);
/**
* @notice Emitted when the curve shift block delta is changed
* @param _blockDelta new block delta setting
**/
event CurveShiftBlockDeltaSet(uint256 _blockDelta);
/**
* @dev Emitted when new forge is added
* @param marketFactoryId Human Readable Market Factory ID in Bytes
* @param marketFactoryAddress The Market Factory Address
*/
event NewMarketFactory(bytes32 indexed marketFactoryId, address indexed marketFactoryAddress);
/**
* @notice Set/update validity of a forge-factory pair
* @param _forgeId the forge id
* @param _marketFactoryId the market factory id
* @param _valid valid or not
**/
function setForgeFactoryValidity(
bytes32 _forgeId,
bytes32 _marketFactoryId,
bool _valid
) external;
/**
* @notice Sets the PendleTreasury contract addresses.
* @param newTreasury Address of new treasury contract.
**/
function setTreasury(address newTreasury) external;
/**
* @notice Gets a reference to the PendleRouter contract.
* @return Returns the router contract reference.
**/
function router() external view returns (IPendleRouter);
/**
* @notice Gets a reference to the PendleRouter contract.
* @return Returns the router contract reference.
**/
function pausingManager() external view returns (IPendlePausingManager);
/**
* @notice Gets the treasury contract address where fees are being sent to.
* @return Address of the treasury contract.
**/
function treasury() external view returns (address);
/***********
* FORGE *
***********/
/**
* @notice Emitted when a forge for a protocol is added.
* @param forgeId Forge and protocol identifier.
* @param forgeAddress The address of the added forge.
**/
event ForgeAdded(bytes32 indexed forgeId, address indexed forgeAddress);
/**
* @notice Adds a new forge for a protocol.
* @param forgeId Forge and protocol identifier.
* @param forgeAddress The address of the added forge.
**/
function addForge(bytes32 forgeId, address forgeAddress) external;
/**
* @notice Store new OT and XYT details.
* @param forgeId Forge and protocol identifier.
* @param ot The address of the new XYT.
* @param xyt The address of the new XYT.
* @param underlyingAsset Token address of the underlying asset.
* @param expiry Yield contract expiry in epoch time.
**/
function storeTokens(
bytes32 forgeId,
address ot,
address xyt,
address underlyingAsset,
uint256 expiry
) external;
/**
* @notice Set a new forge fee
* @param _forgeFee new forge fee
**/
function setForgeFee(uint256 _forgeFee) external;
/**
* @notice Gets the OT and XYT tokens.
* @param forgeId Forge and protocol identifier.
* @param underlyingYieldToken Token address of the underlying yield token.
* @param expiry Yield contract expiry in epoch time.
* @return ot The OT token references.
* @return xyt The XYT token references.
**/
function getPendleYieldTokens(
bytes32 forgeId,
address underlyingYieldToken,
uint256 expiry
) external view returns (IPendleYieldToken ot, IPendleYieldToken xyt);
/**
* @notice Gets a forge given the identifier.
* @param forgeId Forge and protocol identifier.
* @return forgeAddress Returns the forge address.
**/
function getForgeAddress(bytes32 forgeId) external view returns (address forgeAddress);
/**
* @notice Checks if an XYT token is valid.
* @param forgeId The forgeId of the forge.
* @param underlyingAsset Token address of the underlying asset.
* @param expiry Yield contract expiry in epoch time.
* @return True if valid, false otherwise.
**/
function isValidXYT(
bytes32 forgeId,
address underlyingAsset,
uint256 expiry
) external view returns (bool);
/**
* @notice Checks if an OT token is valid.
* @param forgeId The forgeId of the forge.
* @param underlyingAsset Token address of the underlying asset.
* @param expiry Yield contract expiry in epoch time.
* @return True if valid, false otherwise.
**/
function isValidOT(
bytes32 forgeId,
address underlyingAsset,
uint256 expiry
) external view returns (bool);
function validForgeFactoryPair(bytes32 _forgeId, bytes32 _marketFactoryId)
external
view
returns (bool);
/**
* @notice Gets a reference to a specific OT.
* @param forgeId Forge and protocol identifier.
* @param underlyingYieldToken Token address of the underlying yield token.
* @param expiry Yield contract expiry in epoch time.
* @return ot Returns the reference to an OT.
**/
function otTokens(
bytes32 forgeId,
address underlyingYieldToken,
uint256 expiry
) external view returns (IPendleYieldToken ot);
/**
* @notice Gets a reference to a specific XYT.
* @param forgeId Forge and protocol identifier.
* @param underlyingAsset Token address of the underlying asset
* @param expiry Yield contract expiry in epoch time.
* @return xyt Returns the reference to an XYT.
**/
function xytTokens(
bytes32 forgeId,
address underlyingAsset,
uint256 expiry
) external view returns (IPendleYieldToken xyt);
/***********
* MARKET *
***********/
event MarketPairAdded(address indexed market, address indexed xyt, address indexed token);
function addMarketFactory(bytes32 marketFactoryId, address marketFactoryAddress) external;
function isMarket(address _addr) external view returns (bool result);
function isXyt(address _addr) external view returns (bool result);
function addMarket(
bytes32 marketFactoryId,
address xyt,
address token,
address market
) external;
function setMarketFees(uint256 _swapFee, uint256 _protocolSwapFee) external;
function setInterestUpdateRateDeltaForMarket(uint256 _interestUpdateRateDeltaForMarket)
external;
function setLockParams(uint256 _lockNumerator, uint256 _lockDenominator) external;
function setExpiryDivisor(uint256 _expiryDivisor) external;
function setCurveShiftBlockDelta(uint256 _blockDelta) external;
/**
* @notice Displays the number of markets currently existing.
* @return Returns markets length,
**/
function allMarketsLength() external view returns (uint256);
function forgeFee() external view returns (uint256);
function interestUpdateRateDeltaForMarket() external view returns (uint256);
function expiryDivisor() external view returns (uint256);
function lockNumerator() external view returns (uint256);
function lockDenominator() external view returns (uint256);
function swapFee() external view returns (uint256);
function protocolSwapFee() external view returns (uint256);
function curveShiftBlockDelta() external view returns (uint256);
function getMarketByIndex(uint256 index) external view returns (address market);
/**
* @notice Gets a market given a future yield token and an ERC20 token.
* @param xyt Token address of the future yield token as base asset.
* @param token Token address of an ERC20 token as quote asset.
* @return market Returns the market address.
**/
function getMarket(
bytes32 marketFactoryId,
address xyt,
address token
) external view returns (address market);
/**
* @notice Gets a market factory given the identifier.
* @param marketFactoryId MarketFactory identifier.
* @return marketFactoryAddress Returns the factory address.
**/
function getMarketFactoryAddress(bytes32 marketFactoryId)
external
view
returns (address marketFactoryAddress);
function getMarketFromKey(
address xyt,
address token,
bytes32 marketFactoryId
) external view returns (address market);
}
// SPDX-License-Identifier: MIT
/*
* MIT License
* ===========
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*/
pragma solidity 0.7.6;
import "./IPendleRouter.sol";
import "./IPendleRewardManager.sol";
import "./IPendleYieldContractDeployer.sol";
import "./IPendleData.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IPendleForge {
/**
* @dev Emitted when the Forge has minted the OT and XYT tokens.
* @param forgeId The forgeId
* @param underlyingAsset The address of the underlying yield token.
* @param expiry The expiry of the XYT token
* @param amountToTokenize The amount of yield bearing assets to tokenize
* @param amountTokenMinted The amount of OT/XYT minted
**/
event MintYieldTokens(
bytes32 forgeId,
address indexed underlyingAsset,
uint256 indexed expiry,
uint256 amountToTokenize,
uint256 amountTokenMinted,
address indexed user
);
/**
* @dev Emitted when the Forge has created new yield token contracts.
* @param forgeId The forgeId
* @param underlyingAsset The address of the underlying asset.
* @param expiry The date in epoch time when the contract will expire.
* @param ot The address of the ownership token.
* @param xyt The address of the new future yield token.
**/
event NewYieldContracts(
bytes32 forgeId,
address indexed underlyingAsset,
uint256 indexed expiry,
address ot,
address xyt,
address yieldBearingAsset
);
/**
* @dev Emitted when the Forge has redeemed the OT and XYT tokens.
* @param forgeId The forgeId
* @param underlyingAsset the address of the underlying asset
* @param expiry The expiry of the XYT token
* @param amountToRedeem The amount of OT to be redeemed.
* @param redeemedAmount The amount of yield token received
**/
event RedeemYieldToken(
bytes32 forgeId,
address indexed underlyingAsset,
uint256 indexed expiry,
uint256 amountToRedeem,
uint256 redeemedAmount,
address indexed user
);
/**
* @dev Emitted when interest claim is settled
* @param forgeId The forgeId
* @param underlyingAsset the address of the underlying asset
* @param expiry The expiry of the XYT token
* @param user Interest receiver Address
* @param amount The amount of interest claimed
**/
event DueInterestsSettled(
bytes32 forgeId,
address indexed underlyingAsset,
uint256 indexed expiry,
uint256 amount,
uint256 forgeFeeAmount,
address indexed user
);
/**
* @dev Emitted when forge fee is withdrawn
* @param forgeId The forgeId
* @param underlyingAsset the address of the underlying asset
* @param expiry The expiry of the XYT token
* @param amount The amount of interest claimed
**/
event ForgeFeeWithdrawn(
bytes32 forgeId,
address indexed underlyingAsset,
uint256 indexed expiry,
uint256 amount
);
function setUpEmergencyMode(
address _underlyingAsset,
uint256 _expiry,
address spender
) external;
function newYieldContracts(address underlyingAsset, uint256 expiry)
external
returns (address ot, address xyt);
function redeemAfterExpiry(
address user,
address underlyingAsset,
uint256 expiry
) external returns (uint256 redeemedAmount);
function redeemDueInterests(
address user,
address underlyingAsset,
uint256 expiry
) external returns (uint256 interests);
function updateDueInterests(
address underlyingAsset,
uint256 expiry,
address user
) external;
function updatePendingRewards(
address _underlyingAsset,
uint256 _expiry,
address _user
) external;
function redeemUnderlying(
address user,
address underlyingAsset,
uint256 expiry,
uint256 amountToRedeem
) external returns (uint256 redeemedAmount);
function mintOtAndXyt(
address underlyingAsset,
uint256 expiry,
uint256 amountToTokenize,
address to
)
external
returns (
address ot,
address xyt,
uint256 amountTokenMinted
);
function withdrawForgeFee(address underlyingAsset, uint256 expiry) external;
function getYieldBearingToken(address underlyingAsset) external returns (address);
/**
* @notice Gets a reference to the PendleRouter contract.
* @return Returns the router contract reference.
**/
function router() external view returns (IPendleRouter);
function data() external view returns (IPendleData);
function rewardManager() external view returns (IPendleRewardManager);
function yieldContractDeployer() external view returns (IPendleYieldContractDeployer);
function rewardToken() external view returns (IERC20);
/**
* @notice Gets the bytes32 ID of the forge.
* @return Returns the forge and protocol identifier.
**/
function forgeId() external view returns (bytes32);
function dueInterests(
address _underlyingAsset,
uint256 expiry,
address _user
) external view returns (uint256);
function yieldTokenHolders(address _underlyingAsset, uint256 _expiry)
external
view
returns (address yieldTokenHolder);
}
// SPDX-License-Identifier: MIT
/*
* MIT License
* ===========
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*/
pragma solidity 0.7.6;
import "./IPendleForge.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IPendleForgeV2 is IPendleForge {
function setUpEmergencyModeV2(
address _underlyingAsset,
uint256 _expiry,
address spender,
bool extraFlag
) external;
}
// SPDX-License-Identifier: MIT
/*
* MIT License
* ===========
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*/
pragma solidity 0.7.6;
import "./IPendleCompoundForge.sol";
// Forges should implement this Interface to guarantee compatibility with GenericMarket & Liq
interface IPendleGenericForge is IPendleCompoundForge {
}
// SPDX-License-Identifier: MIT
/*
* MIT License
* ===========
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*/
pragma solidity 0.7.6;
pragma abicoder v2;
import "./IPendleRouter.sol";
import "./IPendleBaseToken.sol";
import "../libraries/PendleStructs.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IPendleMarket is IERC20 {
/**
* @notice Emitted when reserves pool has been updated
* @param reserve0 The XYT reserves.
* @param weight0 The XYT weight
* @param reserve1 The generic token reserves.
* For the generic Token weight it can be inferred by (2^40) - weight0
**/
event Sync(uint256 reserve0, uint256 weight0, uint256 reserve1);
event RedeemLpInterests(address user, uint256 interests);
function setUpEmergencyMode(address spender) external;
function bootstrap(
address user,
uint256 initialXytLiquidity,
uint256 initialTokenLiquidity
) external returns (PendingTransfer[2] memory transfers, uint256 exactOutLp);
function addMarketLiquiditySingle(
address user,
address inToken,
uint256 inAmount,
uint256 minOutLp
) external returns (PendingTransfer[2] memory transfers, uint256 exactOutLp);
function addMarketLiquidityDual(
address user,
uint256 _desiredXytAmount,
uint256 _desiredTokenAmount,
uint256 _xytMinAmount,
uint256 _tokenMinAmount
) external returns (PendingTransfer[2] memory transfers, uint256 lpOut);
function removeMarketLiquidityDual(
address user,
uint256 inLp,
uint256 minOutXyt,
uint256 minOutToken
) external returns (PendingTransfer[2] memory transfers);
function removeMarketLiquiditySingle(
address user,
address outToken,
uint256 exactInLp,
uint256 minOutToken
) external returns (PendingTransfer[2] memory transfers);
function swapExactIn(
address inToken,
uint256 inAmount,
address outToken,
uint256 minOutAmount
) external returns (uint256 outAmount, PendingTransfer[2] memory transfers);
function swapExactOut(
address inToken,
uint256 maxInAmount,
address outToken,
uint256 outAmount
) external returns (uint256 inAmount, PendingTransfer[2] memory transfers);
function redeemLpInterests(address user) external returns (uint256 interests);
function getReserves()
external
view
returns (
uint256 xytBalance,
uint256 xytWeight,
uint256 tokenBalance,
uint256 tokenWeight,
uint256 currentBlock
);
function factoryId() external view returns (bytes32);
function token() external view returns (address);
function xyt() external view returns (address);
}
// SPDX-License-Identifier: MIT
/*
* MIT License
* ===========
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*/
pragma solidity 0.7.6;
import "./IPendleRouter.sol";
interface IPendleMarketFactory {
/**
* @notice Creates a market given a protocol ID, future yield token, and an ERC20 token.
* @param xyt Token address of the futuonlyCorere yield token as base asset.
* @param token Token address of an ERC20 token as quote asset.
* @return market Returns the address of the newly created market.
**/
function createMarket(address xyt, address token) external returns (address market);
/**
* @notice Gets a reference to the PendleRouter contract.
* @return Returns the router contract reference.
**/
function router() external view returns (IPendleRouter);
function marketFactoryId() external view returns (bytes32);
}
// SPDX-License-Identifier: MIT
/*
* MIT License
* ===========
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*/
pragma solidity 0.7.6;
interface IPendlePausingManager {
event AddPausingAdmin(address admin);
event RemovePausingAdmin(address admin);
event PendingForgeEmergencyHandler(address _pendingForgeHandler);
event PendingMarketEmergencyHandler(address _pendingMarketHandler);
event PendingLiqMiningEmergencyHandler(address _pendingLiqMiningHandler);
event ForgeEmergencyHandlerSet(address forgeEmergencyHandler);
event MarketEmergencyHandlerSet(address marketEmergencyHandler);
event LiqMiningEmergencyHandlerSet(address liqMiningEmergencyHandler);
event PausingManagerLocked();
event ForgeHandlerLocked();
event MarketHandlerLocked();
event LiqMiningHandlerLocked();
event SetForgePaused(bytes32 forgeId, bool settingToPaused);
event SetForgeAssetPaused(bytes32 forgeId, address underlyingAsset, bool settingToPaused);
event SetForgeAssetExpiryPaused(
bytes32 forgeId,
address underlyingAsset,
uint256 expiry,
bool settingToPaused
);
event SetForgeLocked(bytes32 forgeId);
event SetForgeAssetLocked(bytes32 forgeId, address underlyingAsset);
event SetForgeAssetExpiryLocked(bytes32 forgeId, address underlyingAsset, uint256 expiry);
event SetMarketFactoryPaused(bytes32 marketFactoryId, bool settingToPaused);
event SetMarketPaused(bytes32 marketFactoryId, address market, bool settingToPaused);
event SetMarketFactoryLocked(bytes32 marketFactoryId);
event SetMarketLocked(bytes32 marketFactoryId, address market);
event SetLiqMiningPaused(address liqMiningContract, bool settingToPaused);
event SetLiqMiningLocked(address liqMiningContract);
function forgeEmergencyHandler()
external
view
returns (
address handler,
address pendingHandler,
uint256 timelockDeadline
);
function marketEmergencyHandler()
external
view
returns (
address handler,
address pendingHandler,
uint256 timelockDeadline
);
function liqMiningEmergencyHandler()
external
view
returns (
address handler,
address pendingHandler,
uint256 timelockDeadline
);
function permLocked() external view returns (bool);
function permForgeHandlerLocked() external view returns (bool);
function permMarketHandlerLocked() external view returns (bool);
function permLiqMiningHandlerLocked() external view returns (bool);
function isPausingAdmin(address) external view returns (bool);
function setPausingAdmin(address admin, bool isAdmin) external;
function requestForgeHandlerChange(address _pendingForgeHandler) external;
function requestMarketHandlerChange(address _pendingMarketHandler) external;
function requestLiqMiningHandlerChange(address _pendingLiqMiningHandler) external;
function applyForgeHandlerChange() external;
function applyMarketHandlerChange() external;
function applyLiqMiningHandlerChange() external;
function lockPausingManagerPermanently() external;
function lockForgeHandlerPermanently() external;
function lockMarketHandlerPermanently() external;
function lockLiqMiningHandlerPermanently() external;
function setForgePaused(bytes32 forgeId, bool paused) external;
function setForgeAssetPaused(
bytes32 forgeId,
address underlyingAsset,
bool paused
) external;
function setForgeAssetExpiryPaused(
bytes32 forgeId,
address underlyingAsset,
uint256 expiry,
bool paused
) external;
function setForgeLocked(bytes32 forgeId) external;
function setForgeAssetLocked(bytes32 forgeId, address underlyingAsset) external;
function setForgeAssetExpiryLocked(
bytes32 forgeId,
address underlyingAsset,
uint256 expiry
) external;
function checkYieldContractStatus(
bytes32 forgeId,
address underlyingAsset,
uint256 expiry
) external returns (bool _paused, bool _locked);
function setMarketFactoryPaused(bytes32 marketFactoryId, bool paused) external;
function setMarketPaused(
bytes32 marketFactoryId,
address market,
bool paused
) external;
function setMarketFactoryLocked(bytes32 marketFactoryId) external;
function setMarketLocked(bytes32 marketFactoryId, address market) external;
function checkMarketStatus(bytes32 marketFactoryId, address market)
external
returns (bool _paused, bool _locked);
function setLiqMiningPaused(address liqMiningContract, bool settingToPaused) external;
function setLiqMiningLocked(address liqMiningContract) external;
function checkLiqMiningStatus(address liqMiningContract)
external
returns (bool _paused, bool _locked);
}
// SPDX-License-Identifier: MIT
/*
* MIT License
* ===========
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*/
pragma solidity 0.7.6;
interface IPendleRewardManager {
/*
the on-chain contracts does not have names for the UpdateFrequencySet. The name is temporarily added to work with
Typechain
*/
event UpdateFrequencySet(address[] underlyingAssets, uint256[] frequencies);
event SkippingRewardsSet(bool);
event DueRewardsSettled(
bytes32 forgeId,
address underlyingAsset,
uint256 expiry,
uint256 amountOut,
address user
);
function redeemRewards(
address _underlyingAsset,
uint256 _expiry,
address _user
) external returns (uint256 dueRewards);
function updatePendingRewards(
address _underlyingAsset,
uint256 _expiry,
address _user
) external;
function updateParamLManual(address _underlyingAsset, uint256 _expiry) external;
function setUpdateFrequency(
address[] calldata underlyingAssets,
uint256[] calldata frequencies
) external;
function setSkippingRewards(bool skippingRewards) external;
function forgeId() external returns (bytes32);
}
// SPDX-License-Identifier: MIT
/*
* MIT License
* ===========
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*/
pragma solidity 0.7.6;
pragma abicoder v2;
import "../interfaces/IWETH.sol";
import "./IPendleData.sol";
import "../libraries/PendleStructs.sol";
import "./IPendleMarketFactory.sol";
interface IPendleRouter {
/**
* @notice Emitted when a market for a future yield token and an ERC20 token is created.
* @param marketFactoryId Forge identifier.
* @param xyt The address of the tokenized future yield token as the base asset.
* @param token The address of an ERC20 token as the quote asset.
* @param market The address of the newly created market.
**/
event MarketCreated(
bytes32 marketFactoryId,
address indexed xyt,
address indexed token,
address indexed market
);
/**
* @notice Emitted when a swap happens on the market.
* @param trader The address of msg.sender.
* @param inToken The input token.
* @param outToken The output token.
* @param exactIn The exact amount being traded.
* @param exactOut The exact amount received.
* @param market The market address.
**/
event SwapEvent(
address indexed trader,
address inToken,
address outToken,
uint256 exactIn,
uint256 exactOut,
address market
);
/**
* @dev Emitted when user adds liquidity
* @param sender The user who added liquidity.
* @param token0Amount the amount of token0 (xyt) provided by user
* @param token1Amount the amount of token1 provided by user
* @param market The market address.
* @param exactOutLp The exact LP minted
*/
event Join(
address indexed sender,
uint256 token0Amount,
uint256 token1Amount,
address market,
uint256 exactOutLp
);
/**
* @dev Emitted when user removes liquidity
* @param sender The user who removed liquidity.
* @param token0Amount the amount of token0 (xyt) given to user
* @param token1Amount the amount of token1 given to user
* @param market The market address.
* @param exactInLp The exact Lp to remove
*/
event Exit(
address indexed sender,
uint256 token0Amount,
uint256 token1Amount,
address market,
uint256 exactInLp
);
/**
* @notice Gets a reference to the PendleData contract.
* @return Returns the data contract reference.
**/
function data() external view returns (IPendleData);
/**
* @notice Gets a reference of the WETH9 token contract address.
* @return WETH token reference.
**/
function weth() external view returns (IWETH);
/***********
* FORGE *
***********/
function newYieldContracts(
bytes32 forgeId,
address underlyingAsset,
uint256 expiry
) external returns (address ot, address xyt);
function redeemAfterExpiry(
bytes32 forgeId,
address underlyingAsset,
uint256 expiry
) external returns (uint256 redeemedAmount);
function redeemDueInterests(
bytes32 forgeId,
address underlyingAsset,
uint256 expiry,
address user
) external returns (uint256 interests);
function redeemUnderlying(
bytes32 forgeId,
address underlyingAsset,
uint256 expiry,
uint256 amountToRedeem
) external returns (uint256 redeemedAmount);
function renewYield(
bytes32 forgeId,
uint256 oldExpiry,
address underlyingAsset,
uint256 newExpiry,
uint256 renewalRate
)
external
returns (
uint256 redeemedAmount,
uint256 amountRenewed,
address ot,
address xyt,
uint256 amountTokenMinted
);
function tokenizeYield(
bytes32 forgeId,
address underlyingAsset,
uint256 expiry,
uint256 amountToTokenize,
address to
)
external
returns (
address ot,
address xyt,
uint256 amountTokenMinted
);
/***********
* MARKET *
***********/
function addMarketLiquidityDual(
bytes32 _marketFactoryId,
address _xyt,
address _token,
uint256 _desiredXytAmount,
uint256 _desiredTokenAmount,
uint256 _xytMinAmount,
uint256 _tokenMinAmount
)
external
payable
returns (
uint256 amountXytUsed,
uint256 amountTokenUsed,
uint256 lpOut
);
function addMarketLiquiditySingle(
bytes32 marketFactoryId,
address xyt,
address token,
bool forXyt,
uint256 exactInAsset,
uint256 minOutLp
) external payable returns (uint256 exactOutLp);
function removeMarketLiquidityDual(
bytes32 marketFactoryId,
address xyt,
address token,
uint256 exactInLp,
uint256 minOutXyt,
uint256 minOutToken
) external returns (uint256 exactOutXyt, uint256 exactOutToken);
function removeMarketLiquiditySingle(
bytes32 marketFactoryId,
address xyt,
address token,
bool forXyt,
uint256 exactInLp,
uint256 minOutAsset
) external returns (uint256 exactOutXyt, uint256 exactOutToken);
/**
* @notice Creates a market given a protocol ID, future yield token, and an ERC20 token.
* @param marketFactoryId Market Factory identifier.
* @param xyt Token address of the future yield token as base asset.
* @param token Token address of an ERC20 token as quote asset.
* @return market Returns the address of the newly created market.
**/
function createMarket(
bytes32 marketFactoryId,
address xyt,
address token
) external returns (address market);
function bootstrapMarket(
bytes32 marketFactoryId,
address xyt,
address token,
uint256 initialXytLiquidity,
uint256 initialTokenLiquidity
) external payable;
function swapExactIn(
address tokenIn,
address tokenOut,
uint256 inTotalAmount,
uint256 minOutTotalAmount,
bytes32 marketFactoryId
) external payable returns (uint256 outTotalAmount);
function swapExactOut(
address tokenIn,
address tokenOut,
uint256 outTotalAmount,
uint256 maxInTotalAmount,
bytes32 marketFactoryId
) external payable returns (uint256 inTotalAmount);
function redeemLpInterests(address market, address user) external returns (uint256 interests);
}
// SPDX-License-Identifier: MIT
/*
* MIT License
* ===========
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*/
pragma solidity 0.7.6;
interface IPendleYieldContractDeployer {
function forgeId() external returns (bytes32);
function forgeOwnershipToken(
address _underlyingAsset,
string memory _name,
string memory _symbol,
uint8 _decimals,
uint256 _expiry
) external returns (address ot);
function forgeFutureYieldToken(
address _underlyingAsset,
string memory _name,
string memory _symbol,
uint8 _decimals,
uint256 _expiry
) external returns (address xyt);
function deployYieldTokenHolder(address yieldToken, uint256 expiry)
external
returns (address yieldTokenHolder);
}
// SPDX-License-Identifier: MIT
/*
* MIT License
* ===========
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*/
pragma solidity 0.7.6;
interface IPendleYieldContractDeployerV2 {
function forgeId() external returns (bytes32);
function forgeOwnershipToken(
address underlyingAsset,
string memory name,
string memory symbol,
uint8 decimals,
uint256 expiry
) external returns (address ot);
function forgeFutureYieldToken(
address underlyingAsset,
string memory name,
string memory symbol,
uint8 decimals,
uint256 expiry
) external returns (address xyt);
function deployYieldTokenHolder(
address yieldToken,
uint256 expiry,
uint256[] calldata container
) external returns (address yieldTokenHolder);
}
// SPDX-License-Identifier: MIT
/*
* MIT License
* ===========
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*/
pragma solidity 0.7.6;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./IPendleBaseToken.sol";
import "./IPendleForge.sol";
interface IPendleYieldToken is IERC20, IPendleBaseToken {
/**
* @notice Emitted when burning OT or XYT tokens.
* @param user The address performing the burn.
* @param amount The amount to be burned.
**/
event Burn(address indexed user, uint256 amount);
/**
* @notice Emitted when minting OT or XYT tokens.
* @param user The address performing the mint.
* @param amount The amount to be minted.
**/
event Mint(address indexed user, uint256 amount);
/**
* @notice Burns OT or XYT tokens from user, reducing the total supply.
* @param user The address performing the burn.
* @param amount The amount to be burned.
**/
function burn(address user, uint256 amount) external;
/**
* @notice Mints new OT or XYT tokens for user, increasing the total supply.
* @param user The address to send the minted tokens.
* @param amount The amount to be minted.
**/
function mint(address user, uint256 amount) external;
/**
* @notice Gets the forge address of the PendleForge contract for this yield token.
* @return Retuns the forge address.
**/
function forge() external view returns (IPendleForge);
/**
* @notice Returns the address of the underlying asset.
* @return Returns the underlying asset address.
**/
function underlyingAsset() external view returns (address);
/**
* @notice Returns the address of the underlying yield token.
* @return Returns the underlying yield token address.
**/
function underlyingYieldToken() external view returns (address);
/**
* @notice let the router approve itself to spend OT/XYT/LP from any wallet
* @param user user to approve
**/
function approveRouter(address user) external;
}
// SPDX-License-Identifier: MIT
/*
* MIT License
* ===========
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*/
pragma solidity 0.7.6;
interface IPendleYieldTokenHolder {
function redeemRewards() external;
function setUpEmergencyMode(address spender) external;
function yieldToken() external returns (address);
function forge() external returns (address);
function rewardToken() external returns (address);
function expiry() external returns (uint256);
}
// SPDX-License-Identifier: MIT
/*
* MIT License
* ===========
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*/
pragma solidity 0.7.6;
import "./IPendleYieldTokenHolder.sol";
interface IPendleYieldTokenHolderV2 is IPendleYieldTokenHolder {
function setUpEmergencyModeV2(address spender, bool extraFlag) external;
function pushYieldTokens(
address to,
uint256 amount,
uint256 minNYieldAfterPush
) external;
function afterReceiveTokens(uint256 amount) external;
}
// SPDX-License-Identifier: MIT
/*
* MIT License
* ===========
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*/
pragma solidity 0.7.6;
pragma abicoder v2;
import "../core/PendleGovernanceManager.sol";
interface IPermissionsV2 {
function governanceManager() external returns (PendleGovernanceManager);
}
// SPDX-License-Identifier: MIT
/*
* MIT License
* ===========
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*/
pragma solidity 0.7.6;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IWETH is IERC20 {
event Deposit(address indexed dst, uint256 wad);
event Withdrawal(address indexed src, uint256 wad);
function deposit() external payable;
function withdraw(uint256 wad) external;
}
// SPDX-License-Identifier: MIT
/*
* MIT License
* ===========
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*/
pragma solidity 0.7.6;
pragma abicoder v2;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IWXBTRFLY is IERC20 {
function wrapFromxBTRFLY(uint256 _amount) external returns (uint256);
function unwrapToxBTRFLY(uint256 _amount) external returns (uint256);
function xBTRFLY() external view returns (address);
function xBTRFLYValue(uint256 _amount) external view returns (uint256);
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.7.0;
pragma abicoder v2;
import "@openzeppelin/contracts/math/SafeMath.sol";
library Math {
using SafeMath for uint256;
uint256 internal constant BIG_NUMBER = (uint256(1) << uint256(200));
uint256 internal constant PRECISION_BITS = 40;
uint256 internal constant RONE = uint256(1) << PRECISION_BITS;
uint256 internal constant PI = (314 * RONE) / 10**2;
uint256 internal constant PI_PLUSONE = (414 * RONE) / 10**2;
uint256 internal constant PRECISION_POW = 1e2;
function checkMultOverflow(uint256 _x, uint256 _y) internal pure returns (bool) {
if (_y == 0) return false;
return (((_x * _y) / _y) != _x);
}
/**
@notice find the integer part of log2(p/q)
=> find largest x s.t p >= q * 2^x
=> find largest x s.t 2^x <= p / q
*/
function log2Int(uint256 _p, uint256 _q) internal pure returns (uint256) {
uint256 res = 0;
uint256 remain = _p / _q;
while (remain > 0) {
res++;
remain /= 2;
}
return res - 1;
}
/**
@notice log2 for a number that it in [1,2)
@dev _x is FP, return a FP
@dev function is from Kyber. Long modified the condition to be (_x >= one) && (_x < two)
to avoid the case where x = 2 may lead to incorrect result
*/
function log2ForSmallNumber(uint256 _x) internal pure returns (uint256) {
uint256 res = 0;
uint256 one = (uint256(1) << PRECISION_BITS);
uint256 two = 2 * one;
uint256 addition = one;
require((_x >= one) && (_x < two), "MATH_ERROR");
require(PRECISION_BITS < 125, "MATH_ERROR");
for (uint256 i = PRECISION_BITS; i > 0; i--) {
_x = (_x * _x) / one;
addition = addition / 2;
if (_x >= two) {
_x = _x / 2;
res += addition;
}
}
return res;
}
/**
@notice log2 of (p/q). returns result in FP form
@dev function is from Kyber.
@dev _p & _q is FP, return a FP
*/
function logBase2(uint256 _p, uint256 _q) internal pure returns (uint256) {
uint256 n = 0;
if (_p > _q) {
n = log2Int(_p, _q);
}
require(n * RONE <= BIG_NUMBER, "MATH_ERROR");
require(!checkMultOverflow(_p, RONE), "MATH_ERROR");
require(!checkMultOverflow(n, RONE), "MATH_ERROR");
require(!checkMultOverflow(uint256(1) << n, _q), "MATH_ERROR");
uint256 y = (_p * RONE) / (_q * (uint256(1) << n));
uint256 log2Small = log2ForSmallNumber(y);
assert(log2Small <= BIG_NUMBER);
return n * RONE + log2Small;
}
/**
@notice calculate ln(p/q). returned result >= 0
@dev function is from Kyber.
@dev _p & _q is FP, return a FP
*/
function ln(uint256 p, uint256 q) internal pure returns (uint256) {
uint256 ln2Numerator = 6931471805599453094172;
uint256 ln2Denomerator = 10000000000000000000000;
uint256 log2x = logBase2(p, q);
require(!checkMultOverflow(ln2Numerator, log2x), "MATH_ERROR");
return (ln2Numerator * log2x) / ln2Denomerator;
}
/**
@notice extract the fractional part of a FP
@dev value is a FP, return a FP
*/
function fpart(uint256 value) internal pure returns (uint256) {
return value % RONE;
}
/**
@notice convert a FP to an Int
@dev value is a FP, return an Int
*/
function toInt(uint256 value) internal pure returns (uint256) {
return value / RONE;
}
/**
@notice convert an Int to a FP
@dev value is an Int, return a FP
*/
function toFP(uint256 value) internal pure returns (uint256) {
return value * RONE;
}
/**
@notice return e^exp in FP form
@dev estimation by formula at http://pages.mtu.edu/~shene/COURSES/cs201/NOTES/chap04/exp.html
the function is based on exp function of:
https://github.com/NovakDistributed/macroverse/blob/master/contracts/RealMath.sol
@dev the function is expected to converge quite fast, after about 20 iteration
@dev exp is a FP, return a FP
*/
function rpowe(uint256 exp) internal pure returns (uint256) {
uint256 res = 0;
uint256 curTerm = RONE;
for (uint256 n = 0; ; n++) {
res += curTerm;
curTerm = rmul(curTerm, rdiv(exp, toFP(n + 1)));
if (curTerm == 0) {
break;
}
if (n == 500) {
/*
testing shows that in the most extreme case, it will take 430 turns to converge.
however, it's expected that the numbers will not exceed 2^120 in normal situation
the most extreme case is rpow((1<<256)-1,(1<<40)-1) (equal to rpow((2^256-1)/2^40,0.99..9))
*/
revert("RPOWE_SLOW_CONVERGE");
}
}
return res;
}
/**
@notice calculate base^exp with base and exp being FP int
@dev to improve accuracy, base^exp = base^(int(exp)+frac(exp))
= base^int(exp) * base^frac
@dev base & exp are FP, return a FP
*/
function rpow(uint256 base, uint256 exp) internal pure returns (uint256) {
if (exp == 0) {
// Anything to the 0 is 1
return RONE;
}
if (base == 0) {
// 0 to anything except 0 is 0
return 0;
}
uint256 frac = fpart(exp); // get the fractional part
uint256 whole = exp - frac;
uint256 wholePow = rpowi(base, toInt(whole)); // whole is a FP, convert to Int
uint256 fracPow;
// instead of calculating base ^ frac, we will calculate e ^ (frac*ln(base))
if (base < RONE) {
/* since the base is smaller than 1.0, ln(base) < 0.
Since 1 / (e^(frac*ln(1/base))) = e ^ (frac*ln(base)),
we will calculate 1 / (e^(frac*ln(1/base))) instead.
*/
uint256 newExp = rmul(frac, ln(rdiv(RONE, base), RONE));
fracPow = rdiv(RONE, rpowe(newExp));
} else {
/* base is greater than 1, calculate normally */
uint256 newExp = rmul(frac, ln(base, RONE));
fracPow = rpowe(newExp);
}
return rmul(wholePow, fracPow);
}
/**
@notice return base^exp with base in FP form and exp in Int
@dev this function use a technique called: exponentiating by squaring
complexity O(log(q))
@dev function is from Kyber.
@dev base is a FP, exp is an Int, return a FP
*/
function rpowi(uint256 base, uint256 exp) internal pure returns (uint256) {
uint256 res = exp % 2 != 0 ? base : RONE;
for (exp /= 2; exp != 0; exp /= 2) {
base = rmul(base, base);
if (exp % 2 != 0) {
res = rmul(res, base);
}
}
return res;
}
/**
@dev y is an Int, returns an Int
@dev babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method)
@dev from Uniswap
*/
function sqrt(uint256 y) internal pure returns (uint256 z) {
if (y > 3) {
z = y;
uint256 x = y / 2 + 1;
while (x < z) {
z = x;
x = (y / x + x) / 2;
}
} else if (y != 0) {
z = 1;
}
}
/**
@notice divide 2 FP, return a FP
@dev function is from Balancer.
@dev x & y are FP, return a FP
*/
function rdiv(uint256 x, uint256 y) internal pure returns (uint256) {
return (y / 2).add(x.mul(RONE)).div(y);
}
/**
@notice multiply 2 FP, return a FP
@dev function is from Balancer.
@dev x & y are FP, return a FP
*/
function rmul(uint256 x, uint256 y) internal pure returns (uint256) {
return (RONE / 2).add(x.mul(y)).div(RONE);
}
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function subMax0(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a - b : 0;
}
}
// SPDX-License-Identifier: BUSL-1.1
// solhint-disable ordering
pragma solidity 0.7.6;
pragma abicoder v2;
import "@openzeppelin/contracts/math/SafeMath.sol";
import "../../libraries/ExpiryUtilsLib.sol";
import "../../interfaces/IPendleBaseToken.sol";
import "../../interfaces/IPendleData.sol";
import "../../interfaces/IPendleForgeV2.sol";
import "../../interfaces/IPendleRewardManager.sol";
import "../../interfaces/IPendleYieldContractDeployer.sol";
import "../../interfaces/IPendleYieldContractDeployerV2.sol";
import "../../interfaces/IPendleYieldTokenHolderV2.sol";
import "../../periphery/WithdrawableV2.sol";
import "../../libraries/MathLib.sol";
import "../../libraries/TokenUtilsLib.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
/// @notice common contract base for a forge implementation.
/// @dev Each specific forge implementation will need to override necessary virtual functions
abstract contract PendleForgeBaseV2 is IPendleForgeV2, WithdrawableV2, ReentrancyGuard {
using ExpiryUtils for string;
using SafeMath for uint256;
using Math for uint256;
struct PendleTokens {
IPendleYieldToken xyt;
IPendleYieldToken ot;
}
// the container here will contain any data needed by tokens. Fields of type that are not
// uin256 will be upcasted to uint256 and downcasted when use
struct TokenInfo {
bool registered;
uint256[] container;
}
IPendleRouter public immutable override router;
IPendleData public immutable override data;
bytes32 public immutable override forgeId;
IERC20 public immutable override rewardToken;
IPendleRewardManager public immutable override rewardManager;
IPendleYieldContractDeployer public immutable override yieldContractDeployer;
IPendlePausingManager public immutable pausingManager;
mapping(address => mapping(uint256 => mapping(address => uint256)))
public
override dueInterests;
mapping(address => mapping(uint256 => uint256)) public totalFee;
mapping(address => mapping(uint256 => address)) public override yieldTokenHolders; // yieldTokenHolders[underlyingAsset][expiry]
mapping(address => TokenInfo) public tokenInfo;
string private constant OT = "OT";
string private constant XYT = "YT";
event RegisterTokens(bytes32 forgeId, address underlyingAsset, uint256[] container);
modifier onlyXYT(address _underlyingAsset, uint256 _expiry) {
require(
msg.sender == address(data.xytTokens(forgeId, _underlyingAsset, _expiry)),
"ONLY_YT"
);
_;
}
modifier onlyOT(address _underlyingAsset, uint256 _expiry) {
require(
msg.sender == address(data.otTokens(forgeId, _underlyingAsset, _expiry)),
"ONLY_OT"
);
_;
}
modifier onlyRouter() {
require(msg.sender == address(router), "ONLY_ROUTER");
_;
}
constructor(
address _governanceManager,
IPendleRouter _router,
bytes32 _forgeId,
address _rewardToken,
address _rewardManager,
address _yieldContractDeployer
) PermissionsV2(_governanceManager) {
require(address(_router) != address(0), "ZERO_ADDRESS");
require(_forgeId != 0x0, "ZERO_BYTES");
// In the case there is no rewardToken, a valid ERC20 token must still be passed in for
// compatibility reasons
TokenUtils.requireERC20(_rewardToken);
router = _router;
forgeId = _forgeId;
IPendleData _dataTemp = IPendleRouter(_router).data();
data = _dataTemp;
rewardToken = IERC20(_rewardToken);
rewardManager = IPendleRewardManager(_rewardManager);
yieldContractDeployer = IPendleYieldContractDeployer(_yieldContractDeployer);
pausingManager = _dataTemp.pausingManager();
}
/**
@dev INVARIANT: All write functions must go through this check.
All XYT/OT transfers must go through this check as well. As such, XYT/OT transfers are also paused
*/
function checkNotPaused(address _underlyingAsset, uint256 _expiry) internal virtual {
(bool paused, ) = pausingManager.checkYieldContractStatus(
forgeId,
_underlyingAsset,
_expiry
);
require(!paused, "YIELD_CONTRACT_PAUSED");
}
/**
@dev function has been depreciated but must still be left here to conform with the interface
*/
function setUpEmergencyMode(
address,
uint256,
address
) external pure override {
revert("FUNCTION_DEPRECIATED");
}
/**
@dev Only the forgeEmergencyHandler can call this function, when its in emergencyMode this
will allow a spender to spend the whole balance of the specified tokens of the yieldTokenHolder contract
@dev the spender should ideally be a contract with logic for users to withdraw out their funds
@param extraFlag an optional flag for any forges which need an additional flag (like SushiComplex
which allows either normal withdraw or emergencyWithdraw)
*/
function setUpEmergencyModeV2(
address _underlyingAsset,
uint256 _expiry,
address spender,
bool extraFlag
) external virtual override {
(, bool emergencyMode) = pausingManager.checkYieldContractStatus(
forgeId,
_underlyingAsset,
_expiry
);
require(emergencyMode, "NOT_EMERGENCY");
(address forgeEmergencyHandler, , ) = pausingManager.forgeEmergencyHandler();
require(msg.sender == forgeEmergencyHandler, "NOT_EMERGENCY_HANDLER");
IPendleYieldTokenHolderV2(yieldTokenHolders[_underlyingAsset][_expiry])
.setUpEmergencyModeV2(spender, extraFlag);
}
/**
@dev each element in the _underlyingAssets array will have one auxillary array in _tokenInfos
to store necessary data.
@dev only governance can call this. In V2 we no longer allow users to self-register new tokens
*/
function registerTokens(address[] calldata _underlyingAssets, uint256[][] calldata _tokenInfos)
external
virtual
onlyGovernance
{
require(_underlyingAssets.length == _tokenInfos.length, "LENGTH_MISMATCH");
for (uint256 i = 0; i < _underlyingAssets.length; ++i) {
TokenInfo storage info = tokenInfo[_underlyingAssets[i]];
require(!info.registered, "EXISTED_TOKENS");
verifyToken(_underlyingAssets[i], _tokenInfos[i]);
info.registered = true;
info.container = _tokenInfos[i];
_registerNewAssetsWithRewardManager(_underlyingAssets[i], _tokenInfos[i]);
emit RegisterTokens(forgeId, _underlyingAssets[i], _tokenInfos[i]);
}
}
/**
@dev this function should be implemented on a best effort basis, since we only call from
governance anyway
*/
function verifyToken(address _underlyingAsset, uint256[] calldata _tokenInfo) public virtual;
/**
@notice to create a newYieldContract
@dev Conditions:
* only call by Router
* the yield contract for this pair of _underlyingAsset & _expiry must not exist yet (checked on Router)
*/
function newYieldContracts(address _underlyingAsset, uint256 _expiry)
external
virtual
override
onlyRouter
returns (address ot, address xyt)
{
checkNotPaused(_underlyingAsset, _expiry);
address yieldToken = getYieldBearingToken(_underlyingAsset);
uint8 underlyingAssetDecimals = IPendleYieldToken(_underlyingAsset).decimals();
// Deploy the OT contract -> XYT contract -> yieldTokenHolder
ot = yieldContractDeployer.forgeOwnershipToken(
_underlyingAsset,
OT.concat(IPendleBaseToken(yieldToken).name(), _expiry, " "),
OT.concat(IPendleBaseToken(yieldToken).symbol(), _expiry, "-"),
underlyingAssetDecimals,
_expiry
);
xyt = yieldContractDeployer.forgeFutureYieldToken(
_underlyingAsset,
XYT.concat(IPendleBaseToken(yieldToken).name(), _expiry, " "),
XYT.concat(IPendleBaseToken(yieldToken).symbol(), _expiry, "-"),
underlyingAssetDecimals,
_expiry
);
// Because we have to conform with the IPendleForge interface, we must store
// YieldContractDeployerV2 as V1, then upcast here
yieldTokenHolders[_underlyingAsset][_expiry] = IPendleYieldContractDeployerV2(
address(yieldContractDeployer)
).deployYieldTokenHolder(yieldToken, _expiry, tokenInfo[_underlyingAsset].container);
data.storeTokens(forgeId, ot, xyt, _underlyingAsset, _expiry);
emit NewYieldContracts(forgeId, _underlyingAsset, _expiry, ot, xyt, yieldToken);
}
/**
@notice To redeem the underlying asset & due interests after the XYT has expired
@dev Conditions:
* only be called by Router
* only callable after XYT has expired (checked on Router)
*/
function redeemAfterExpiry(
address _user,
address _underlyingAsset,
uint256 _expiry
) external virtual override onlyRouter returns (uint256 redeemedAmount) {
checkNotPaused(_underlyingAsset, _expiry);
PendleTokens memory tokens = _getTokens(_underlyingAsset, _expiry);
uint256 expiredOTamount = tokens.ot.balanceOf(_user);
require(expiredOTamount > 0, "NOTHING_TO_REDEEM");
// burn ot only, since users don't need xyt to redeem this
tokens.ot.burn(_user, expiredOTamount);
// calc the value of the OT after since it expired (total of its underlying value + dueInterests since expiry)
// no forge fee is charged on redeeming OT. Forge fee is only charged on redeeming XYT
redeemedAmount = _calcTotalAfterExpiry(_underlyingAsset, _expiry, expiredOTamount);
// redeem the interest of any XYT (of the same underlyingAsset+expiry) that the user is having
redeemedAmount = redeemedAmount.add(
_beforeTransferDueInterests(tokens, _underlyingAsset, _expiry, _user, false)
);
// transfer back to the user
_pushYieldToken(_underlyingAsset, _expiry, _user, redeemedAmount);
// Notice for anyone taking values from this event:
// The redeemedAmount includes the interest due to any XYT held
// to get the exact yieldToken redeemed from OT, we need to deduct the (amount +forgeFeeAmount) of interests
// settled that was emitted in the DueInterestsSettled event emitted earlier in this same transaction
emit RedeemYieldToken(
forgeId,
_underlyingAsset,
_expiry,
expiredOTamount,
redeemedAmount,
_user
);
}
/**
@notice To redeem the underlying asset & due interests before the expiry of the XYT.
In this case, for each OT used to redeem, there must be an XYT (of the same yield contract)
@dev Conditions:
* only be called by Router
* only callable if the XYT hasn't expired
*/
function redeemUnderlying(
address _user,
address _underlyingAsset,
uint256 _expiry,
uint256 _amountToRedeem
) external virtual override onlyRouter returns (uint256 redeemedAmount) {
checkNotPaused(_underlyingAsset, _expiry);
PendleTokens memory tokens = _getTokens(_underlyingAsset, _expiry);
tokens.ot.burn(_user, _amountToRedeem);
tokens.xyt.burn(_user, _amountToRedeem);
/*
* calc the amount of underlying asset for OT + the amount of dueInterests for XYT
* dueInterests for XYT has been updated during the process of burning XYT, so we skip
updating dueInterests in the _beforeTransferDueInterests function
*/
redeemedAmount = _calcUnderlyingToRedeem(_underlyingAsset, _amountToRedeem).add(
_beforeTransferDueInterests(tokens, _underlyingAsset, _expiry, _user, true)
);
// transfer back to the user
_pushYieldToken(_underlyingAsset, _expiry, _user, redeemedAmount);
// Notice for anyone taking values from this event:
// The redeemedAmount includes the interest due to the XYT held
// to get the exact yieldToken redeemed from OT+XYT, we need to deduct the
// (amount +forgeFeeAmount) of interests settled that was emitted in the
// DueInterestsSettled event emitted earlier in this same transaction
emit RedeemYieldToken(
forgeId,
_underlyingAsset,
_expiry,
_amountToRedeem,
redeemedAmount,
_user
);
return redeemedAmount;
}
/**
@notice To redeem the due interests. This function can always be called regardless of whether
the XYT has expired or not
@dev Conditions:
* only be called by Router
*/
function redeemDueInterests(
address _user,
address _underlyingAsset,
uint256 _expiry
) external virtual override onlyRouter returns (uint256 amountOut) {
checkNotPaused(_underlyingAsset, _expiry);
PendleTokens memory tokens = _getTokens(_underlyingAsset, _expiry);
// update the dueInterests of the user before we transfer out
amountOut = _beforeTransferDueInterests(tokens, _underlyingAsset, _expiry, _user, false);
_pushYieldToken(_underlyingAsset, _expiry, _user, amountOut);
}
/**
@notice To update the dueInterests for users(before their balances of XYT changes)
@dev This must be called before any transfer / mint/ burn action of XYT
(and this has been implemented in the beforeTokenTransfer of the PendleFutureYieldToken)
@dev Conditions:
* Can only be called by the respective XYT contract, before transferring XYTs
*/
function updateDueInterests(
address _underlyingAsset,
uint256 _expiry,
address _user
) external virtual override onlyXYT(_underlyingAsset, _expiry) nonReentrant {
checkNotPaused(_underlyingAsset, _expiry);
PendleTokens memory tokens = _getTokens(_underlyingAsset, _expiry);
uint256 principal = tokens.xyt.balanceOf(_user);
_updateDueInterests(principal, _underlyingAsset, _expiry, _user);
}
/**
@notice To redeem the rewards (COMP, StkAAVE, SUSHI,...) for users(before their balances of OT changes)
@dev This must be called before any transfer / mint/ burn action of OT
(and this has been implemented in the beforeTokenTransfer of the PendleOwnershipToken)
@dev Conditions:
* Can only be called by the respective OT contract, before transferring OTs
Note:
This function is just a proxy to call to rewardManager
*/
function updatePendingRewards(
address _underlyingAsset,
uint256 _expiry,
address _user
) external virtual override onlyOT(_underlyingAsset, _expiry) nonReentrant {
checkNotPaused(_underlyingAsset, _expiry);
rewardManager.updatePendingRewards(_underlyingAsset, _expiry, _user);
}
/**
@notice To mint OT & XYT given that the user has transferred in _amountToTokenize of yieldToken
@dev The newly minted OT & XYT can be minted to somebody else different from the user who transfer the aToken/cToken in
@dev Conditions:
* Should only be called by Router
* The yield contract (OT & XYT) must not be expired yet (checked at Router)
*/
function mintOtAndXyt(
address _underlyingAsset,
uint256 _expiry,
uint256 _amountToTokenize,
address _to
)
external
virtual
override
onlyRouter
returns (
address ot,
address xyt,
uint256 amountTokenMinted
)
{
checkNotPaused(_underlyingAsset, _expiry);
// surely if any users call tokenizeYield, they will have to call this function
IPendleYieldTokenHolderV2(yieldTokenHolders[_underlyingAsset][_expiry]).afterReceiveTokens(
_amountToTokenize
);
PendleTokens memory tokens = _getTokens(_underlyingAsset, _expiry);
amountTokenMinted = _calcAmountToMint(_underlyingAsset, _amountToTokenize);
// updatePendingRewards will be called in mint
tokens.ot.mint(_to, amountTokenMinted);
// updateDueInterests will be called in mint
tokens.xyt.mint(_to, amountTokenMinted);
emit MintYieldTokens(
forgeId,
_underlyingAsset,
_expiry,
_amountToTokenize,
amountTokenMinted,
_to
);
return (address(tokens.ot), address(tokens.xyt), amountTokenMinted);
}
/**
@notice To withdraw the forgeFee
@dev Conditions:
* Should only be called by Governance
* This function must be the only way to withdrawForgeFee
*/
function withdrawForgeFee(address _underlyingAsset, uint256 _expiry)
external
virtual
override
onlyGovernance
{
checkNotPaused(_underlyingAsset, _expiry);
//ping to update interest up to now
_updateForgeFee(_underlyingAsset, _expiry, 0);
uint256 _totalFee = totalFee[_underlyingAsset][_expiry];
totalFee[_underlyingAsset][_expiry] = 0;
address treasuryAddress = data.treasury();
_pushYieldToken(_underlyingAsset, _expiry, treasuryAddress, _totalFee);
emit ForgeFeeWithdrawn(forgeId, _underlyingAsset, _expiry, _totalFee);
}
function getYieldBearingToken(address _underlyingAsset)
public
virtual
override
returns (address);
/**
@notice To be called before the dueInterest of any users is redeemed.
@param _skipUpdateDueInterests: this is set to true, if there was already a call to _updateDueInterests() in this transaction
INVARIANT: there must be a transfer of the interests (amountOut) to the user after this function is called
*/
function _beforeTransferDueInterests(
PendleTokens memory _tokens,
address _underlyingAsset,
uint256 _expiry,
address _user,
bool _skipUpdateDueInterests
) internal virtual returns (uint256 amountOut) {
uint256 principal = _tokens.xyt.balanceOf(_user);
if (!_skipUpdateDueInterests) {
_updateDueInterests(principal, _underlyingAsset, _expiry, _user);
}
amountOut = dueInterests[_underlyingAsset][_expiry][_user];
dueInterests[_underlyingAsset][_expiry][_user] = 0;
uint256 forgeFee = data.forgeFee();
uint256 forgeFeeAmount;
/*
* Collect the forgeFee
* INVARIANT: all XYT interest payout must go through this line
*/
if (forgeFee > 0) {
forgeFeeAmount = amountOut.rmul(forgeFee);
amountOut = amountOut.sub(forgeFeeAmount);
_updateForgeFee(_underlyingAsset, _expiry, forgeFeeAmount);
}
emit DueInterestsSettled(
forgeId,
_underlyingAsset,
_expiry,
amountOut,
forgeFeeAmount,
_user
);
}
/**
@dev Must be the only way to transfer yieldToken out
@dev summary of invariance logic:
- This is the only function where the underlying yield tokens are transfered out
- After this function executes (at the end of the .pushYieldTokens() function), we require that
there must be enough yield tokens left to entertain all OT holders redeeming
- As such, protocol users are always assured that they can redeem back their underlying yield tokens
- Further note: this pushYieldTokens function relies on the same calc functions
(_calcUnderlyingToRedeem and _calcTotalAfterExpiry) as the functions that called pushYieldTokens.
Why it is safe to do that? Because to drain funds, hackers need to compromise the calc functions to
return a very large result (hence large _amount in this function) but in the same transaction,
they also need to compromise the very same calc function to return a very small result (to fool
the contract that all the underlyingAsset of OTs are still intact). Doing these 2
compromises in one single transaction is much harder than doing just one
*/
function _pushYieldToken(
address _underlyingAsset,
uint256 _expiry,
address _user,
uint256 _amount
) internal virtual {
if (_amount == 0) return;
PendleTokens memory tokens = _getTokens(_underlyingAsset, _expiry);
uint256 otBalance = tokens.ot.totalSupply();
uint256 minNYieldAfterPush = block.timestamp < _expiry
? _calcUnderlyingToRedeem(_underlyingAsset, otBalance)
: _calcTotalAfterExpiry(_underlyingAsset, _expiry, otBalance);
IPendleYieldTokenHolderV2(yieldTokenHolders[_underlyingAsset][_expiry]).pushYieldTokens(
_user,
_amount,
minNYieldAfterPush
);
}
function _registerNewAssetsWithRewardManager(
address _underlyingAsset,
uint256[] calldata _tokenInfos
) internal virtual {}
function _getTokens(address _underlyingAsset, uint256 _expiry)
internal
view
virtual
returns (PendleTokens memory _tokens)
{
(_tokens.ot, _tokens.xyt) = data.getPendleYieldTokens(forgeId, _underlyingAsset, _expiry);
}
// There shouldn't be any fund in here
// hence governance is allowed to withdraw anything from here.
function _allowedToWithdraw(address) internal pure virtual override returns (bool allowed) {
allowed = true;
}
/// INVARIANT: after _updateDueInterests is called, dueInterests[][][] must already be
/// updated with all the due interest for the user, until exactly the current timestamp (no caching whatsoever)
/// Refer to updateDueInterests function for more info
function _updateDueInterests(
uint256 _principal,
address _underlyingAsset,
uint256 _expiry,
address _user
) internal virtual;
/**
@notice To update the amount of forgeFee (taking into account the compound interest effect)
@dev To be called whenever the forge collect fees, or before withdrawing the fee
@param _feeAmount the new fee that this forge just collected
*/
function _updateForgeFee(
address _underlyingAsset,
uint256 _expiry,
uint256 _feeAmount
) internal virtual;
/// calculate the (principal + interest) from the last action before expiry to now.
function _calcTotalAfterExpiry(
address _underlyingAsset,
uint256 _expiry,
uint256 redeemedAmount
) internal virtual returns (uint256 totalAfterExpiry);
function _calcUnderlyingToRedeem(address, uint256 _amountToRedeem)
internal
virtual
returns (uint256 underlyingToRedeem);
function _calcAmountToMint(address, uint256 _amountToTokenize)
internal
virtual
returns (uint256 amountToMint);
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.7.6;
contract PendleGovernanceManager {
address public governance;
address public pendingGovernance;
event GovernanceClaimed(address newGovernance, address previousGovernance);
event TransferGovernancePending(address pendingGovernance);
constructor(address _governance) {
require(_governance != address(0), "ZERO_ADDRESS");
governance = _governance;
}
modifier onlyGovernance() {
require(msg.sender == governance, "ONLY_GOVERNANCE");
_;
}
/**
* @dev Allows the pendingGovernance address to finalize the change governance process.
*/
function claimGovernance() external {
require(pendingGovernance == msg.sender, "WRONG_GOVERNANCE");
emit GovernanceClaimed(pendingGovernance, governance);
governance = pendingGovernance;
pendingGovernance = address(0);
}
/**
* @dev Allows the current governance to set the pendingGovernance address.
* @param _governance The address to transfer ownership to.
*/
function transferGovernance(address _governance) external onlyGovernance {
require(_governance != address(0), "ZERO_ADDRESS");
pendingGovernance = _governance;
emit TransferGovernancePending(pendingGovernance);
}
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.7.6;
pragma abicoder v2;
import "@openzeppelin/contracts/math/SafeMath.sol";
import "../../interfaces/IPendleGenericForge.sol";
import "../../interfaces/IWXBTRFLY.sol";
import "../abstractV2/PendleForgeBaseV2.sol";
/**
* @dev the contract's logic is almost the same as Wonderland Forge
* @dev no override for _registerNewAssetsWithRewardManager because this contract doesn't
have any rewards
*/
contract PendleRedactedForge is PendleForgeBaseV2, IPendleGenericForge {
using SafeMath for uint256;
using CompoundMath for uint256;
IERC20 public immutable xBTRFLY;
IWXBTRFLY public immutable wxBTRFLY;
mapping(address => mapping(uint256 => uint256)) public lastRateBeforeExpiry;
mapping(address => mapping(uint256 => mapping(address => uint256))) public lastRate;
constructor(
address _governanceManager,
IPendleRouter _router,
bytes32 _forgeId,
address _rewardToken,
address _rewardManager,
address _yieldContractDeployer,
IWXBTRFLY _wxBTRFLY
)
PendleForgeBaseV2(
_governanceManager,
_router,
_forgeId,
_rewardToken,
_rewardManager,
_yieldContractDeployer
)
{
xBTRFLY = IERC20(_wxBTRFLY.xBTRFLY());
wxBTRFLY = _wxBTRFLY;
}
function verifyToken(address _underlyingAsset, uint256[] calldata _tokenInfo)
public
virtual
override
{
require(_underlyingAsset == address(xBTRFLY), "NOT_XBTRFLY");
require(
_tokenInfo.length == 1 && address(_tokenInfo[0]) == address(wxBTRFLY),
"INVALID_TOKEN_INFO"
);
}
function getExchangeRate(address) public virtual override returns (uint256) {
return wxBTRFLY.xBTRFLYValue(CompoundMath.ONE_E_18);
}
function getYieldBearingToken(address _underlyingAsset)
public
view
override(IPendleForge, PendleForgeBaseV2)
returns (address yieldBearingTokenAddr)
{
require(tokenInfo[_underlyingAsset].registered, "INVALID_UNDERLYING_ASSET");
yieldBearingTokenAddr = address(tokenInfo[_underlyingAsset].container[0]);
}
function _calcTotalAfterExpiry(
address _underlyingAsset,
uint256 _expiry,
uint256 _redeemedAmount
) internal view override returns (uint256 totalAfterExpiry) {
totalAfterExpiry = _redeemedAmount.cdiv(lastRateBeforeExpiry[_underlyingAsset][_expiry]);
}
function getExchangeRateBeforeExpiry(address _underlyingAsset, uint256 _expiry)
internal
returns (uint256 exchangeRate)
{
if (block.timestamp > _expiry) {
return lastRateBeforeExpiry[_underlyingAsset][_expiry];
}
exchangeRate = getExchangeRate(_underlyingAsset);
lastRateBeforeExpiry[_underlyingAsset][_expiry] = exchangeRate;
}
function _calcUnderlyingToRedeem(address _underlyingAsset, uint256 _amountToRedeem)
internal
override
returns (uint256 underlyingToRedeem)
{
underlyingToRedeem = _amountToRedeem.cdiv(getExchangeRate(_underlyingAsset));
}
function _calcAmountToMint(address _underlyingAsset, uint256 _amountToTokenize)
internal
override
returns (uint256 amountToMint)
{
amountToMint = _amountToTokenize.cmul(getExchangeRate(_underlyingAsset));
}
function _updateDueInterests(
uint256 _principal,
address _underlyingAsset,
uint256 _expiry,
address _user
) internal override {
uint256 prevRate = lastRate[_underlyingAsset][_expiry][_user];
uint256 currentRate = getExchangeRateBeforeExpiry(_underlyingAsset, _expiry);
lastRate[_underlyingAsset][_expiry][_user] = currentRate;
// first time getting XYT, or there is no update in exchangeRate
if (prevRate == 0 || prevRate == currentRate) {
return;
}
uint256 interestFromXyt = _principal.mul(currentRate.sub(prevRate)).cdiv(
prevRate.mul(currentRate)
);
dueInterests[_underlyingAsset][_expiry][_user] = dueInterests[_underlyingAsset][_expiry][
_user
].add(interestFromXyt);
}
function _updateForgeFee(
address _underlyingAsset,
uint256 _expiry,
uint256 _feeAmount
) internal override {
totalFee[_underlyingAsset][_expiry] = totalFee[_underlyingAsset][_expiry].add(_feeAmount);
}
}
library CompoundMath {
uint256 internal constant ONE_E_18 = 1e18;
using SafeMath for uint256;
function cmul(uint256 x, uint256 y) internal pure returns (uint256) {
return x.mul(y).div(ONE_E_18);
}
function cdiv(uint256 x, uint256 y) internal pure returns (uint256) {
return x.mul(ONE_E_18).div(y);
}
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.7.6;
struct TokenReserve {
uint256 weight;
uint256 balance;
}
struct PendingTransfer {
uint256 amount;
bool isOut;
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.7.6;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../core/PendleGovernanceManager.sol";
import "../interfaces/IPermissionsV2.sol";
abstract contract PermissionsV2 is IPermissionsV2 {
PendleGovernanceManager public immutable override governanceManager;
address internal initializer;
constructor(address _governanceManager) {
require(_governanceManager != address(0), "ZERO_ADDRESS");
initializer = msg.sender;
governanceManager = PendleGovernanceManager(_governanceManager);
}
modifier initialized() {
require(initializer == address(0), "NOT_INITIALIZED");
_;
}
modifier onlyGovernance() {
require(msg.sender == _governance(), "ONLY_GOVERNANCE");
_;
}
function _governance() internal view returns (address) {
return governanceManager.governance();
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor () internal {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and make it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
import "./IERC20.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using SafeMath for uint256;
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
// solhint-disable-next-line max-line-length
require((value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).add(value);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) { // Return data is optional
// solhint-disable-next-line max-line-length
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
/**
* @dev Returns the substraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b > a) return (false, 0);
return (true, a - b);
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a / b);
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a % b);
}
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) return 0;
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: division by zero");
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: modulo by zero");
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
return a - b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryDiv}.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a % b;
}
}
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.7.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
library TokenUtils {
using SafeERC20 for IERC20;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
token.safeTransfer(to, value);
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
token.safeTransferFrom(from, to, value);
}
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
token.approve(spender, 0);
token.approve(spender, value);
}
function infinityApprove(IERC20 token, address spender) internal {
if (token.allowance(address(this), spender) <= type(uint256).max / 2) {
safeApprove(token, spender, type(uint256).max);
}
}
function requireERC20(address tokenAddr) internal view {
require(IERC20(tokenAddr).totalSupply() > 0, "INVALID_ERC20");
}
function requireERC20(IERC20 token) internal view {
require(token.totalSupply() > 0, "INVALID_ERC20");
}
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.7.6;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "./PermissionsV2.sol";
abstract contract WithdrawableV2 is PermissionsV2 {
using SafeERC20 for IERC20;
event EtherWithdraw(uint256 amount, address sendTo);
event TokenWithdraw(IERC20 token, uint256 amount, address sendTo);
/**
* @dev Allows governance to withdraw Ether in a Pendle contract
* in case of accidental ETH transfer into the contract.
* @param amount The amount of Ether to withdraw.
* @param sendTo The recipient address.
*/
function withdrawEther(uint256 amount, address payable sendTo) external onlyGovernance {
(bool success, ) = sendTo.call{value: amount}("");
require(success, "WITHDRAW_FAILED");
emit EtherWithdraw(amount, sendTo);
}
/**
* @dev Allows governance to withdraw all IERC20 compatible tokens in a Pendle
* contract in case of accidental token transfer into the contract.
* @param token IERC20 The address of the token contract.
* @param amount The amount of IERC20 tokens to withdraw.
* @param sendTo The recipient address.
*/
function withdrawToken(
IERC20 token,
uint256 amount,
address sendTo
) external onlyGovernance {
require(_allowedToWithdraw(address(token)), "TOKEN_NOT_ALLOWED");
token.safeTransfer(sendTo, amount);
emit TokenWithdraw(token, amount, sendTo);
}
// must be overridden by the sub contracts, so we must consider explicitly
// in each and every contract which tokens are allowed to be withdrawn
function _allowedToWithdraw(address) internal view virtual returns (bool allowed);
}
{
"compilationTarget": {
"contracts/core/RedactedCartel/PendleRedactedForge.sol": "PendleRedactedForge"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_governanceManager","type":"address"},{"internalType":"contract IPendleRouter","name":"_router","type":"address"},{"internalType":"bytes32","name":"_forgeId","type":"bytes32"},{"internalType":"address","name":"_rewardToken","type":"address"},{"internalType":"address","name":"_rewardManager","type":"address"},{"internalType":"address","name":"_yieldContractDeployer","type":"address"},{"internalType":"contract IWXBTRFLY","name":"_wxBTRFLY","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"forgeId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"underlyingAsset","type":"address"},{"indexed":true,"internalType":"uint256","name":"expiry","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"forgeFeeAmount","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"DueInterestsSettled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"sendTo","type":"address"}],"name":"EtherWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"forgeId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"underlyingAsset","type":"address"},{"indexed":true,"internalType":"uint256","name":"expiry","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ForgeFeeWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"forgeId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"underlyingAsset","type":"address"},{"indexed":true,"internalType":"uint256","name":"expiry","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountToTokenize","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountTokenMinted","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"MintYieldTokens","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"forgeId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"underlyingAsset","type":"address"},{"indexed":true,"internalType":"uint256","name":"expiry","type":"uint256"},{"indexed":false,"internalType":"address","name":"ot","type":"address"},{"indexed":false,"internalType":"address","name":"xyt","type":"address"},{"indexed":false,"internalType":"address","name":"yieldBearingAsset","type":"address"}],"name":"NewYieldContracts","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"forgeId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"underlyingAsset","type":"address"},{"indexed":true,"internalType":"uint256","name":"expiry","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountToRedeem","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"redeemedAmount","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"RedeemYieldToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"forgeId","type":"bytes32"},{"indexed":false,"internalType":"address","name":"underlyingAsset","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"container","type":"uint256[]"}],"name":"RegisterTokens","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IERC20","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"sendTo","type":"address"}],"name":"TokenWithdraw","type":"event"},{"inputs":[],"name":"data","outputs":[{"internalType":"contract IPendleData","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"dueInterests","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"forgeId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"getExchangeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_underlyingAsset","type":"address"}],"name":"getYieldBearingToken","outputs":[{"internalType":"address","name":"yieldBearingTokenAddr","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governanceManager","outputs":[{"internalType":"contract PendleGovernanceManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"lastRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"lastRateBeforeExpiry","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_underlyingAsset","type":"address"},{"internalType":"uint256","name":"_expiry","type":"uint256"},{"internalType":"uint256","name":"_amountToTokenize","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"mintOtAndXyt","outputs":[{"internalType":"address","name":"ot","type":"address"},{"internalType":"address","name":"xyt","type":"address"},{"internalType":"uint256","name":"amountTokenMinted","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_underlyingAsset","type":"address"},{"internalType":"uint256","name":"_expiry","type":"uint256"}],"name":"newYieldContracts","outputs":[{"internalType":"address","name":"ot","type":"address"},{"internalType":"address","name":"xyt","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pausingManager","outputs":[{"internalType":"contract IPendlePausingManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_underlyingAsset","type":"address"},{"internalType":"uint256","name":"_expiry","type":"uint256"}],"name":"redeemAfterExpiry","outputs":[{"internalType":"uint256","name":"redeemedAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_underlyingAsset","type":"address"},{"internalType":"uint256","name":"_expiry","type":"uint256"}],"name":"redeemDueInterests","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_underlyingAsset","type":"address"},{"internalType":"uint256","name":"_expiry","type":"uint256"},{"internalType":"uint256","name":"_amountToRedeem","type":"uint256"}],"name":"redeemUnderlying","outputs":[{"internalType":"uint256","name":"redeemedAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_underlyingAssets","type":"address[]"},{"internalType":"uint256[][]","name":"_tokenInfos","type":"uint256[][]"}],"name":"registerTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardManager","outputs":[{"internalType":"contract IPendleRewardManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"router","outputs":[{"internalType":"contract IPendleRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"setUpEmergencyMode","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_underlyingAsset","type":"address"},{"internalType":"uint256","name":"_expiry","type":"uint256"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"bool","name":"extraFlag","type":"bool"}],"name":"setUpEmergencyModeV2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"tokenInfo","outputs":[{"internalType":"bool","name":"registered","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"totalFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_underlyingAsset","type":"address"},{"internalType":"uint256","name":"_expiry","type":"uint256"},{"internalType":"address","name":"_user","type":"address"}],"name":"updateDueInterests","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_underlyingAsset","type":"address"},{"internalType":"uint256","name":"_expiry","type":"uint256"},{"internalType":"address","name":"_user","type":"address"}],"name":"updatePendingRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_underlyingAsset","type":"address"},{"internalType":"uint256[]","name":"_tokenInfo","type":"uint256[]"}],"name":"verifyToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address payable","name":"sendTo","type":"address"}],"name":"withdrawEther","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_underlyingAsset","type":"address"},{"internalType":"uint256","name":"_expiry","type":"uint256"}],"name":"withdrawForgeFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"sendTo","type":"address"}],"name":"withdrawToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"wxBTRFLY","outputs":[{"internalType":"contract IWXBTRFLY","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"xBTRFLY","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"yieldContractDeployer","outputs":[{"internalType":"contract IPendleYieldContractDeployer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"yieldTokenHolders","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]