StrategyPendlePT

Description:

Multi-signature wallet contract requiring multiple confirmations for transaction execution.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "altitude-v2/contracts/strategies/farming/strategies/pendle/StrategyPendlePT.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

import "./StrategyPendleBase.sol";
import "../../../../libraries/uniswap-v3/TransferHelper.sol";

/**
 * @title StrategyPendlePT Contract
 * @dev Contract for holding Pendle PT tokens
 * @author Altitude Labs
 **/

contract StrategyPendlePT is StrategyPendleBase {
    constructor(
        address farmDispatcherAddress_,
        address swapStrategy_,
        address router_,
        address routerStatic_,
        address oracle_,
        address market_,
        address farmAsset_,
        uint256 slippage_,
        address rewardsAddress_,
        address[] memory rewardAssets_,
        address[] memory nonSkimAssets_
    )
        StrategyPendleBase(
            farmDispatcherAddress_,
            swapStrategy_,
            router_,
            routerStatic_,
            oracle_,
            market_,
            farmAsset_,
            slippage_,
            rewardsAddress_,
            rewardAssets_,
            nonSkimAssets_
        )
    {}

    /// @notice Acquires Pendle PT tokens
    /// @param amount Amount of asset to deposit
    function _deposit(uint256 amount) internal override {
        if (market.isExpired()) {
            revert PFS_MARKET_EXPIRED();
        }

        amount = _swap(asset, farmAsset, amount);

        uint256 twapRate = oracle.getPtToSyRate(address(market), twapDuration);
        TransferHelper.safeApprove(farmAsset, address(router), amount);
        (uint256 netPtOut, , ) = router.swapExactTokenForPt(
            address(this),
            address(market),
            0,
            _emptyApproxParams(),
            _createTokenInputStruct(amount),
            _emptyLimit()
        );

        _validateRate((SY.previewDeposit(farmAsset, amount) * 1e18) / twapRate, netPtOut);
    }

    function _exitExpiredMarket() internal returns (bool) {
        if (market.isExpired()) {
            // Exit an expired market
            uint256 ptBalance = PT.balanceOf(address(this));
            if (ptBalance > 0) {
                PT.approve(address(router), ptBalance);
                router.redeemPyToToken(address(this), address(YT), ptBalance, _emptyTokenOutputStruct());
            }

            return true;
        }

        return false;
    }

    /// @notice Sells Pendle PT tokens
    /// @param amountToWithdraw Amount of asset to withdraw
    function _withdraw(uint256 amountToWithdraw) internal override {
        if (!_exitExpiredMarket()) {
            if (farmAsset != asset) {
                // If a conversion is happening, we substitute the requested sum with the
                // input amount we'd need to provide to get it in a swap
                amountToWithdraw = swapStrategy.getAmountIn(farmAsset, asset, amountToWithdraw);
            }

            uint256 ptBalance = PT.balanceOf(address(this));

            // amountToWithdraw is going to be reassigned as amount of PT tokens needed to receive requested amount of farm asset
            try
                routerStatic.swapPtForExactSyStatic(address(market), SY.previewDeposit(farmAsset, amountToWithdraw))
            returns (uint256 netPtIn, uint256, uint256, uint256) {
                if (netPtIn > ptBalance) {
                    // If requested amount is more than we have - withdraw all
                    amountToWithdraw = ptBalance;
                } else {
                    amountToWithdraw = netPtIn;
                }
            } catch {
                // The call can revert if there's not enough liquidity
                amountToWithdraw = ptBalance;
            }

            uint256 twapRate = oracle.getPtToSyRate(address(market), twapDuration);
            PT.approve(address(router), amountToWithdraw);
            (uint256 netTokenOut, , ) = router.swapExactPtForToken(
                address(this),
                address(market),
                amountToWithdraw,
                _emptyTokenOutputStruct(),
                _emptyLimit()
            );
            _validateRate((amountToWithdraw * twapRate) / 1e18, SY.previewDeposit(farmAsset, netTokenOut));
        }

        // Swap the farm asset to borrow asset (if required)
        _swap(farmAsset, asset, type(uint256).max);
    }

    /// @notice Withdraw the whole balance without slippage checks
    function _emergencyWithdraw() internal override {
        if (_exitExpiredMarket()) {
            return;
        }

        uint256 ptAmount = PT.balanceOf(address(this));
        if (ptAmount > 0) {
            PT.approve(address(router), ptAmount);
            router.swapExactPtForToken(
                address(this),
                address(market),
                ptAmount,
                _emptyTokenOutputStruct(),
                _emptyLimit()
            );
        }
    }

    /// @notice Return farm asset amount specific for the farm provider
    function _getFarmAssetAmount() internal view virtual override returns (uint256) {
        uint256 ptBalance = PT.balanceOf(address(this));
        if (ptBalance > 0) {
            if (market.isExpired()) {
                ptBalance = routerStatic.redeemPyToTokenStatic(address(YT), ptBalance, farmAsset);
            } else {
                (ptBalance, , , , ) = routerStatic.swapExactPtForTokenStatic(address(market), ptBalance, farmAsset);
            }
        }

        return ptBalance;
    }
}
"
    },
    "altitude-v2/contracts/strategies/farming/strategies/pendle/StrategyPendleBase.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

import "../FarmDropStrategy.sol";
import "../../../SkimStrategy.sol";
import "../../../../libraries/uniswap-v3/TransferHelper.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@pendle/core-v2/contracts/interfaces/IPAllActionV3.sol";
import "@pendle/core-v2/contracts/interfaces/IPMarket.sol";
import "@pendle/core-v2/contracts/interfaces/IPPYLpOracle.sol";
import "@pendle/core-v2/contracts/interfaces/IPRouterStatic.sol";
import "../../../../interfaces/internal/strategy/farming/IPendleFarmStrategy.sol";
/**
 * @title StrategyPendleBase Contract
 * @dev Contract for interacting with Pendle protocol
 * @author Altitude Labs
 **/

