aToken is a wrapper of the underlying, their conversion rate is 1-1.// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.23;
import "../../SYBase.sol";
import "./libraries/AaveAdapterLib.sol";
import "../../../../interfaces/AaveV3/IAaveV3AToken.sol";
import "../../../../interfaces/AaveV3/IAaveV3Pool.sol";
// @NOTE: In this contract, we denote the "scaled balance" term as "share"
contract PendleAaveV3SY is SYBase {
using PMath for uint256;
SYBase, which is not upgradable. 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);
}
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 _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);
}
}
aToken is the underlying wrapper, we only need to handle the case where tokenIn is underlying and wrap/unwrap it. function exchangeRate() public view virtual override returns (uint256) {
return _getNormalizedIncome() / 1e9;
}
function _previewDeposit(
address,
uint256 amountTokenToDeposit
) internal view override returns (uint256 /*amountSharesOut*/) {
return AaveAdapterLib.calcSharesFromAssetUp(amountTokenToDeposit, _getNormalizedIncome());
}
function _previewRedeem(
address,
uint256 amountSharesToRedeem
) internal view override returns (uint256 /*amountTokenOut*/) {
return AaveAdapterLib.calcSharesToAssetDown(amountSharesToRedeem, _getNormalizedIncome());
}
tokenIn/ tokenOut are aToken and underlying. Since their conversion rate is 1-1, we can omit them. function _getNormalizedIncome() internal view returns (uint256) {
return IAaveV3Pool(aavePool).getReserveNormalizedIncome(underlying);
}
function getTokensIn() public view override returns (address[] memory res) {
return ArrayLib.create(underlying, aToken);
}
function getTokensOut() public view override returns (address[] memory res) {
return ArrayLib.create(underlying, aToken);
}
function isValidTokenIn(address token) public view override returns (bool) {
return token == aToken || token == underlying;
}
function isValidTokenOut(address token) public view override returns (bool) {
return token == aToken || token == underlying;
}
See [ function getTokensIn() public view virtual override returns (address[] memory res) { res = new address; res[0] = asset; res[1] = yieldToken; }
function getTokensOut() public view virtual override returns (address[] memory res) {
res = new address[](2);
res[0] = asset;
res[1] = yieldToken;
}
function isValidTokenIn(address token) public view virtual override returns (bool) {
return token == yieldToken || token == asset;
}
function isValidTokenOut(address token) public view virtual override returns (bool) {
return token == yieldToken || token == asset;
}](<https://pendle.notion.site/function-getTokensIn-public-view-virtual-override-returns-address-memory-res-res-n-1f2567a21d3780b8995ac792a3061453>)
function assetInfo() external view returns (AssetType assetType, address assetAddress, uint8 assetDecimals) {
return (AssetType.TOKEN, underlying, IERC20Metadata(underlying).decimals());
}
}
See ‣