Skip to content

Commit

Permalink
added Interfaces for pendle
Browse files Browse the repository at this point in the history
  • Loading branch information
MrDeadCe11 committed Jul 4, 2024
1 parent 453222d commit ceefdea
Show file tree
Hide file tree
Showing 7 changed files with 334 additions and 0 deletions.
50 changes: 50 additions & 0 deletions src/contracts/oracles/pendle/PendlePTRelayer.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.24;

import '@pendle/contracts/oracles/PendlePYLpOracle.sol';
import '@pendle/contracts/interfaces/IPAllActionV3.sol';
import '@pendle/contracts/interfaces/IPMarket.sol';
import '@interfaces/oracles/IBaseOracle.sol';

/**
* @title PendleRelayer
* @notice This contracts transforms a Pendle TWAP price feed into a standard IBaseOracle feed
*
*/
contract PendleRelayer is IBaseOracle {
using PendlePYOracleLib for IPMarket;
using PendleLpOracleLib for IPMarket;

IStandardizedYield public SY;
IPPrincipalToken public PT;
IPYieldToken public YT;

IPMarket public market;
PendlePYLpOracle public oracle;

uint32 public twapDuration;

constructor(address _market, address _oracle, uint32 _twapDuration) {
require(_market != address(0) && _oracle != address(0), 'Invalid address');
require(twapDuration != 0, 'Invalid TWAP duration');

market = IPMarket(_market);
oracle = PendlePYLpOracle(_oracle);
twapDuration = _twapDuration;

(SY, PT, YT) = market.readTokens();

// test if oracle is ready
(bool increaseCardinalityRequired,, bool oldestObservationSatisfied) = oracle.getOracleState(_market, _twapDuration);
// It's required to call IPMarket(market).increaseObservationsCardinalityNext(cardinalityRequired) and wait
// for at least the twapDuration, to allow data population.
// also
// It's necessary to wait for at least the twapDuration, to allow data population.
require(!increaseCardinalityRequired && oldestObservationSatisfied, 'Oracle not ready');
}

function getResultWithValidity() external view returns (uint256 _resullt, bool _validity) {}

function read() external view returns (uint256 _value) {}
function symbol() external view returns (string memory _symbol) {}
}
16 changes: 16 additions & 0 deletions src/interfaces/oracles/pendle/IPMarket.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;

import {IStandardizedYield} from '@interfaces/oracles/pendle/IStandardizedYield.sol';
import {IPPrincipalToken} from '@interfaces/oracles/pendle/IPPrincipalToken.sol';
import {IPYieldToken} from '@interfaces/oracles/pendle/IPYieldToken.sol';

interface IPMarket {
/**
* required functions:
* getPtToSYRate
* readTokens()
*/
function getPtToSyRate(address market, uint32 duration) external view returns (uint256);
function readTokens() external view returns (IStandardizedYield _SY, IPPrincipalToken _PT, IPYieldToken _YT);
}
8 changes: 8 additions & 0 deletions src/interfaces/oracles/pendle/IPOracle.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;

interface IPOracle {
/**
* required functions:
*/
}
22 changes: 22 additions & 0 deletions src/interfaces/oracles/pendle/IPPrincipalToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;

import {IERC20Metadata} from '@interfaces/utils/IERC20Metadata.sol';

interface IPPrincipalToken is IERC20Metadata {
function burnByYT(address user, uint256 amount) external;

function mintByYT(address user, uint256 amount) external;

function initialize(address _YT) external;

function SY() external view returns (address);

function YT() external view returns (address);

function factory() external view returns (address);

function expiry() external view returns (uint256);

function isExpired() external view returns (bool);
}
71 changes: 71 additions & 0 deletions src/interfaces/oracles/pendle/IPYieldToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;

import {IERC20Metadata} from '@interfaces/utils/IERC20Metadata.sol';

interface IRewardManager {
function userReward(address token, address user) external view returns (uint128 index, uint128 accrued);
}

interface IPInterestManagerYT {
event CollectInterestFee(uint256 amountInterestFee);

function userInterest(address user) external view returns (uint128 lastPYIndex, uint128 accruedInterest);
}

interface IPYieldToken is IERC20Metadata, IRewardManager, IPInterestManagerYT {
event NewInterestIndex(uint256 indexed newIndex);

event Mint(
address indexed caller,
address indexed receiverPT,
address indexed receiverYT,
uint256 amountSyToMint,
uint256 amountPYOut
);

event Burn(address indexed caller, address indexed receiver, uint256 amountPYToRedeem, uint256 amountSyOut);

event RedeemRewards(address indexed user, uint256[] amountRewardsOut);

event RedeemInterest(address indexed user, uint256 interestOut);

event CollectRewardFee(address indexed rewardToken, uint256 amountRewardFee);

function mintPY(address receiverPT, address receiverYT) external returns (uint256 amountPYOut);

function redeemPY(address receiver) external returns (uint256 amountSyOut);

function redeemPYMulti(
address[] calldata receivers,
uint256[] calldata amountPYToRedeems
) external returns (uint256[] memory amountSyOuts);

function redeemDueInterestAndRewards(
address user,
bool redeemInterest,
bool redeemRewards
) external returns (uint256 interestOut, uint256[] memory rewardsOut);

function rewardIndexesCurrent() external returns (uint256[] memory);

function pyIndexCurrent() external returns (uint256);

function pyIndexStored() external view returns (uint256);

function getRewardTokens() external view returns (address[] memory);

function SY() external view returns (address);

function PT() external view returns (address);

function factory() external view returns (address);

function expiry() external view returns (uint256);

function isExpired() external view returns (bool);

function doCacheIndexSameBlock() external view returns (bool);

function pyIndexLastUpdatedBlock() external view returns (uint128);
}
143 changes: 143 additions & 0 deletions src/interfaces/oracles/pendle/IStandardizedYield.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;