abstract contract StrategyPendleBase is FarmDropStrategy, SkimStrategy, IPendleFarmStrategy {
    IPAllActionV3 public immutable router;
    IPRouterStatic public immutable routerStatic;
    IPPYLpOracle public immutable oracle;
    IPMarket public immutable market;
    IStandardizedYield public immutable SY;
    IPPrincipalToken public immutable PT;
    IPYieldToken public immutable YT;
    /// @dev Pendle exchange rates are 18 decimals. We need to mind the underlying decimals.
    uint8 internal immutable SY_DECIMALS;

    uint256 public constant SLIPPAGE_BASE = 1_000_000;
    /// @notice Price slippage tolerance, where 1e6 = 100%
    uint256 public slippage;
    /// @notice TWAP duration in seconds, used to check `slippage`
    uint32 public twapDuration = 1800;

    constructor(
        address farmDispatcherAddress_,
        address swapStrategy_,
        address router_,
        address routerStatic_,
        address oracle_,
        address market_,
        address farmAsset_,
        uint256 slippage_,
        address rewardsAddress_,
        address[] memory rewardAssets_,
        address[] memory nonSkimAssets_
    )
        FarmDropStrategy(farmAsset_, farmDispatcherAddress_, rewardsAddress_, rewardAssets_, swapStrategy_)
        SkimStrategy(nonSkimAssets_)
    {
        router = IPAllActionV3(router_);
        routerStatic = IPRouterStatic(routerStatic_);
        oracle = IPPYLpOracle(oracle_);
        market = IPMarket(market_);

        if (market.isExpired()) {
            revert PFS_MARKET_EXPIRED();
        }

        if (slippage_ > SLIPPAGE_BASE) {
            revert PFS_INVALID_SLIPPAGE();
        }

        (SY, PT, YT) = IPMarket(market).readTokens();
        slippage = slippage_;
        SY_DECIMALS = SY.decimals();

        _validateTwapDuration(twapDuration);
    }

    /// @notice Set the twap duration
    /// @param twapDuration_ New duration in seconds
    function setTwapDuration(uint32 twapDuration_) external override onlyOwner {
        _validateTwapDuration(twapDuration_);
        emit SetTwapDuration(twapDuration, twapDuration_);
        twapDuration = twapDuration_;
    }

    /// @notice Set the acceptable slippage for market operations
    /// @param slippage_ New slippage value, where SLIPPAGE_BASE = 1e6 = 100%
    function setSlippage(uint256 slippage_) external override onlyOwner {
        if (slippage_ > SLIPPAGE_BASE) {
            revert PFS_SLIPPAGE(slippage, slippage_);
        }
        emit SetSlippage(slippage, slippage_);
        slippage = slippage_;
    }

    /// @notice Internal reusable function
    function _recogniseRewardsInBase() internal override {
        SY.claimRewards(address(this));
        YT.redeemDueInterestAndRewards(address(this), true, true);
        market.redeemRewards(address(this));

        /// @dev YT interest is in SY
        uint256 syBalance = SY.balanceOf(address(this));
        if (syBalance > 0) {
            SY.redeem(address(this), syBalance, farmAsset, 0, false);
        }

        for (uint256 i; i < rewardAssets.length; ++i) {
            _swap(rewardAssets[i], asset, type(uint256).max);
        }
        // Update drop percentage
        super._recogniseRewardsInBase();
    }

    function _validateTwapDuration(uint32 twapDuration_) internal view {
        // Make sure the oracle has enough TWAP data
        (bool increaseCardinalityRequired, uint16 cardinalityRequired, bool oldestObservationSatisfied) = oracle
            .getOracleState(address(market), twapDuration_);
        if (increaseCardinalityRequired) {
            // Oracle requires cardinality increase
            revert PFS_ORACLE_CARDINALITY(cardinalityRequired);
        }
        if (!oldestObservationSatisfied) {
            // Wait at least TWAP_DURATION seconds to populate observations
            revert PFS_ORACLE_UNPOPULATED();
        }
    }

    function _emptyLimit() internal pure returns (LimitOrderData memory) {}

    function _emptySwap() internal pure returns (SwapData memory) {}

    function _emptyApproxParams() internal pure returns (ApproxParams memory) {
        return ApproxParams(0, type(uint256).max, 0, 256, 1e14);
    }

    function _createTokenInputStruct(uint256 amountIn) internal view returns (TokenInput memory) {
        return
            TokenInput({
                tokenIn: farmAsset,
                netTokenIn: amountIn,
                tokenMintSy: farmAsset,
                pendleSwap: address(0),
                swapData: _emptySwap()
            });
    }

    function _emptyTokenOutputStruct() internal view returns (TokenOutput memory) {
        return
            TokenOutput({
                tokenOut: farmAsset,
                minTokenOut: 0,
                tokenRedeemSy: farmAsset,
                pendleSwap: address(0),
                swapData: _emptySwap()
            });
    }

    /// @notice Validate the difference for input and output value for market operations is within our tolerance
    function _validateRate(uint256 input, uint256 output) internal view {
        uint256 delta = (input * slippage) / SLIPPAGE_BASE;
        if (slippage > 0 && delta == 0) {
            /// @dev If the amount is so small that slippage didn't have an effect due to rounding
            delta = 1;
        }

        if (input - delta > output) {
            revert PFS_SLIPPAGE(input, output);
        }
    }
}
"
    },
    "altitude-v2/contracts/libraries/uniswap-v3/TransferHelper.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

/**
 * @title Transfer Helper Library
 * @dev Contains helper methods for interacting with ERC20 tokens that do not consistently return true/false
 * @author Uniswap
 **/
library TransferHelper {
    // Tranfer helper library Errors
    error TH_SAFE_TRANSFER_FAILED();
    error TH_SAFE_TRANSFER_FROM_FAILED();
    error TH_SAFE_TRANSFER_NATIVE_FAILED();
    error TH_SAFE_APPROVE();
    error TH_SAFE_APPROVE_RESET();

    function safeTransfer(address token, address to, uint256 value) internal {
        bool toThrow = _call(token, abi.encodeWithSelector(IERC20.transfer.selector, to, value));
        if (toThrow) {
            revert TH_SAFE_TRANSFER_FAILED();
        }
    }

    function safeTransferFrom(address token, address from, address to, uint256 value) internal {
        bool toThrow = _call(token, abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value));
        if (toThrow) {
            revert TH_SAFE_TRANSFER_FROM_FAILED();
        }
    }

    /// @notice Approves the stipulated contract to spend the given allowance in the given token
    /// @dev Errors with 'SA' if transfer fails
    /// @param token The contract address of the token to be approved
    /// @param to The target of the approval
    /// @param value The amount of the given token the target will be allowed to spend
    function safeApprove(address token, address to, uint256 value) internal {
        // Reset approval first
        bool toThrow = _call(token, abi.encodeWithSelector(IERC20.approve.selector, to, 0));
        if (toThrow) {
            revert TH_SAFE_APPROVE_RESET();
        }

        toThrow = _call(token, abi.encodeWithSelector(IERC20.approve.selector, to, value));
        if (toThrow) {
            revert TH_SAFE_APPROVE();
        }
    }

    function _call(address token, bytes memory data) internal returns (bool) {
        (bool success, bytes memory resultData) = token.call(data);
        if (!success || (resultData.length > 0 && !abi.decode(resultData, (bool)))) {
            return true;
        }

        return false;
    }

    function safeTransferNative(address to, uint256 value) internal {
        (bool success, ) = to.call{value: value}(new bytes(0));
        if (!success) {
            revert TH_SAFE_TRANSFER_NATIVE_FAILED();
        }
    }
}
"
    },
    "altitude-v2/contracts/strategies/farming/strategies/FarmDropStrategy.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/access/Ownable.sol";

