Cuentas
0xd9...b57b
0xd9...b57B

0xd9...b57B

$500
¡El código fuente de este contrato está verificado!
Metadatos del Contrato
Compilador
0.8.19+commit.7dd6d404
Idioma
Solidity
Código Fuente del Contrato
Archivo 1 de 8: Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     *
     * Furthermore, `isContract` will also return true if the target contract within
     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
     * which only has an effect at the end of a transaction.
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}
Código Fuente del Contrato
Archivo 2 de 8: Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}
Código Fuente del Contrato
Archivo 3 de 8: CurveDepositZap.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.19;

import "Ownable.sol";
import "SafeERC20.sol";
import "IVault.sol";

interface ICurveToken {
    function minter() external view returns (address);
}

interface ICurvePool {
    function remove_liquidity_one_coin(
        uint256 _burn_amount,
        int128 i,
        uint256 _min_received
    ) external returns (uint256);

    function calc_withdraw_one_coin(uint256 _burn_amount, int128 i) external view returns (uint256);

    function coins(uint256 arg0) external view returns (address);

    function balances(uint256 i) external view returns (uint256);
}

interface ICurvePoolV2 {
    function remove_liquidity_one_coin(
        uint256 _burn_amount,
        uint256 i,
        uint256 _min_received
    ) external returns (uint256);

    function gamma() external view returns (uint256);

    // changed interface only appears to be used in 2-coin v2 pools
    function calc_token_amount(uint256[2] calldata amounts) external view returns (uint256);

    function calc_withdraw_one_coin(uint256 _burn_amount, uint256 i) external view returns (uint256);
}

interface ICurvePool2 is ICurvePool {
    function add_liquidity(uint256[2] calldata _amounts, uint256 _min_mint_amount) external returns (uint256);

    function remove_liquidity(uint256 _burn_amount, uint256[2] calldata _min_amounts) external;

    function calc_token_amount(uint256[2] calldata _amounts, bool _is_deposit) external view returns (uint256);
}

interface ICurvePool3 is ICurvePool {
    function add_liquidity(uint256[3] calldata _amounts, uint256 _min_mint_amount) external returns (uint256);

    function remove_liquidity(uint256 _burn_amount, uint256[3] calldata _min_amounts) external;

    function calc_token_amount(uint256[3] calldata _amounts, bool _is_deposit) external view returns (uint256);
}

interface ICurvePool4 is ICurvePool {
    function add_liquidity(uint256[4] calldata _amounts, uint256 _min_mint_amount) external returns (uint256);

    function remove_liquidity(uint256 _burn_amount, uint256[4] calldata _min_amounts) external;

    function calc_token_amount(uint256[4] calldata _amounts, bool _is_deposit) external view returns (uint256);
}

interface ICurvePoolNg {
    function N_COINS() external view returns (uint256);

    function add_liquidity(uint256[] calldata amounts, uint256 min_mint_amount) external returns (uint256);

    function remove_liquidity(uint256 burn_amount, uint256[] calldata min_amounts) external;

    function calc_token_amount(uint256[] calldata amounts, bool is_deposit) external view returns (uint256);
}

interface IDepositToken {
    function emissionId() external view returns (uint256);

    function lpToken() external view returns (address);

    function deposit(address receiver, uint256 amount) external returns (bool);

    function withdraw(address receiver, uint256 amount) external returns (bool);
}

/**
    @title PRISMA Curve Deposit Zap
    @notice Deposits tokens into Curve and stakes LP tokens into Curve/Convex via Prisma
    @dev Integrating Curve is difficult because of a lack of standard interfaces. This zap
         appears to work today, but there is no guarantee it will work tomorrow.
 */