import {IERC20Metadata} from '@interfaces/utils/IERC20Metadata.sol';

interface IStandardizedYield is IERC20Metadata {
/// @dev Emitted when any base tokens is deposited to mint shares
event Deposit(
address indexed caller,
address indexed receiver,
address indexed tokenIn,
uint256 amountDeposited,
uint256 amountSyOut
);

/// @dev Emitted when any shares are redeemed for base tokens
event Redeem(
address indexed caller,
address indexed receiver,
address indexed tokenOut,
uint256 amountSyToRedeem,
uint256 amountTokenOut
);

/// @dev check `assetInfo()` for more information
enum AssetType {
TOKEN,
LIQUIDITY
}

/// @dev Emitted when (`user`) claims their rewards
event ClaimRewards(address indexed user, address[] rewardTokens, uint256[] rewardAmounts);

/**
* @notice mints an amount of shares by depositing a base token.
* @param receiver shares recipient address
* @param tokenIn address of the base tokens to mint shares
* @param amountTokenToDeposit amount of base tokens to be transferred from (`msg.sender`)
* @param minSharesOut reverts if amount of shares minted is lower than this
* @return amountSharesOut amount of shares minted
* @dev Emits a {Deposit} event
*
* Requirements:
* - (`tokenIn`) must be a valid base token.
*/
function deposit(
address receiver,
address tokenIn,
uint256 amountTokenToDeposit,
uint256 minSharesOut
) external payable returns (uint256 amountSharesOut);

/**
* @notice redeems an amount of base tokens by burning some shares
* @param receiver recipient address
* @param amountSharesToRedeem amount of shares to be burned
* @param tokenOut address of the base token to be redeemed
* @param minTokenOut reverts if amount of base token redeemed is lower than this
* @param burnFromInternalBalance if true, burns from balance of `address(this)`, otherwise burns from `msg.sender`
* @return amountTokenOut amount of base tokens redeemed
* @dev Emits a {Redeem} event
*
* Requirements:
* - (`tokenOut`) must be a valid base token.
*/
function redeem(
address receiver,
uint256 amountSharesToRedeem,
address tokenOut,
uint256 minTokenOut,
bool burnFromInternalBalance
) external returns (uint256 amountTokenOut);

/**
* @notice exchangeRate * syBalance / 1e18 must return the asset balance of the account
* @notice vice-versa, if a user uses some amount of tokens equivalent to X asset, the amount of sy
* he can mint must be X * exchangeRate / 1e18
* @dev SYUtils's assetToSy & syToAsset should be used instead of raw multiplication
* & division
*/
function exchangeRate() external view returns (uint256 res);

/**
* @notice claims reward for (`user`)
* @param user the user receiving their rewards
* @return rewardAmounts an array of reward amounts in the same order as `getRewardTokens`
* @dev
* Emits a `ClaimRewards` event
* See {getRewardTokens} for list of reward tokens
*/
function claimRewards(address user) external returns (uint256[] memory rewardAmounts);

/**
* @notice get the amount of unclaimed rewards for (`user`)
* @param user the user to check for
* @return rewardAmounts an array of reward amounts in the same order as `getRewardTokens`
*/
function accruedRewards(address user) external view returns (uint256[] memory rewardAmounts);

function rewardIndexesCurrent() external returns (uint256[] memory indexes);

function rewardIndexesStored() external view returns (uint256[] memory indexes);

/**
* @notice returns the list of reward token addresses
*/
function getRewardTokens() external view returns (address[] memory);

/**
* @notice returns the address of the underlying yield token
*/
function yieldToken() external view returns (address);

/**
* @notice returns all tokens that can mint this SY
*/
function getTokensIn() external view returns (address[] memory res);

/**
* @notice returns all tokens that can be redeemed by this SY
*/
function getTokensOut() external view returns (address[] memory res);

function isValidTokenIn(address token) external view returns (bool);

function isValidTokenOut(address token) external view returns (bool);

function previewDeposit(
address tokenIn,
uint256 amountTokenToDeposit
) external view returns (uint256 amountSharesOut);

function previewRedeem(address tokenOut, uint256 amountSharesToRedeem) external view returns (uint256 amountTokenOut);

/**
* @notice This function contains information to interpret what the asset is
* @return assetType the type of the asset (0 for ERC20 tokens, 1 for AMM liquidity tokens,
* 2 for bridged yield bearing tokens like wstETH, rETH on Arbi whose the underlying asset doesn't exist on the chain)
* @return assetAddress the address of the asset
* @return assetDecimals the decimals of the asset
*/
function assetInfo() external view returns (AssetType assetType, address assetAddress, uint8 assetDecimals);
}
24 changes: 24 additions & 0 deletions src/interfaces/utils/IERC20Metadata.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {IERC20} from '@openzepplin/token/ERC20/IERC20.sol';

/**
* @dev Interface for the optional metadata functions from the ERC-20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);

/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);

/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}

0 comments on commit ceefdea

Please sign in to comment.