import "./FarmStrategy.sol";
import "../../../interfaces/internal/strategy/farming/IFarmDropStrategy.sol";

/**
 * @title FarmDropStrategy Contract
 * @dev Provides tools to monitor drops in the farm balance value
 * @author Altitude Labs
 **/

abstract contract FarmDropStrategy is Ownable, FarmStrategy, IFarmDropStrategy {
    uint256 public override expectedBalance;
    uint256 public override dropPercentage;
    uint256 public constant override DROP_UNITS = 1e18;

    /// @notice Default drop threshold to revert deposit/withdraw calls is 5%
    uint256 public override dropThreshold = (DROP_UNITS * 5) / 100;

    constructor(
        address farmAssetAddress,
        address farmDispatcherAddress,
        address rewardsAddress,
        address[] memory rewardAssets_,
        address swapStrategyAddress
    ) FarmStrategy(farmAssetAddress, farmDispatcherAddress, rewardsAddress, rewardAssets_, swapStrategyAddress) {}

    /// @notice Set the threshold for reverting deposit/withdraw
    /// @param dropThreshold_ The new threshold in percentage (of DROP_UNITS, 1e18)
    function setDropThreshold(uint256 dropThreshold_) external onlyOwner {
        if (dropThreshold_ > DROP_UNITS) {
            revert FDS_OUT_OF_BOUNDS();
        }

        dropThreshold = dropThreshold_;
    }

    /// @notice Deal with a farm drop during deposit
    /// If a farm drop is detected, the deposit will be reverted
    /// @param amount The amount to deposit
    function deposit(uint256 amount) public override(FarmStrategy, IFarmStrategy) {
        uint256 currentBalance = balance();
        _updateDropPercentage(currentBalance, 0);
        if (dropPercentage > dropThreshold) {
            revert FDS_DROP_EXCEEDED(dropPercentage, dropThreshold);
        }

        // deposit and check for any deposit fees
        expectedBalance = currentBalance;
        super.deposit(amount);
        currentBalance = balance();
        _updateDropPercentage(currentBalance, amount);
        expectedBalance = currentBalance;
    }

    /// @notice Track and handle any possible farm drop on withdraw
    /// If a farm drop is detected, the withdraw will be reverted
    /// @param amountRequested The amount to withdraw

    function withdraw(
        uint256 amountRequested
    ) public override(FarmStrategy, IFarmStrategy) returns (uint256 amountWithdrawn) {
        _updateDropPercentage(balance(), 0);
        if (dropPercentage > dropThreshold) {
            revert FDS_DROP_EXCEEDED(dropPercentage, dropThreshold);
        }
        amountWithdrawn = super.withdraw(amountRequested);
        expectedBalance = balance();
    }

    /// @notice Update the drop percentage on emergencyWithdraw
    function emergencyWithdraw() public override(FarmStrategy, IFarmStrategy) {
        _updateDropPercentage(balance(), 0);
        super.emergencyWithdraw();
        expectedBalance = balance();
    }

    /// @notice Update the drop percentage on emergencySwap
    /// @param assets The assets to swap
    function emergencySwap(
        address[] calldata assets
    ) public override(FarmStrategy, IFarmStrategy) returns (uint256 amountWithdrawn) {
        _updateDropPercentage(balance(), 0);
        amountWithdrawn = super.emergencySwap(assets);
        expectedBalance = balance();
    }

    /// @notice Account for increase/decrease in the farm drop percentage
    /// @param amount Expected balance increase
    function _updateDropPercentage(uint256 currentBalance, uint256 amount) internal {
        dropPercentage = _calculateDropPercentage(currentBalance, expectedBalance + amount, dropPercentage);
    }

    /// @notice Calculates the current drop in farm value as percentage
    /// @return percentage The total drop in farm value as a percentage
    function currentDropPercentage() public view override returns (uint256) {
        return _calculateDropPercentage(balance(), expectedBalance, dropPercentage);
    }

    /// @notice Decrease drop percentage with the rewards that are used to restore it
    function _recogniseRewardsInBase() internal virtual override {
        /// @dev It is assumed the balance to be bigger than the expected one
        // as the rewards have been recognised from the inherited contract
        // The drop percentage is to be decreased with the new rewards
        _updateDropPercentage(balance(), 0);
    }

    /// @notice Track and handle any possible farm drop on recogniseRewardsInBase
    /// @return rewards The amount of rewards recognised
    function recogniseRewardsInBase() public virtual override(FarmStrategy, IFarmStrategy) returns (uint256 rewards) {
        rewards = super.recogniseRewardsInBase();
        expectedBalance = balance();
    }

    /// @notice Calculates the drop in farm value as percentage
    /// @param currentBalance_ The current amount in farming
    /// @param expectedBalance_ The expected amount in farming
    /// @param accumulatedDrop_ The drop percentage accumulated so far
    /// @return amount The total drop in farm value as a percentage
    function _calculateDropPercentage(
        uint256 currentBalance_,
        uint256 expectedBalance_,
        uint256 accumulatedDrop_
    ) private pure returns (uint256) {
        if (expectedBalance_ == 0) {
            // If we expect the farm to be empty there can be no drop
            return 0;
        }

        if (currentBalance_ > expectedBalance_) {
            // Gained value
            uint256 percentage = ((currentBalance_ - expectedBalance_) * DROP_UNITS) / expectedBalance_;
            uint256 percentageAdjustment = (accumulatedDrop_ + ((accumulatedDrop_ * percentage) / DROP_UNITS));
            if (percentageAdjustment > percentage) {
                accumulatedDrop_ = percentageAdjustment - percentage;
            } else {
                // Farm is at net gain, new peak from where we will start tracking losses
                accumulatedDrop_ = 0;
            }
        } else {
            if (currentBalance_ == 0) {
                // Lost everything shortcut
                accumulatedDrop_ = DROP_UNITS;
            } else {
                // Lost some
                uint256 percentage = ((expectedBalance_ - currentBalance_) * DROP_UNITS) / expectedBalance_;
                accumulatedDrop_ = (accumulatedDrop_ - ((accumulatedDrop_ * percentage) / DROP_UNITS)) + percentage;
            }
        }

        return accumulatedDrop_;
    }

    /// @notice Reset drop percentage
    function reset() external override onlyOwner {
        dropPercentage = 0;
        expectedBalance = balance();

        emit ResetDropPercentage();
    }
}
"
    },
    "altitude-v2/contracts/strategies/SkimStrategy.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

import "../libraries/uniswap-v3/TransferHelper.sol";
import "../interfaces/internal/strategy/ISkimStrategy.sol";

