InfinifiWithdrawalSubcompressor

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": {
    "contracts/compressors/subcompressors/withdrawal/InfinifiWithdrawalSubcompressor.sol": {
      "content": "// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundaiton, 2025.
pragma solidity ^0.8.23;

import {ICreditAccountV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditAccountV3.sol";
import {ICreditManagerV3} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditManagerV3.sol";

import {IWithdrawalSubcompressor} from "../../../interfaces/IWithdrawalSubcompressor.sol";
import {
    WithdrawalOutput,
    WithdrawableAsset,
    RequestableWithdrawal,
    ClaimableWithdrawal,
    PendingWithdrawal,
    WithdrawalLib
} from "../../../types/WithdrawalInfo.sol";
import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol";

import {InfinifiUnwindingGateway} from
    "@gearbox-protocol/integrations-v3/contracts/helpers/infinifi/InfinifiUnwindingGateway.sol";
import {InfinifiUnwindingPhantomToken} from
    "@gearbox-protocol/integrations-v3/contracts/helpers/infinifi/InfinifiUnwindingPhantomToken.sol";

import {
    IInfinifiLockingController,
    IInfinifiUnwindingModule,
    UnwindingPosition
} from "@gearbox-protocol/integrations-v3/contracts/integrations/infinifi/IInfinifiGateway.sol";
import {
    IInfinifiUnwindingGateway,
    UserUnwindingData
} from "@gearbox-protocol/integrations-v3/contracts/interfaces/infinifi/IInfinifiUnwindingGateway.sol";
import {IInfinifiGatewayAdapter} from
    "@gearbox-protocol/integrations-v3/contracts/interfaces/infinifi/IInfinifiGatewayAdapter.sol";
import {IInfinifiUnwindingGatewayAdapter} from
    "@gearbox-protocol/integrations-v3/contracts/interfaces/infinifi/IInfinifiUnwindingGatewayAdapter.sol";
import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol";

import {WAD} from "@gearbox-protocol/core-v3/contracts/libraries/Constants.sol";

contract InfinifiWithdrawalSubcompressor is IWithdrawalSubcompressor {
    using WithdrawalLib for PendingWithdrawal[];

    uint256 public constant version = 3_10;
    bytes32 public constant contractType = "GLOBAL::INFINIFI_WD_SC";

    uint256 internal constant EPOCH = 1 weeks;
    uint256 internal constant EPOCH_OFFSET = 3 days;

    function getWithdrawableAssets(address creditManager, address token)
        external
        view
        returns (WithdrawableAsset[] memory)
    {
        address infinifiUnwindingGateway = InfinifiUnwindingPhantomToken(token).infinifiUnwindingGateway();

        address asset = IInfinifiUnwindingGateway(infinifiUnwindingGateway).iUSD();

        address unwindingGatewayAdapter = ICreditManagerV3(creditManager).contractToAdapter(infinifiUnwindingGateway);

        address[] memory lockedTokens =
            IInfinifiUnwindingGatewayAdapter(unwindingGatewayAdapter).getAllowedLockedTokens();

        WithdrawableAsset[] memory withdrawableAssets = new WithdrawableAsset[](lockedTokens.length);

        for (uint256 i = 0; i < lockedTokens.length; i++) {
            uint32 unwindingEpochs =
                IInfinifiGatewayAdapter(unwindingGatewayAdapter).lockedTokenToUnwindingEpoch(lockedTokens[i]);
            withdrawableAssets[i] = WithdrawableAsset(
                lockedTokens[i], token, asset, _getClaimableAtFromCurrent(unwindingEpochs) - block.timestamp
            );
        }

        return withdrawableAssets;
    }

    function getCurrentWithdrawals(address creditAccount, address token)
        external
        view
        returns (ClaimableWithdrawal[] memory, PendingWithdrawal[] memory)
    {
        address infinifiUnwindingGateway = InfinifiUnwindingPhantomToken(token).infinifiUnwindingGateway();

        ClaimableWithdrawal[] memory claimableWithdrawals = new ClaimableWithdrawal[](1);
        claimableWithdrawals[0] = _getClaimableWithdrawal(creditAccount, token, infinifiUnwindingGateway);

        if (claimableWithdrawals[0].outputs.length == 0 || claimableWithdrawals[0].outputs[0].amount == 0) {
            claimableWithdrawals = new ClaimableWithdrawal[](0);
        }

        PendingWithdrawal[] memory pendingWithdrawals = _getPendingWithdrawals(creditAccount, infinifiUnwindingGateway);

        for (uint256 i = 0; i < pendingWithdrawals.length; ++i) {
            pendingWithdrawals[i].withdrawalPhantomToken = token;
        }

        return (claimableWithdrawals, pendingWithdrawals);
    }

    function getWithdrawalRequestResult(address creditAccount, address token, address withdrawalToken, uint256 amount)
        external
        view
        returns (RequestableWithdrawal memory requestableWithdrawal)
    {
        address infinifiUnwindingGateway = InfinifiUnwindingPhantomToken(withdrawalToken).infinifiUnwindingGateway();

        address unwindingGatewayAdapter = ICreditManagerV3(ICreditAccountV3(creditAccount).creditManager())
            .contractToAdapter(infinifiUnwindingGateway);

        uint32 unwindingEpochs = IInfinifiGatewayAdapter(unwindingGatewayAdapter).lockedTokenToUnwindingEpoch(token);

        if (unwindingEpochs == 0) {
            return requestableWithdrawal;
        }

        requestableWithdrawal.token = token;
        requestableWithdrawal.amountIn = amount;
        requestableWithdrawal.outputs = new WithdrawalOutput[](1);
        requestableWithdrawal.requestCalls = new MultiCall[](1);
        requestableWithdrawal.claimableAt = _getClaimableAtFromCurrent(unwindingEpochs);

        requestableWithdrawal.requestCalls[0] = MultiCall(
            address(unwindingGatewayAdapter),
            abi.encodeCall(IInfinifiUnwindingGatewayAdapter.startUnwinding, (amount, unwindingEpochs))
        );

        requestableWithdrawal.outputs[0] = WithdrawalOutput(withdrawalToken, true, 0);

        address lockingController = IInfinifiUnwindingGateway(infinifiUnwindingGateway).lockingController();

        uint256 exchangeRate = IInfinifiLockingController(lockingController).exchangeRate(unwindingEpochs);

        requestableWithdrawal.outputs[0].amount = amount * exchangeRate / WAD;

        return requestableWithdrawal;
    }

    function _getPendingWithdrawals(address creditAccount, address unwindingGateway)
        internal
        view
        returns (PendingWithdrawal[] memory pendingWithdrawals)
    {
        address asset = IInfinifiUnwindingGateway(unwindingGateway).iUSD();

        UserUnwindingData memory userUnwindingData =
            IInfinifiUnwindingGateway(unwindingGateway).getUserUnwindingData(creditAccount);

        if (userUnwindingData.unwindingTimestamp == 0) {
            return pendingWithdrawals;
        }

        if (
            block.timestamp
                < _getClaimableAtFromUnwindingPosition(unwindingGateway, userUnwindingData.unwindingTimestamp)
        ) {
            pendingWithdrawals = new PendingWithdrawal[](1);
            pendingWithdrawals[0].token = IInfinifiLockingController(
                IInfinifiUnwindingGateway(unwindingGateway).lockingController()
            ).shareToken(userUnwindingData.unwindingEpochs);
            pendingWithdrawals[0].expectedOutputs = new WithdrawalOutput[](1);
            pendingWithdrawals[0].expectedOutputs[0] = WithdrawalOutput(
                asset, false, InfinifiUnwindingGateway(unwindingGateway).getPendingAssets(creditAccount)
            );
            pendingWithdrawals[0].claimableAt =
                _getClaimableAtFromUnwindingPosition(unwindingGateway, userUnwindingData.unwindingTimestamp);
        }

        return pendingWithdrawals;
    }

    function _getClaimableWithdrawal(address creditAccount, address withdrawalToken, address unwindingGateway)
        internal
        view
        returns (ClaimableWithdrawal memory withdrawal)
    {
        address asset = IInfinifiUnwindingGateway(unwindingGateway).iUSD();

        UserUnwindingData memory userUnwindingData =
            IInfinifiUnwindingGateway(unwindingGateway).getUserUnwindingData(creditAccount);

        if (userUnwindingData.unwindingTimestamp == 0) {
            return withdrawal;
        }

        withdrawal.token = IInfinifiLockingController(IInfinifiUnwindingGateway(unwindingGateway).lockingController())
            .shareToken(userUnwindingData.unwindingEpochs);
        withdrawal.outputs = new WithdrawalOutput[](1);
        withdrawal.outputs[0] = WithdrawalOutput(asset, false, 0);

        if (userUnwindingData.isWithdrawn) {
            withdrawal.outputs[0].amount = userUnwindingData.unclaimedAssets;
        } else {
            uint256 pendingAssets = InfinifiUnwindingGateway(unwindingGateway).getPendingAssets(creditAccount);

            if (
                block.timestamp
                    < _getClaimableAtFromUnwindingPosition(unwindingGateway, userUnwindingData.unwindingTimestamp)
                    || pendingAssets == 0
            ) {
                return withdrawal;
            }

            withdrawal.outputs[0].amount = pendingAssets;
        }

        withdrawal.withdrawalPhantomToken = withdrawalToken;
        withdrawal.withdrawalTokenSpent = withdrawal.outputs[0].amount;

        withdrawal.claimCalls = new MultiCall[](1);

        address unwindingGatewayAdapter =
            ICreditManagerV3(ICreditAccountV3(creditAccount).creditManager()).contractToAdapter(unwindingGateway);

        withdrawal.claimCalls = new MultiCall[](1);

        withdrawal.claimCalls[0] = MultiCall(
            address(unwindingGatewayAdapter),
            abi.encodeCall(IInfinifiUnwindingGatewayAdapter.withdraw, (withdrawal.outputs[0].amount))
        );

        return withdrawal;
    }

    function _getClaimableAtFromUnwindingPosition(address unwindingGateway, uint256 unwindingTimestamp)
        internal
        view
        returns (uint256)
    {
        address unwindingModule = IInfinifiUnwindingGateway(unwindingGateway).unwindingModule();
        UnwindingPosition memory position =
            IInfinifiUnwindingModule(unwindingModule).positions(_unwindingId(unwindingGateway, unwindingTimestamp));

        uint32 claimableEpoch = position.toEpoch;

        return _timestampFromEpoch(claimableEpoch);
    }

    function _getClaimableAtFromCurrent(uint32 unwindingEpochs) internal view returns (uint256) {
        uint32 currentEpoch = _epochFromTimestamp(block.timestamp);
        return _timestampFromEpoch(unwindingEpochs + currentEpoch + 1);
    }

    function _epochFromTimestamp(uint256 timestamp) internal pure returns (uint32) {
        return uint32((timestamp - EPOCH_OFFSET) / EPOCH);
    }

    function _timestampFromEpoch(uint32 epoch) internal pure returns (uint256) {
        return uint256(epoch) * EPOCH + EPOCH_OFFSET;
    }

    function _unwindingId(address unwindingGateway, uint256 unwindingTimestamp) internal pure returns (bytes32) {
        return keccak256(abi.encode(unwindingGateway, unwindingTimestamp));
    }
}
"
    },
    "lib/@gearbox-protocol/core-v3/contracts/interfaces/ICreditAccountV3.sol": {
      "content": "// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.17;

import {IVersion} from "./base/IVersion.sol";

/// @title Credit account V3 interface
interface ICreditAccountV3 is IVersion {
    function factory() external view returns (address);

    function creditManager() external view returns (address);

    function safeTransfer(address token, address to, uint256 amount) external;

    function execute(address target, bytes calldata data) external returns (bytes memory result);

    function rescue(address target, bytes calldata data) external;
}
"
    },
    "lib/@gearbox-protocol/core-v3/contracts/interfaces/ICreditManagerV3.sol": {
      "content": "// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.17;

import {IVersion} from "./base/IVersion.sol";

/// @notice Debt management type
///         - `INCREASE_DEBT` borrows additional funds from the pool, updates account's debt and cumulative interest index
///         - `DECREASE_DEBT` repays debt components (quota interest and fees -> base interest and fees -> debt principal)
///           and updates all corresponding state variables (base interest index, quota interest and fees, debt).
///           When repaying all the debt, ensures that account has no enabled quotas.
enum ManageDebtAction {
    INCREASE_DEBT,
    DECREASE_DEBT
}

/// @notice Collateral/debt calculation mode
///         - `GENERIC_PARAMS` returns generic data like account debt and cumulative indexes
///         - `DEBT_ONLY` is same as `GENERIC_PARAMS` but includes more detailed debt info, like accrued base/quota
///           interest and fees
///         - `FULL_COLLATERAL_CHECK_LAZY` checks whether account is sufficiently collateralized in a lazy fashion,
///           i.e. it stops iterating over collateral tokens once TWV reaches the desired target.
///           Since it may return underestimated TWV, it's only available for internal use.
///         - `DEBT_COLLATERAL` is same as `DEBT_ONLY` but also returns total value and total LT-weighted value of
///           account's tokens, this mode is used during account liquidation
///         - `DEBT_COLLATERAL_SAFE_PRICES` is same as `DEBT_COLLATERAL` but uses safe prices from price oracle
enum CollateralCalcTask {
    GENERIC_PARAMS,
    DEBT_ONLY,
    FULL_COLLATERAL_CHECK_LAZY,
    DEBT_COLLATERAL,
    DEBT_COLLATERAL_SAFE_PRICES
}

struct CreditAccountInfo {
    uint256 debt;
    uint256 cumulativeIndexLastUpdate;
    uint128 cumulativeQuotaInterest;
    uint128 quotaFees;
    uint256 enabledTokensMask;
    uint16 flags;
    uint64 lastDebtUpdate;
    address borrower;
}

struct CollateralDebtData {
    uint256 debt;
    uint256 cumulativeIndexNow;
    uint256 cumulativeIndexLastUpdate;
    uint128 cumulativeQuotaInterest;
    uint256 accruedInterest;
    uint256 accruedFees;
    uint256 totalDebtUSD;
    uint256 totalValue;
    uint256 totalValueUSD;
    uint256 twvUSD;
    uint256 enabledTokensMask;
    uint256 quotedTokensMask;
    address[] quotedTokens;
    address _poolQuotaKeeper;
}

struct CollateralTokenData {
    address token;
    uint16 ltInitial;
    uint16 ltFinal;
    uint40 timestampRampStart;
    uint24 rampDuration;
}

interface ICreditManagerV3Events {
    /// @notice Emitted when new credit configurator is set
    event SetCreditConfigurator(address indexed newConfigurator);
}

/// @title Credit manager V3 interface
interface ICreditManagerV3 is IVersion, ICreditManagerV3Events {
    function pool() external view returns (address);

    function underlying() external view returns (address);

    function creditFacade() external view returns (address);

    function creditConfigurator() external view returns (address);

    function accountFactory() external view returns (address);

    function name() external view returns (string memory);

    // ------------------ //
    // ACCOUNT MANAGEMENT //
    // ------------------ //

    function openCreditAccount(address onBehalfOf) external returns (address);

    function closeCreditAccount(address creditAccount) external;

    function liquidateCreditAccount(
        address creditAccount,
        CollateralDebtData calldata collateralDebtData,
        address to,
        bool isExpired
    ) external returns (uint256 remainingFunds, uint256 loss);

    function manageDebt(address creditAccount, uint256 amount, uint256 enabledTokensMask, ManageDebtAction action)
        external
        returns (uint256 newDebt, uint256, uint256);

    function addCollateral(address payer, address creditAccount, address token, uint256 amount)
        external
        returns (uint256);

    function withdrawCollateral(address creditAccount, address token, uint256 amount, address to)
        external
        returns (uint256);

    function externalCall(address creditAccount, address target, bytes calldata callData)
        external
        returns (bytes memory result);

    function approveToken(address creditAccount, address token, address spender, uint256 amount) external;

    // -------- //
    // ADAPTERS //
    // -------- //

    function adapterToContract(address adapter) external view returns (address targetContract);

    function contractToAdapter(address targetContract) external view returns (address adapter);

    function execute(bytes calldata data) external returns (bytes memory result);

    function approveCreditAccount(address token, uint256 amount) external;

    function setActiveCreditAccount(address creditAccount) external;

    function getActiveCreditAccountOrRevert() external view returns (address creditAccount);

    // ----------------- //
    // COLLATERAL CHECKS //
    // ----------------- //

    function priceOracle() external view returns (address);

    function fullCollateralCheck(
        address creditAccount,
        uint256 enabledTokensMask,
        uint256[] calldata collateralHints,
        uint16 minHealthFactor,
        bool useSafePrices
    ) external returns (uint256);

    function isLiquidatable(address creditAccount, uint16 minHealthFactor) external view returns (bool);

    function calcDebtAndCollateral(address creditAccount, CollateralCalcTask task)
        external
        view
        returns (CollateralDebtData memory cdd);

    // ------ //
    // QUOTAS //
    // ------ //

    function poolQuotaKeeper() external view returns (address);

    function quotedTokensMask() external view returns (uint256);

    function updateQuota(address creditAccount, address token, int96 quotaChange, uint96 minQuota, uint96 maxQuota)
        external
        returns (uint256 tokensToEnable, uint256 tokensToDisable);

    // --------------------- //
    // CREDIT MANAGER PARAMS //
    // --------------------- //

    function maxEnabledTokens() external view returns (uint8);

    function fees()
        external
        view
        returns (
            uint16 feeInterest,
            uint16 feeLiquidation,
            uint16 liquidationDiscount,
            uint16 feeLiquidationExpired,
            uint16 liquidationDiscountExpired
        );

    function collateralTokensCount() external view returns (uint8);

    function getTokenMaskOrRevert(address token) external view returns (uint256 tokenMask);

    function getTokenByMask(uint256 tokenMask) external view returns (address token);

    function liquidationThresholds(address token) external view returns (uint16 lt);

    function ltParams(address token)
        external
        view
        returns (uint16 ltInitial, uint16 ltFinal, uint40 timestampRampStart, uint24 rampDuration);

    function collateralTokenByMask(uint256 tokenMask)
        external
        view
        returns (address token, uint16 liquidationThreshold);

    // ------------ //
    // ACCOUNT INFO //
    // ------------ //

    function creditAccountInfo(address creditAccount)
        external
        view
        returns (
            uint256 debt,
            uint256 cumulativeIndexLastUpdate,
            uint128 cumulativeQuotaInterest,
            uint128 quotaFees,
            uint256 enabledTokensMask,
            uint16 flags,
            uint64 lastDebtUpdate,
            address borrower
        );

    function getBorrowerOrRevert(address creditAccount) external view returns (address borrower);

    function flagsOf(address creditAccount) external view returns (uint16);

    function setFlagFor(address creditAccount, uint16 flag, bool value) external;

    function enabledTokensMaskOf(address creditAccount) external view returns (uint256);

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

    function creditAccounts(uint256 offset, uint256 limit) external view returns (address[] memory);

    function creditAccountsLen() external view returns (uint256);

    // ------------- //
    // CONFIGURATION //
    // ------------- //

    function addToken(address token) external;

    function setCollateralTokenData(
        address token,
        uint16 ltInitial,
        uint16 ltFinal,
        uint40 timestampRampStart,
        uint24 rampDuration
    ) external;

    function setFees(
        uint16 feeInterest,
        uint16 feeLiquidation,
        uint16 liquidationDiscount,
        uint16 feeLiquidationExpired,
        uint16 liquidationDiscountExpired
    ) external;

    function setContractAllowance(address adapter, address targetContract) external;

    function setCreditFacade(address creditFacade) external;

    function setPriceOracle(address priceOracle) external;

    function setCreditConfigurator(address creditConfigurator) external;
}
"
    },
    "contracts/interfaces/IWithdrawalSubcompressor.sol": {
      "content": "// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2025.
pragma solidity ^0.8.23;

import {IVersion} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IVersion.sol";
import {
    WithdrawableAsset,
    RequestableWithdrawal,
    ClaimableWithdrawal,
    PendingWithdrawal
} from "../types/WithdrawalInfo.sol";

interface IWithdrawalSubcompressor is IVersion {
    function getWithdrawableAssets(address creditManager, address token)
        external
        view
        returns (WithdrawableAsset[] memory);

    function getCurrentWithdrawals(address creditAccount, address token)
        external
        view
        returns (ClaimableWithdrawal[] memory, PendingWithdrawal[] memory);

    function getWithdrawalRequestResult(address creditAccount, address token, address withdrawalToken, uint256 amount)
        external
        view
        returns (RequestableWithdrawal memory);
}
"
    },
    "contracts/types/WithdrawalInfo.sol": {
      "content": "// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2025.
pragma solidity ^0.8.23;

import {MultiCall} from "@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol";

struct WithdrawalOutput {
    address token;
    bool isDelayed;
    uint256 amount;
}

struct WithdrawableAsset {
    address token;
    address withdrawalPhantomToken;
    address underlying;
    uint256 withdrawalLength;
}

struct RequestableWithdrawal {
    address token;
    uint256 amountIn;
    WithdrawalOutput[] outputs;
    MultiCall[] requestCalls;
    uint256 claimableAt;
}

struct ClaimableWithdrawal {
    address token;
    address withdrawalPhantomToken;
    uint256 withdrawalTokenSpent;
    WithdrawalOutput[] outputs;
    MultiCall[] claimCalls;
}

struct PendingWithdrawal {
    address token;
    address withdrawalPhantomToken;
    WithdrawalOutput[] expectedOutputs;
    uint256 claimableAt;
}

library WithdrawalLib {
    function push(WithdrawableAsset[] memory w, WithdrawableAsset memory asset)
        internal
        pure
        returns (WithdrawableAsset[] memory)
    {
        WithdrawableAsset[] memory newWithdrawableAssets = new WithdrawableAsset[](w.length + 1);
        for (uint256 i = 0; i < w.length; i++) {
            newWithdrawableAssets[i] = w[i];
        }
        newWithdrawableAssets[w.length] = asset;
        return newWithdrawableAssets;
    }

    function concat(WithdrawableAsset[] memory w0, WithdrawableAsset[] memory w1)
        internal
        pure
        returns (WithdrawableAsset[] memory)
    {
        WithdrawableAsset[] memory newWithdrawableAssets = new WithdrawableAsset[](w0.length + w1.length);
        for (uint256 i = 0; i < w0.length; i++) {
            newWithdrawableAssets[i] = w0[i];
        }
        for (uint256 i = 0; i < w1.length; i++) {
            newWithdrawableAssets[w0.length + i] = w1[i];
        }
        return newWithdrawableAssets;
    }

    function concat(RequestableWithdrawal[] memory w0, RequestableWithdrawal[] memory w1)
        internal
        pure
        returns (RequestableWithdrawal[] memory)
    {
        RequestableWithdrawal[] memory withdrawals = new RequestableWithdrawal[](w0.length + w1.length);
        for (uint256 i = 0; i < w0.length; i++) {
            withdrawals[i] = w0[i];
        }
        for (uint256 i = 0; i < w1.length; i++) {
            withdrawals[w0.length + i] = w1[i];
        }
        return withdrawals;
    }

    function push(ClaimableWithdrawal[] memory w, ClaimableWithdrawal memory withdrawal)
        internal
        pure
        returns (ClaimableWithdrawal[] memory)
    {
        ClaimableWithdrawal[] memory newClaimableWithdrawals = new ClaimableWithdrawal[](w.length + 1);
        for (uint256 i = 0; i < w.length; i++) {
            newClaimableWithdrawals[i] = w[i];
        }
        newClaimableWithdrawals[w.length] = withdrawal;
        return newClaimableWithdrawals;
    }

    function concat(ClaimableWithdrawal[] memory w0, ClaimableWithdrawal[] memory w1)
        internal
        pure
        returns (ClaimableWithdrawal[] memory)
    {
        ClaimableWithdrawal[] memory withdrawals = new ClaimableWithdrawal[](w0.length + w1.length);
        for (uint256 i = 0; i < w0.length; i++) {
            withdrawals[i] = w0[i];
        }
        for (uint256 i = 0; i < w1.length; i++) {
            withdrawals[w0.length + i] = w1[i];
        }
        return withdrawals;
    }

    function push(PendingWithdrawal[] memory w, PendingWithdrawal memory withdrawal)
        internal
        pure
        returns (PendingWithdrawal[] memory)
    {
        PendingWithdrawal[] memory newPendingWithdrawals = new PendingWithdrawal[](w.length + 1);
        for (uint256 i = 0; i < w.length; i++) {
            newPendingWithdrawals[i] = w[i];
        }
        newPendingWithdrawals[w.length] = withdrawal;
        return newPendingWithdrawals;
    }

    function concat(PendingWithdrawal[] memory w0, PendingWithdrawal[] memory w1)
        internal
        pure
        returns (PendingWithdrawal[] memory)
    {
        PendingWithdrawal[] memory withdrawals = new PendingWithdrawal[](w0.length + w1.length);
        for (uint256 i = 0; i < w0.length; i++) {
            withdrawals[i] = w0[i];
        }
        for (uint256 i = 0; i < w1.length; i++) {
            withdrawals[w0.length + i] = w1[i];
        }
        return withdrawals;
    }

    function filterEmpty(PendingWithdrawal[] memory pendingWithdrawals)
        internal
        pure
        returns (PendingWithdrawal[] memory)
    {
        PendingWithdrawal[] memory filteredPendingWithdrawals = new PendingWithdrawal[](0);
        for (uint256 i = 0; i < pendingWithdrawals.length; i++) {
            if (pendingWithdrawals[i].expectedOutputs.length > 0) {
                for (uint256 j = 0; j < pendingWithdrawals[i].expectedOutputs.length; j++) {
                    if (pendingWithdrawals[i].expectedOutputs[j].amount > 0) {
                        filteredPendingWithdrawals = push(filteredPendingWithdrawals, pendingWithdrawals[i]);
                        break;
                    }
                }
            }
        }

        return filteredPendingWithdrawals;
    }

    function filterEmpty(ClaimableWithdrawal[] memory claimableWithdrawals)
        internal
        pure
        returns (ClaimableWithdrawal[] memory)
    {
        ClaimableWithdrawal[] memory filteredClaimableWithdrawals = new ClaimableWithdrawal[](0);
        for (uint256 i = 0; i < claimableWithdrawals.length; i++) {
            if (claimableWithdrawals[i].outputs.length > 0) {
                for (uint256 j = 0; j < claimableWithdrawals[i].outputs.length; j++) {
                    if (claimableWithdrawals[i].outputs[j].amount > 0) {
                        filteredClaimableWithdrawals = push(filteredClaimableWithdrawals, claimableWithdrawals[i]);
                        break;
                    }
                }
            }
        }

        return filteredClaimableWithdrawals;
    }
}
"
    },
    "lib/@gearbox-protocol/core-v3/contracts/interfaces/ICreditFacadeV3.sol": {
      "content": "// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.17;

import {AllowanceAction} from "./ICreditConfiguratorV3.sol";
import "./ICreditFacadeV3Multicall.sol";
import {IACLTrait} from "./base/IACLTrait.sol";
import {PriceUpdate} from "./base/IPriceFeedStore.sol";
import {IVersion} from "./base/IVersion.sol";

/// @notice Multicall element
/// @param target Call target, which is either credit facade or adapter
/// @param callData Call data
struct MultiCall {
    address target;
    bytes callData;
}

/// @notice Debt limits packed into a single slot
/// @param minDebt Minimum debt amount per credit account
/// @param maxDebt Maximum debt amount per credit account
struct DebtLimits {
    uint128 minDebt;
    uint128 maxDebt;
}

/// @notice Collateral check params
/// @param collateralHints Optional array of token masks to check first to reduce the amount of computation
///        when known subset of account's collateral tokens covers all the debt
/// @param minHealthFactor Min account's health factor in bps in order not to revert
struct FullCheckParams {
    uint256[] collateralHints;
    uint16 minHealthFactor;
}

interface ICreditFacadeV3Events {
    /// @notice Emitted when a new credit account is opened
    event OpenCreditAccount(
        address indexed creditAccount, address indexed onBehalfOf, address indexed caller, uint256 referralCode
    );

    /// @notice Emitted when account is closed
    event CloseCreditAccount(address indexed creditAccount, address indexed borrower);

    /// @notice Emitted when account is liquidated
    event LiquidateCreditAccount(
        address indexed creditAccount, address indexed liquidator, address to, uint256 remainingFunds
    );

    /// @notice Emitted when account is partially liquidated
    event PartiallyLiquidateCreditAccount(
        address indexed creditAccount,
        address indexed token,
        address indexed liquidator,
        uint256 repaidDebt,
        uint256 seizedCollateral,
        uint256 fee
    );

    /// @notice Emitted when collateral is added to account
    event AddCollateral(address indexed creditAccount, address indexed token, uint256 amount);

    /// @notice Emitted when collateral is withdrawn from account
    event WithdrawCollateral(address indexed creditAccount, address indexed token, uint256 amount, address to);

    /// @notice Emitted when a multicall is started
    event StartMultiCall(address indexed creditAccount, address indexed caller);

    /// @notice Emitted when phantom token is withdrawn by account
    event WithdrawPhantomToken(address indexed creditAccount, address indexed token, uint256 amount);

    /// @notice Emitted when a call from account to an external contract is made during a multicall
    event Execute(address indexed creditAccount, address indexed targetContract);

    /// @notice Emitted when a multicall is finished
    event FinishMultiCall();
}

/// @title Credit facade V3 interface
interface ICreditFacadeV3 is IVersion, IACLTrait, ICreditFacadeV3Events {
    function creditManager() external view returns (address);

    function underlying() external view returns (address);

    function treasury() external view returns (address);

    function priceFeedStore() external view returns (address);

    function degenNFT() external view returns (address);

    function weth() external view returns (address);

    function botList() external view returns (address);

    function maxDebtPerBlockMultiplier() external view returns (uint8);

    function maxQuotaMultiplier() external view returns (uint256);

    function expirable() external view returns (bool);

    function expirationDate() external view returns (uint40);

    function debtLimits() external view returns (uint128 minDebt, uint128 maxDebt);

    function lossPolicy() external view returns (address);

    function forbiddenTokenMask() external view returns (uint256);

    // ------------------ //
    // ACCOUNT MANAGEMENT //
    // ------------------ //

    function openCreditAccount(address onBehalfOf, MultiCall[] calldata calls, uint256 referralCode)
        external
        payable
        returns (address creditAccount);

    function closeCreditAccount(address creditAccount, MultiCall[] calldata calls) external payable;

    function liquidateCreditAccount(
        address creditAccount,
        address to,
        MultiCall[] calldata calls,
        bytes memory lossPolicyData
    ) external;

    function liquidateCreditAccount(address creditAccount, address to, MultiCall[] calldata calls) external;

    function partiallyLiquidateCreditAccount(
        address creditAccount,
        address token,
        uint256 repaidAmount,
        uint256 minSeizedAmount,
        address to,
        PriceUpdate[] calldata priceUpdates
    ) external returns (uint256 seizedAmount);

    function multicall(address creditAccount, MultiCall[] calldata calls) external payable;

    function botMulticall(address creditAccount, MultiCall[] calldata calls) external;

    // ------------- //
    // CONFIGURATION //
    // ------------- //

    function setExpirationDate(uint40 newExpirationDate) external;

    function setDebtLimits(uint128 newMinDebt, uint128 newMaxDebt, uint8 newMaxDebtPerBlockMultiplier) external;

    function setLossPolicy(address newLossPolicy) external;

    function setTokenAllowance(address token, AllowanceAction allowance) external;

    function pause() external;

    function unpause() external;
}
"
    },
    "lib/@gearbox-protocol/integrations-v3/contracts/helpers/infinifi/InfinifiUnwindingGateway.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.23;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IVersion} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IVersion.sol";
import {SanityCheckTrait} from "@gearbox-protocol/core-v3/contracts/traits/SanityCheckTrait.sol";

import {
    IInfinifiGateway,
    IInfinifiLockingController,
    IInfinifiUnwindingModule,
    UnwindingPosition
} from "../../integrations/infinifi/IInfinifiGateway.sol";

import {IInfinifiUnwindingGateway, UserUnwindingData} from "../../interfaces/infinifi/IInfinifiUnwindingGateway.sol";

/// @title Infinifi Withdrawal Gateway
contract InfinifiUnwindingGateway is IInfinifiUnwindingGateway {
    bytes32 public constant override contractType = "GATEWAY::INFINIFI_UNWINDING";
    uint256 public constant override version = 3_10;

    uint256 internal constant EPOCH = 1 weeks;
    uint256 internal constant EPOCH_OFFSET = 3 days;

    address public immutable iUSD;

    address public immutable infinifiGateway;

    address public immutable lockingController;

    address public immutable unwindingModule;

    uint256 public lastUnwindingTimestamp;

    mapping(address => UserUnwindingData) internal userToUnwindingData;

    constructor(address _infinifiGateway) {
        infinifiGateway = _infinifiGateway;
        iUSD = IInfinifiGateway(infinifiGateway).getAddress("receiptToken");
        lockingController = IInfinifiGateway(infinifiGateway).getAddress("lockingController");
        unwindingModule = IInfinifiLockingController(lockingController).unwindingModule();
    }

    function startUnwinding(uint256 shares, uint32 unwindingEpochs) external {
        if (block.timestamp == lastUnwindingTimestamp) revert MoreThanOneUnwindingPerBlockException();

        UserUnwindingData storage userUnwindingData = userToUnwindingData[msg.sender];
        if (userUnwindingData.unwindingTimestamp != 0) revert UserAlreadyUnwindingException();

        address lockedToken = IInfinifiLockingController(lockingController).shareToken(unwindingEpochs);

        IERC20(lockedToken).transferFrom(msg.sender, address(this), shares);
        IERC20(lockedToken).approve(infinifiGateway, shares);

        userUnwindingData.shares = shares;
        userUnwindingData.unwindingTimestamp = block.timestamp;
        userUnwindingData.isWithdrawn = false;
        userUnwindingData.unwindingEpochs = unwindingEpochs;
        lastUnwindingTimestamp = block.timestamp;

        IInfinifiGateway(infinifiGateway).startUnwinding(shares, unwindingEpochs);
    }

    function withdraw(uint256 amount) external {
        UserUnwindingData memory userUnwindingData = userToUnwindingData[msg.sender];
        if (userUnwindingData.unwindingTimestamp == 0) revert UserNotUnwindingException();

        uint256 claimableTimestamp = _getClaimableTimestamp(userUnwindingData);

        if (block.timestamp < claimableTimestamp) revert UnwindingNotClaimableException();

        if (!userUnwindingData.isWithdrawn) {
            uint256 balanceBefore = IERC20(iUSD).balanceOf(address(this));
            IInfinifiGateway(infinifiGateway).withdraw(userUnwindingData.unwindingTimestamp);
            userUnwindingData.isWithdrawn = true;
            userUnwindingData.unclaimedAssets = IERC20(iUSD).balanceOf(address(this)) - balanceBefore;
        }

        uint256 pendingAssets = _getPendingAssets(userUnwindingData);
        if (pendingAssets < amount) revert InsufficientPendingAssetsException();

        userUnwindingData.unclaimedAssets -= amount;
        IERC20(iUSD).transfer(msg.sender, amount);

        if (userUnwindingData.unclaimedAssets <= 1) {
            userUnwindingData.unwindingTimestamp = 0;
            userUnwindingData.shares = 0;
            userUnwindingData.unclaimedAssets = 0;
            userUnwindingData.unwindingEpochs = 0;
            userUnwindingData.isWithdrawn = false;
        }

        userToUnwindingData[msg.sender] = userUnwindingData;
    }

    function getPendingAssets(address user) public view returns (uint256) {
        return _getPendingAssets(userToUnwindingData[user]);
    }

    function getUserUnwindingData(address user) external view returns (UserUnwindingData memory) {
        return userToUnwindingData[user];
    }

    function _getPendingAssets(UserUnwindingData memory userUnwindingData) internal view returns (uint256) {
        if (userUnwindingData.unwindingTimestamp == 0) return 0;

        return userUnwindingData.isWithdrawn
            ? userUnwindingData.unclaimedAssets
            : IInfinifiUnwindingModule(unwindingModule).balanceOf(address(this), userUnwindingData.unwindingTimestamp);
    }

    function _getClaimableTimestamp(UserUnwindingData memory userUnwindingData) internal view returns (uint256) {
        UnwindingPosition memory position =
            IInfinifiUnwindingModule(unwindingModule).positions(_unwindingId(userUnwindingData.unwindingTimestamp));

        uint256 claimableEpoch = position.toEpoch;

        return claimableEpoch * EPOCH + EPOCH_OFFSET;
    }

    function _unwindingId(uint256 unwindingTimestamp) internal view returns (bytes32) {
        return keccak256(abi.encode(address(this), unwindingTimestamp));
    }
}
"
    },
    "lib/@gearbox-protocol/integrations-v3/contracts/helpers/infinifi/InfinifiUnwindingPhantomToken.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.23;