contract CurveDepositZap is Ownable {
    using SafeERC20 for IERC20;

    struct CurvePool {
        address pool;
        bool isMetapool;
        bool isCryptoswap;
        bool isStableNg;
        address[] coins;
    }

    IPrismaVault public immutable vault;

    mapping(address lpToken => CurvePool) poolData;
    mapping(address depositToken => address lpToken) depositTokenToLpToken;

    event PoolAdded(address pool, address lpToken, bool isMetapool, bool isCryptoswap, address[] coins);
    event DepositTokenRegistered(address depositToken, address pool);

    constructor(IPrismaVault _vault, address[2][] memory _basePools) {
        vault = _vault;
        for (uint i = 0; i < _basePools.length; i++) {
            addCurvePool(_basePools[i][0], _basePools[i][1]);
        }
    }

    /**
        @notice Get an array of coins used in `depositToken`
        @dev Arrays for `amounts` or `minReceived` correspond to the returned coins
     */
    function getCoins(address depositToken) public view returns (address[] memory coins) {
        (, CurvePool memory pool) = _getDepositTokenData(depositToken);

        if (!pool.isMetapool) {
            return pool.coins;
        }
        CurvePool memory basePool = poolData[pool.coins[1]];
        coins = new address[](basePool.coins.length + 1);
        coins[0] = pool.coins[0];
        for (uint i = 1; i < coins.length; i++) {
            coins[i] = basePool.coins[i - 1];
        }
        return coins;
    }

    /**
        @notice Get the expected amount of LP tokens returned when adding
                liquidity to `depositToken`
        @dev Used to calculate `minReceived` when calling `addLiquidity`
     */
    function getAddLiquidityReceived(address depositToken, uint256[] memory amounts) external view returns (uint256) {
        (, CurvePool memory pool) = _getDepositTokenData(depositToken);

        if (pool.isMetapool) {
            CurvePool memory basePool = poolData[pool.coins[1]];
            require(amounts.length == basePool.coins.length + 1, "Incorrect amounts.length");
            bool isBaseDeposit;
            for (uint i = 1; i < amounts.length; i++) {
                if (amounts[i] > 0) {
                    isBaseDeposit = true;
                    break;
                }
            }
            if (isBaseDeposit) {
                amounts[1] = _calcTokenAmount(basePool, 1, amounts);
            } else {
                amounts[1] = 0;
            }
        } else {
            require(amounts.length == pool.coins.length, "Incorrect amounts.length");
        }
        return _calcTokenAmount(pool, 0, amounts);
    }

    function _calcTokenAmount(
        CurvePool memory pool,
        uint256 i,
        uint256[] memory amounts
    ) internal view returns (uint256) {
        uint256 numCoins = pool.coins.length;

        if (pool.isStableNg) {
            return ICurvePoolNg(pool.pool).calc_token_amount(amounts, true);
        }
        if (numCoins == 2) {
            if (pool.isCryptoswap) {
                return ICurvePoolV2(pool.pool).calc_token_amount([amounts[i], amounts[i + 1]]);
            } else {
                return ICurvePool2(pool.pool).calc_token_amount([amounts[i], amounts[i + 1]], true);
            }
        }
        if (numCoins == 3) {
            return ICurvePool3(pool.pool).calc_token_amount([amounts[i], amounts[i + 1], amounts[i + 2]], true);
        }
        if (numCoins == 4) {
            return
                ICurvePool4(pool.pool).calc_token_amount(
                    [amounts[i], amounts[i + 1], amounts[i + 2], amounts[i + 3]],
                    true
                );
        }
        // should be impossible to get here
        revert();
    }

    /**
        @notice Get the expected amount of coins returned when removing
                liquidity from `depositToken`
        @dev Used to calculate `minReceived` when calling `removeLiquidity`
     */
    function getRemoveLiquidityReceived(
        address depositToken,
        uint256 burnAmount
    ) external view returns (uint256[] memory received) {
        (address lpToken, CurvePool memory pool) = _getDepositTokenData(depositToken);

        if (pool.isMetapool) {
            CurvePool memory basePool = poolData[pool.coins[1]];
            uint256 length = basePool.coins.length;
            received = new uint256[](length + 1);
            uint256 supply = IERC20(lpToken).totalSupply();
            received[0] = (ICurvePool(pool.pool).balances(0) * burnAmount) / supply;

            burnAmount = (ICurvePool(pool.pool).balances(1) * burnAmount) / supply;
            supply = IERC20(pool.coins[1]).totalSupply();
            for (uint i = 0; i < length; i++) {
                received[i + 1] = (ICurvePool(basePool.pool).balances(i) * burnAmount) / supply;
            }
            return received;
        } else {
            uint256 length = pool.coins.length;
            received = new uint256[](length);
            uint256 supply = IERC20(lpToken).totalSupply();
            for (uint i = 0; i < length; i++) {
                received[i] = (ICurvePool(pool.pool).balances(i) * burnAmount) / supply;
            }
            return received;
        }
    }

    /**
        @notice Get the expected amount of coins returned when removing
                liquidity one-sided from `depositToken`
        @dev Used to calculate `minReceived` when calling `removeLiquidityOneCoin`
     */
    function getRemoveLiquidityOneCoinReceived(
        address depositToken,
        uint256 burnAmount,
        uint256 index
    ) external view returns (uint256) {
        (, CurvePool memory pool) = _getDepositTokenData(depositToken);

        if (index != 0 && pool.isMetapool) {
            if (pool.isCryptoswap) {
                burnAmount = ICurvePoolV2(pool.pool).calc_withdraw_one_coin(burnAmount, 1);
            } else {
                burnAmount = ICurvePool(pool.pool).calc_withdraw_one_coin(burnAmount, 1);
            }
            pool = poolData[pool.coins[1]];
            index -= 1;
        }
        if (pool.isCryptoswap) {
            return ICurvePoolV2(pool.pool).calc_withdraw_one_coin(burnAmount, index);
        } else {
            return ICurvePool(pool.pool).calc_withdraw_one_coin(burnAmount, int128(int256(index)));
        }
    }

    /**
        @notice For emergencies if someone accidentally sent some ERC20 tokens here
     */
    function recoverERC20(IERC20 token, uint256 amount) external onlyOwner {
        token.safeTransfer(msg.sender, amount);
    }

    /**
        @notice Owner-only method to add data about a curve pool
        @dev Pools used as bases for metapools must be added this way prior to
             the metapool being added, otherwise things could break strangely.
     */
    function addCurvePool(address pool, address lpToken) public onlyOwner {
        _addPoolData(pool, lpToken);
    }

    /**
        @notice Register a deposit token
        @dev Also called the first time liquidity is added or removed via the zap,
             this method is only needed to ensure the view methods work prior.
     */
    function registerDepositToken(address depositToken) external {
        require(depositTokenToLpToken[depositToken] == address(0), "Already registered");
        _getDepositTokenDataWrite(depositToken);
    }

    /**
        @dev Fetch data about the Curve pool related to `depositToken`
     */
    function _getDepositTokenData(address depositToken) internal view returns (address lpToken, CurvePool memory pd) {
        lpToken = IDepositToken(depositToken).lpToken();
        address pool = _getPoolFromLpToken(lpToken);
        return (lpToken, _getPoolData(pool));
    }

    /**
        @dev Non-view version of `_getDepositTokenData`. The first call for each
             `depositToken` stores data locally and sets required token approvals.
     */
    function _getDepositTokenDataWrite(address depositToken) internal returns (CurvePool memory pd) {
        address lpToken = depositTokenToLpToken[depositToken];
        if (lpToken != address(0)) return poolData[lpToken];

        lpToken = IDepositToken(depositToken).lpToken();
        depositTokenToLpToken[depositToken] = lpToken;
        pd = poolData[lpToken];

        //address pool = poolData[lpToken].pool;
        if (pd.pool == address(0)) {
            uint256 id = IDepositToken(depositToken).emissionId();
            (address receiver, ) = vault.idToReceiver(id);
            require(receiver == depositToken, "receiver != depositToken");

            pd = _addPoolData(_getPoolFromLpToken(lpToken), lpToken);
        }
        IERC20(lpToken).safeApprove(depositToken, type(uint256).max);
        emit DepositTokenRegistered(depositToken, pd.pool);
        return pd;
    }

    function _addPoolData(address pool, address lpToken) internal returns (CurvePool memory pd) {
        pd = _getPoolData(pool);
        for (uint i = 0; i < pd.coins.length; i++) {
            IERC20(pd.coins[i]).safeApprove(pd.pool, type(uint256).max);
        }
        poolData[lpToken] = pd;
        emit PoolAdded(pd.pool, lpToken, pd.isMetapool, pd.isCryptoswap, pd.coins);
        return pd;
    }

    function _getPoolData(address pool) internal view returns (CurvePool memory pd) {
        pd.pool = pool;
        address[] memory coins = new address[](4);
        uint256 i;
        for (; i < 4; i++) {
            try ICurvePool(pool).coins(i) returns (address _coin) {
                coins[i] = _coin;
            } catch {
                assembly {
                    mstore(coins, i)
                }
                break;
            }
        }
        pd.coins = coins;
        address lastCoin = coins[i - 1];
        address basePool = poolData[lastCoin].pool;
        if (basePool != address(0)) pd.isMetapool = true;
        try ICurvePoolV2(pool).gamma() returns (uint256) {
            pd.isCryptoswap = true;
        } catch {
            try ICurvePoolNg(pool).N_COINS() returns (uint256) {
                pd.isStableNg = true;
            } catch {}
        }
        return pd;
    }

    function _getPoolFromLpToken(address lpToken) internal view returns (address pool) {
        try ICurveToken(lpToken).minter() returns (address _pool) {
            pool = _pool;
        } catch {
            pool = lpToken;
        }
        return pool;
    }

    /**
        @notice Add liquidity to Curve and stake LP tokens via `depositToken`
        @param depositToken Address of Prisma `CurveDepositToken` or `ConvexDepositToken` deployment
        @param amounts Array of coin amounts to deposit into Curve
        @param minReceived Minimum amount of Curve LP tokens received when adding liquidity
        @param receiver Address to deposit into Prisma on behalf of
        @return lpTokenAmount Amount of LP tokens deposited into `depositToken`
     */
    function addLiquidity(
        address depositToken,
        uint256[] memory amounts,
        uint256 minReceived,
        address receiver
    ) external returns (uint256 lpTokenAmount) {
        CurvePool memory pool = _getDepositTokenDataWrite(depositToken);
        if (amounts[0] > 0) IERC20(pool.coins[0]).safeTransferFrom(msg.sender, address(this), amounts[0]);

        if (pool.isMetapool) {
            CurvePool memory basePool = poolData[pool.coins[1]];
            uint256 length = basePool.coins.length + 1;
            require(amounts.length == length, "Incorrect amounts.length");
            bool isBaseDeposit;
            for (uint i = 1; i < length; i++) {
                if (amounts[i] > 0) {
                    isBaseDeposit = true;
                    IERC20(basePool.coins[i - 1]).safeTransferFrom(msg.sender, address(this), amounts[i]);
                }
            }
            if (isBaseDeposit) {
                amounts[1] = _addLiquidity(basePool, length - 1, 1, amounts, 0);
            } else {
                amounts[1] = 0;
            }
        } else {
            uint256 length = pool.coins.length;
            require(amounts.length == length, "Incorrect amounts.length");
            for (uint i = 1; i < length; i++) {
                if (amounts[i] > 0) {
                    IERC20(pool.coins[i]).safeTransferFrom(msg.sender, address(this), amounts[i]);
                }
            }
        }
        lpTokenAmount = _addLiquidity(pool, pool.coins.length, 0, amounts, minReceived);

        IDepositToken(depositToken).deposit(receiver, lpTokenAmount);

        return lpTokenAmount;
    }

    function _addLiquidity(
        CurvePool memory pool,
        uint256 numCoins,
        uint256 i,
        uint256[] memory amounts,
        uint256 minReceived
    ) internal returns (uint256) {
        if (pool.isStableNg) {
            return ICurvePoolNg(pool.pool).add_liquidity(amounts, minReceived);
        }
        if (numCoins == 2) {
            return ICurvePool2(pool.pool).add_liquidity([amounts[i], amounts[i + 1]], minReceived);
        }
        if (numCoins == 3) {
            return ICurvePool3(pool.pool).add_liquidity([amounts[i], amounts[i + 1], amounts[i + 2]], minReceived);
        }
        if (numCoins == 4) {
            return
                ICurvePool4(pool.pool).add_liquidity(
                    [amounts[i], amounts[i + 1], amounts[i + 2], amounts[i + 3]],
                    minReceived
                );
        }
        // should be impossible to get here
        revert();
    }

    /**
        @notice Withdraw LP tokens from `depositToken` and remove liquidity from Curve
        @param depositToken Address of Prisma `CurveDepositToken` or `ConvexDepositToken` deployment
        @param burnAmount Amount of Curve LP tokens to withdraw
        @param minReceived Minimum coin amounts received when removing liquidity
        @param receiver Address to send withdrawn coins to
        @return received Array of withdrawn coin amounts
     */
    function removeLiquidity(
        address depositToken,
        uint256 burnAmount,
        uint256[] calldata minReceived,
        address receiver
    ) external returns (uint256[] memory received) {
        CurvePool memory pool = _getDepositTokenDataWrite(depositToken);

        IERC20(depositToken).transferFrom(msg.sender, address(this), burnAmount);
        IDepositToken(depositToken).withdraw(address(this), burnAmount);

        if (pool.isMetapool) return _removeLiquidityMeta(pool, burnAmount, minReceived, receiver);
        else return _removeLiquidityPlain(pool, burnAmount, minReceived, receiver);
    }

    function _removeLiquidityMeta(
        CurvePool memory pool,
        uint256 burnAmount,
        uint256[] calldata minReceived,
        address receiver
    ) internal returns (uint256[] memory) {
        CurvePool memory basePool = poolData[pool.coins[1]];
        uint256 length = basePool.coins.length;
        require(minReceived.length == length + 1, "Incorrect minReceived.length");
        uint256[] memory received = new uint256[](length + 1);

        _removeLiquidity(pool, 2, burnAmount);

        IERC20 coin = IERC20(pool.coins[0]);
        uint256 amount = coin.balanceOf(address(this));
        require(amount >= minReceived[0], "Slippage");
        coin.safeTransfer(receiver, amount);
        received[0] = amount;

        burnAmount = IERC20(pool.coins[1]).balanceOf(address(this));
        _removeLiquidity(basePool, length, burnAmount);

        for (uint i = 0; i < length; i++) {
            coin = IERC20(basePool.coins[i]);
            amount = coin.balanceOf(address(this));
            require(amount >= minReceived[i + 1], "Slippage");
            coin.safeTransfer(receiver, amount);
            received[i + 1] = amount;
        }
        return received;
    }

    function _removeLiquidityPlain(
        CurvePool memory pool,
        uint256 burnAmount,
        uint256[] calldata minReceived,
        address receiver
    ) internal returns (uint256[] memory) {
        uint length = pool.coins.length;
        require(minReceived.length == length, "Incorrect minReceived.length");
        uint256[] memory received = new uint256[](length);

        _removeLiquidity(pool, length, burnAmount);

        for (uint i = 0; i < length; i++) {
            IERC20 coin = IERC20(pool.coins[i]);
            uint256 amount = coin.balanceOf(address(this));
            require(amount >= minReceived[i], "Slippage");
            coin.safeTransfer(receiver, amount);
            received[i] = amount;
        }
        return received;
    }

    function _removeLiquidity(CurvePool memory pool, uint256 numCoins, uint256 burnAmount) internal {
        if (pool.isStableNg) {
            ICurvePoolNg(pool.pool).remove_liquidity(burnAmount, new uint256[](numCoins));
        } else if (numCoins == 2) {
            ICurvePool2(pool.pool).remove_liquidity(burnAmount, [uint256(0), uint256(0)]);
        } else if (numCoins == 3) {
            ICurvePool3(pool.pool).remove_liquidity(burnAmount, [uint256(0), uint256(0), uint256(0)]);
        } else if (numCoins == 4) {
            ICurvePool4(pool.pool).remove_liquidity(burnAmount, [uint256(0), uint256(0), uint256(0), uint256(0)]);
        }
    }

    /**
        @notice Withdraw LP tokens from `depositToken` and remove liquidity from Curve single-sided
        @param depositToken Address of Prisma `CurveDepositToken` or `ConvexDepositToken` deployment
        @param burnAmount Amount of Curve LP tokens to withdraw
        @param index Index of coin to withdraw (from `getCoins`)
        @param minReceived Minimum amount received when removing liquidity
        @param receiver Address to send withdrawn coins to
        @return received Amount of coin received in withdrawal
     */
    function removeLiquidityOneCoin(
        address depositToken,
        uint256 burnAmount,
        uint256 index,
        uint256 minReceived,
        address receiver
    ) external returns (uint256) {
        CurvePool memory pool = _getDepositTokenDataWrite(depositToken);

        IERC20(depositToken).transferFrom(msg.sender, address(this), burnAmount);
        IDepositToken(depositToken).withdraw(address(this), burnAmount);

        if (index != 0 && pool.isMetapool) {
            if (pool.isCryptoswap) {
                burnAmount = ICurvePoolV2(pool.pool).remove_liquidity_one_coin(burnAmount, 1, 0);
            } else {
                burnAmount = ICurvePool(pool.pool).remove_liquidity_one_coin(burnAmount, 1, 0);
            }
            pool = poolData[pool.coins[1]];
            index -= 1;
        }

        uint256 amount;
        if (pool.isCryptoswap) {
            amount = ICurvePoolV2(pool.pool).remove_liquidity_one_coin(burnAmount, index, minReceived);
        } else {
            amount = ICurvePool(pool.pool).remove_liquidity_one_coin(burnAmount, int128(int256(index)), minReceived);
        }
        IERC20(pool.coins[index]).safeTransfer(receiver, amount);

        return amount;
    }

    /**
        @notice Withdraw from `srcToken` and deposit to `destToken`
        @dev `srcToken` and `destToken` must both use the same LP token
        @param srcToken Address of `CurveDepositToken` or `ConvexDepositToken` to withdraw from
        @param destToken Address of `CurveDepositToken` or `ConvexDepositToken` to deposit to
        @param amount Quantity of tokens to transfer
        @param receiver Address to send `destToken` balance to
     */
    function zapBetweenCurveConvex(
        address srcToken,
        address destToken,
        uint256 amount,
        address receiver
    ) external returns (bool) {
        address srcPool = _getDepositTokenDataWrite(srcToken).pool;
        address destPool = _getDepositTokenDataWrite(destToken).pool;
        require(srcPool == destPool, "Pools use different LP tokens");
        IERC20(srcToken).transferFrom(msg.sender, address(this), amount);
        IDepositToken(srcToken).withdraw(address(this), amount);
        IDepositToken(destToken).deposit(receiver, amount);

        return true;
    }
}
Código Fuente del Contrato
Archivo 4 de 8: IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.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);
}
Código Fuente del Contrato
Archivo 5 de 8: IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}
Código Fuente del Contrato
Archivo 6 de 8: IVault.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IPrismaVault {
    struct InitialAllowance {
        address receiver;
        uint256 amount;
    }

    event BoostCalculatorSet(address boostCalculator);
    event BoostDelegationSet(address indexed boostDelegate, bool isEnabled, uint256 feePct, address callback);
    event EmissionScheduleSet(address emissionScheduler);
    event IncreasedAllocation(address indexed receiver, uint256 increasedAmount);
    event NewReceiverRegistered(address receiver, uint256 id);
    event ReceiverIsActiveStatusModified(uint256 indexed id, bool isActive);
    event UnallocatedSupplyIncreased(uint256 increasedAmount, uint256 unallocatedTotal);
    event UnallocatedSupplyReduced(uint256 reducedAmount, uint256 unallocatedTotal);

    function allocateNewEmissions(uint256 id) external returns (uint256);

    function batchClaimRewards(
        address receiver,
        address boostDelegate,
        address[] calldata rewardContracts,
        uint256 maxFeePct
    ) external returns (bool);

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

    function registerReceiver(address receiver, uint256 count) external returns (bool);

    function setBoostCalculator(address _boostCalculator) external returns (bool);

    function setBoostDelegationParams(bool isEnabled, uint256 feePct, address callback) external returns (bool);

    function setEmissionSchedule(address _emissionSchedule) external returns (bool);

    function setInitialParameters(
        address _emissionSchedule,
        address _boostCalculator,
        uint256 totalSupply,
        uint64 initialLockWeeks,
        uint128[] calldata _fixedInitialAmounts,
        InitialAllowance[] calldata initialAllowances
    ) external;

    function setReceiverIsActive(uint256 id, bool isActive) external returns (bool);

    function transferAllocatedTokens(address claimant, address receiver, uint256 amount) external returns (bool);

    function transferTokens(address token, address receiver, uint256 amount) external returns (bool);

    function PRISMA_CORE() external view returns (address);

    function allocated(address) external view returns (uint256);

    function boostCalculator() external view returns (address);

    function boostDelegation(address) external view returns (bool isEnabled, uint16 feePct, address callback);

    function claimableRewardAfterBoost(
        address account,
        address receiver,
        address boostDelegate,
        address rewardContract
    ) external view returns (uint256 adjustedAmount, uint256 feeToDelegate);

    function emissionSchedule() external view returns (address);

    function getClaimableWithBoost(address claimant) external view returns (uint256 maxBoosted, uint256 boosted);

    function getWeek() external view returns (uint256 week);

    function guardian() external view returns (address);

    function idToReceiver(uint256) external view returns (address account, bool isActive);

    function lockWeeks() external view returns (uint64);

    function locker() external view returns (address);

    function owner() external view returns (address);

    function claimableBoostDelegationFees(address claimant) external view returns (uint256 amount);

    function prismaToken() external view returns (address);

    function receiverUpdatedWeek(uint256) external view returns (uint16);

    function totalUpdateWeek() external view returns (uint64);

    function unallocatedTotal() external view returns (uint128);

    function voter() external view returns (address);

    function weeklyEmissions(uint256) external view returns (uint128);
}
Código Fuente del Contrato
Archivo 7 de 8: Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "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. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling 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);
    }
}
Código Fuente del Contrato
Archivo 8 de 8: SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "IERC20.sol";
import "IERC20Permit.sol";
import "Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
     * Revert on invalid signature.
     */
    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return
            success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
    }
}
Configuraciones
{
  "compilationTarget": {
    "CurveDepositZap.sol": "CurveDepositZap"
  },
  "evmVersion": "paris",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "remappings": []
}
ABI
[{"inputs":[{"internalType":"contract IPrismaVault","name":"_vault","type":"address"},{"internalType":"address[2][]","name":"_basePools","type":"address[2][]"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"depositToken","type":"address"},{"indexed":false,"internalType":"address","name":"pool","type":"address"}],"name":"DepositTokenRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"pool","type":"address"},{"indexed":false,"internalType":"address","name":"lpToken","type":"address"},{"indexed":false,"internalType":"bool","name":"isMetapool","type":"bool"},{"indexed":false,"internalType":"bool","name":"isCryptoswap","type":"bool"},{"indexed":false,"internalType":"address[]","name":"coins","type":"address[]"}],"name":"PoolAdded","type":"event"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"address","name":"lpToken","type":"address"}],"name":"addCurvePool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"depositToken","type":"address"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"uint256","name":"minReceived","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"lpTokenAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"depositToken","type":"address"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"getAddLiquidityReceived","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"depositToken","type":"address"}],"name":"getCoins","outputs":[{"internalType":"address[]","name":"coins","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"depositToken","type":"address"},{"internalType":"uint256","name":"burnAmount","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRemoveLiquidityOneCoinReceived","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"depositToken","type":"address"},{"internalType":"uint256","name":"burnAmount","type":"uint256"}],"name":"getRemoveLiquidityReceived","outputs":[{"internalType":"uint256[]","name":"received","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"recoverERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"depositToken","type":"address"}],"name":"registerDepositToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"depositToken","type":"address"},{"internalType":"uint256","name":"burnAmount","type":"uint256"},{"internalType":"uint256[]","name":"minReceived","type":"uint256[]"},{"internalType":"address","name":"receiver","type":"address"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256[]","name":"received","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"depositToken","type":"address"},{"internalType":"uint256","name":"burnAmount","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"minReceived","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"removeLiquidityOneCoin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"contract IPrismaVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"srcToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"zapBetweenCurveConvex","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]