/**
 * @title SkimStrategy
 * @dev Contract for skiming assets
 * @author Altitude Labs
 **/

contract SkimStrategy is Ownable, ISkimStrategy {
    /** @notice Assets that are not allowed for skim */
    mapping(address => bool) public nonSkimAssets;

    /// @param assets Assets that are not allowed for skim
    constructor(address[] memory assets) {
        uint256 assetsLength = assets.length;
        for (uint256 i; i < assetsLength; ) {
            nonSkimAssets[assets[i]] = true;
            unchecked {
                ++i;
            }
        }
    }

    /** @notice Transfer tokens out of the strategy
     * @dev Used to even out distributions when rewards accrue in batches
     * @param assets Token addresses
     * @param receiver Receiving account
     */
    function skim(address[] calldata assets, address receiver) public override onlyOwner {
        if (receiver == address(0)) {
            revert SK_INVALID_RECEIVER();
        }

        uint256 assetsLength = assets.length;
        for (uint256 i; i < assetsLength; ) {
            if (nonSkimAssets[assets[i]]) {
                revert SK_NON_SKIM_ASSET();
            }

            TransferHelper.safeTransfer(assets[i], receiver, IERC20(assets[i]).balanceOf(address(this)));

            unchecked {
                ++i;
            }
        }
    }
}
"
    },
    "altitude-v2/node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @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);

    /**
     * @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 `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, 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 `from` to `to` 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 from,
        address to,
        uint256 amount
    ) external returns (bool);
}
"
    },
    "altitude-v2/node_modules/@pendle/core-v2/contracts/interfaces/IPAllActionV3.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity ^0.8.0;

import "./IPActionAddRemoveLiqV3.sol";
import "./IPActionSwapPTV3.sol";
import "./IPActionSwapYTV3.sol";
import "./IPActionMiscV3.sol";
import "./IPActionCallbackV3.sol";
import "./IPActionStorageV4.sol";
import "./IPActionSimple.sol";

interface IPAllActionV3 is
    IPActionAddRemoveLiqV3,
    IPActionSwapPTV3,
    IPActionSwapYTV3,
    IPActionMiscV3,
    IPActionCallbackV3,
    IPActionStorageV4,
    IPActionSimple
{}
"
    },
    "altitude-v2/node_modules/@pendle/core-v2/contracts/interfaces/IPMarket.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "./IPPrincipalToken.sol";
import "./IPYieldToken.sol";
import "./IStandardizedYield.sol";
import "./IPGauge.sol";
import "../core/Market/MarketMathCore.sol";

interface IPMarket is IERC20Metadata, IPGauge {
    event Mint(address indexed receiver, uint256 netLpMinted, uint256 netSyUsed, uint256 netPtUsed);

    event Burn(
        address indexed receiverSy,
        address indexed receiverPt,
        uint256 netLpBurned,
        uint256 netSyOut,
        uint256 netPtOut
    );

    event Swap(
        address indexed caller,
        address indexed receiver,
        int256 netPtOut,
        int256 netSyOut,
        uint256 netSyFee,
        uint256 netSyToReserve
    );

    event UpdateImpliedRate(uint256 indexed timestamp, uint256 lnLastImpliedRate);

    event IncreaseObservationCardinalityNext(
        uint16 observationCardinalityNextOld,
        uint16 observationCardinalityNextNew
    );

    function mint(
        address receiver,
        uint256 netSyDesired,
        uint256 netPtDesired
    ) external returns (uint256 netLpOut, uint256 netSyUsed, uint256 netPtUsed);

    function burn(
        address receiverSy,
        address receiverPt,
        uint256 netLpToBurn
    ) external returns (uint256 netSyOut, uint256 netPtOut);

    function swapExactPtForSy(
        address receiver,
        uint256 exactPtIn,
        bytes calldata data
    ) external returns (uint256 netSyOut, uint256 netSyFee);

    function swapSyForExactPt(
        address receiver,
        uint256 exactPtOut,
        bytes calldata data
    ) external returns (uint256 netSyIn, uint256 netSyFee);

    function redeemRewards(address user) external returns (uint256[] memory);

    function readState(address router) external view returns (MarketState memory market);

    function observe(uint32[] memory secondsAgos) external view returns (uint216[] memory lnImpliedRateCumulative);

    function increaseObservationsCardinalityNext(uint16 cardinalityNext) external;

    function readTokens() external view returns (IStandardizedYield _SY, IPPrincipalToken _PT, IPYieldToken _YT);

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

    function isExpired() external view returns (bool);

    function expiry() external view returns (uint256);

    function observations(
        uint256 index
    ) external view returns (uint32 blockTimestamp, uint216 lnImpliedRateCumulative, bool initialized);

    function _storage()
        external
        view
        returns (
            int128 totalPt,
            int128 totalSy,
            uint96 lastLnImpliedRate,
            uint16 observationIndex,
            uint16 observationCardinality,
            uint16 observationCardinalityNext
        );
}
"
    },
    "altitude-v2/node_modules/@pendle/core-v2/contracts/interfaces/IPPYLpOracle.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;

interface IPPYLpOracle {
    event SetBlockCycleNumerator(uint16 newBlockCycleNumerator);

    function getPtToAssetRate(address market, uint32 duration) external view returns (uint256);

    function getYtToAssetRate(address market, uint32 duration) external view returns (uint256);

    function getLpToAssetRate(address market, uint32 duration) external view returns (uint256);

    function getPtToSyRate(address market, uint32 duration) external view returns (uint256);

    function getYtToSyRate(address market, uint32 duration) external view returns (uint256);

    function getLpToSyRate(address market, uint32 duration) external view returns (uint256);

    function getOracleState(
        address market,
        uint32 duration
    )
        external
        view
        returns (bool increaseCardinalityRequired, uint16 cardinalityRequired, bool oldestObservationSatisfied);
}
"
    },
    "altitude-v2/node_modules/@pendle/core-v2/contracts/interfaces/IPRouterStatic.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;

import "./IPActionMarketAuxStatic.sol";
import "./IPActionMintRedeemStatic.sol";
import "./IPActionInfoStatic.sol";
import "./IPActionMarketCoreStatic.sol";
import "./IPActionVePendleStatic.sol";
import "./IPMiniDiamond.sol";
import "./IPActionStorageStatic.sol";

//solhint-disable-next-line no-empty-blocks
interface IPRouterStatic is
    IPActionMintRedeemStatic,
    IPActionInfoStatic,
    IPActionMarketAuxStatic,
    IPActionMarketCoreStatic,
    IPActionVePendleStatic,
    IPMiniDiamond,
    IPActionStorageStatic
{}
"
    },
    "altitude-v2/contracts/interfaces/internal/strategy/farming/IPendleFarmStrategy.sol": {
      "content": "// SPDX-License-Identifier: AGPL-3.0.
pragma solidity 0.8.28;

import "./IFarmStrategy.sol";

import "@pendle/core-v2/contracts/interfaces/IPAllActionV3.sol";
import "@pendle/core-v2/contracts/interfaces/IPMarket.sol";
import "@pendle/core-v2/contracts/interfaces/IPPYLpOracle.sol";
import "@pendle/core-v2/contracts/interfaces/IPRouterStatic.sol";

/**
 * @author Altitude Protocol
 **/