import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {PhantomERC20} from "../PhantomERC20.sol";
import {IPhantomToken} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IPhantomToken.sol";
import {IInfinifiUnwindingGateway} from "../../interfaces/infinifi/IInfinifiUnwindingGateway.sol";

/// @title Infinifi Unwinding phantom token
/// @notice Phantom ERC-20 token that represents the balance of the pending and claimable withdrawals in Infinifi Unwinding Gateway
contract InfinifiUnwindingPhantomToken is PhantomERC20, Ownable, IPhantomToken {
    event SetClaimer(address indexed claimer);

    error SubvaultClaimerMismatchException();

    bytes32 public constant override contractType = "PHANTOM_TOKEN::INFINIFI_UNWIND";

    uint256 public constant override version = 3_10;

    address public immutable infinifiUnwindingGateway;

    /// @notice Constructor
    /// @param _infinifiUnwindingGateway The Infinifi Unwinding Gateway where the pending assets are tracked
    constructor(address _infinifiUnwindingGateway)
        PhantomERC20(
            IInfinifiUnwindingGateway(_infinifiUnwindingGateway).iUSD(),
            "Infinifi Unwinding iUSD",
            "wdiUSD",
            IERC20Metadata(IInfinifiUnwindingGateway(_infinifiUnwindingGateway).iUSD()).decimals()
        )
    {
        infinifiUnwindingGateway = _infinifiUnwindingGateway;
    }

    /// @notice Returns the amount of assets pending/claimable for withdrawal
    /// @param account The account for which the calculation is performed
    function balanceOf(address account) public view returns (uint256 balance) {
        return IInfinifiUnwindingGateway(infinifiUnwindingGateway).getPendingAssets(account);
    }

    /// @notice Returns phantom token's target contract and underlying
    function getPhantomTokenInfo() external view override returns (address, address) {
        return (infinifiUnwindingGateway, underlying);
    }

    function serialize() external view override returns (bytes memory) {
        return abi.encode(infinifiUnwindingGateway, underlying);
    }
}
"
    },
    "lib/@gearbox-protocol/integrations-v3/contracts/integrations/infinifi/IInfinifiGateway.sol": {
      "content": "// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.23;

struct UnwindingPosition {
    uint256 shares;
    uint32 fromEpoch;
    uint32 toEpoch;
    uint256 fromRewardWeight;
    uint256 rewardWeightDecrease;
}

interface IInfinifiGateway {
    function mint(address to, uint256 amount) external;

    function stake(address to, uint256 amount) external;

    function unstake(address to, uint256 amount) external;

    function createPosition(uint256 amount, uint32 unwindingEpochs, address recipient) external;

    function startUnwinding(uint256 shares, uint32 unwindingEpochs) external;

    function withdraw(uint256 unwindingTimestamp) external;

    function redeem(address to, uint256 amount, uint256 minAssetsOut) external;

    function claimRedemption() external;

    function getAddress(string memory name) external view returns (address);
}

interface IInfinifiMintController {
    function receiptToken() external view returns (address);

    function assetToReceipt(uint256 _assetAmount) external view returns (uint256);
}

interface IInfinifiLockingController {
    function getEnabledBuckets() external view returns (uint32[] memory);

    function shareToken(uint32 unwindingEpochs) external view returns (address);

    function unwindingModule() external view returns (address);

    function exchangeRate(uint32 unwindingEpochs) external view returns (uint256);
}

interface IInfinifiUnwindingModule {
    function balanceOf(address user, uint256 unwindingTimestamp) external view returns (uint256);

    function positions(bytes32 id) external view returns (UnwindingPosition memory);
}

interface IInfinifiRedeemController {
    function receiptToAsset(uint256 amount) external view returns (uint256);

    function accounting() external view returns (address);
}

interface IInfinifiAccounting {
    function totalAssetsOf(address asset, uint256 farmType) external view returns (uint256);
}
"
    },
    "lib/@gearbox-protocol/integrations-v3/contracts/interfaces/infinifi/IInfinifiUnwindingGateway.sol": {
      "content": "// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2025.
pragma solidity ^0.8.23;

import {IVersion} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IVersion.sol";

struct UserUnwindingData {
    uint256 shares;
    uint32 unwindingEpochs;
    uint256 unwindingTimestamp;
    uint256 unclaimedAssets;
    bool isWithdrawn;
}

interface IInfinifiUnwindingGatewayExceptions {
    /// @notice Thrown when a user attempts a second unwinding in the same block
    error MoreThanOneUnwindingPerBlockException();

    /// @notice Thrown when a user attempts to start unwinding while already unwinding
    error UserAlreadyUnwindingException();

    /// @notice Thrown when a user attempts to withdraw while not unwinding
    error UserNotUnwindingException();

    /// @notice Thrown when a user attempts to withdraw an unwinding that is not claimable
    error UnwindingNotClaimableException();

    /// @notice Thrown when a user attempts to withdraw an unwinding for more assets than are pending
    error InsufficientPendingAssetsException();
}

interface IInfinifiUnwindingGateway is IVersion, IInfinifiUnwindingGatewayExceptions {
    function iUSD() external view returns (address);

    function lockingController() external view returns (address);

    function unwindingModule() external view returns (address);

    function getUserUnwindingData(address user) external view returns (UserUnwindingData memory);

    function startUnwinding(uint256 shares, uint32 unwindingEpochs) external;

    function withdraw(uint256 unwindingTimestamp) external;

    function getPendingAssets(address user) external view returns (uint256);
}
"
    },
    "lib/@gearbox-protocol/integrations-v3/contracts/interfaces/infinifi/IInfinifiGatewayAdapter.sol": {
      "content": "// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2025.
pragma solidity ^0.8.23;

import {IAdapter} from "@gearbox-protocol/core-v3/contracts/interfaces/base/IAdapter.sol";

struct LockedTokenStatus {
    address lockedToken;
    uint32 unwindingEpochs;
    bool allowed;
}

interface IInfinifiGatewayEvents {
    event SetLockedTokenStatus(address lockedToken, uint32 unwindingEpochs, bool allowed);
}

interface IInfinifiGatewayExceptions {
    /// @notice Thrown when the passed unwinding epochs for the locked token do not match actual unwinding epochs in Infinifi
    error LockedTokenUnwindingEpochsMismatchException();

    /// @notice Thrown when the locked token is not allowed
    error LockedTokenNotAllowedException();
}

/// @title Infinifi Gateway adapter interface
interface IInfinifiGatewayAdapter is IAdapter, IInfinifiGatewayExceptions, IInfinifiGatewayEvents {
    function usdc() external view returns (address);

    function iusd() external view returns (address);

    function siusd() external view returns (address);

    function lockedTokenToUnwindingEpoch(address lockedToken) external view returns (uint32);

    function mint(address to, uint256 amount) external returns (bool useSafePrices);

    function mintDiff(uint256 leftoverAmount) external returns (bool useSafePrices);

    function stake(address to, uint256 amount) external returns (bool useSafePrices);

    function stakeDiff(uint256 leftoverAmount) external returns (bool useSafePrices);

    function unstake(address to, uint256 amount) external returns (bool useSafePrices);

    function unstakeDiff(uint256 leftoverAmount) external returns (bool useSafePrices);

    function createPosition(uint256 amount, uint32 unwindingEpochs) external returns (bool useSafePrices);

    function createPositionDiff(uint256 leftoverAmount, uint32 unwindingEpochs) external returns (bool useSafePrices);

    function redeem(address to, uint256 amount, uint256 minAssetsOut) external returns (bool useSafePrices);

    function redeemDiff(uint256 leftoverAmount, uint256 minRateRAY) external returns (bool useSafePrices);

    function claimRedemption() external returns (bool useSafePrices);

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

    function setLockedTokenBatchStatus(LockedTokenStatus[] calldata lockedTokens) external;
}
"
    },
    "lib/@gearbox-protocol/integrations-v3/contracts/interfaces/infinifi/IInfinifiUnwindingGatewayAdapter.sol": {
      "content": "// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2025.
pragma solidity ^0.8.23;

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

struct LockedTokenStatus {
    address lockedToken;
    uint32 unwindingEpochs;
    bool allowed;
}

interface IInfinifiGatewayEvents {
    event SetLockedTokenStatus(address lockedToken, uint32 unwindingEpochs, bool allowed);
}

interface IInfinifiGatewayExceptions {
    /// @notice Thrown when the passed unwinding epochs for the locked token do not match actual unwinding epochs in Infinifi
    error LockedTokenUnwindingEpochsMismatchException();

    /// @notice Thrown when the locked token is not allowed
    error LockedTokenNotAllowedException();
}

interface IInfinifiUnwindingGatewayAdapter is
    IPhantomTokenAdapter,
    IInfinifiGatewayExceptions,
    IInfinifiGatewayEvents
{
    function lockedTokenToUnwindingEpoch(address lockedToken) external view returns (uint32);

    function startUnwinding(uint256 shares, uint32 unwindingEpochs) external returns (bool);

    function withdraw(uint256 amount) external returns (bool);

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

    function setLockedTokenBatchStatus(LockedTokenStatus[] calldata lockedTokens) external;
}
"
    },
    "lib/@openzeppelin/contracts/interfaces/IERC4626.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC4626.sol)

