StandardizedYield

PendleAaveV3SY

Constructor

/// --- Pendle-SY-Public/contracts/core/StandardizedYield/implementations/AaveV3/PendleAaveV3SY.sol --- address public immutable aToken; address public immutable aavePool; address public immutable underlying; constructor( string memory _name, string memory _symbol, address _aavePool, address _aToken ) SYBase(_name, _symbol, _aToken) { aToken = _aToken; aavePool = _aavePool; underlying = IAaveV3AToken(aToken).UNDERLYING_ASSET_ADDRESS(); _safeApproveInf(underlying, _aavePool); } /// --- Pendle-SY-Public/contracts/core/libraries/TokenHelper.sol --- uint256 internal constant LOWER_BOUND_APPROVAL = type(uint96).max / 2; // some tokens use 96 bits for approval function _safeApproveInf(address token, address to) internal { if (token == NATIVE) return; if (IERC20(token).allowance(address(this), to) < LOWER_BOUND_APPROVAL) { _safeApprove(token, to, 0); _safeApprove(token, to, type(uint256).max); } }

deposit

deposit function allows user to deposit aToken like aUSDC (or underlying asset USDC) into StandardizedYield contract, and mint stUSDC.
  • It allows user to deposit aUSDC or USDC. If user deposits underlying asset which is USDC, SY contract supplies USDC to aave pool to get aUSDC. Anyway, SY contract always receives aToken.
  • in aToken contract, the recorded balance is the normalized asset amount. The balanceOf function returns unnormalized value (which is the true balance of USDC owned by user considering interest)
  • amount of shares minted by SY contract is the normalized USDC amount.
/// --- Pendle-SY-Public/contracts/core/StandardizedYield/SYBase.sol --- /** * @dev See {IStandardizedYield-deposit} */ function deposit( address receiver, address tokenIn, uint256 amountTokenToDeposit, uint256 minSharesOut ) external payable nonReentrant returns (uint256 amountSharesOut) { if (!isValidTokenIn(tokenIn)) revert Errors.SYInvalidTokenIn(tokenIn); if (amountTokenToDeposit == 0) revert Errors.SYZeroDeposit(); _transferIn(tokenIn, msg.sender, amountTokenToDeposit); amountSharesOut = _deposit(tokenIn, amountTokenToDeposit); if (amountSharesOut < minSharesOut) revert Errors.SYInsufficientSharesOut(amountSharesOut, minSharesOut); _mint(receiver, amountSharesOut); emit Deposit(msg.sender, receiver, tokenIn, amountTokenToDeposit, amountSharesOut); } /// --- Pendle-SY-Public/contracts/core/StandardizedYield/implementations/AaveV3/PendleAaveV3SY.sol --- function isValidTokenIn(address token) public view override returns (bool) { return token == aToken || token == underlying; } function _deposit( address tokenIn, uint256 amountDeposited ) internal virtual override returns (uint256 amountSharesOut) { if (tokenIn == underlying) { IAaveV3Pool(aavePool).supply(underlying, amountDeposited, address(this), 0); } amountSharesOut = AaveAdapterLib.calcSharesFromAssetUp(amountDeposited, _getNormalizedIncome()); } function _getNormalizedIncome() internal view returns (uint256) { return IAaveV3Pool(aavePool).getReserveNormalizedIncome(underlying); } /// --- Pendle-SY-Public/contracts/core/StandardizedYield/implementations/AaveV3/libraries/AaveAdapterLib.sol --- function calcSharesFromAssetUp(uint256 amountAssets, uint256 index) internal pure returns (uint256) { return WadRayMath.rayDiv(amountAssets, index); } /// --- Pendle-SY-Public/contracts/core/libraries/TokenHelper.sol --- function _transferIn(address token, address from, uint256 amount) internal { if (token == NATIVE) require(msg.value == amount, "eth mismatch"); else if (amount != 0) IERC20(token).safeTransferFrom(from, address(this), amount); }

redeem

redeem function allows user to burn their SY shares to get underlying assets back.
In PendleAaveV3SY contract, it can withdraw underlying asset from AAVE pool and sends to user, or just sends the aToken to user.
/// --- Pendle-SY-Public/contracts/core/StandardizedYield/SYBase.sol --- /** * @dev See {IStandardizedYield-redeem} */ function redeem( address receiver, uint256 amountSharesToRedeem, address tokenOut, uint256 minTokenOut, bool burnFromInternalBalance ) external nonReentrant returns (uint256 amountTokenOut) { if (!isValidTokenOut(tokenOut)) revert Errors.SYInvalidTokenOut(tokenOut); if (amountSharesToRedeem == 0) revert Errors.SYZeroRedeem(); if (burnFromInternalBalance) { _burn(address(this), amountSharesToRedeem); } else { _burn(msg.sender, amountSharesToRedeem); } amountTokenOut = _redeem(receiver, tokenOut, amountSharesToRedeem); if (amountTokenOut < minTokenOut) revert Errors.SYInsufficientTokenOut(amountTokenOut, minTokenOut); emit Redeem(msg.sender, receiver, tokenOut, amountSharesToRedeem, amountTokenOut); } /// --- Pendle-SY-Public/contracts/core/StandardizedYield/implementations/AaveV3/PendleAaveV3SY.sol --- function isValidTokenOut(address token) public view override returns (bool) { return token == aToken || token == underlying; } function _redeem( address receiver, address tokenOut, uint256 amountSharesToRedeem ) internal override returns (uint256 amountTokenOut) { amountTokenOut = AaveAdapterLib.calcSharesToAssetDown(amountSharesToRedeem, _getNormalizedIncome()); if (tokenOut == underlying) { IAaveV3Pool(aavePool).withdraw(underlying, amountTokenOut, receiver); } else { _transferOut(aToken, receiver, amountTokenOut); } }

exchangeRate

exchangeRate function returns exchange rate between SY token and underlying asset.
As AAveV3SY token amount equals normalized aToken amount, so the exchange rate is the interest index of aToken.
function exchangeRate() public view virtual override returns (uint256) { return _getNormalizedIncome() / 1e9; }

assetInfo

assetInfo function returns underlying asset information.
function assetInfo() external view returns (AssetType assetType, address assetAddress, uint8 assetDecimals) { return (AssetType.TOKEN, underlying, IERC20Metadata(underlying).decimals()); }