interface IPendleFarmStrategy is IFarmStrategy {
    function router() external view returns (IPAllActionV3);

    function routerStatic() external view returns (IPRouterStatic);

    function oracle() external view returns (IPPYLpOracle);

    function market() external view returns (IPMarket);

    function SY() external view returns (IStandardizedYield);

    function PT() external view returns (IPPrincipalToken);

    function YT() external view returns (IPYieldToken);

    function SLIPPAGE_BASE() external view returns (uint256);

    function slippage() external view returns (uint256);

    function twapDuration() external view returns (uint32);

    event SetTwapDuration(uint32 oldDuration, uint32 newDuration);
    event SetSlippage(uint256 oldSlippage, uint256 newSlippage);

    error PFS_ORACLE_CARDINALITY(uint16 cardinalityRequired);
    error PFS_ORACLE_UNPOPULATED();
    error PFS_SLIPPAGE(uint256 twapRate, uint256 currentRate);
    error PFS_MARKET_EXPIRED();
    error PFS_INVALID_SLIPPAGE();

    function setTwapDuration(uint32 twapDuration_) external;

    function setSlippage(uint256 slippage_) external;
}
"
    },
    "altitude-v2/node_modules/@openzeppelin/contracts/access/Ownable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}
"
    },
    "altitude-v2/contracts/strategies/farming/strategies/FarmStrategy.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

import "../../swap/SwapStrategyConfiguration.sol";
import "../../../libraries/uniswap-v3/TransferHelper.sol";
import "../../../interfaces/internal/access/IIngress.sol";
import "../../../interfaces/internal/vault/IVaultCore.sol";
import "../../../interfaces/internal/strategy/farming/IFarmStrategy.sol";
import "../../../interfaces/internal/strategy/farming/IFarmDispatcher.sol";

/**
 * @title FarmStrategy Contract
 * @author Altitude Labs
 **/