pragma solidity ^0.8.0;

import "../token/ERC20/IERC20.sol";
import "../token/ERC20/extensions/IERC20Metadata.sol";

/**
 * @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in
 * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].
 *
 * _Available since v4.7._
 */
interface IERC4626 is IERC20, IERC20Metadata {
    event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);

    event Withdraw(
        address indexed sender,
        address indexed receiver,
        address indexed owner,
        uint256 assets,
        uint256 shares
    );

    /**
     * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
     *
     * - MUST be an ERC-20 token contract.
     * - MUST NOT revert.
     */
    function asset() external view returns (address assetTokenAddress);

    /**
     * @dev Returns the total amount of the underlying asset that is “managed” by Vault.
     *
     * - SHOULD include any compounding that occurs from yield.
     * - MUST be inclusive of any fees that are charged against assets in the Vault.
     * - MUST NOT revert.
     */
    function totalAssets() external view returns (uint256 totalManagedAssets);

    /**
     * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal
     * scenario where all the conditions are met.
     *
     * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
     * - MUST NOT show any variations depending on the caller.
     * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
     * - MUST NOT revert.
     *
     * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
     * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
     * from.
     */
    function convertToShares(uint256 assets) external view returns (uint256 shares);

    /**
     * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal
     * scenario where all the conditions are met.
     *
     * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
     * - MUST NOT show any variations depending on the caller.
     * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
     * - MUST NOT revert.
     *
     * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
     * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
     * from.
     */
    function convertToAssets(uint256 shares) external view returns (uint256 assets);

    /**
     * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
     * through a deposit call.
     *
     * - MUST return a limited value if receiver is subject to some deposit limit.
     * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
     * - MUST NOT revert.
     */
    function maxDeposit(address receiver) external view returns (uint256 maxAssets);

    /**
     * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
     * current on-chain conditions.
     *
     * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
     *   call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
     *   in the same transaction.
     * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
     *   deposit would be accepted, regardless if the user has enough tokens approved, etc.
     * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
     * - MUST NOT revert.
     *
     * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
     * share price or some other type of condition, meaning the depositor will lose assets by depositing.
     */
    function previewDeposit(uint256 assets) external view returns (uint256 shares);

    /**
     * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.
     *
     * - MUST emit the Deposit event.
     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
     *   deposit execution, and are accounted for during deposit.
     * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not
     *   approving enough underlying tokens to the Vault contract, etc).
     *
     * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
     */
    function deposit(uint256 assets, address receiver) external returns (uint256 shares);

    /**
     * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
     * - MUST return a limited value if receiver is subject to some mint limit.
     * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
     * - MUST NOT revert.
     */
    function maxMint(address receiver) external view returns (uint256 maxShares);

    /**
     * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
     * current on-chain conditions.
     *
     * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
     *   in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the
     *   same transaction.
     * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
     *   would be accepted, regardless if the user has enough tokens approved, etc.
     * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
     * - MUST NOT revert.
     *
     * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
     * share price or some other type of condition, meaning the depositor will lose assets by minting.
     */
    function previewMint(uint256 shares) external view returns (uint256 assets);

    /**
     * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
     *
     * - MUST emit the Deposit event.
     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint
     *   execution, and are accounted for during mint.
     * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not
     *   approving enough underlying tokens to the Vault contract, etc).
     *
     * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
     */
    function mint(uint256 shares, address receiver) external returns (uint256 assets);

    /**
     * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
     * Vault, through a withdraw call.
     *
     * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
     * - MUST NOT revert.
     */
    function maxWithdraw(address owner) external view returns (uint256 maxAssets);

    /**
     * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
     * given current on-chain conditions.
     *
     * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw
     *   call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if
     *   called
     *   in the same transaction.
     * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though
     *   the withdrawal would be accepted, regardless if the user has enough shares, etc.
     * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
     * - MUST NOT revert.
     *
     * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
     * share price or some other type of condition, meaning the depositor will lose assets by depositing.
     */
    function previewWithdraw(uint256 assets) external view returns (uint256 shares);

    /**
     * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.
     *
     * - MUST emit the Withdraw event.
     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
     *   withdraw execution, and are accounted for during withdraw.
     * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
     *   not having enough shares, etc).
     *
     * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
     * Those methods should be performed separately.
     */
    function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);

    /**
     * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,
     * through a redeem call.
     *
     * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
     * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.
     * - MUST NOT revert.
     */
    function maxRedeem(address owner) external view returns (uint256 maxShares);

    /**
     * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,
     * given current on-chain conditions.
     *
     * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call
     *   in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the
     *   same transaction.
     * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the
     *   redemption would be accepted, regardless if the user has enough shares, etc.
     * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
     * - MUST NOT revert.
     *
     * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in
     * share price or some other type of condition, meaning the depositor will lose assets by redeeming.
     */
    function previewRedeem(uint256 shares) external view returns (uint256 assets);

    /**
     * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.
     *
     * - MUST emit the Withdraw event.
     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
     *   redeem execution, and are accounted for during redeem.
     * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner
     *   not having enough shares, etc).
     *
     * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
     * Those methods should be performed separately.
     */
    function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
}
"
    },
    "lib/@gearbox-protocol/core-v3/contracts/libraries/Constants.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.17;

