PendleYieldContractFactory

createYieldContract

createYieldContract contract allows anyone to create PT and YT token pair from SY token with expiry.
  • Each PT–YT pair has an associated expiry. Pendle uses an expiryDivisor to align expiries to whole-day units — on Ethereum mainnet, this divisor is set to 86,400 seconds (one day).
  • It uses BaseSplitCodeFactory._create2 to deploy YT token. Because YT token has a large contract size. To prevent PendleYieldContractFactory's size from exceeding 24 kb limit, it uses BaseSplitCodeFactory to store YT contract code in two contracts, and it reads and combines bytecodes from them to get the integral creation code of YT contract in memory and deploys it.
  • Symbol of deployed PT token is PT-[X]. Symbol of deployed YT token is YT-[X].
/// --- pendle-core-v2-public/contracts/core/YieldContracts/PendleYieldContractFactory.sol --- // SY => expiry => address // returns address(0) if not created mapping(address => mapping(uint256 => address)) public getPT; mapping(address => mapping(uint256 => address)) public getYT; /** * @notice Create a pair of (PT, YT) from any SY and valid expiry. Anyone can create a yield contract * @dev It's intentional to make expiry an uint32 to guard against fat fingers. uint32.max is year 2106 */ function createYieldContract( address SY, uint32 expiry, bool doCacheIndexSameBlock ) external returns (address PT, address YT) { if (MiniHelpers.isTimeInThePast(expiry) || expiry % expiryDivisor != 0) revert Errors.YCFactoryInvalidExpiry(); if (getPT[SY][expiry] != address(0)) revert Errors.YCFactoryYieldContractExisted(); IStandardizedYield _SY = IStandardizedYield(SY); (, , uint8 assetDecimals) = _SY.assetInfo(); string memory syCoreName = _stripSYPrefix(_SY.name()); string memory syCoreSymbol = _stripSYPrefix(_SY.symbol()); PT = Create2.deploy( 0, bytes32(block.chainid), abi.encodePacked( type(PendlePrincipalToken).creationCode, abi.encode( SY, PT_PREFIX.concat(syCoreName, expiry, " "), PT_PREFIX.concat(syCoreSymbol, expiry, "-"), assetDecimals, expiry ) ) ); YT = BaseSplitCodeFactory._create2( 0, bytes32(block.chainid), abi.encode( SY, PT, YT_PREFIX.concat(syCoreName, expiry, " "), YT_PREFIX.concat(syCoreSymbol, expiry, "-"), assetDecimals, expiry, doCacheIndexSameBlock ), ytCreationCodeContractA, ytCreationCodeSizeA, ytCreationCodeContractB, ytCreationCodeSizeB ); IPPrincipalToken(PT).initialize(YT); getPT[SY][expiry] = PT; getYT[SY][expiry] = YT; isPT[PT] = true; isYT[YT] = true; emit CreateYieldContract(SY, expiry, PT, YT); } /// --- pendle-core-v2-public/contracts/core/libraries/MiniHelpers.sol --- function isTimeInThePast(uint256 timestamp) internal view returns (bool) { return (timestamp <= block.timestamp); // same definition as isCurrentlyExpired }