abstract contract FarmStrategy is Ownable, SwapStrategyConfiguration, IFarmStrategy {
    address public override asset; // baseAsset of farmDispatcher
    address public override farmAsset; // asset of the farm
    address public override farmDispatcher; // farmDispatcher address
    address[] public override rewardAssets; // reward tokens to recognise
    address public override rewardsRecipient; // where to send rewards

    modifier onlyDispatcher() {
        if (msg.sender != farmDispatcher) {
            revert FS_ONLY_DISPATCHER();
        }
        _;
    }

    /// @param farmAssetAddress The address of the token we are farming with
    /// @param farmDispatcherAddress The manager of the strategy
    /// @param rewardsAddress Where to send any reward tokens
    /// @param rewardAssets_ Reward tokens to recognise
    /// @param swapStrategyAddress Swap strategy needed in case farmAsset != baseAsset
    constructor(
        address farmAssetAddress,
        address farmDispatcherAddress,
        address rewardsAddress,
        address[] memory rewardAssets_,
        address swapStrategyAddress
    ) SwapStrategyConfiguration(swapStrategyAddress) {
        farmAsset = farmAssetAddress;
        farmDispatcher = farmDispatcherAddress;
        rewardsRecipient = rewardsAddress;
        rewardAssets = rewardAssets_;
        asset = IFarmDispatcher(farmDispatcher).asset();
    }

    /// @notice Sets the reward tokens to be recognised
    /// @param rewardAssets_ Token addresses
    function setRewardAssets(address[] memory rewardAssets_) external onlyOwner {
        emit SetRewardAssets(rewardAssets, rewardAssets_);

        rewardAssets = rewardAssets_;
    }

    /// @notice Deposits own funds into the Farm Provider
    /// @param amount amount to deposit
    function deposit(uint256 amount) public virtual override onlyDispatcher {
        if (amount > 0) {
            // Transfer funds from dispatcher
            TransferHelper.safeTransferFrom(asset, msg.sender, address(this), amount);

            _deposit(IERC20(asset).balanceOf(address(this)));

            emit Deposit(amount);
        }
    }

    /// @notice Withdraws from the Farm Provider
    /// @param amountRequested The amount to withdraw
    /// @return amountWithdrawn The amount actually withdrawn
    function withdraw(
        uint256 amountRequested
    ) public virtual override onlyDispatcher returns (uint256 amountWithdrawn) {
        if (amountRequested > 0) {
            // When trying to withdraw all
            if (amountRequested == type(uint256).max) {
                // balanceAvailable() skips the swap slippage check, as that will happen in the actual withdraw
                amountRequested = balanceAvailable();
            }

            _withdraw(amountRequested);
            amountWithdrawn = IERC20(asset).balanceOf(address(this));

            if (amountWithdrawn > 0) {
                TransferHelper.safeTransfer(asset, msg.sender, amountWithdrawn);
            }

            emit Withdraw(amountWithdrawn);
        }
    }

    /// @notice Withdraw everything from the farm with minimal constraints
    /// @dev Should be invoked via protected rpc
    /// @dev We may want to perform intermediate actions, so this is step one of a two step process
    /// @dev Step two is emergencySwap()
    function emergencyWithdraw() public virtual onlyOwner {
        _emergencyWithdraw();

        emit EmergencyWithdraw();
    }

    /// @notice Swap specified tokens to asset
    /// @param assets The assets to swap
    /// @return amountWithdrawn The amount withdrawn after swap
    function emergencySwap(
        address[] calldata assets
    ) public virtual override onlyOwner returns (uint256 amountWithdrawn) {
        _emergencySwap(assets);

        amountWithdrawn = IERC20(asset).balanceOf(address(this));
        TransferHelper.safeTransfer(asset, farmDispatcher, amountWithdrawn);

        emit EmergencySwap();
    }

    /// @notice Claim and swap reward tokens to base asset. Then transfer to the dispatcher for compounding
    /// @return rewards An amount of rewards being recognised
    function recogniseRewardsInBase() public virtual override returns (uint256 rewards) {
        _recogniseRewardsInBase();

        rewards = IERC20(asset).balanceOf(address(this));
        TransferHelper.safeTransfer(asset, rewardsRecipient, rewards);

        emit RewardsRecognition(rewards);
    }

    /// @notice Return the balance in borrow asset excluding rewards (includes slippage validations)
    /// @dev Reverts if slippage is too high
    /// @return balance that can be withdrawn from the farm
    function balance() public view virtual returns (uint256) {
        // Get amount of tokens
        uint256 farmAssetAmount = _getFarmAssetAmount();
        (uint256 totalBalance, uint256 swapAmount) = _balance(farmAssetAmount);

        if (swapAmount > 0) {
            // Validate slippage
            uint256 minimumAssetAmount = swapStrategy.getMinimumAmountOut(farmAsset, asset, farmAssetAmount);

            if (swapAmount < minimumAssetAmount) {
                // Amount is no good since slippage is too high.
                // @dev harvest() earnings calculation relies on .balance() so it is important to revert on a bad value
                revert SSC_SWAP_AMOUNT(minimumAssetAmount, swapAmount);
            }
        }

        return totalBalance;
    }

    /// @notice Return the balance in borrow asset excluding rewards (no slippage validations)
    /// @dev Function will not revert on high slippage, should used with care in transactions
    /// @return availableBalance Balance that can be withdrawn from the farm
    function balanceAvailable() public view virtual returns (uint256 availableBalance) {
        // No slippage validations
        (availableBalance, ) = _balance(_getFarmAssetAmount());
    }

    /// @notice Return the max amount that can be withdrawn at the moment
    /// @param farmAssetAmount The amount from the farm provider
    /// @return totalBalance The amount available to be withdrawn (including amount swapped)
    /// @return swapAmount Amount of totalBalance that is subject to swapping
    function _balance(
        uint256 farmAssetAmount
    ) internal view virtual returns (uint256 totalBalance, uint256 swapAmount) {
        totalBalance = IERC20(asset).balanceOf(address(this));
        if (farmAssetAmount > 0) {
            if (farmAsset == asset) {
                totalBalance += farmAssetAmount;
            } else {
                // amount of borrow asset we'd get if we swap
                swapAmount = swapStrategy.getAmountOut(farmAsset, asset, farmAssetAmount);

                totalBalance += swapAmount;
            }
        }
    }

    function _getFarmAssetAmount() internal view virtual returns (uint256);

    function _deposit(uint256 amount) internal virtual;

    function _withdraw(uint256 amount) internal virtual;

    function _emergencyWithdraw() internal virtual;

    function _recogniseRewardsInBase() internal virtual;

    /// @notice Swap assets to borrow asset
    /// @param assets Array of assets to swap
    function _emergencySwap(address[] calldata assets) internal virtual {
        for (uint256 i; i < assets.length; ++i) {
            _swap(assets[i], asset, type(uint256).max);
        }
    }

    /// @notice Swap between different assets
    /// @param inputAsset Input asset address
    /// @param outputAsset Output asset address
    /// @param amount Amount to swap
    function _swap(address inputAsset, address outputAsset, uint256 amount) internal virtual returns (uint256) {
        if (inputAsset != outputAsset) {
            if (amount == type(uint256).max) {
                amount = IERC20(inputAsset).balanceOf(address(this));
            }

            if (amount > 0) {
                TransferHelper.safeApprove(inputAsset, address(swapStrategy), amount);

                amount = swapStrategy.swapInBase(inputAsset, outputAsset, amount);
            }
        }

        return amount;
    }
}
"
    },
    "altitude-v2/contracts/interfaces/internal/strategy/farming/IFarmDropStrategy.sol": {
      "content": "// SPDX-License-Identifier: AGPL-3.0.
pragma solidity 0.8.28;

import "./IFarmStrategy.sol";

/**
 * @author Altitude Protocol
 **/
interface IFarmDropStrategy is IFarmStrategy {
    event ResetDropPercentage();

    error FDS_DROP_EXCEEDED(uint256 current, uint256 threshold);
    error FDS_OUT_OF_BOUNDS();

    function dropThreshold() external view returns (uint256);

    function dropPercentage() external view returns (uint256);

    function expectedBalance() external view returns (uint256);

    function currentDropPercentage() external view returns (uint256);

    function DROP_UNITS() external view returns (uint256);

    function setDropThreshold(uint256 dropThreshold_) external;

    function reset() external;
}
"
    },
    "altitude-v2/contracts/interfaces/internal/strategy/ISkimStrategy.sol": {
      "content": "// SPDX-License-Identifier: AGPL-3.0.
pragma solidity 0.8.28;

/**
 * @author Altitude Protocol
 **/

interface ISkimStrategy {
    /** @notice Emitted when an asset is not allowed for skim */
    error SK_NON_SKIM_ASSET();
    /** @notice Emitted when the receiver address is invalid */
    error SK_INVALID_RECEIVER();

    function nonSkimAssets(address asset) external view returns (bool);

    function skim(address[] calldata assets, address receiver) external;
}
"
    },
    "altitude-v2/node_modules/@pendle/core-v2/contracts/interfaces/IPActionAddRemoveLiqV3.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;

import "../router/math/MarketApproxLib.sol";
import "./IPAllActionTypeV3.sol";
import {IPAllEventsV3} from "./IPAllEventsV3.sol";

/// Refer to IPAllActionTypeV3.sol for details on the parameters
interface IPActionAddRemoveLiqV3 is IPAllEventsV3 {
    function addLiquidityDualTokenAndPt(
        address receiver,
        address market,
        TokenInput calldata input,
        uint256 netPtDesired,
        uint256 minLpOut
    ) external payable returns (uint256 netLpOut, uint256 netPtUsed, uint256 netSyInterm);

    function addLiquidityDualSyAndPt(
        address receiver,
        address market,
        uint256 netSyDesired,
        uint256 netPtDesired,
        uint256 minLpOut
    ) external returns (uint256 netLpOut, uint256 netSyUsed, uint256 netPtUsed);

    function addLiquiditySinglePt(
        address receiver,
        address market,
        uint256 netPtIn,
        uint256 minLpOut,
        ApproxParams calldata guessPtSwapToSy,
        LimitOrderData calldata limit
    ) external returns (uint256 netLpOut, uint256 netSyFee);

    function addLiquiditySingleToken(
        address receiver,
        address market,
        uint256 minLpOut,
        ApproxParams calldata guessPtReceivedFromSy,
        TokenInput calldata input,
        LimitOrderData calldata limit
    ) external payable returns (uint256 netLpOut, uint256 netSyFee, uint256 netSyInterm);

    function addLiquiditySingleSy(
        address receiver,
        address market,
        uint256 netSyIn,
        uint256 minLpOut,
        ApproxParams calldata guessPtReceivedFromSy,
        LimitOrderData calldata limit
    ) external returns (uint256 netLpOut, uint256 netSyFee);

    function addLiquiditySingleTokenKeepYt(
        address receiver,
        address market,
        uint256 minLpOut,
        uint256 minYtOut,
        TokenInput calldata input
    ) external payable returns (uint256 netLpOut, uint256 netYtOut, uint256 netSyMintPy, uint256 netSyInterm);