bytes32 constant AP_GEAR_TOKEN = "GLOBAL::GEAR_TOKEN";
bytes32 constant AP_INSTANCE_MANAGER_PROXY = "INSTANCE_MANAGER_PROXY";
bytes32 constant AP_CROSS_CHAIN_GOVERNANCE_PROXY = "CROSS_CHAIN_GOVERNANCE_PROXY";
bytes32 constant AP_PRICE_FEED_STORE = "PRICE_FEED_STORE";
uint256 constant NO_VERSION_CONTROL = 0;

uint256 constant WAD = 1e18;
uint256 constant RAY = 1e27;
uint16 constant PERCENTAGE_FACTOR = 1e4;

uint256 constant SECONDS_PER_YEAR = 365 days;
uint256 constant EPOCH_LENGTH = 7 days;
uint256 constant FIRST_EPOCH_TIMESTAMP = 1702900800;
uint256 constant EPOCHS_TO_WITHDRAW = 4;

uint8 constant MAX_SANE_ENABLED_TOKENS = 20;
uint256 constant MAX_SANE_EPOCH_LENGTH = 28 days;
uint256 constant MAX_SANE_ACTIVE_BOTS = 5;

uint8 constant MAX_WITHDRAW_FEE = 100;

uint8 constant DEFAULT_LIMIT_PER_BLOCK_MULTIPLIER = 2;

uint8 constant BOT_PERMISSIONS_SET_FLAG = 1;

uint256 constant UNDERLYING_TOKEN_MASK = 1;

address constant INACTIVE_CREDIT_ACCOUNT_ADDRESS = address(1);
"
    },
    "lib/@gearbox-protocol/core-v3/contracts/interfaces/base/IVersion.sol": {
      "content": "// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2024.
pragma solidity ^0.8.17;

/// @title Version interface
/// @notice Defines contract version and type
interface IVersion {
    /// @notice Contract version
    function version() external view returns (uint256);

    /// @notice Contract type
    function contractType() external view returns (bytes32);
}
"
    },
    "lib/@gearbox-protocol/core-v3/contracts/interfaces/ICreditConfiguratorV3.sol": {
      "content": "//

Tags:
ERC20, Multisig, Mintable, Pausable, Swap, Staking, Yield, Upgradeable, Multi-Signature, Factory, Oracle|addr:0xce15eafd9034de14b2bc17e56dc45fc423da7385|verified:true|block:23524229|tx:0xe575bb3cd4a8d97e7ffd1ab865592c50f0426f14e8a79c5285b1d9a5bb80f554|first_check:1759829467

Submitted on: 2025-10-07 11:31:08

Comments

Log in to comment.

No comments yet.