    function addLiquiditySingleSyKeepYt(
        address receiver,
        address market,
        uint256 netSyIn,
        uint256 minLpOut,
        uint256 minYtOut
    ) external returns (uint256 netLpOut, uint256 netYtOut, uint256 netSyMintPy);

    function removeLiquidityDualTokenAndPt(
        address receiver,
        address market,
        uint256 netLpToRemove,
        TokenOutput calldata output,
        uint256 minPtOut
    ) external returns (uint256 netTokenOut, uint256 netPtOut, uint256 netSyInterm);

    function removeLiquidityDualSyAndPt(
        address receiver,
        address market,
        uint256 netLpToRemove,
        uint256 minSyOut,
        uint256 minPtOut
    ) external returns (uint256 netSyOut, uint256 netPtOut);

    function removeLiquiditySinglePt(
        address receiver,
        address market,
        uint256 netLpToRemove,
        uint256 minPtOut,
        ApproxParams calldata guessPtReceivedFromSy,
        LimitOrderData calldata limit
    ) external returns (uint256 netPtOut, uint256 netSyFee);

    function removeLiquiditySingleToken(
        address receiver,
        address market,
        uint256 netLpToRemove,
        TokenOutput calldata output,
        LimitOrderData calldata limit
    ) external returns (uint256 netTokenOut, uint256 netSyFee, uint256 netSyInterm);

    function removeLiquiditySingleSy(
        address receiver,
        address market,
        uint256 netLpToRemove,
        uint256 minSyOut,
        LimitOrderData calldata limit
    ) external returns (uint256 netSyOut, uint256 netSyFee);
}
"
    },
    "altitude-v2/node_modules/@pendle/core-v2/contracts/interfaces/IPActionSwapPTV3.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;

import "../router/math/MarketApproxLib.sol";
import "./IPAllActionTypeV3.sol";
import {IPAllEventsV3} from "./IPAllEventsV3.sol";

/// Refer to IPAllActionTypeV3.sol for details on the parameters
interface IPActionSwapPTV3 is IPAllEventsV3 {
    function swapExactTokenForPt(
        address receiver,
        address market,
        uint256 minPtOut,
        ApproxParams calldata guessPtOut,
        TokenInput calldata input,
        LimitOrderData calldata limit
    ) external payable returns (uint256 netPtOut, uint256 netSyFee, uint256 netSyInterm);

    function swapExactSyForPt(
        address receiver,
        address market,
        uint256 exactSyIn,
        uint256 minPtOut,
        ApproxParams calldata guessPtOut,
        LimitOrderData calldata limit
    ) external returns (uint256 netPtOut, uint256 netSyFee);

    function swapExactPtForToken(
        address receiver,
        address market,
        uint256 exactPtIn,
        TokenOutput calldata output,
        LimitOrderData calldata limit
    ) external returns (uint256 netTokenOut, uint256 netSyFee, uint256 netSyInterm);

    function swapExactPtForSy(
        address receiver,
        address market,
        uint256 exactPtIn,
        uint256 minSyOut,
        LimitOrderData calldata limit
    ) external returns (uint256 netSyOut, uint256 netSyFee);
}
"
    },
    "altitude-v2/node_modules/@pendle/core-v2/contracts/interfaces/IPActionSwapYTV3.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;

import "../router/math/MarketApproxLib.sol";
import "./IPAllActionTypeV3.sol";
import {IPAllEventsV3} from "./IPAllEventsV3.sol";

/// Refer to IPAllActionTypeV3.sol for details on the parameters
interface IPActionSwapYTV3 is IPAllEventsV3 {
    function swapExactTokenForYt(
        address receiver,
        address market,
        uint256 minYtOut,
        ApproxParams calldata guessYtOut,
        TokenInput calldata input,
        LimitOrderData calldata limit
    ) external payable returns (uint256 netYtOut, uint256 netSyFee, uint256 netSyInterm);

    function swapExactSyForYt(
        address receiver,
        address market,
        uint256 exactSyIn,
        uint256 minYtOut,
        ApproxParams calldata guessYtOut,
        LimitOrderData calldata limit
    ) external returns (uint256 netYtOut, uint256 netSyFee);

    function swapExactYtForToken(
        address receiver,
        address market,
        uint256 exactYtIn,
        TokenOutput calldata output,
        LimitOrderData calldata limit
    ) external returns (uint256 netTokenOut, uint256 netSyFee, uint256 netSyInterm);

    function swapExactYtForSy(
        address receiver,
        address market,
        uint256 exactYtIn,
        uint256 minSyOut,
        LimitOrderData calldata limit
    ) external returns (uint256 netSyOut, uint256 netSyFee);

    function swapExactPtForYt(
        address receiver,
        address market,
        uint256 exactPtIn,
        uint256 minYtOut,
        ApproxParams calldata guessTotalPtToSwap
    ) external returns (uint256 netYtOut, uint256 netSyFee);

    function swapExactYtForPt(
        address receiver,
        address market,
        uint256 exactYtIn,
        uint256 minPtOut,
        ApproxParams calldata guessTotalPtFromSwap
    ) external returns (uint256 netPtOut, uint256 netSyFee);
}
"
    },
    "altitude-v2/node_modules/@pendle/core-v2/contracts/interfaces/IPActionMiscV3.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;

import "../router/math/MarketApproxLib.sol";
import "./IPAllActionTypeV3.sol";
import {IPAllEventsV3} from "./IPAllEventsV3.sol";
import "./IStandardizedYield.sol";
import "./IPMarket.sol";

/// Refer to IPAllActionTypeV3.sol for details on the parameters
interface IPActionMiscV3 is IPAllEventsV3 {
    struct Call3 {
        bool allowFailure;
        bytes callData;
    }

    struct Result {
        bool success;
        bytes returnData;
    }

    function mintSyFromToken(
        address receiver,
        address SY,
        uint256 minSyOut,
        TokenInput calldata input
    ) external payable returns (uint256 netSyOut);

    function redeemSyToToken(
        address receiver,
        address SY,
        uint256 netSyIn,
        TokenOutput calldata output
    ) external returns (uint256 netTokenOut);

    function mintPyFromToken(
        address receiver,
        address YT,
        uint256 minPyOut,
        TokenInput calldata input
    ) external payable returns (uint256 netPyOut, uint256 netSyInterm);

    function redeemPyToToken(
        address receiver,
        address YT,
        uint256 netPyIn,
        TokenOutput calldata output
    ) external returns (uint256 netTokenOut, uint256 netSyInterm);

    function mintPyFromSy(
        address receiver,
        address YT,
        uint256 netSyIn,
        uint256 minPyOut
    ) external returns (uint256 netPyOut);

    function redeemPyToSy(
        address receiver,
        address YT,
        uint256 netPyIn,
        uint256 minSyOut
    ) external returns (uint256 netSyOut);

    function redeemDueInterestAndRewards(
        address user,
        address[] calldata sys,
        address[] calldata yts,
        address[] calldata markets
    ) external;

    function redeemDueInterestAndRewardsV2(
        IStandardizedYield[] calldata SYs,
        RedeemYtIncomeToTokenStruct[] calldata YTs,
        IPMarket[] calldata markets,
        IPSwapAggregator pendleSwap,
        SwapDataExtra[] calldata swaps
    ) external returns (uint256[] memory netOutFromSwaps, uint256[] memory netInterests);

    function swapTokensToTokens(
        IPSwapAggregator pendleSwap,
        SwapDataExtra[] calldata swaps,
        uint256[] calldata netSwaps
    ) external payable returns (uint256[] memory netOutFromSwaps);

    function swapTokenToToken(
        address receiver,
        uint256 minTokenOut,
        TokenInput calldata inp
    ) external payable returns (uint256 netTokenOut);

    function swapTokenToTokenViaSy(
        address receiver,
        address SY,
        TokenInput calldata input,
        address tokenRedeemSy,
        uint256 minTokenOut
    ) external payable returns (uint256 netTokenOut, uint256 netSyInterm);

    function exitPreExpToToken(
        address receiver,
        address market,
        uint256 netPtIn,
        uint256 netYtIn,
        uint256 netLpIn,
        TokenOutput calldata output,
        LimitOrderData calldata limit
    ) external returns (uint256 netTokenOut, ExitPreExpReturnParams memory params);

    function exitPreExpToSy(
        address receiver,
        address market,
        uint256 netPtIn,
        uint256 netYtIn,
        uint256 netLpIn,
        uint256 minSyOut,
        LimitOrderData calldata limit
    ) external returns (ExitPreExpReturnParams memory params);

    function exitPostExpToToken(
        address receiver,
        address market,
        uint256 netPtIn,
        uint256 netLpIn,
        TokenOutput calldata output
    ) external returns (uint256 netTokenOut, ExitPostExpReturnParams memory params);

    function exitPostExpToSy(
        address receiver,
        address market,
        uint256 netPtIn,
        uint256 netLpIn,
        uint256 minSyOut
    ) external returns (ExitPostExpReturnParams memory params);

    function callAndReflect(
        address payable reflector,
        bytes calldata selfCall1,
        bytes calldata selfCall2,
        bytes calldata reflectCall
    ) external payable returns (bytes memory selfRes1, bytes memory selfRes2, bytes memory reflectRes);

    function boostMarkets(address[] memory markets) external;

    function multicall(Call3[] calldata calls) external payable returns (Result[] memory res);

    function simulate(address target, bytes calldata data) external payable;
}
"
    },
    "altitude-v2/node_modules/@pendle/core-v2/contracts/interfaces/IPActionCallbackV3.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;

import "./IPMarketSwapCallback.sol";
import "./IPLimitRouter.sol";

interface IPActionCallbackV3 is IPMarketSwapCallback, IPLimitRouterCallback {}
"
    },
    "altitude-v2/node_modules/@pendle/core-v2/contracts/interfaces/IPActionStorageV4.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;

import {IPAllEventsV3} from "./IPAllEventsV3.sol";

interface IPActionStorageV4 is IPAllEventsV3 {
    struct SelectorsToFacet {
        address facet;
        bytes4[] selectors;
    }

    function owner() external view returns (address);

    function pendingOwner() external view returns (address);

    function transferOwnership(address newOwner, bool direct, bool renounce) external;

    function claimOwnership() external;

    function setSelectorToFacets(SelectorsToFacet[] calldata arr) external;

    function selectorToFacet(bytes4 selector) external view returns (address);
}
"
    },
    "altitude-v2/node_modules/@pendle/core-v2/contracts/interfaces/IPActionSimple.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;

import {TokenInput} from "./IPAllActionTypeV3.sol";
import {IPAllEventsV3} from "./IPAllEventsV3.sol";
import "./IPAllActionTypeV3.sol";

/// All of these functions are for internal router use only and should not be called directly.
interface IPActionSimple is IPAllEventsV3 {
    function addLiquiditySinglePtSimple(
        address receiver,
        address market,
        uint256 netPtIn,
        uint256 minLpOut
    ) external returns (uint256 netLpOut, uint256 netSyFee);

    function addLiquiditySingleTokenSimple(
        address receiver,
        address market,
        uint256 minLpOut,
        TokenInput calldata input
    ) external payable returns (uint256 netLpOut, uint256 netSyFee, uint256 netSyInterm);

    function addLiquiditySingleSySimple(
        address receiver,
        address market,
        uint256 netSyIn,
        uint256 minLpOut
    ) external returns (uint256 netLpOut, uint256 netSyFee);

    function removeLiquiditySinglePtSimple(
        address receiver,
        address market,
        uint256 netLpToRemove,
        uint256 minPtOut
    ) external returns (uint256 netPtOut, uint256 netSyFee);

    function swapExactTokenForPtSimple(
        address receiver,
        address market,
        uint256 minPtOut,
        TokenInput calldata input
    ) external payable returns (uint256 netPtOut, uint256 netSyFee, uint256 netSyInterm);

    function swapExactSyForPtSimple(
        address receiver,
        address market,
        uint256 exactSyIn,
        uint256 minPtOut
    ) external returns (uint256 netPtOut, uint256 netSyFee);

    function swapExactTokenForYtSimple(
        address receiver,
        address market,
        uint256 minYtOut,
        TokenInput calldata input
    ) external payable returns (uint256 netYtOut, uint256 netSyFee, uint256 netSyInterm);

    function swapExactSyForYtSimple(
        address receiver,
        address market,
        uint256 exactSyIn,
        uint256 minYtOut
    ) external returns (uint256 netYtOut, uint256 netSyFee);
}
"
    },
    "altitude-v2/node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
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);
}
"
    },
    "altitude-v2/node_modules/@pendle/core-v2/contracts/interfaces/IPPrincipalToken.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/extensions/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);
}
"
    },
    "altitude-v2/node_modules/@pendle/core-v2/contracts/interfaces/IPYieldToken.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "./IRewardManager.sol";
import "./IPInterestManagerYT.sol";

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);

Tags:
ERC20, Multisig, Mintable, Burnable, Pausable, Swap, Liquidity, Yield, Upgradeable, Multi-Signature, Factory, Oracle|addr:0x371169180ed56d8297956ea9629fd91caf4b5b7f|verified:true|block:23425796|tx:0x4a115f50b8e2e42afbd4fdb16a8073b43ed773095ae07bd7d43b1dd9b078cfe2|first_check:1758723650

Submitted on: 2025-09-24 16:20:55

Comments

Log in to comment.

No comments yet.