MON Price: $0.018729 (+2.24%)

Contract

0x1D60A3F3f84F095b3D6001fbc135F6D42c812269

Overview

MON Balance

Monad Chain LogoMonad Chain LogoMonad Chain Logo0 MON

MON Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Swap And Deposit484526282026-01-13 13:55:2111 days ago1768312521IN
0x1D60A3F3...42c812269
749.98047252 MON0.0455263101.94
Swap And Deposit480554052026-01-11 17:42:1712 days ago1768153337IN
0x1D60A3F3...42c812269
201,250.1184628 MON0.05892285102.10004247
Swap And Deposit471420592026-01-07 11:56:2117 days ago1767786981IN
0x1D60A3F3...42c812269
2 MON0.06832398102
Swap And Deposit463875442026-01-03 23:44:4320 days ago1767483883IN
0x1D60A3F3...42c812269
1 MON0.05010423102
Swap And Deposit463639642026-01-03 21:07:1620 days ago1767474436IN
0x1D60A3F3...42c812269
7,400 MON0.0818784103
Swap And Deposit461101362026-01-02 16:51:3022 days ago1767372690IN
0x1D60A3F3...42c812269
3,050 MON0.04078222102.10004247
Swap And Deposit458372232026-01-01 10:29:0323 days ago1767263343IN
0x1D60A3F3...42c812269
59,000 MON0.05883821101.9576227
Swap And Deposit458336982026-01-01 10:05:3323 days ago1767261933IN
0x1D60A3F3...42c812269
55,000 MON0.05904413102.31444914
Swap And Deposit452450912025-12-29 16:34:5726 days ago1767026097IN
0x1D60A3F3...42c812269
267.74435022 MON0.07441564104
Swap And Deposit445579462025-12-26 11:39:0029 days ago1766749140IN
0x1D60A3F3...42c812269
1 MON0.06291085105
Swap And Deposit445576452025-12-26 11:36:5929 days ago1766749019IN
0x1D60A3F3...42c812269
1 MON0.0623117104
Swap And Deposit445575562025-12-26 11:36:2329 days ago1766748983IN
0x1D60A3F3...42c812269
1 MON0.06966367104
Swap And Deposit443178282025-12-25 8:55:2230 days ago1766652922IN
0x1D60A3F3...42c812269
20,000 MON0.0920745127.6
Swap And Deposit438642322025-12-23 6:21:4432 days ago1766470904IN
0x1D60A3F3...42c812269
0.2 MON0.108199125
Swap And Deposit437782172025-12-22 20:47:2432 days ago1766436444IN
0x1D60A3F3...42c812269
44.53562838 MON0.07631681106.657
Swap And Deposit431339542025-12-19 21:01:2735 days ago1766178087IN
0x1D60A3F3...42c812269
35 MON0.08520329107.1
Swap And Deposit430575512025-12-19 12:30:5836 days ago1766147458IN
0x1D60A3F3...42c812269
5 MON0.1002331110
Swap And Deposit430504892025-12-19 11:43:4736 days ago1766144627IN
0x1D60A3F3...42c812269
12.23646073 MON0.11670996152.12
Swap And Deposit428385142025-12-18 12:07:5137 days ago1766059671IN
0x1D60A3F3...42c812269
7 MON0.04559236102
Swap And Deposit427776212025-12-18 5:20:4337 days ago1766035243IN
0x1D60A3F3...42c812269
61,000 MON0.07392705102.361
Swap And Deposit427760672025-12-18 5:10:2037 days ago1766034620IN
0x1D60A3F3...42c812269
29,000 MON0.08471351104
Swap And Deposit426136472025-12-17 11:05:3138 days ago1765969531IN
0x1D60A3F3...42c812269
100 MON0.0577494100
Swap And Deposit425008702025-12-16 22:32:1938 days ago1765924339IN
0x1D60A3F3...42c812269
1,500 MON0.08119373102.06
Swap And Deposit415001102025-12-12 6:50:0343 days ago1765522203IN
0x1D60A3F3...42c812269
2,282.95838064 MON0.08879339102.5
Swap And Deposit411947552025-12-10 20:41:3644 days ago1765399296IN
0x1D60A3F3...42c812269
36.36339199 MON0.05352195102
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
484526282026-01-13 13:55:2111 days ago1768312521
0x1D60A3F3...42c812269
749.98047252 MON
480554052026-01-11 17:42:1712 days ago1768153337
0x1D60A3F3...42c812269
201,250.1184628 MON
471420592026-01-07 11:56:2117 days ago1767786981
0x1D60A3F3...42c812269
2 MON
463875442026-01-03 23:44:4320 days ago1767483883
0x1D60A3F3...42c812269
1 MON
463639642026-01-03 21:07:1620 days ago1767474436
0x1D60A3F3...42c812269
7,400 MON
461101362026-01-02 16:51:3022 days ago1767372690
0x1D60A3F3...42c812269
3,050 MON
458372232026-01-01 10:29:0323 days ago1767263343
0x1D60A3F3...42c812269
59,000 MON
458336982026-01-01 10:05:3323 days ago1767261933
0x1D60A3F3...42c812269
55,000 MON
452450912025-12-29 16:34:5726 days ago1767026097
0x1D60A3F3...42c812269
267.74435022 MON
445579462025-12-26 11:39:0029 days ago1766749140
0x1D60A3F3...42c812269
1 MON
445576452025-12-26 11:36:5929 days ago1766749019
0x1D60A3F3...42c812269
1 MON
445575562025-12-26 11:36:2329 days ago1766748983
0x1D60A3F3...42c812269
1 MON
443178282025-12-25 8:55:2230 days ago1766652922
0x1D60A3F3...42c812269
20,000 MON
438642322025-12-23 6:21:4432 days ago1766470904
0x1D60A3F3...42c812269
0.2 MON
437782172025-12-22 20:47:2432 days ago1766436444
0x1D60A3F3...42c812269
44.53562838 MON
431339542025-12-19 21:01:2735 days ago1766178087
0x1D60A3F3...42c812269
35 MON
430575512025-12-19 12:30:5836 days ago1766147458
0x1D60A3F3...42c812269
5 MON
430504892025-12-19 11:43:4736 days ago1766144627
0x1D60A3F3...42c812269
12.23646073 MON
428385142025-12-18 12:07:5137 days ago1766059671
0x1D60A3F3...42c812269
7 MON
427776212025-12-18 5:20:4337 days ago1766035243
0x1D60A3F3...42c812269
61,000 MON
427760672025-12-18 5:10:2037 days ago1766034620
0x1D60A3F3...42c812269
29,000 MON
426136472025-12-17 11:05:3138 days ago1765969531
0x1D60A3F3...42c812269
100 MON
425008702025-12-16 22:32:1938 days ago1765924339
0x1D60A3F3...42c812269
1,500 MON
415001102025-12-12 6:50:0343 days ago1765522203
0x1D60A3F3...42c812269
2,282.95838064 MON
411947552025-12-10 20:41:3644 days ago1765399296
0x1D60A3F3...42c812269
36.36339199 MON
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
NativeVaultZapper

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 200 runs

Other Settings:
cancun EvmVersion, BSL 1.1 license
/**
 *Submitted for verification at monadscan.com on 2025-11-25
*/

// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.28;

// contracts/libraries/ConstantsLib.sol

/// @dev Scalar for math. `WAD` * `WAD`.
uint256 constant WAD_SQUARED = 1e36;

/// @dev Scalar for math. `WAD` * `WAD` / `BPS`.
///      1e18 * 1e18 / 1e4
uint256 constant WAD_SQUARED_BPS_OFFSET = 1e32;

/// @dev Scalar for math. Increased precision when WAD is insufficient
///      but WAD_SQUARED runs the risk of overflow.
uint256 constant RAY = 1e27;

/// @dev Scalar for math. `WAD` * `BPS`.
uint256 constant WAD_BPS = 1e22;

/// @dev Scalar for math. Base precision matching ether.
uint256 constant WAD = 1e18;

/// @dev Scalar for math. Represents basis points typically used in TradFi.
uint256 constant BPS = 1e4;

/// @dev Return value indicating no price returned at all.
uint256 constant BAD_SOURCE = 2;

/// @dev Return value indicating price divergence or a missing price feed.
uint256 constant CAUTION = 1;

/// @dev Return value indicating no price error.
uint256 constant NO_ERROR = 0;

/// @dev Extra time added to top end Oracle feed heartbeat incase of
///      transaction congestion delaying an update.
uint256 constant HEARTBEAT_GRACE_PERIOD = 120;

/// @dev Unix time has 31,536,000 seconds per year.
///      All my homies hate leap seconds and leap years.
uint256 constant SECONDS_PER_YEAR = 31_536_000;

// contracts/libraries/external/FixedPointMathLib.sol

/// @notice Arithmetic library with operations for fixed-point numbers.
/// @dev Reduced function scope from full FixedPointMathLib library to only what is needed for Curvance.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
library FixedPointMathLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
    error MulDivFailed();

    /// @dev The full precision multiply-divide operation failed, either due
    /// to the result being larger than 256 bits, or a division by a zero.
    error FullMulDivFailed();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  GENERAL NUMBER UTILITIES                  */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Calculates `floor(x * y / d)` with full precision.
    /// Throws if result overflows a uint256 or when `d` is zero.
    /// Credit to Remco Bloemen under MIT license: https://2π.com/21/muldiv
    function fullMulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            for {} 1 {} {
                // 512-bit multiply `[p1 p0] = x * y`.
                // Compute the product mod `2**256` and mod `2**256 - 1`
                // then use the Chinese Remainder Theorem to reconstruct
                // the 512 bit result. The result is stored in two 256
                // variables such that `product = p1 * 2**256 + p0`.

                // Least significant 256 bits of the product.
                result := mul(x, y) // Temporarily use `result` as `p0` to save gas.
                let mm := mulmod(x, y, not(0))
                // Most significant 256 bits of the product.
                let p1 := sub(mm, add(result, lt(mm, result)))

                // Handle non-overflow cases, 256 by 256 division.
                if iszero(p1) {
                    if iszero(d) {
                        mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
                        revert(0x1c, 0x04)
                    }
                    result := div(result, d)
                    break
                }

                // Make sure the result is less than `2**256`. Also prevents `d == 0`.
                if iszero(gt(d, p1)) {
                    mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
                    revert(0x1c, 0x04)
                }

                /*------------------- 512 by 256 division --------------------*/

                // Make division exact by subtracting the remainder from `[p1 p0]`.
                // Compute remainder using mulmod.
                let r := mulmod(x, y, d)
                // `t` is the least significant bit of `d`.
                // Always greater or equal to 1.
                let t := and(d, sub(0, d))
                // Divide `d` by `t`, which is a power of two.
                d := div(d, t)
                // Invert `d mod 2**256`
                // Now that `d` is an odd number, it has an inverse
                // modulo `2**256` such that `d * inv = 1 mod 2**256`.
                // Compute the inverse by starting with a seed that is correct
                // correct for four bits. That is, `d * inv = 1 mod 2**4`.
                let inv := xor(2, mul(3, d))
                // Now use Newton-Raphson iteration to improve the precision.
                // Thanks to Hensel's lifting lemma, this also works in modular
                // arithmetic, doubling the correct bits in each step.
                inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**8
                inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**16
                inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**32
                inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**64
                inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**128
                result :=
                    mul(
                        // Divide [p1 p0] by the factors of two.
                        // Shift in bits from `p1` into `p0`. For this we need
                        // to flip `t` such that it is `2**256 / t`.
                        or(
                            mul(sub(p1, gt(r, result)), add(div(sub(0, t), t), 1)),
                            div(sub(result, r), t)
                        ),
                        // inverse mod 2**256
                        mul(inv, sub(2, mul(d, inv)))
                    )
                break
            }
        }
    }

    /// @dev Calculates `floor(x * y / d)` with full precision, rounded up.
    /// Throws if result overflows a uint256 or when `d` is zero.
    /// Credit to Uniswap-v3-core under MIT license:
    /// https://github.com/Uniswap/v3-core/blob/contracts/libraries/FullMath.sol
    function fullMulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) {
        result = fullMulDiv(x, y, d);
        /// @solidity memory-safe-assembly
        assembly {
            if mulmod(x, y, d) {
                result := add(result, 1)
                if iszero(result) {
                    mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
                    revert(0x1c, 0x04)
                }
            }
        }
    }

    /// @dev Returns `floor(x * y / d)`.
    /// Reverts if `x * y` overflows, or `d` is zero.
    function mulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y))
            if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) {
                mstore(0x00, 0xad251c27) // `MulDivFailed()`.
                revert(0x1c, 0x04)
            }
            z := div(mul(x, y), d)
        }
    }

    /// @dev Returns `ceil(x * y / d)`.
    /// Reverts if `x * y` overflows, or `d` is zero.
    function mulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y))
            if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) {
                mstore(0x00, 0xad251c27) // `MulDivFailed()`.
                revert(0x1c, 0x04)
            }
            z := add(iszero(iszero(mod(mul(x, y), d))), div(mul(x, y), d))
        }
    }

    /// @dev Returns the square root of `x`.
    function sqrt(uint256 x) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // `floor(sqrt(2**15)) = 181`. `sqrt(2**15) - 181 = 2.84`.
            z := 181 // The "correct" value is 1, but this saves a multiplication later.

            // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
            // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.

            // Let `y = x / 2**r`. We check `y >= 2**(k + 8)`
            // but shift right by `k` bits to ensure that if `x >= 256`, then `y >= 256`.
            let r := shl(7, lt(0xffffffffffffffffffffffffffffffffff, x))
            r := or(r, shl(6, lt(0xffffffffffffffffff, shr(r, x))))
            r := or(r, shl(5, lt(0xffffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffffff, shr(r, x))))
            z := shl(shr(1, r), z)

            // Goal was to get `z*z*y` within a small factor of `x`. More iterations could
            // get y in a tighter range. Currently, we will have y in `[256, 256*(2**16))`.
            // We ensured `y >= 256` so that the relative difference between `y` and `y+1` is small.
            // That's not possible if `x < 256` but we can just verify those cases exhaustively.

            // Now, `z*z*y <= x < z*z*(y+1)`, and `y <= 2**(16+8)`, and either `y >= 256`, or `x < 256`.
            // Correctness can be checked exhaustively for `x < 256`, so we assume `y >= 256`.
            // Then `z*sqrt(y)` is within `sqrt(257)/sqrt(256)` of `sqrt(x)`, or about 20bps.

            // For `s` in the range `[1/256, 256]`, the estimate `f(s) = (181/1024) * (s+1)`
            // is in the range `(1/2.84 * sqrt(s), 2.84 * sqrt(s))`,
            // with largest error when `s = 1` and when `s = 256` or `1/256`.

            // Since `y` is in `[256, 256*(2**16))`, let `a = y/65536`, so that `a` is in `[1/256, 256)`.
            // Then we can estimate `sqrt(y)` using
            // `sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2**18`.

            // There is no overflow risk here since `y < 2**136` after the first branch above.
            z := shr(18, mul(z, add(shr(r, x), 65536))) // A `mul()` is saved from starting `z` at 181.

            // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))

            // If `x+1` is a perfect square, the Babylonian method cycles between
            // `floor(sqrt(x))` and `ceil(sqrt(x))`. This statement ensures we return floor.
            // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
            z := sub(z, lt(div(x, z), z))
        }
    }
}

// contracts/interfaces/ICentralRegistry.sol

/// TYPES ///

/// @notice Configuration data for a separately supported blockchain.
/// @param isSupported Whether the chain is supported or not.
/// @param messagingChainId Messaging Chain ID where this address authorized.
/// @param domain Domain for the chain.
/// @param messagingHub Messaging Hub address on the chain.
/// @param votingHub Voting Hub address on the chain.
/// @param cveAddress CVE address on the chain.
/// @param feeTokenAddress Fee token address on the chain.
/// @param crosschainRelayer Crosschain relayer address on the chain.
struct ChainConfig {
    bool isSupported;
    uint16 messagingChainId;
    uint32 domain;
    address messagingHub;
    address votingHub;
    address cveAddress;
    address feeTokenAddress;
    address crosschainRelayer;
}

interface ICentralRegistry {
    /// @notice The length of one protocol epoch, in seconds.
    function EPOCH_DURATION() external view returns (uint256);

    /// @notice Sequencer uptime oracle on this chain (for L2s).
    function SEQUENCER_ORACLE() external view returns (address);

    /// @notice Returns Genesis Epoch Timestamp of Curvance.
    function genesisEpoch() external view returns (uint256);

    /// @notice Returns Protocol DAO address.
    function daoAddress() external view returns (address);

    /// @notice Returns Protocol Emergency Council address.
    function emergencyCouncil() external view returns (address);

    /// @notice Indicates if address has DAO permissions or not.
    function hasDaoPermissions(
        address addressToCheck
    ) external view returns (bool);

    /// @notice Indicates if address has elevated DAO permissions or not.
    function hasElevatedPermissions(
        address addressToCheck
    ) external view returns (bool);

    /// @notice Indicates if address has lock creation permissions or not.
    function hasLockingPermissions(
        address addressToCheck
    ) external view returns (bool);

    /// @notice Indicates if address has auction permissions or not.
    function hasAuctionPermissions(
        address addressToCheck
    ) external view returns (bool);

    /// @notice Indicates if address has market permissions or not.
    function hasMarketPermissions(
        address addressToCheck
    ) external view returns (bool);

    /// @notice Indicates if address has harvest permissions or not.
    function hasHarvestPermissions(
        address addressToCheck
    ) external view returns (bool);

    /// @notice Returns Reward Manager address.
    function rewardManager() external view returns (address);

    /// @notice Returns Gauge Manager address.
    function gaugeManager() external view returns (address);

    /// @notice Returns CVE address.
    function cve() external view returns (address);

    /// @notice Returns veCVE address.
    function veCVE() external view returns (address);

    /// @notice Returns Voting Hub address.
    function votingHub() external view returns (address);

    /// @notice Returns Messaging Hub address.
    function messagingHub() external view returns (address);

    /// @notice Returns Oracle Manager address.
    function oracleManager() external view returns (address);

    /// @notice Returns Fee Manager address.
    function feeManager() external view returns (address);

    /// @notice Returns Fee Token address.
    function feeToken() external view returns (address);

    /// @notice Returns Crosschain Core contract address.
    function crosschainCore() external view returns (address);

    /// @notice Returns Crosschain Relayer contract address.
    function crosschainRelayer() external view returns (address);

    /// @notice Returns Token Messenger contract address.
    function tokenMessager() external view returns (address);

    /// @notice Returns Messenger Transmitter contract address.
    function messageTransmitter() external view returns (address);

    /// @notice Returns domain value.
    function domain() external view returns (uint32);

    /// @notice Returns protocol gas fee on harvest, in `BPS`.
    function protocolCompoundFee() external view returns (uint256);

    /// @notice Returns protocol yield fee on strategy harvest, in `BPS`.
    function protocolYieldFee() external view returns (uint256);

    /// @notice Returns protocol yield + gas fee on strategy harvest,
    ///         in `BPS`.
    function protocolHarvestFee() external view returns (uint256);

    /// @notice Returns protocol fee on leverage actions, in `BPS`.
    function protocolLeverageFee() external view returns (uint256);

    /// @notice Returns default fee on interest generated from active loans,
    ///         in `BPS`.
    function defaultProtocolInterestFee() external view returns (uint256);

    /// @notice Returns earlyUnlockPenaltyMultiplier value, in `BPS`.
    function earlyUnlockPenaltyMultiplier() external view returns (uint256);

    /// @notice Returns voteBoostMultiplier value, in `BPS`.
    function voteBoostMultiplier() external view returns (uint256);

    /// @notice Returns lockBoostMultiplier value, in `BPS`.
    function lockBoostMultiplier() external view returns (uint256);

    /// @notice Returns swap slippage limit, in `BPS`.
    function slippageLimit() external view returns (uint256);

    /// @notice Returns an array of Chain IDs recorded in the Crosschain
    ///         Protocol's Chain ID format.
    function foreignChainIds() external view returns (uint256[] memory);

    /// @notice Returns an array of Curvance markets on this chain.
    function marketManagers() external view returns (address[] memory);

    /// @notice Increments a caller's approval index.
    /// @dev By incrementing their approval index, a user's delegates will all
    ///      have their delegation authority revoked across all Curvance
    ///      contracts.
    ///      Emits an {ApprovalIndexIncremented} event.
    function incrementApprovalIndex() external;

    /// @notice Returns `user`'s approval index.
    /// @param user The user to check approval index for.
    function userApprovalIndex(address user) external view returns (uint256);

    /// @notice Returns whether a user has delegation disabled.
    /// @param user The user to check delegation status for.
    function checkNewDelegationDisabled(
        address user
    ) external view returns (bool);

    /// @notice Returns whether a particular GETH chainId is supported.
    /// ChainId => messagingHub address, 2 = supported; 1 = unsupported.
    function chainConfig(
        uint256 chainId
    ) external view returns (ChainConfig memory);

    /// @notice Returns the GETH chainId corresponding chainId corresponding
    ///         to Crosschain Messaging Protocol's `chainId`.
    /// @param chainId The Crosschain Messaging Protocol's chainId.
    /// @return The GETH chainId corresponding chainId corresponding to
    ///         Crosschain Messaging Protocol's `chainId`.
    function messagingToGETHChainId(
        uint16 chainId
    ) external view returns (uint256);

    /// @notice Returns the Crosschain Messaging Protocol's ChainId
    ///         corresponding to the GETH `chainId`.
    /// @param chainId The GETH chainId.
    /// @return The Crosschain Messaging Protocol's ChainId
    ///         corresponding to the GETH `chainId`.
    function GETHToMessagingChainId(
        uint256 chainId
    ) external view returns (uint256);

    /// @notice Indicates if an address is a market manager or not.
    function isMarketManager(
        address addressToCheck
    ) external view returns (bool);

    /// @notice Maps an intent target address to the contract that will
    ///         inspect provided external calldata.
    function externalCalldataChecker(
        address addressToCheck
    ) external view returns (address);

    /// @notice Maps a Multicall target address to the contract that will
    ///         inspect provided multicall calldata.
    function multicallChecker(
        address addressToCheck
    ) external view returns (address);

    /// @notice Indicates the amount of token rewards allocated on this chain,
    ///         for an epoch.
    function emissionsAllocatedByEpoch(
        uint256 epoch
    ) external view returns (uint256);

    /// @notice Indicates the amount of token rewards allocated across all
    ///         chains, for an era. An era is a particular period in time in
    ///         which rewards are constant, before a halvening event moves the
    ///         protocol to a new era.
    function targetEmissionAllocationByEra(
        uint256 era
    ) external view returns (uint256);

    /// @notice Unlocks a market to process auction-based liquidations.
    /// @param marketToUnlock The address of the market manager to unlock
    ///                       auction-based liquidations with a specific
    ///                       liquidation bonus.
    function unlockAuctionForMarket(address marketToUnlock) external;

    /// @notice Checks if a market is unlocked for auction operations.
    /// @return Whether the caller is an unlocked market, approved for
    ///         auction-based liquidations.
    function isMarketUnlocked() external view returns (bool);

    /// @notice Sets the amount of token rewards allocated on this chain,
    ///         for an epoch.
    /// @dev Only callable by the Voting Hub.
    /// @param epoch The epoch having its token emission values set.
    /// @param emissionsAllocated The amount of token rewards allocated on
    ///                           this chain, for an epoch.
    function setEmissionsAllocatedByEpoch(
        uint256 epoch,
        uint256 emissionsAllocated
    ) external;

    /// @notice Checks whether `user` has transferability enabled or disabled
    ///         for their tokens.
    /// @dev This is inherited from ActionRegistry portion of centralRegistry.
    /// @param user The address to check whether transferability is enabled or
    ///             disabled for.
    /// @return result Indicates whether `user` has transferability disabled
    ///                or not, true = disabled, false = not disabled.
    function checkTransfersDisabled(
        address user
    ) external view returns (bool result);
}

// contracts/interfaces/IDynamicIRM.sol

interface IDynamicIRM {
    /// @notice Returns the interval at which interest rates are adjusted.
    /// @notice The interval at which interest rates are adjusted,
    ///         in seconds.
    function ADJUSTMENT_RATE() external view returns (uint256);

    /// @notice The borrowable token linked to this interest rate model
    ///         contract.
    function linkedToken() external view returns (address);

    /// @notice Calculates the current borrow rate, per second.
    /// @dev This function's intention is for frontend data querying and
    ///     should not be used for onchain execution.
    /// @param assetsHeld The amount of underlying assets held in the pool.
    /// @param debt The amount of outstanding debt in the pool.
    /// @return result The borrow interest rate percentage, per second,
    ///                in `WAD`.
    function borrowRate(
        uint256 assetsHeld,
        uint256 debt
    ) external view returns (uint256 result);

    /// @notice Calculates the current borrow rate per second,
    ///         with updated vertex multiplier applied.
    /// @param assetsHeld The amount of underlying assets held in the pool.
    /// @param debt The amount of outstanding debt in the pool.
    /// @return result The borrow rate percentage per second, in `WAD`.
    function predictedBorrowRate(
        uint256 assetsHeld,
        uint256 debt
    ) external view returns (uint256 result);

    /// @notice Calculates the current supply rate, per second.
    /// @dev This function's intention is for frontend data querying and
    ///     should not be used for onchain execution.
    /// @param assetsHeld The amount of underlying assets held in the pool.
    /// @param debt The amount of outstanding debt in the pool.
    /// @param interestFee The current interest rate protocol fee
    ///                    for the market token.
    /// @return result The supply interest rate percentage, per second,
    ///                in `WAD`.
    function supplyRate(
        uint256 assetsHeld,
        uint256 debt,
        uint256 interestFee
    ) external view returns (uint256 result);

    /// @notice Calculates the interest rate paid per second by borrowers,
    ///         in percentage paid, per second, in `WAD`, and updates
    ///         `vertexMultiplier` if necessary.
    /// @param assetsHeld The amount of underlying assets held in the pool.
    /// @param debt The amount of outstanding debt in the pool.
    /// @return ratePerSecond The interest rate paid per second by borrowers,
    ///                       in percentage paid, per second, in `WAD`.
    /// @return adjustmentRate The period of time at which interest rates are
    ///                        adjusted, in seconds.
    function adjustedBorrowRate(
        uint256 assetsHeld,
        uint256 debt
    ) external returns (uint256 ratePerSecond, uint256 adjustmentRate);

    /// @notice Calculates the borrow utilization rate of the market.
    /// @param assetsHeld The amount of underlying assets held in the pool.
    /// @param outstandingDebt The amount of outstanding debt in the pool.
    /// @return The utilization rate between [0, WAD].
    function utilizationRate(
        uint256 assetsHeld,
        uint256 outstandingDebt
    ) external view returns (uint256);
}

// contracts/interfaces/IERC165.sol

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(
        bytes4 interfaceId
    ) external view returns (bool);
}

// contracts/interfaces/IERC20.sol

// @dev Interface of the ERC20 standard
interface IERC20 {
    // @dev Returns the name of the token.
    function name() external view returns (string memory);

    // @dev Returns the symbol of the token.
    function symbol() external view returns (string memory);

    // @dev Returns the decimals of the token.
    function decimals() external view returns (uint8);

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

    // @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.
    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);
}

// contracts/interfaces/IMarketManager.sol

interface IMarketManager {
    /// TYPES ///

    /// @notice Data structure passed communicating the intended liquidation
    ///         scenario to review based on current liquidity levels.
    /// @param collateralToken The token which was used as collateral
    ///                        by `account` and may be seized.
    /// @param debtToken The token to potentially repay which has
    ///                  outstanding debt by `account`.
    /// @param numAccounts The number of accounts to be, potentially,
    ///                    liquidated.
    /// @param liquidateExact Whether the liquidator desires a specific
    ///                       liquidation amount.
    /// @param liquidatedShares Empty variable slot to store how much
    ///                         `collateralToken` will be seized as
    ///                         part of a particular liquidation.
    /// @param debtRepaid Empty variable slot to store how much
    ///                   `debtToken` will be repaid as part of a
    ///                   particular liquidation.
    /// @param badDebt Empty variable slot to store how much bad debt will
    ///                be realized by lenders as part of a particular
    ///                liquidation.
    struct LiqAction {
        address collateralToken;
        address debtToken;
        uint256 numAccounts;
        bool liquidateExact;
        uint256 liquidatedShares;
        uint256 debtRepaid;
        uint256 badDebt;
    }

    /// @notice Data structure returned communicating outcome of a liquidity
    ///         scenario review based on current liquidity levels.
    /// @param liquidatedShares An array containing the collateral amounts to
    ///                         liquidate from accounts, in shares.
    /// @param debtRepaid The total amount of debt to repay from accounts,
    ///                   in assets.
    /// @param badDebtRealized The total amount of debt to realize as losses
    ///                        for lenders, in assets.
    struct LiqResult {
        uint256[] liquidatedShares;
        uint256 debtRepaid;
        uint256 badDebtRealized;
    }

    /// @notice Returns whether minting, collateralization, borrowing of
    ///         `cToken` is paused.
    /// @param cToken The address of the Curvance token to return
    ///               action statuses of.
    /// @return bool Whether minting `cToken` is paused or not.
    /// @return bool Whether collateralization `cToken` is paused or not.
    /// @return bool Whether borrowing `cToken` is paused or not.
    function actionsPaused(
        address cToken
    ) external view returns (bool, bool, bool);

    /// @notice Returns the current collateralization configuration
    ///         of `cToken`.
    /// @param cToken The address of the Curvance token to return
    ///               collateralization configuration of.
    /// @return The ratio at which this token can be borrowed against
    ///         when collateralized.
    /// @return The collateral requirement where dipping below this
    ///         will cause a soft liquidation.
    /// @return The collateral requirement where dipping below
    ///         this will cause a hard liquidation.
    function collConfig(address cToken) external view returns (
         uint256, uint256, uint256
    );

    /// @notice Returns the current liquidation configuration
    ///         of `cToken`.
    /// @param cToken The address of the Curvance token to return
    ///               liquidation configuration of.
    /// @return The base ratio at which this token will be
    ///         compensated on soft liquidation.
    /// @return The liquidation incentive curve length between soft
    ///         liquidation to hard liquidation, in `WAD`. e.g. 5% base
    ///         incentive with 8% curve length results in 13% liquidation
    ///         incentive on hard liquidation.
    /// @return The minimum possible liquidation incentive for during an
    ///         auction, in `WAD`.
    /// @return The maximum possible liquidation incentive for during an
    ///         auction, in `WAD`.
    /// @return Maximum % that a liquidator can repay when soft
    ///         liquidating an account, in `WAD`.
    /// @return Curve length between soft liquidation and hard liquidation,
    ///         should be equal to 100% - `closeFactorBase`, in `WAD`.
    /// @return The minimum possible close factor for during an auction,
    ///         in `WAD`.
    /// @return The maximum possible close factor for during an auction,
    ///         in `WAD`.
    function liquidationConfig(address cToken) external view returns (
        uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256
    );

    /// @notice Enables an auction-based liquidation, potentially with a dynamic
    ///         close factor and liquidation penalty values in transient storage.
    /// @dev Transient storage enforces any liquidator outside auction-based
    ///      liquidations uses the default risk parameters.
    /// @param cToken The Curvance token to configure liquidations for during
    ///               an auction-based liquidation.
    /// @param incentive The auction liquidation incentive value, in `BPS`.
    /// @param closeFactor The auction close factor value, in `BPS`.
    function setTransientLiquidationConfig(
        address cToken,
        uint256 incentive,
        uint256 closeFactor
    ) external;

    /// @notice Called from the AuctionManager as a post hook after liquidations
    ///         are tried to enable all collateral to be liquidated outside
    ///         an Auction tx.
    /// @notice Resets the liquidation risk parameters in transient storage to
    ///         zero.
    /// @dev This is redundant since the transient values will be reset after
    ///      the liquidation transaction, but can be useful during meta calls
    ///      with multiple liquidations during a single transaction. 
    function resetTransientLiquidationConfig() external;

    /// @notice Checks if the account should be allowed to mint tokens
    ///         in the given market.
    /// @param cToken The token to verify mints against.
    function canMint(address cToken) external;

    /// @notice Checks if the account should be allowed to collateralize
    ///         their shares of the given market.
    ///         Prunes unused positions in `account` data.
    /// @dev May emit a {PositionUpdated} event.
    /// @param cToken The token to verify collateralization of.
    /// @param account The account which would collateralize the asset.
    /// @param newNetCollateral The amount of shares that would be
    ///                         collateralized in total if allowed.
    function canCollateralize(
        address cToken,
        address account,
        uint256 newNetCollateral
    ) external;

    /// @notice Checks if the account should be allowed to redeem tokens
    ///         in the given market, and then redeems.
    /// @dev This can only be called by the cToken itself.
    /// @param cToken The token to verify the redemption against.
    /// @param shares The number of cToken shares to redeem for the
    ///               underlying asset in the market.
    /// @param account The account which would redeem `shares`.
    /// @param balanceOf The current cToken share balance of `account`.
    /// @param collateralPosted The current cToken shares posted as
    ///                         collateral by `account`.
    /// @param forceRedeemCollateral Whether the collateral should be always
    ///                              reduced.
    function canRedeemWithCollateralRemoval(
        address cToken,
        uint256 shares,
        address account,
        uint256 balanceOf,
        uint256 collateralPosted,
        bool forceRedeemCollateral
    ) external returns (uint256);

    /// @notice Checks if the account should be allowed to borrow
    ///         the underlying asset of the given market.
    ///         Prunes unused positions in `account` data.
    /// @dev May emit a {PositionUpdated} event.
    /// @param cToken The token to verify borrowability of.
    /// @param assets The amount of underlying assets `account` would borrow.
    /// @param account The account which would borrow the asset.
    /// @param newNetDebt The amount of assets that would be
    ///                   outstanding debt in total if allowed.
    function canBorrow(
        address cToken,
        uint256 assets,
        address account,
        uint256 newNetDebt
    ) external;

    /// @notice Checks if the account should be allowed to borrow
    ///         the underlying asset of the given market,
    ///         and notifies the market of the borrow.
    /// @dev This can only be called by the market itself.
    /// @param cToken The market to verify the borrow against.
    /// @param assets The amount of underlying assets `account` would borrow.
    /// @param account The account which would borrow the asset.
    /// @param newNetDebt The amount of assets that would be
    ///                   outstanding debt in total if allowed.
    function canBorrowWithNotify(
        address cToken,
        uint256 assets,
        address account,
        uint256 newNetDebt
    ) external;

    /// @notice Checks if the account should be allowed to repay a borrow
    ///         in the given market, may clean up positions.
    /// @param cToken The Curvance token to verify the repayment of.
    /// @param newNetDebt The new debt amount owed by `account` after
    ///                   repayment.
    /// @param debtAsset The debt asset being repaid to `cToken`.
    /// @param decimals The decimals that `debtToken` is measured in.
    /// @param account The account who will have their loan repaid.
    function canRepayWithReview(
        address cToken,
        uint256 newNetDebt,
        address debtAsset,
        uint256 decimals,
        address account
    ) external;

    /// @notice Checks if the liquidation should be allowed to occur,
    ///         and returns how many collateralized shares should be seized
    ///         on liquidation.
    /// @param debtAmounts The amounts of outstanding debt the liquidator
    ///                    wishes to repay, in underlying assets, empty if
    ///                    intention is to liquidate maximum amount possible
    ///                    for each account.
    /// @param liquidator The address of the account trying to liquidate
    ///                   `accounts`.
    /// @param accounts The addresses of the accounts to be liquidated.
    /// @param action A LiqAction struct containing:
    ///               collateralToken The token which is used as collateral
    ///                               by `account` and may be seized.
    ///               debtToken The token to potentially repay which has
    ///                         outstanding debt by `account`.
    ///               numAccounts The number of accounts to be, potentially,
    ///                           liquidated.
    ///               liquidateExact Whether the liquidator desires a
    ///                              specific liquidation amount.
    ///               collateralLiquidated Empty variable slot to store how
    ///                                    much `collateralToken` will be
    ///                                    seized as part of a particular
    ///                                    liquidation.
    ///               debtRepaid Empty variable slot to store how much
    ///                          `debtToken` will be repaid as part of a
    ///                          particular liquidation.
    ///               badDebt Empty variable slot to store how much bad debt
    ///                       will be realized as part of a particular
    ///                       liquidation.
    /// @return result A LiqResult struct containing:
    ///                liquidatedShares An array containing the collateral
    ///                                 amounts to liquidate from
    ///                                 `accounts`.
    ///                debtRepaid The total amount of debt to repay from
    ///                           `accounts`.
    ///                badDebtRealized The total amount of debt to realize as
    ///                                losses for lenders inside this market.
    /// @return An array containing the debt amounts to repay from
    ///        `accounts`, in assets.
    function canLiquidate(
        uint256[] memory debtAmounts,
        address liquidator,
        address[] calldata accounts,
        IMarketManager.LiqAction memory action
    ) external returns (LiqResult memory, uint256[] memory);

    /// @notice Checks if the seizing of `collateralToken` by repayment of
    ///         `debtToken` should be allowed.
    /// @param collateralToken The Curvance token which was used as collateral
    ///                        and will be seized.
    /// @param debtToken The Curvance token which has outstanding debt to and
    ///                  would be repaid during `collateralToken` seizure.
    function canSeize(address collateralToken, address debtToken) external;

    /// @notice Checks if the account should be allowed to transfer collateral
    ///         tokens in the given market.
    /// @param cToken The Curvance token to verify the transfer of.
    /// @param shares The amount of `cToken` to transfer.
    /// @param account The account which will transfer `shares`.
    /// @param balanceOf The current balance that `account` has of `cToken`
    ///                  shares.
    /// @param collateralPosted The amount of `cToken` shares posted as
    ///                         collateral by `account`.
    /// @param isCollateral Boolean indicating whether the token is currently
    ///                     being used as collateral.
    function canTransfer(
        address cToken,
        uint256 shares,
        address account,
        uint256 balanceOf,
        uint256 collateralPosted,
        bool isCollateral
    ) external returns (uint256);

    /// @notice Updates `account` cooldownTimestamp to the current block
    ///         timestamp.
    /// @dev The caller must be a listed cToken in the `markets` mapping.
    /// @param cToken The address of the token that the account is borrowing.
    /// @param account The address of the account that has just borrowed.
    function notifyBorrow(address cToken, address account) external;

    /// @notice A list of all tokens inside this market for
    ///         offchain querying.
    function queryTokensListed() external view returns (address[] memory);

    /// @notice Returns whether `cToken` is listed in the lending market.
    /// @param cToken market token address.
    function isListed(address cToken) external view returns (bool);

    /// @notice The total amount of `cToken` that can be posted as collateral,
    ///         in shares.
    function collateralCaps(address cToken) external view returns (uint256);

    /// @notice The total amount of `cToken` underlying that can be borrowed,
    ///         in assets.
    function debtCaps(address cToken) external view returns (uint256);

    /// @notice Returns whether `addressToCheck` is an approved position
    ///         manager or not.
    /// @param addressToCheck Address to check for position management
    ///                       authority.
    function isPositionManager(
        address addressToCheck
    ) external view returns (bool);

    /// @notice Returns the assets an account has entered.
    /// @param account The address of the account to pull assets for.
    /// @return A dynamic list with the assets `account` has entered.
    function assetsOf(
        address account
    ) external view returns (address[] memory);

    /// @notice Determine `account`'s current status between collateral,
    ///         debt, and additional liquidity.
    /// @param account The account to determine liquidity for.
    /// @return The current total collateral amount of `account`.
    /// @return The maximum debt amount of `account` can take out with
    ///         their current collateral.
    /// @return The current total borrow amount of `account`.
    function statusOf(
        address account
    ) external returns (uint256, uint256, uint256);
}

// contracts/interfaces/IMulticallChecker.sol

interface IMulticallChecker {
    function checkCalldata(
        address caller,
        address target,
        bytes memory data
    ) external;
}

// contracts/interfaces/IPluginDelegable.sol

interface IPluginDelegable {
    /// @notice Returns whether a user or contract has the ability to act
    ///         on behalf of an account.
    /// @param user The address to check whether `delegate` has delegation
    ///             permissions.
    /// @param delegate The address that will be approved or restricted
    ///                 from delegated actions on behalf of the caller.
    /// @return result Indicates whether `delegate` is an approved delegate or
    ///                not of `user`, true = disabled, false = not disabled.
    function isDelegate(
        address user,
        address delegate
    ) external view returns (bool result);

    /// @notice Approves or restricts `delegate`'s authority to operate
    ///         on the caller's behalf.
    /// @dev NOTE: Be careful who you approve here!
    ///      They can delay actions such as asset redemption through repeated
    ///      denial of service.
    ///      Emits a {DelegateApproval} event.
    /// @param delegate The address that will be approved or restricted
    ///                 from delegated actions on behalf of the caller.
    /// @param isApproved Whether `delegate` is being approved or restricted
    ///                   of authority to operate on behalf of caller.
    function setDelegateApproval(address delegate, bool isApproved) external;
}

// contracts/interfaces/IWETH.sol

interface IWETH {
    function balanceOf(address user) external view returns (uint256);

    function deposit() external payable;

    function withdraw(uint256 amount) external;
}

// contracts/libraries/LowLevelCallsHelper.sol

library LowLevelCallsHelper {
    /// ERRORS ///

    error LowLevelCallsHelper__InsufficientBalance();
    error LowLevelCallsHelper__CallFailed();

    /// INTERNAL FUNCTIONS ///

    /// @notice Executes a low level .call() and validates that execution
    ///         was safely performed.
    /// @dev Bubbles up errors and reverts if anything along the execution
    ///      path failed or was a red flag.
    /// @param target The target contract address to execute .call() at.
    /// @param data The bytecode data to attach to the .call() execution
    ///             including the function signature hash and function call
    ///             parameters.
    function _call(
        address target,
        bytes memory data
    ) internal returns (bytes memory) {
        (bool success, bytes memory returnData) = target.call{value: 0}(data);
        
        return _verifyResult(target, success, returnData);
    }

    /// @notice Executes a low level .call(), with attached native token
    ///         and validates that execution was safely performed.
    /// @dev Bubbles up errors and reverts if anything along the execution
    ///      path failed or was a red flag.
    /// @param target The target contract address to execute .call() at.
    /// @param data The bytecode data to attach to the .call() execution
    ///             including the function signature hash and function call
    ///             parameters.
    /// @param value The amount of native token to attach to the low level
    ///              call.
    function _callWithNative(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert LowLevelCallsHelper__InsufficientBalance();
        }

        (bool success, bytes memory returnData) = target.call{
            value: value
        }(data);

        return _verifyResult(target, success, returnData);
    }

    /// @notice Executes a low level .delegatecall() and validates that
    ///         execution was safely performed.
    /// @dev Bubbles up errors and reverts if anything along the execution
    ///      path failed or was a red flag.
    /// @param target The target contract address to execute .delegatecall()
    ///               at.
    /// @param data The bytecode data to attach to the .call() execution
    ///             including the function signature hash and function call
    ///             parameters.
    function _delegateCall(
        address target,
        bytes memory data
    ) internal returns (bytes memory) {
        (bool success, bytes memory returnData) = target.delegatecall(data);

        return _verifyResult(target, success, returnData);
    }

    /// @dev Validates whether the low level call or delegate call was
    ///      successful and reverts in cases of bubbled up revert messages
    ///      or if `target` was not actually a contract.
    function _verifyResult(
        address target,
        bool success,
        bytes memory returnData
    ) internal view returns (bytes memory) {
        _propagateError(success, returnData);

        // If the call was successful but there was no return data we need
        // to make sure a contract was actually called as expected.
        if (returnData.length == 0 && target.code.length == 0) {
            revert LowLevelCallsHelper__CallFailed();
        }

        return returnData;
    }

    /// @dev Propagates an error message, if necessary.
    /// @param success If transaction was successful.
    /// @param resultData The transaction result data.
    function _propagateError(
        bool success,
        bytes memory resultData
    ) internal pure {
        if (!success) {
            if (resultData.length == 0) {
                revert LowLevelCallsHelper__CallFailed();
            }

            // Bubble up error if there was one given.
            assembly {
                revert(add(32, resultData), mload(resultData))
            }
        }
    }
}

// contracts/libraries/ReentrancyGuardTransient.sol

/// @notice Reentrancy guard mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ReentrancyGuardTransient.sol)
/// @dev Mai: Edited to always use transient storage.
abstract contract ReentrancyGuard {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Unauthorized reentrant call.
    error Reentrancy();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                          STORAGE                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Equivalent to: `uint32(bytes4(keccak256("Reentrancy()"))) | 1 << 71`.
    /// 9 bytes is large enough to avoid collisions in practice,
    /// but not too large to result in excessive bytecode bloat.
    uint256 private constant _REENTRANCY_GUARD_SLOT = 0x8000000000ab143c06;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      REENTRANCY GUARD                      */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Guards a function from reentrancy.
    modifier nonReentrant() virtual {
        /// @solidity memory-safe-assembly
        assembly {
            if tload(_REENTRANCY_GUARD_SLOT) {
                mstore(0x00, 0xab143c06) // `Reentrancy()`.
                revert(0x1c, 0x04)
            }
            tstore(_REENTRANCY_GUARD_SLOT, address())
        }
        _;
        /// @solidity memory-safe-assembly
        assembly {
            tstore(_REENTRANCY_GUARD_SLOT, 0)
        }
    }

    /// @dev Guards a view function from read-only reentrancy.
    modifier nonReadReentrant() virtual {
        /// @solidity memory-safe-assembly
        assembly {
            if tload(_REENTRANCY_GUARD_SLOT) {
                mstore(0x00, 0xab143c06) // `Reentrancy()`.
                revert(0x1c, 0x04)
            }
        }
        _;
    }
}

// contracts/libraries/external/SafeTransferLib.sol

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
///
/// @dev Note:
/// - For ETH transfers, please use `forceSafeTransferETH` for DoS protection.
/// - For ERC20s, this implementation won't check that a token has code,
///   responsibility is delegated to the caller.
library SafeTransferLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The ETH transfer has failed.
    error ETHTransferFailed();

    /// @dev The ERC20 `transferFrom` has failed.
    error TransferFromFailed();

    /// @dev The ERC20 `transfer` has failed.
    error TransferFailed();

    /// @dev The ERC20 `approve` has failed.
    error ApproveFailed();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Suggested gas stipend for contract receiving ETH that disallows any storage writes.
    uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300;

    /// @dev Suggested gas stipend for contract receiving ETH to perform a few
    /// storage reads and writes, but low enough to prevent griefing.
    uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       ETH OPERATIONS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // If the ETH transfer MUST succeed with a reasonable gas budget, use the force variants.
    //
    // The regular variants:
    // - Forwards all remaining gas to the target.
    // - Reverts if the target reverts.
    // - Reverts if the current contract has insufficient balance.
    //
    // The force variants:
    // - Forwards with an optional gas stipend
    //   (defaults to `GAS_STIPEND_NO_GRIEF`, which is sufficient for most cases).
    // - If the target reverts, or if the gas stipend is exhausted,
    //   creates a temporary contract to force send the ETH via `SELFDESTRUCT`.
    //   Future compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758.
    // - Reverts if the current contract has insufficient balance.
    //
    // The try variants:
    // - Forwards with a mandatory gas stipend.
    // - Instead of reverting, returns whether the transfer succeeded.

    /// @dev Sends `amount` (in wei) ETH to `to`.
    function safeTransferETH(address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(call(gas(), to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Sends all the ETH in the current contract to `to`.
    function safeTransferAllETH(address to) internal {
        /// @solidity memory-safe-assembly
        assembly {
            // Transfer all the ETH and check if it succeeded or not.
            if iszero(call(gas(), to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if lt(selfbalance(), amount) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
            if iszero(call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends all the ETH in the current contract to `to`, with a `gasStipend`.
    function forceSafeTransferAllETH(address to, uint256 gasStipend) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`.
    function forceSafeTransferETH(address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if lt(selfbalance(), amount) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
            if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends all the ETH in the current contract to `to`, with `GAS_STIPEND_NO_GRIEF`.
    function forceSafeTransferAllETH(address to) internal {
        /// @solidity memory-safe-assembly
        assembly {
            // forgefmt: disable-next-item
            if iszero(call(GAS_STIPEND_NO_GRIEF, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            success := call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)
        }
    }

    /// @dev Sends all the ETH in the current contract to `to`, with a `gasStipend`.
    function trySafeTransferAllETH(address to, uint256 gasStipend)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            success := call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      ERC20 OPERATIONS                      */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have at least `amount` approved for
    /// the current contract to manage.
    function safeTransferFrom(address token, address from, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, amount) // Store the `amount` argument.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends all of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have their entire balance approved for
    /// the current contract to manage.
    function safeTransferAllFrom(address token, address from, address to)
        internal
        returns (uint256 amount)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
            // Read the balance, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20)
                )
            ) {
                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x00, 0x23b872dd) // `transferFrom(address,address,uint256)`.
            amount := mload(0x60) // The `amount` is already at 0x60. We'll need to return it.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransfer(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sends all of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransferAll(address token, address to) internal returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`.
            mstore(0x20, address()) // Store the address of the current contract.
            // Read the balance, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20)
                )
            ) {
                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x14, to) // Store the `to` argument.
            amount := mload(0x34) // The `amount` is already at 0x34. We'll need to return it.
            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
    /// Reverts upon failure.
    function safeApprove(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
            // Perform the approval, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
    /// If the initial attempt to approve fails, attempts to reset the approved amount to zero,
    /// then retries the approval again (some tokens, e.g. USDT, requires this).
    /// Reverts upon failure.
    function safeApproveWithRetry(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
            // Perform the approval, retrying upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x34, 0) // Store 0 for the `amount`.
                mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
                pop(call(gas(), token, 0, 0x10, 0x44, codesize(), 0x00)) // Reset the approval.
                mstore(0x34, amount) // Store back the original `amount`.
                // Retry the approval, reverting upon failure.
                if iszero(
                    and(
                        or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                        call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                    )
                ) {
                    mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
                    revert(0x1c, 0x04)
                }
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Returns the amount of ERC20 `token` owned by `account`.
    /// Returns zero if the `token` does not exist.
    function balanceOf(address token, address account) internal view returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, account) // Store the `account` argument.
            mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
            amount :=
                mul(
                    mload(0x20),
                    and( // The arguments of `and` are evaluated from right to left.
                        gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                        staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)
                    )
                )
        }
    }
}

// contracts/libraries/external/ERC165Checker.sol

// @author Modified from OpenZeppelin Contracts (utils/introspection/ERC165Checker.sol)

/**
 * @dev Library used to query support of an interface declared via {IERC165}.
 *
 * Note that these functions return the actual result of the query: they do not
 * `revert` if an interface is not supported. It is up to the caller to decide
 * what to do in these cases.
 */
library ERC165Checker {
    // As per the EIP-165 spec, no interface should ever match 0xffffffff
    bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;

    /**
     * @dev Returns true if `account` supports the {IERC165} interface.
     */
    function supportsERC165(address account) internal view returns (bool) {
        // Any contract that implements ERC165 must explicitly indicate support of
        // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
        return
            supportsERC165InterfaceUnchecked(
                account,
                type(IERC165).interfaceId
            ) &&
            !supportsERC165InterfaceUnchecked(account, _INTERFACE_ID_INVALID);
    }

    /**
     * @dev Returns true if `account` supports the interface defined by
     * `interfaceId`. Support for {IERC165} itself is queried automatically.
     *
     * See {IERC165-supportsInterface}.
     */
    function supportsInterface(
        address account,
        bytes4 interfaceId
    ) internal view returns (bool) {
        // query support of both ERC165 as per the spec and support of _interfaceId
        return
            supportsERC165(account) &&
            supportsERC165InterfaceUnchecked(account, interfaceId);
    }

    /**
     * @notice Query if a contract implements an interface, does not check ERC165 support
     * @param account The address of the contract to query for support of an interface
     * @param interfaceId The interface identifier, as specified in ERC-165
     * @return true if the contract at account indicates support of the interface with
     * identifier interfaceId, false otherwise
     * @dev Assumes that account contains a contract that supports ERC165, otherwise
     * the behavior of this method is undefined. This precondition can be checked
     * with {supportsERC165}.
     *
     * Some precompiled contracts will falsely indicate support for a given interface, so caution
     * should be exercised when using this function.
     *
     * Interface identification is specified in ERC-165.
     */
    function supportsERC165InterfaceUnchecked(
        address account,
        bytes4 interfaceId
    ) internal view returns (bool) {
        // prepare call
        bytes memory encodedParams = abi.encodeCall(
            IERC165.supportsInterface,
            (interfaceId)
        );

        // perform static call
        bool success;
        uint256 returnSize;
        uint256 returnValue;
        assembly {
            success := staticcall(
                30000,
                account,
                add(encodedParams, 0x20),
                mload(encodedParams),
                0x00,
                0x20
            )
            returnSize := returndatasize()
            returnValue := mload(0x00)
        }

        return success && returnSize >= 0x20 && returnValue > 0;
    }
}

// contracts/interfaces/IVault.sol

interface IVault {
    function deposit(
        uint256 assets,
        address receiver
    ) external payable returns (uint256 shares);

    function redeem(
        uint256 shares,
        address receiver,
        address owner
    ) external returns (uint256 assets);

    function previewDeposit(
        uint256 assets
    ) external returns (uint256 shares);

    function previewRedeem(
        uint256 shares
    ) external returns (uint256 assets);

    function asset() external view returns (IERC20);
}

// contracts/libraries/CentralRegistryLib.sol

/// @title Curvance Central Registry Validation Library
/// @notice For validating that Central Registry is configured properly
///         on launch.
library CentralRegistryLib {
    /// ERRORS ///

    error CentralRegistryLib__InvalidCentralRegistry();

    /// INTERNAL FUNCTIONS ///

    /// @notice Validates that `cr` is the Protocol Central Registry.
    /// @param cr The proposed Protocol Central Registry.
    function _isCentralRegistry(ICentralRegistry cr) internal view {
        if (
            !ERC165Checker.supportsInterface(
                address(cr),
                type(ICentralRegistry).interfaceId
            )
        ) {
            revert CentralRegistryLib__InvalidCentralRegistry();
        }
    }
}

// contracts/libraries/Multicall.sol

/// @title Curvance Multicall helper.
/// @notice Multicall implementation to support pull based oracles and
///         other chained actions within Curvance.
abstract contract Multicall {
    /// TYPES ///

    /// @notice Struct containing information on the desired
    ///         multicall action to execute. 
    /// @param target The address of the target contract to execute the call at.
    /// @param isPriceUpdate Boolean indicating if the call is a price update.
    /// @param data The data to attach to the call.
    struct MulticallAction {
        address target;
        bool isPriceUpdate;
        bytes data;
    }

    /// ERRORS ///

    error Multicall__InvalidTarget();
    error Multicall__UnknownCalldata();

    /// EXTERNAL FUNCTIONS ///

    /// @notice Executes multiple calls in a single transaction.
    ///         This can be used to update oracle prices before
    ///         a liquidity dependent action.
    function multicall(
        MulticallAction[] calldata calls
    ) external returns (bytes[] memory results) {
        ICentralRegistry cr = _getCentralRegistry();
        uint256 numCalls = calls.length;
        results = new bytes[](numCalls);
        MulticallAction memory cachedCall;

        for (uint256 i; i < numCalls; ++i) {
            cachedCall = calls[i];
            
            if (cachedCall.isPriceUpdate) {
                // CASE: We need to update a pull based price oracle and we
                //       need a direct call to the target address.
                address checker = cr.multicallChecker(cachedCall.target);

                // Validate we know how to verify this calldata.
                if (checker == address(0)) {
                    revert Multicall__UnknownCalldata();
                }

                IMulticallChecker(checker).checkCalldata(
                    msg.sender,
                    cachedCall.target,
                    cachedCall.data
                );

                results[i] = LowLevelCallsHelper.
                    _call(cachedCall.target, cachedCall.data);
                
                continue;
            }

            // CASE: Not a price update and we need delegate the call to the
            //       current address.

            if (address(this) != cachedCall.target) {
                revert Multicall__InvalidTarget();
            }

            results[i] = LowLevelCallsHelper.
                _delegateCall(address(this), cachedCall.data);
        }
    }

    /// @notice Returns the Protocol Central Registry contract in interface
    ///         form.
    /// @dev MUST be overridden in every multicallable contract's
    ///      implementation.
    function _getCentralRegistry()
        internal
        view
        virtual
        returns (ICentralRegistry);
}

// contracts/libraries/CommonLib.sol

/// @title Curvance Common Library
/// @notice A utility library for common functions used throughout the
///        Curvance Protocol.
library CommonLib {

    /// @notice Returns whether `tokenA` matches `tokenB` or not.
    /// @param tokenA The first token address to compare.
    /// @param tokenB The second token address to compare.
    /// @return Whether `tokenA` matches `tokenB` or not.
    function _isMatchingToken(
        address tokenA,
        address tokenB
    ) internal pure returns (bool) {
        if (tokenA == tokenB) {
            return true;
        }

        if (_isNative(tokenA) && _isNative(tokenB)) {
            return true;
        }

        return false;
    }

    /// @notice Returns whether `token` is referring to network gas token
    ///         or not.
    /// @param token The address to review.
    /// @return result Whether `token` is referring to network gas token or
    ///                not.
    function _isNative(address token) internal pure returns (bool result) {
        result = token == address(0) ||
            token == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
    }

    /// @notice Returns balance of `token` for this contract.
    /// @param token The token address to query balance of.
    /// @return b The balance of `token` inside address(this).
    function _balanceOf(address token) internal view returns (uint256 b) {
        b = _isNative(token) ? address(this).balance :
            IERC20(token).balanceOf(address(this));
    }

    /// @notice Returns the Oracle Manager in interface form from `cr`.
    /// @param cr The address of the Protocol Central Registry.
    /// @return oracleManager The Oracle Manager in interface form.
    function _oracleManager(
        ICentralRegistry cr
    ) internal view returns (IOracleManager oracleManager) {
        oracleManager = IOracleManager(cr.oracleManager());
    }
}

// contracts/interfaces/IBorrowableCToken.sol

interface IBorrowableCToken {
    /// ICToken GENERIC FUNCTIONS ///

    /// @notice Starts a cToken market, executed via marketManager.
    /// @dev This initial mint is a failsafe against rounding exploits,
    ///      although, we protect against them in many ways,
    ///      better safe than sorry.
    /// @param by The account initializing deposits.
    function initializeDeposits(address by) external returns (bool);

    /// @notice Returns the decimals of the cToken.
    /// @dev We pull directly from underlying incase its a proxy contract,
    ///      and changes decimals on us.
    /// @return The number of decimals for this cToken,
    ///         matching the underlying token.
    function decimals() external view returns (uint8);

    /// @notice Returns whether the underlying token can be borrowed.
    /// @dev true = Borrowable; false = Not Borrowable.
    /// @return Whether this token is borrowable or not.
    function isBorrowable() external view returns (bool);

    /// @notice The token balance of an account.
    /// @dev Account address => account token balance.
    /// @param account The address of the account to query token balance for.
    function balanceOf(address account) external view returns (uint256);

    /// @notice Returns the address of the underlying asset.
    /// @return The address of the underlying asset.
    function asset() external view returns (address);

    /// @notice Returns the current vesting yield information.
    /// @return vestingRate % per second in `asset()`.
    /// @return vestingEnd When the current vesting period ends and interest
    ///                    rates paid will update.
    /// @return lastVestingClaim Last time pending vested yield was claimed.
    /// @return debtIndex The current market debt index.
    function getYieldInformation() external view returns (
        uint256 vestingRate,
        uint256 vestingEnd,
        uint256 lastVestingClaim,
        uint256 debtIndex
    );

    /// @notice Get a snapshot of `account` data in this Curvance token.
    /// @dev Used by marketManager to more efficiently perform
    ///      liquidity checks.
    ///      NOTE: Does not accrue pending interest as part of the call.
    /// @param account The address of the account to snapshot.
    /// @return The account snapshot of `account`.
    function getSnapshot(
        address account
    ) external view returns (AccountSnapshot memory);

    /// @notice Total number of cTokens in circulation.
    function totalSupply() external view returns (uint256);

    /// @notice Returns the total amount of assets held by the market.
    /// @return The total amount of assets held by the market.
    function totalAssets() external view returns (uint256);

    /// @notice Address of the Market Manager linked to this contract.
    function marketManager() external view returns (IMarketManager);

    /// @notice Returns the amount of assets that would be exchanged
    ///         by the vault for `shares` provided.
    /// @param shares The number of shares to theoretically use
    ///               for conversion to assets.
    /// @return The number of assets a user would receive for converting
    ///         `shares`.
    function convertToAssets(uint256 shares) external view returns (uint256);

    /// @notice Returns share -> asset exchange rate, in `WAD`.
    /// @dev Oracle Manager calculates cToken value from this exchange rate.
    function exchangeRate() external view returns (uint256);

    /// @notice Executes multiple calls in a single transaction.
    ///         This can be used to update oracle prices before
    ///         a liquidity dependent action.
    function multicall(
        Multicall.MulticallAction[] memory calls
    ) external returns (bytes[] memory results);

    /// @notice Caller deposits `assets` into the market and `receiver`
    ///         receives shares.
    /// @param assets The amount of the underlying assets to deposit.
    /// @param receiver The account that should receive the shares.
    /// @return shares The amount of shares received by `receiver`.
    function deposit(
        uint256 assets,
        address receiver
    ) external returns (uint256 shares);

    /// @notice Caller deposits `assets` into the market, `receiver` receives
    ///         shares, and collateralization of `assets` is enabled.
    /// @dev The caller must be depositing for themselves, or be managing
    ///      their position through a Position Manager contract.
    ///      If the caller is not approved to collateralize the function will
    ///      simply deposit assets on behalf of `receiver`.
    /// @param assets The amount of the underlying assets to deposit.
    /// @param receiver The account that should receive the shares.
    /// @return shares The amount of shares received by `receiver`.
    function depositAsCollateral(
        uint256 assets,
        address receiver
    ) external returns (uint256 shares);

    /// @notice Caller deposits `assets` into the market, `receiver` receives
    ///         shares, and collateralization of `assets` is enabled.
    /// @dev Requires that `receiver` approves the caller prior to
    ///      collateralize on their behalf.
    ///      NOTE: Be careful who you approve here!
    ///      They can delay redemption of assets through repeated
    ///      collateralization preventing withdrawal.
    ///      If the caller is not approved to collateralize the function will
    ///      simply deposit assets on behalf of `receiver`.
    /// @param assets The amount of the underlying assets to deposit.
    /// @param receiver The account that should receive the shares.
    /// @return shares The amount of shares received by `receiver`.
    function depositAsCollateralFor(
        uint256 assets,
        address receiver
    ) external returns (uint256 shares);

    /// @notice Withdraws assets, quoted in `shares` from the market,
    ///         and burns `owner` shares.
    /// @dev Does not force collateral to be withdrawn.
    /// @param shares The amount of shares to be redeemed.
    /// @param receiver The account that should receive the assets.
    /// @param owner The account that will burn their shares to withdraw
    ///              assets.
    /// @return assets The amount of assets redeemed by `owner`.
    function redeem(
        uint256 shares,
        address receiver,
        address owner
    ) external returns (uint256 assets);

    /// @notice Withdraws assets, quoted in `shares` from the market,
    ///         and burns `owner` shares, sending assets to `receiver`.
    /// @dev Does not force collateral to be withdrawn.
    /// @param shares The amount of shares to redeemed.
    /// @param receiver The account that should receive the assets.
    /// @param owner The account that will burn their shares to withdraw
    ///              assets.
    /// @return assets The amount of assets redeemed by `owner` and sent to
    ///                `receiver`.
    function redeemFor(
        uint256 shares,
        address receiver,
        address owner
    ) external returns (uint256 assets);

    /// @notice Caller withdraws assets from the market and burns their
    ///         shares, on behalf of `owner`.
    /// @dev Forces collateral to be withdrawn from `owner` collateralPosted.
    /// @param shares The amount of shares to redeemed.
    /// @param receiver The account that should receive the assets.
    /// @param owner The account that will burn their shares to withdraw
    ///              assets.
    /// @return assets The amount of assets redeemed by `owner` and sent to
    ///                `receiver`.
    function redeemCollateralFor(
        uint256 shares,
        address receiver,
        address owner
    ) external returns (uint256 assets);

    /// @notice Used by a Position Manager contract to redeem assets from
    ///         collateralized shares by `account` to perform a complex
    ///         action.
    /// @param assets The amount of the underlying assets to redeem.
    /// @param owner The owner address of assets to redeem.
    /// @param action Instructions for a deleverage action containing:
    ///               cToken Address of the cToken that will be redeemed from
    ///                      and assets swapped into `borrowableCToken` asset.
    ///               collateralAssets The amount of `cToken` that will be
    ///                                deleveraged, in assets.
    ///               borrowableCToken Address of the borrowableCToken that
    ///                                will have its debt paid.
    ///               repayAssets The amount of `borrowableCToken` asset that
    ///                           will be repaid to lenders.
    ///               swapActions Swap actions instructions converting
    ///                           collateral asset into debt asset to
    ///                           facilitate deleveraging.
    ///               auxData Optional auxiliary data for execution of a
    ///                       deleverage action.
    function withdrawByPositionManager(
        uint256 assets,
        address owner,
        IPositionManager.DeleverageAction memory action
    ) external;

    /// @notice Amount of tokens that has been posted as collateral,
    ///         in shares.
    function marketCollateralPosted() external view returns (uint256);

    /// @notice Shares of this token that an account has posted as collateral.
    /// @param account The address of the account to check collateral posted
    ///                of.
    function collateralPosted(address account) external view returns (uint256);

    /// @notice Transfers tokens from `account` to `liquidator`.
    /// @dev Will fail unless called by a cToken during the process
    ///      of liquidation.
    /// @param shares An array containing the number of cToken shares
    ///               to seize.
    /// @param liquidator The account receiving seized cTokens.
    /// @param accounts An array containing the accounts having
    ///                 collateral seized.
    function seize(
        uint256[] calldata shares,
        address liquidator,
        address[] calldata accounts
    ) external;

    /// @notice Allows users to simulate the effects of their deposit at
    ///         the current block.
    /// @param assets The number of assets to preview a deposit call.
    /// @return The shares received for depositing `assets`.
    function previewDeposit(uint256 assets) external view returns (uint256);

    /// IBorrowableCToken SPECIFIC FUNCTIONS ///

    /// @notice Address of the current Dynamic IRM.
    function IRM() external view returns (IDynamicIRM);

    /// @notice Fee that goes to protocol for interested generated for
    ///         lenders, in `WAD`.
    function interestFee() external view returns (uint256);

    /// @notice Can accrue interest yield, configure next interest accrual
    ///         period, and updates vesting data, if needed.
    /// @dev May emit a {RatesAdjusted} event.
    function accrueIfNeeded() external;

    /// @notice The amount of tokens that has been borrowed as debt,
    ///         in assets.
    function marketOutstandingDebt() external view returns (uint256);

    /// @notice Returns the current debt balance for `account`.
    /// @dev Note: Pending interest is not applied in this calculation.
    /// @param account The address whose debt balance should be calculated.
    /// @return result The current outstanding debt balance of `account`.
    function debtBalance(
        address account
    ) external view returns (uint256 result);

    /// @notice Updates pending interest and returns the current outstanding
    ///         debt owed by `account`.
    /// @param account The address whose debt balance should be calculated.
    /// @return result The current outstanding debt of `account`, with pending
    ///                interest applied.
    function debtBalanceUpdated(
        address account
    ) external returns (uint256 result);

    /// @notice Updates pending interest and returns the up-to-date exchange
    ///         rate from the underlying to the BorrowableCToken.
    /// @return result The share -> asset exchange rate, in `WAD`.
    function exchangeRateUpdated() external returns (uint256);

    /// @notice Used by a delegated user to borrow underlying tokens
    ///         from lenders, based on collateral posted inside this market
    ///         by `account`.
    /// @dev Updates pending interest before executing the borrow.
    ///      NOTE: Be careful who you approve here!
    ///      Not only can they take borrowed funds, but, they can delay
    ///      repayment through repeated borrows preventing withdrawal.
    /// @param assets The amount of the underlying asset to borrow.
    /// @param receiver The account who will receive the borrowed assets.
    /// @param owner The account who will have their assets borrowed
    ///              against.
    function borrowFor(
        uint256 assets,
        address receiver,
        address owner
    ) external;

    /// @notice Used by a Position Manager contract to borrow assets from
    ///         lenders, based on collateralized shares by `account` to
    ///         perform a complex action.
    /// @param assets The amount of the underlying assets to borrow.
    /// @param owner The account address to borrow on behalf of.
    /// @param action Instructions for a leverage action containing:
    ///               borrowableCToken Address of the borrowableCToken that
    ///                                will be borrowed from and assets
    ///                                swapped into `cToken` asset.
    ///               borrowAssets The amount borrowed from
    ///                            `borrowableCToken`, in assets.
    ///               cToken Curvance token assets that borrowed funds will be
    ///                      swapped into.
    ///               swapAction Swap action instructions converting debt
    ///                          asset into collateral asset to facilitate
    ///                          leveraging.
    ///               auxData Optional auxiliary data for execution of a
    ///                       leverage action.
    function borrowForPositionManager(
        uint256 assets,
        address owner,
        IPositionManager.LeverageAction memory action
    ) external;

    /// @notice Repays underlying tokens to lenders, on behalf of `account`,
    ///         freeing up their collateral posted inside this market.
    /// @dev Updates pending interest before executing the repay.
    /// @param assets The amount to repay, or 0 for the full outstanding
    ///               amount.
    /// @param owner The account address to repay on behalf of.
    function repayFor(uint256 assets, address owner) external;

    /// @notice Gets balance of this contract, in terms of the underlying.
    /// @dev This excludes changes in underlying token balance by the
    ///      current transaction, if any.
    /// @return The quantity of underlying tokens held by the market.
    function assetsHeld() external view returns (uint256);
}

// contracts/interfaces/ICToken.sol

struct AccountSnapshot {
    address asset;
    address underlying;
    uint8 decimals;
    bool isCollateral;
    uint256 collateralPosted;
    uint256 debtBalance;
}

interface ICToken {
    /// @notice Starts a cToken market, executed via marketManager.
    /// @dev This initial mint is a failsafe against rounding exploits,
    ///      although, we protect against them in many ways,
    ///      better safe than sorry.
    /// @param by The account initializing deposits.
    function initializeDeposits(address by) external returns (bool);

    /// @notice Returns the decimals of the cToken.
    /// @dev We pull directly from underlying incase its a proxy contract,
    ///      and changes decimals on us.
    /// @return The number of decimals for this cToken,
    ///         matching the underlying token.
    function decimals() external view returns (uint8);

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

    /// @notice Returns whether the underlying token can be borrowed.
    /// @dev true = Borrowable; false = Not Borrowable.
    /// @return Whether this token is borrowable or not.
    function isBorrowable() external view returns (bool);

    /// @notice The token balance of an account.
    /// @dev Account address => account token balance.
    /// @param account The address of the account to query token balance for.
    function balanceOf(address account) external view returns (uint256);

    /// @notice Returns the address of the underlying asset.
    /// @return The address of the underlying asset.
    function asset() external view returns (address);

    /// @notice Updates pending assets and returns a snapshot of the cToken
    ///         and `account` data.
    /// @dev Used by marketManager to more efficiently perform
    ///      liquidity checks.
    /// @return result The snapshot of the cToken and `account` data.
    function getSnapshotUpdated(
        address account
    ) external returns (AccountSnapshot memory result);

    /// @notice Get a snapshot of `account` data in this Curvance token.
    /// @dev NOTE: Does not accrue pending assets as part of the call.
    /// @param account The address of the account to snapshot.
    /// @return The account snapshot of `account`.
    function getSnapshot(
        address account
    ) external view returns (AccountSnapshot memory);

    /// @notice Total number of cTokens in circulation.
    function totalSupply() external view returns (uint256);

    /// @notice Returns the total amount of assets held by the market.
    /// @return The total amount of assets held by the market.
    function totalAssets() external view returns (uint256);

    /// @notice Address of the Market Manager linked to this contract.
    function marketManager() external view returns (IMarketManager);

    /// @notice Returns the amount of assets that would be exchanged
    ///         by the vault for `shares` provided.
    /// @param shares The number of shares to theoretically use
    ///               for conversion to assets.
    /// @return The number of assets a user would receive for converting
    ///         `shares`.
    function convertToAssets(uint256 shares) external view returns (uint256);

    /// @notice Updates pending assets and returns the up-to-date exchange
    ///         rate from the underlying to the BorrowableCToken.
    /// @dev Oracle Manager calculates cToken value from this exchange rate.
    /// @return The share -> asset exchange rate, in `WAD`.
    function exchangeRateUpdated() external returns (uint256) ;

    /// @notice Returns the up-to-date exchange rate from the underlying to
    ///         the BorrowableCToken.
    /// @dev Oracle Manager calculates cToken value from this exchange rate.
    /// @return The share -> asset exchange rate, in `WAD`.
    function exchangeRate() external view returns (uint256);

    /// @notice Executes multiple calls in a single transaction.
    ///         This can be used to update oracle prices before
    ///         a liquidity dependent action.
    function multicall(
        Multicall.MulticallAction[] memory calls
    ) external returns (bytes[] memory results);

    /// @notice Caller deposits `assets` into the market and `receiver`
    ///         receives shares.
    /// @param assets The amount of the underlying assets to deposit.
    /// @param receiver The account that should receive the shares.
    /// @return shares The amount of shares received by `receiver`.
    function deposit(
        uint256 assets,
        address receiver
    ) external returns (uint256 shares);

    /// @notice Caller deposits `assets` into the market, `receiver` receives
    ///         shares, and collateralization of `assets` is enabled.
    /// @dev The caller must be depositing for themselves, or be managing
    ///      their position through a Position Manager contract.
    /// @param assets The amount of the underlying assets to deposit.
    /// @param receiver The account that should receive the shares.
    /// @return shares The amount of shares received by `receiver`.
    function depositAsCollateral(
        uint256 assets,
        address receiver
    ) external returns (uint256 shares);

    /// @notice Caller deposits `assets` into the market, `receiver` receives
    ///         shares, and collateralization of `assets` is enabled.
    /// @dev Requires that `receiver` approves the caller prior to
    ///      collateralize on their behalf.
    ///      NOTE: Be careful who you approve here!
    ///      They can delay redemption of assets through repeated
    ///      collateralization preventing withdrawal.
    /// @param assets The amount of the underlying assets to deposit.
    /// @param receiver The account that should receive the shares.
    /// @return shares The amount of shares received by `receiver`.
    function depositAsCollateralFor(
        uint256 assets,
        address receiver
    ) external returns (uint256 shares);

    /// @notice Withdraws assets, quoted in `shares` from the market,
    ///         and burns `owner` shares.
    /// @dev Does not force collateral to be withdrawn.
    /// @param shares The amount of shares to be redeemed.
    /// @param receiver The account that should receive the assets.
    /// @param owner The account that will burn their shares to withdraw
    ///              assets.
    /// @return assets The amount of assets redeemed by `owner`.
    function redeem(
        uint256 shares,
        address receiver,
        address owner
    ) external returns (uint256 assets);

    /// @notice Withdraws assets, quoted in `shares` from the market,
    ///         and burns `owner` shares, sending assets to `receiver`.
    /// @dev Does not force collateral to be withdrawn.
    /// @param shares The amount of shares to redeemed.
    /// @param receiver The account that should receive the assets.
    /// @param owner The account that will burn their shares to withdraw
    ///              assets.
    /// @return assets The amount of assets redeemed by `owner` and sent to
    ///                `receiver`.
    function redeemFor(
        uint256 shares,
        address receiver,
        address owner
    ) external returns (uint256 assets);

    /// @notice Caller withdraws assets from the market and burns their
    ///         shares, on behalf of `owner`.
    /// @dev Forces collateral to be withdrawn from `owner` collateralPosted.
    /// @param shares The amount of shares to redeemed.
    /// @param receiver The account that should receive the assets.
    /// @param owner The account that will burn their shares to withdraw
    ///              assets.
    /// @return assets The amount of assets redeemed by `owner` and sent to
    ///                `receiver`.
    function redeemCollateralFor(
        uint256 shares,
        address receiver,
        address owner
    ) external returns (uint256 assets);

    /// @notice Used by a Position Manager contract to redeem assets from
    ///         collateralized shares by `account` to perform a complex
    ///         action.
    /// @param assets The amount of the underlying assets to redeem.
    /// @param owner The owner address of assets to redeem.
    /// @param action Instructions for a deleverage action containing:
    ///               cToken Address of the cToken that will be redeemed from
    ///                      and assets swapped into `borrowableCToken` asset.
    ///               collateralAssets The amount of `cToken` that will be
    ///                                deleveraged, in assets.
    ///               borrowableCToken Address of the borrowableCToken that
    ///                                will have its debt paid.
    ///               repayAssets The amount of `borrowableCToken` asset that
    ///                           will be repaid to lenders.
    ///               swapActions Swap actions instructions converting
    ///                           collateral asset into debt asset to
    ///                           facilitate deleveraging.
    ///               auxData Optional auxiliary data for execution of a
    ///                       deleverage action.
    function withdrawByPositionManager(
        uint256 assets,
        address owner,
        IPositionManager.DeleverageAction memory action
    ) external;

    /// @notice Amount of tokens that has been posted as collateral,
    ///         in shares.
    function marketCollateralPosted() external view returns (uint256);

    /// @notice Shares of this token that an account has posted as collateral.
    /// @param account The address of the account to check collateral posted
    ///                of.
    function collateralPosted(address account) external view returns (uint256);

    /// @notice Transfers tokens from `account` to `liquidator`.
    /// @dev Will fail unless called by a cToken during the process
    ///      of liquidation.
    /// @param shares An array containing the number of cToken shares
    ///               to seize.
    /// @param liquidator The account receiving seized cTokens.
    /// @param accounts An array containing the accounts having
    ///                 collateral seized.
    function seize(
        uint256[] calldata shares,
        address liquidator,
        address[] calldata accounts
    ) external;

    /// @notice Allows users to simulate the effects of their deposit at
    ///         the current block.
    /// @param assets The number of assets to preview a deposit call.
    /// @return The shares received for depositing `assets`.
    function previewDeposit(uint256 assets) external view returns (uint256);
}

// contracts/interfaces/IExternalCalldataChecker.sol

interface IExternalCalldataChecker {
    /// @notice Inspects calldata for compliance with other swap instruction
    ///         parameters.
    /// @dev Used on swap to inspect and validate calldata safety.
    /// @param swapAction Swap action instructions including both direct
    ///                   parameters and decodeable calldata.
    /// @param expectedRecipient Address who will receive proceeds of
    ///                          `swapAction`.
    function checkCalldata(
        SwapperLib.Swap memory swapAction,
        address expectedRecipient
    ) external;
}

// contracts/interfaces/IOracleManager.sol

interface IOracleManager {
    /// @notice Retrieves the price of a specified asset from either single
    ///         or dual oracles.
    /// @dev If the asset has one oracle, it fetches the price from a single feed.
    ///      If it has two or more oracles, it fetches the price from both feeds.
    /// @param asset The address of the asset to retrieve the price for.
    /// @param inUSD Whether the price should be returned in USD or ETH.
    /// @param getLower Whether the lower or higher price should be returned
    ///                 if two feeds are available.
    /// @return price The current price of `asset`.
    /// @return errorCode An error code related to fetching the price:
    ///                   '0' indicates no error fetching price.
    ///                   '1' indicates that price should be taken with
    ///                   caution.
    ///                   '2' indicates a complete failure in receiving
    ///                   a price.
    function getPrice(
        address asset,
        bool inUSD,
        bool getLower
    ) external view returns (uint256 price, uint256 errorCode);

    /// @notice Retrieves the prices of a collateral token and debt token
    ///         underlyings.
    /// @param collateralToken The cToken currently collateralized to price.
    /// @param debtToken The cToken borrowed from to price.
    /// @param errorCodeBreakpoint The error code that will cause liquidity
    ///                            operations to revert.
    /// @return collateralUnderlyingPrice The current price of
    ///                                   `collateralToken` underlying.
    /// @return debtUnderlyingPrice The current price of `debtToken`
    ///                             underlying.
    function getPriceIsolatedPair(
        address collateralToken,
        address debtToken,
        uint256 errorCodeBreakpoint
    ) external returns (uint256, uint256);

    /// @notice Retrieves the prices and account data of multiple assets
    ///         inside a Curvance Market.
    /// @param account The account to retrieve data for.
    /// @param assets An array of asset addresses to retrieve the prices for.
    /// @param errorCodeBreakpoint The error code that will cause liquidity
    ///                            operations to revert.
    /// @return AccountSnapshot[] Contains `assets` data for `account`
    /// @return uint256[] Contains prices for `assets`.
    /// @return uint256 The number of assets `account` is in.
    function getPricesForMarket(
        address account,
        address[] calldata assets,
        uint256 errorCodeBreakpoint
    )
        external
        returns (AccountSnapshot[] memory, uint256[] memory, uint256);

    /// @notice Potentially removes the dependency on pricing from `adaptor`
    ///         for `asset`, triggered by an adaptor's notification of a price
    ///         feed's removal.
    /// @notice Removes a pricing adaptor for `asset` triggered by an
    ///         adaptor's notification of a price feed's removal.
    /// @dev Requires that the adaptor is currently being used for pricing
    ///      for `asset`.
    ///      NOTE: This intentionally does not modify asset deviation values
    ///            because they simply wont be used if there are less than two
    ///            pricing adaptors in use, so no reason to delete data as
    ///            when a second pricing adaptor is configured the deviation
    ///            has the opportunity be to reconfigured anyway.
    /// @param asset The address of the asset to potentially remove the
    ///              pricing adaptor dependency from depending on current
    ///              `asset` configuration.
    function notifyFeedRemoval(address asset) external;

    /// @notice Returns the adaptors used for pricing `asset`.
    /// @param asset The address of the asset to get pricing adaptors for.
    /// @return The current adaptor(s) used for pricing `asset`.
    function getPricingAdaptors(
        address asset
    ) external view returns(address[] memory);

    /// @notice Address => Adaptor approval status.
    /// @param adaptor The address of the adaptor to check.
    /// @return True if the adaptor is supported, false otherwise.
    function isApprovedAdaptor(address adaptor) external view returns (bool);

    /// @notice Whether a token is recognized as a Curvance token or not,
    ///         if it is, will return its underlying asset address instead
    ///         of address (0).
    /// @return The cToken's underlying asset, or address(0) if not a cToken.
    function cTokens(address cToken) external view returns (address);

    /// @notice Checks if a given asset is supported by the Oracle Manager.
    /// @dev An asset is considered supported if it has one
    ///      or more associated price feeds.
    /// @param asset The address of the asset to check.
    /// @return True if the asset is supported, false otherwise.
    function isSupportedAsset(address asset) external view returns (bool);

    /// @notice Check whether L2 sequencer is valid or down.
    /// @return True if sequencer is valid.
    function isSequencerValid() external view returns (bool);
}

// contracts/interfaces/IPositionManager.sol

interface IPositionManager {
    /// TYPES ///

    /// @notice Instructions for a leverage action.
    /// @param borrowableCToken Address of the borrowableCToken that will be
    ///                         borrowed from and assets swapped into `cToken`
    ///                         asset.
    /// @param borrowAssets The amount borrowed from `borrowableCToken`,
    ///                     in assets.
    /// @param cToken Curvance token assets that borrowed funds will be
    ///               swapped into.
    /// @param expectedShares The expected shares received from depositing
    ///                       into `cToken` with swapped `borrowAssets`.
    /// @param swapAction Swap action instructions converting debt asset into
    ///                   collateral asset to facilitate leveraging.
    /// @param auxData Optional auxiliary data for execution of a leverage
    ///                action.
    struct LeverageAction {
        IBorrowableCToken borrowableCToken;
        uint256 borrowAssets;
        ICToken cToken;
        uint256 expectedShares;
        SwapperLib.Swap swapAction;
        bytes auxData;
    }

    /// @notice Instructions for a deleverage action.
    /// @param cToken Address of the cToken that will be redeemed from and
    ///               assets swapped into `borrowableCToken` asset.
    /// @param collateralAssets The amount of `cToken` that will be
    ///                         deleveraged, in assets.
    /// @param borrowableCToken Address of the borrowableCToken that will
    ///                         have its debt paid.
    /// @param repayAssets The amount of `borrowableCToken` asset that will
    ///                    be repaid to lenders.
    /// @param swapActions Swap actions instructions converting collateral
    ///                    asset into debt asset to facilitate deleveraging.
    /// @param auxData Optional auxiliary data for execution of a deleverage
    ///                action.
    struct DeleverageAction {
        ICToken cToken;
        uint256 collateralAssets;
        IBorrowableCToken borrowableCToken;
        uint256 repayAssets;
        SwapperLib.Swap[] swapActions;
        bytes auxData;
    }

    /// @notice Callback function to execute post borrow of
    ///         `borrowableCToken`'s asset and swap it to deposit
    ///         new collateralized shares for `owner`.
    /// @dev Measures slippage after this callback validating that `owner`
    ///      is still within acceptable liquidity requirements.
    /// @param borrowableCToken The borrowableCToken borrowed from.
    /// @param borrowAssets The amount of `borrowableCToken`'s asset borrowed.
    /// @param owner The account borrowing that will be swapped into
    ///              collateral assets deposited into Curvance.
    /// @param action Instructions for a leverage action containing:
    ///               borrowableCToken Address of the borrowableCToken that
    ///                                will be borrowed from and assets
    ///                                swapped into `cToken` asset.
    ///               borrowAssets The amount borrowed from
    ///                            `borrowableCToken`, in assets.
    ///               cToken Curvance token assets that borrowed funds will be
    ///                      swapped into.
    ///               swapAction Swap action instructions converting debt
    ///                          asset into collateral asset to facilitate
    ///                          leveraging.
    ///               auxData Optional auxiliary data for execution of a
    ///                       leverage action.
    function onBorrow(
        address borrowableCToken,
        uint256 borrowAssets,
        address owner,
        LeverageAction memory action
    ) external;

    /// @notice Callback function to execute post redemption of `cToken`'s
    ///         asset and swap it to repay outstanding debt for `owner`.
    /// @dev Measures slippage after this callback validating that `owner`
    ///      is still within acceptable liquidity requirements.
    /// @param cToken The Curvance token redeemed for its underlying.
    /// @param collateralAssets The amount of `cToken` underlying redeemed.
    /// @param owner The account redeeming collateral that will be used to
    ///              repay their active debt.
    /// @param action Instructions for a deleverage action containing:
    ///               cToken Address of the cToken that will be redeemed from
    ///                      and assets swapped into `borrowableCToken` asset.
    ///               collateralAssets The amount of `cToken` that will be
    ///                                deleveraged, in assets.
    ///               borrowableCToken Address of the borrowableCToken that
    ///                                will have its debt paid.
    ///               repayAssets The amount of `borrowableCToken` asset that
    ///                           will be repaid to lenders.
    ///               swapAction Swap actions instructions converting
    ///                          collateral asset into debt asset to
    ///                          facilitate deleveraging.
    ///               auxData Optional auxiliary data for execution of a
    ///                       deleverage action.
    function onRedeem(
        address cToken,
        uint256 collateralAssets,
        address owner,
        DeleverageAction memory action
    ) external;
}

// contracts/libraries/SwapperLib.sol

/// @title Curvance Swapper Library.
/// @notice Helper Library for performing composable swaps with varying
///         degrees of slippage tolerance. "Unsafe" swaps perform a standard
///         slippage check whereas "safe" swaps not only check for standard
///         slippage but also check against the Oracle Manager's prices as
///         well.
///         NOTE: This library does not intend to provide support for fee on
///               transfer tokens though support may be built in the future.
library SwapperLib {
    /// TYPES ///

    /// @notice Instructions to execute a swap, selling `inputToken` for
    ///         `outputToken`.
    /// @param inputToken Address of input token to swap from.
    /// @param inputAmount The amount of `inputToken` to swap.
    /// @param outputToken Address of token to swap into.
    /// @param target Address of the swapper, usually an aggregator.
    /// @param slippage The amount of value-loss acceptable from swapping
    ///                 between tokens.
    /// @param call Swap instruction calldata.
    struct Swap {
        address inputToken;
        uint256 inputAmount;
        address outputToken;
        address target;
        uint256 slippage;
        bytes call;
    }

    /// @notice Address identifying a chain's native token.
    address public constant native =
        0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

    /// ERRORS ///

    error SwapperLib__UnknownCalldata();
    error SwapperLib__TokenPrice(address inputToken);
    error SwapperLib__Slippage(uint256 slippage);
    error SwapperLib__SameTokens();

    /// INTERNAL FUNCTIONS ///

    /// @notice Swaps `action.inputToken` into a `action.outputToken`
    ///         without an extra slippage check.
    /// @param cr The address of the Protocol Central Registry to pull
    ///           addresses from.
    /// @param action Instructions for a swap action containing:
    ///               inputToken Address of input token to swap from.
    ///               inputAmount The amount of `inputToken` to swap.
    ///               outputToken Address of token to swap into.
    ///               target Address of the swapper, usually an aggregator.
    ///               slippage The amount of value-loss acceptable from
    ///                        swapping between tokens.
    ///               call Swap instruction calldata.
    /// @return outAmount The output amount received from swapping.
    function _swapUnsafe(
        ICentralRegistry cr,
        Swap memory action
    ) internal returns (uint256 outAmount) {
        address outputToken = action.outputToken;
        address inputToken = action.inputToken;

        // Do not use this library if the tokens are the same.
        if (CommonLib._isMatchingToken(inputToken, outputToken)) {
            revert SwapperLib__SameTokens();
        }

        address callDataChecker = cr.externalCalldataChecker(action.target);

        // Validate we know how to verify this calldata.
        if (callDataChecker == address(0)) {
            revert SwapperLib__UnknownCalldata();
        }

        // Verify calldata integrity.
        IExternalCalldataChecker(callDataChecker)
            .checkCalldata(action, address(this));

        // Approve `action.inputToken` to target contract, if necessary.
        _approveIfNeeded(inputToken, action.target, action.inputAmount);

        // Cache output token from struct for easier querying.
        
        uint256 balanceBefore = CommonLib._balanceOf(outputToken);

        uint256 callValue = CommonLib._isNative(inputToken) ?
            action.inputAmount : 0;

        // Execute the swap.
        LowLevelCallsHelper._callWithNative(
            action.target,
            action.call,
            callValue
        );

        // Remove any excess approval.
        _removeApprovalIfNeeded(inputToken, action.target);

        outAmount = CommonLib._balanceOf(outputToken) - balanceBefore;
    }

    /// @notice Swaps `action.inputToken` into a `action.outputToken`
    ///         with an extra slippage check.
    /// @param cr The address of the Protocol Central Registry to pull
    ///           addresses from.
    /// @param action Instructions for a swap action containing:
    ///                   inputToken Address of input token to swap from.
    ///                   inputAmount The amount of `inputToken` to swap.
    ///                   outputToken Address of token to swap into.
    ///                   target Address of the swapper, usually an
    ///                          aggregator.
    ///                   slippage The amount of value-loss acceptable from
    ///                            swapping between tokens.
    ///                   call Swap instruction calldata.
    /// @return outAmount The output amount received from swapping.
    function _swapSafe(
        ICentralRegistry cr,
        Swap memory action
    ) internal returns (uint256 outAmount) {
        if (action.slippage >= WAD) {
            revert SwapperLib__Slippage(action.slippage);
        }

        outAmount = _swapUnsafe(cr, action);

        IOracleManager om = CommonLib._oracleManager(cr);
        uint256 valueIn = _getValue(om, action.inputToken, action.inputAmount);
        uint256 valueOut = _getValue(om, action.outputToken, outAmount);

        // Check if swap received positive slippage.
        if (valueOut > valueIn) {
            return outAmount;
        }

        // Calculate % slippage from executed swap.
        uint256 slippage = FixedPointMathLib.mulDivUp(
            valueIn - valueOut,
            WAD,
            valueIn
        );

        if (slippage > action.slippage) {
            revert SwapperLib__Slippage(slippage);
        }
    }

    /// @notice Get the value of a token amount.
    /// @notice Approves `token` spending allowance, if needed.
    /// @param om The Oracle Manager address to call for pricing `token`.
    /// @param token The token address to get the value of.
    /// @param amount The amount of `token` to get the value of.
    function _getValue(
        IOracleManager om,
        address token,
        uint256 amount
    ) internal view returns (uint256 result) {
        // If token is native, normalize to address(0) so it is compatible 
        // with the Oracle Manager.
        if (token == address(0)) {
            token = native;
        }
        
        (uint256 price, uint256 errorCode) = om.getPrice(token, true, true);
        if (errorCode != NO_ERROR) {
            revert SwapperLib__TokenPrice(token);
        }

        // Return price in WAD form.
        result = FixedPointMathLib.mulDiv(
            price,
            amount,
            10 ** (CommonLib._isNative(token) ? 18 : IERC20(token).decimals())
        );
    }

    /// @notice Approves `token` spending allowance, if needed.
    /// @param token The token address to approve.
    /// @param spender The spender address.
    /// @param amount The approval amount.
    function _approveIfNeeded(
        address token,
        address spender,
        uint256 amount
    ) internal {
        if (!CommonLib._isNative(token)) {
            SafeTransferLib.safeApprove(token, spender, amount);
        }
    }

    /// @notice Removes `token` spending allowance, if needed.
    /// @param token The token address to remove approval.
    /// @param spender The spender address.
    function _removeApprovalIfNeeded(address token, address spender) internal {
        if (!CommonLib._isNative(token)) {
            if (IERC20(token).allowance(address(this), spender) > 0) {
                SafeTransferLib.safeApprove(token, spender, 0);
            }
        }
    }
}

// contracts/plugins/BaseZapper.sol

/// @title Curvance Base Zapper.
/// @notice Base contract for executing zap related actions.
/// @dev Curvance zapper contracts enshrine actions that
///      usually would require multiple sequential actions to facilitate,
///      specifically swapping, depositing, redemptions, and repayments.
///
///      Curvance token contracts facilitate these operations through our
///      standard contract interfaces and the plugin system.
///
///      Actions that include collateralization require plugin approval to the
///      corresponding zapper contract, to collateralize on behalf of another
///      user via a zapper both the zapper and the caller must have plugin
///      approval from the account being collateralized on behalf of.
///
///      The "base" contract is the basis on which all zapper contracts are
///      built on top of.
///
///      NOTE: Multicalling swapAndDeposit to perform multiple sequential
///            actions or to update oracle prices is blocked for native gas
///            token denominated actions to prevent double spend transaction
///            failures from delegate call.
///
abstract contract BaseZapper is Multicall, ReentrancyGuard {
    /// TYPES ///

    /// @param cToken The address of the cToken corresponding to the
    ///               redemption action.
    /// @param shares The amount of shares to redeemed.
    /// @param forceRedeemCollateral Whether the collateral should be always
    ///                              reduced from caller's collateralized
    ///                              shares.
    struct RedeemAction {
        address cToken;
        uint256 shares;
        bool forceRedeemCollateral;
    }

    /// CONSTANTS ///

    /// @notice Curvance DAO hub.
    ICentralRegistry public immutable centralRegistry;
    /// @notice The address of wrapped native token on this chain.
    address public immutable wrappedNative;

    /// ERRORS ///

    error BaseZapper__Unauthorized();
    error BaseZapper__UnderlyingTokenIsNotInputToken();
    error BaseZapper__ExecutionError();
    error BaseZapper__InsufficientToRepay();

    /// CONSTRUCTOR ///

    /// @param cr The address of the Protocol Central Registry.
    /// @param wNative The address of wrapped native token.
    constructor(ICentralRegistry cr, address wNative) {
        CentralRegistryLib._isCentralRegistry(cr);
        centralRegistry = cr;
        wrappedNative = wNative;
    }

    /// EXTERNAL FUNCTIONS ///

    /// @notice Allows contract to receive native tokens.
    receive() external payable {}

    /// INTERNAL FUNCTIONS ///

    /// @notice Routes `asset` token into `cToken`, for `receiver`.
    /// @param cToken The Curvance cToken address.
    /// @param asset The input token address, should match
    ///                   `cToken`.asset().
    /// @param assets The amount of `asset` to deposit into cToken
    ///               position.
    /// @param expectedShares The minimum expected amount of shares received
    ///                       from depositing `assets` of `asset` into
    ///                       `cToken` position.
    /// @param collateralizeFor Whether the deposit should be collateralized,
    ///                         requires plugin approval.
    /// @param receiver Address that should receive Curvance cTokens.
    /// @return shares The output amount of shares received.
    function _enterCurvance(
        address cToken,
        address asset,
        uint256 assets,
        uint256 expectedShares,
        bool collateralizeFor,
        address receiver
    ) internal returns (uint256 shares) {
        _checkAddresses(cToken, asset);

        // Approve `cToken` to take `asset`.
        SwapperLib._approveIfNeeded(asset, cToken, assets);

        // The user is trusting this plugin to not use their delegation
        // approval for nefarious reasons such as keeping them stuck in
        // positions, so lets validate that the receiver is a delegate
        // as well.
        if (collateralizeFor) {
            // Enter Curvance position and collateralize it.
            // This requires plugin approval for this zapper, and
            // if its a different user calling on behalf of `receiver`
            // we make sure that user also has delegation approved.
            if (
                msg.sender == receiver ||
                IPluginDelegable(cToken).isDelegate(receiver, msg.sender)
            ) {
                shares = ICToken(cToken).depositAsCollateralFor(
                    assets,
                    receiver
                );
            } else {
                revert BaseZapper__Unauthorized();
            }
        } else {
            // User wants to enter an uncollateralized a position so we dont
            // care if they are zapping for themselves or someone else.
            shares = ICToken(cToken).deposit(assets, receiver);
        }

        // Make sure sufficient shares were received from deposit action.
        if (shares < expectedShares) {
            revert BaseZapper__ExecutionError();
        }

        // Remove any leftover approval, if any.
        SwapperLib._removeApprovalIfNeeded(asset, cToken);
    }

    /// @notice Exits a Curvance position.
    /// @param cToken The address of the cToken to be redeemed from.
    /// @param asset The expected asset of `cToken`.
    /// @param shares The amount of shares to redeemed.
    /// @param expectedAssets The amount of assets expected to be redeemed
    ///                       on exiting Curvance position.
    /// @param forceRedeemCollateral Whether the collateral should be always
    ///                              reduced from callers collateralPosted.
    /// @param receiver Address that should receive redeemed assets.
    function _exitCurvance(
        address cToken,
        address asset,
        uint256 shares,
        uint256 expectedAssets,
        bool forceRedeemCollateral,
        address receiver
    ) internal {
        _checkAddresses(cToken, asset);
        uint256 assets;

        // Transfer tokens exited to the Zapper.
        if (forceRedeemCollateral) {
            assets = ICToken(cToken).redeemCollateralFor(
                shares,
                address(this),
                msg.sender
            );
        } else {
            assets = ICToken(cToken).redeemFor(
                shares,
                address(this),
                msg.sender
            );
        }

        // Make sure sufficient assets were received from redemption action.
        if (assets < expectedAssets) {
            revert BaseZapper__ExecutionError();
        }

        // Return any excess assets remaining back to the user.
        if (assets > expectedAssets) {
            _transferToRecipient(asset, receiver, assets - expectedAssets);
        }
    }

    /// @notice Repays Curvance lenders outstanding debt owed on behalf
    ///         of `receiver`.
    /// @param borrowableCToken The Curvance token address to repay
    ///                         outstanding debt to.
    /// @param debtAsset The asset token for `borrowableCToken` to repay
    ///                  debt in.
    /// @param assetsHeld The amount of `debtAsset` on hand.
    /// @param repayAssets The amount of debt to be repaid.
    /// @param receiver Address that should have outstanding debt repaid.
    /// @return The amount of `debtAsset` that was returned to `receiver`.
    function _repayDebt(
        address borrowableCToken,
        address debtAsset,
        uint256 assetsHeld,
        uint256 repayAssets,
        address receiver
    ) internal returns (uint256) {
        _checkAddresses(borrowableCToken, debtAsset);

        if (repayAssets == 0) {
            // Accrue any interest owed so repayAssets includes all
            // `receiver` debt.
            repayAssets = IBorrowableCToken(borrowableCToken)
                .debtBalanceUpdated(receiver);
        }
        
        // Revert if the swap experienced too much slippage.
        if (assetsHeld < repayAssets) {
            revert BaseZapper__InsufficientToRepay();
        }

        // Approve `debtAsset` transfer to cToken contract, if needed.
        SwapperLib._approveIfNeeded(debtAsset, borrowableCToken, repayAssets);

        // Execute repayment of outstanding debt.
        IBorrowableCToken(borrowableCToken).repayFor(repayAssets, receiver);

        // Remove any leftover approval, if any.
        SwapperLib._removeApprovalIfNeeded(debtAsset, borrowableCToken);
        assetsHeld -= repayAssets;

        // Transfer any remaining `debtAsset` to caller, we return funds to
        // caller instead of `receiver` for teams integrating on top of
        // Curvance and may want to keep those funds.
        if (assetsHeld > 0) {
            _transferToRecipient(debtAsset, msg.sender, assetsHeld);
        }

        return assetsHeld;
    }

    /// @notice Prepares for an upcoming swap based on input parameters
    ///         accounting for both native gas token routing versus
    ///         erc20s.
    /// @param inputToken The token being inputted into the upcoming swap.
    /// @param inputAmount The amount of `inputToken` to be swapped.
    /// @param depositAsWrappedNative Used when `inputToken` is the native gas
    ///                               token, indicates depositing native token
    ///                               into wrapped version or not.
    function _prepareSwap(
        address inputToken,
        uint256 inputAmount,
        bool depositAsWrappedNative
    ) internal {
        if (CommonLib._isNative(inputToken)) {
            // Validate `inputAmount` token attached equal to `msg.value`.
            if (inputAmount != msg.value) {
                revert BaseZapper__ExecutionError();
            }

            if (depositAsWrappedNative) {
                IWETH(wrappedNative).deposit{ value: inputAmount }();
            }
            return;
        }

        // For ERC20 input flows, there should be no msg.value.
        if (msg.value != 0) {
            revert BaseZapper__ExecutionError();
        }

        SafeTransferLib.safeTransferFrom(
            inputToken,
            msg.sender,
            address(this),
            inputAmount
        );
    }

    /// @notice Checks whether address parameters for a particular zapper
    ///         action on valid.
    /// @param cToken The Curvance cToken address.
    /// @param asset The input token address, should match `cToken`.asset().
    function _checkAddresses(address cToken, address asset) internal view {
        // Validate `cToken` is not the zero address.
        if (cToken == address(0)) {
            revert BaseZapper__ExecutionError();
        }

        // Validate `cToken` is listed in the Market Manager.
        IMarketManager mm = ICToken(cToken).marketManager();
        if (
            !centralRegistry.isMarketManager(address(mm)) ||
            !mm.isListed(cToken)
        ) {
            revert BaseZapper__Unauthorized();
        }

        // Validate `asset` matches asset of cToken contract.
        if (asset != ICToken(cToken).asset()) {
            revert BaseZapper__UnderlyingTokenIsNotInputToken();
        }
    }

    /// @notice Helper function for efficiently transferring tokens
    ///         to desired user.
    /// @param token The token to transfer to `receiver`,
    ///              this can be the network gas token.
    /// @param receiver The user receiving `token`.
    /// @param amount The amount of `token` to be transferred to `receiver`.
    function _transferToRecipient(
        address token,
        address receiver,
        uint256 amount
    ) internal {
        // If the token to refund is the chains' native gas token we wrap
        // then transfer it to prevent callback attack vectors.
        if (CommonLib._isNative(token)) {
            IWETH(wrappedNative).deposit{ value: amount }();
            token = wrappedNative;
        }

        SafeTransferLib.safeTransfer(token, receiver, amount);
    }

    /// @notice Returns the Central Registry contract in interface form.
    function _getCentralRegistry()
        internal
        view
        override
        returns (ICentralRegistry)
    {
        return centralRegistry;
    }
}

// contracts/plugins/market/SimpleZapper.sol

/// @title Curvance Simple Zapper.
/// @notice Simple Asset-specific contract for executing zap related
///         actions.
/// @dev Curvance zapper contracts enshrine actions that
///      usually would require multiple sequential actions to facilitate,
///      specifically swapping, depositing, redemptions, and repayments.
///
///      Curvance token contracts facilitate these operations through our
///      standard contract interfaces and the plugin system.
///
///      Actions that include collateralization require plugin approval to the
///      corresponding zapper contract, to collateralize on behalf of another
///      user via a zapper both the zapper and the caller must have plugin
///      approval from the account being collateralized on behalf of.
///
///      The "Simple" contract is the zapper for working with generic
///      non-native erc20 tokens such as USDC or WETH.
///
contract SimpleZapper is BaseZapper {
    /// CONSTRUCTOR ///

    /// @param cr The address of the Protocol Central Registry.
    /// @param wNative The address of wrapped native token.
    constructor(ICentralRegistry cr, address wNative) BaseZapper(cr, wNative) {}

    /// EXTERNAL FUNCTIONS ///

    /// @notice Swaps then deposits `swapAction.outputToken`, a cToken asset,
    ///         and enters into Curvance position, for `receiver`.
    /// @dev Requires plugin approval for collateralization.
    /// @param cToken The Curvance token (cToken) address to deposit into.
    /// @param depositAsWrappedNative Used when `inputToken` is the native gas
    ///                               token, indicates depositing native token
    ///                               into wrapped version or not.
    /// @param swapAction Instructions for executing a swap into collateral
    ///                   asset.
    ///                   Containing:
    ///                   inputToken Address of input token to swap from.
    ///                   inputAmount The amount of `inputToken` to swap.
    ///                   outputToken Address of token to swap into.
    ///                   target Address of the swapper, usually an
    ///                          aggregator.
    ///                   slippage The amount of value-loss acceptable from
    ///                            swapping between tokens.
    ///                   call Swap instruction calldata.
    /// @param expectedShares The minimum expected amount of shares received
    ///                       from depositing `amount` of
    ///                       `swapAction.outputToken` into `cToken` position.
    /// @param collateralizeFor Whether the deposit should be collateralized,
    ///                         requires plugin approval.
    /// @param receiver Address that should receive `cToken` shares.
    /// @return outAmount The `cToken` output shares received by `receiver`.
    function swapAndDeposit(
        address cToken,
        bool depositAsWrappedNative,
        SwapperLib.Swap memory swapAction,
        uint256 expectedShares,
        bool collateralizeFor,
        address receiver
    ) external virtual payable nonReentrant returns (uint256 outAmount) {
        _prepareSwap(
            swapAction.inputToken,
            swapAction.inputAmount,
            depositAsWrappedNative
        );

        // If we are trying to deposit wrapped native, we may be able to skip
        // a swapper call by changing the input token and checking versus
        // output token.
        if (CommonLib._isNative(swapAction.inputToken) && depositAsWrappedNative) {
            // Switch inputToken to wrapped native token address.
            swapAction.inputToken = address(wrappedNative);
        }

        if (CommonLib._isMatchingToken(swapAction.inputToken, swapAction.outputToken)) {
            outAmount = swapAction.inputAmount;
        } else {
            // Execute swap into cToken asset.
            outAmount = SwapperLib._swapUnsafe(centralRegistry, swapAction);
        }

        // Enter Curvance position.
        outAmount = _enterCurvance(
            cToken,
            swapAction.outputToken,
            outAmount,
            expectedShares,
            collateralizeFor,
            receiver
        );
    }

    /// @notice Swaps then repays outstanding debt for `receiver`.
    /// @dev Sends any excess debt token to `receiver`.
    /// @param borrowableCToken The Curvance token address to repay debt to.
    /// @param depositAsWrappedNative Used when `inputToken` is the native gas
    ///                               token, indicates depositing native token
    ///                               into wrapped version or not.
    /// @param swapAction Instructions for executing a swap into debt asset.
    ///                   Containing:
    ///                   inputToken Address of input token to swap from.
    ///                   inputAmount The amount of `inputToken` to swap.
    ///                   outputToken Address of token to swap into.
    ///                   target Address of the swapper, usually an
    ///                          aggregator.
    ///                   slippage The amount of value-loss acceptable from
    ///                            swapping between tokens.
    ///                   call Swap instruction calldata.
    /// @param repayAssets The amount of debt to be repaid, in assets.
    /// @param receiver Address that should have its outstanding debt repaid.
    /// @return outAmount The excess amount of debt token that was returned to
    ///                   `receiver`.
    function swapAndRepay(
        address borrowableCToken,
        bool depositAsWrappedNative,
        SwapperLib.Swap memory swapAction,
        uint256 repayAssets,
        address receiver
    ) external payable nonReentrant returns (uint256 outAmount) {
        _prepareSwap(
            swapAction.inputToken,
            swapAction.inputAmount,
            depositAsWrappedNative
        );

        // If we are trying to repay wrapped native, we may be able to skip
        // a swapper call by changing the input token and checking versus
        // output token.
        if (CommonLib._isNative(swapAction.inputToken) && depositAsWrappedNative) {
            // Switch inputToken to wrapped native token address.
            swapAction.inputToken = address(wrappedNative);
        }

        if (CommonLib._isMatchingToken(swapAction.inputToken, swapAction.outputToken)) {
            outAmount = swapAction.inputAmount;
        } else {
            // Execute swap into cToken asset.
            outAmount = SwapperLib._swapUnsafe(centralRegistry, swapAction);
        }

        // Repay `repayAssets` outstanding debt, 0 defaults to repaying
        // everything.
        outAmount = _repayDebt(
            borrowableCToken,
            swapAction.outputToken,
            outAmount,
            repayAssets,
            receiver
        );
    }

    /// @notice Withdraws from a Curvance position, and swaps it into
    ///         desired token (swapAction.outputToken).
    /// @dev Requires plugin approval for redemption.
    /// @param redeemAction Instructions for a redemption action containing:
    ///                     cToken The address of the cToken corresponding to
    ///                            the redemption action.
    ///                     shares The amount of shares to redeemed.
    ///                     forceRedeemCollateral Whether the collateral
    ///                                           should be always reduced
    ///                                           from caller's collateralized
    ///                                           shares.
    /// @param swapAction Instructions for executing a swap into debt asset.
    ///                   Containing:
    ///                   inputToken Address of input token to swap from.
    ///                   inputAmount The amount of `inputToken` to swap.
    ///                   outputToken Address of token to swap into.
    ///                   target Address of the swapper, usually an
    ///                          aggregator.
    ///                   slippage The amount of value-loss acceptable from
    ///                            swapping between tokens.
    ///                   call Swap instruction calldata.
    /// @param receiver Address that should receive `swapAction.outputToken`.
    /// @return outAmount The amount of `swapAction.outputToken` that was
    ///                   received by `receiver`.
    function redeemAndSwap(
        RedeemAction calldata redeemAction,
        SwapperLib.Swap memory swapAction,
        address receiver
    ) external nonReentrant returns (uint256 outAmount) {
        // Exit Curvance position.
        _exitCurvance(
            redeemAction.cToken,
            swapAction.inputToken,
            redeemAction.shares,
            swapAction.inputAmount,
            redeemAction.forceRedeemCollateral,
            receiver
        );

        if (CommonLib._isMatchingToken(swapAction.inputToken, swapAction.outputToken)) {
            outAmount = swapAction.inputAmount;
        } else {
            outAmount = SwapperLib._swapUnsafe(centralRegistry, swapAction);
        }

        _transferToRecipient(swapAction.outputToken, receiver, outAmount);
    }

    /// @notice Withdraws a Curvance position, swaps it into
    ///         desired token (swapAction.outputToken) and then deposits
    ///         it into a new position.
    /// @dev Requires plugin approval for redemption.
    /// @param cToken The Curvance token (cToken) address.
    /// @param redeemAction Instructions for a redemption action containing:
    ///                     cToken The address of the cToken corresponding to
    ///                            the redemption action.
    ///                     shares The amount of shares to redeemed.
    ///                     forceRedeemCollateral Whether the collateral
    ///                                           should be always reduced
    ///                                           from caller's collateralized
    ///                                           shares.
    /// @param expectedShares The minimum expected amount of shares received
    ///                       from depositing `amount` of
    ///                       `swapAction.outputToken` into `cToken` position.
    /// @param collateralizeFor Whether the deposit should be collateralized,
    ///                         requires plugin approval.
    /// @param receiver Address that should receive `cToken` shares.
    /// @return outAmount The `cToken` output shares received by `receiver`.
    function redeemSwapAndDeposit(
        address cToken,
        RedeemAction calldata redeemAction,
        SwapperLib.Swap memory swapAction,
        uint256 expectedShares,
        bool collateralizeFor,
        address receiver
    ) external nonReentrant returns (uint256 outAmount) {
        // Exit Curvance position.
        _exitCurvance(
            redeemAction.cToken,
            swapAction.inputToken,
            redeemAction.shares,
            swapAction.inputAmount,
            redeemAction.forceRedeemCollateral,
            receiver
        );

        if (CommonLib._isMatchingToken(swapAction.inputToken, swapAction.outputToken)) {
            outAmount = swapAction.inputAmount;
        } else {
            // Execute swap into `swapAction.outputToken` which should be
            // new cToken asset.
            outAmount = SwapperLib._swapUnsafe(centralRegistry, swapAction);
        }

        // Enter Curvance position.
        outAmount = _enterCurvance(
            cToken,
            swapAction.outputToken,
            outAmount,
            expectedShares,
            collateralizeFor,
            receiver
        );
    }
}

// contracts/plugins/market/NativeVaultZapper.sol

/// @title Curvance Native Vault Zapper.
/// @notice Native Vault-specific contract for executing zap related
///         actions.
/// @dev Curvance zapper contracts enshrine actions that
///      usually would require multiple sequential actions to facilitate,
///      specifically swapping, depositing, redemptions, and repayments.
///
///      Curvance token contracts facilitate these operations through our
///      standard contract interfaces and the plugin system.
///
///      Actions that include collateralization require plugin approval to the
///      corresponding zapper contract, to collateralize on behalf of another
///      user via a zapper both the zapper and the caller must have plugin
///      approval from the account being collateralized on behalf of.
///
///      The "Native Vault" contract is the zapper for working with
///      native-token based erc4626-like tokens such as shMON or aprMON. No type
///      specific "redeemAnd" is written as execution is intended to be the
///      as the "simple" zappers where redemptions are done directly on the
///      corresponding cToken.
///
contract NativeVaultZapper is SimpleZapper {
    /// CONSTRUCTOR ///

    /// @param cr The address of the Protocol Central Registry.
    /// @param wNative The address of wrapped native token.
    constructor(ICentralRegistry cr, address wNative) SimpleZapper(cr, wNative) {}

    /// EXTERNAL FUNCTIONS ///

    /// @notice Swaps, then deposits `swapAction.outputToken`, a cToken
    ///         asset, and enters into Curvance position, for `receiver`.
    /// @dev Requires plugin approval for collateralization.
    /// @param cToken The Curvance token (cToken) address to deposit into.
    /// @param swapAction Instructions for executing a swap into collateral
    ///                   asset.
    ///                   Containing:
    ///                   inputToken Address of input token to swap from.
    ///                   inputAmount The amount of `inputToken` to swap.
    ///                   outputToken Address of token to swap into.
    ///                   target Address of the swapper, usually an
    ///                          aggregator.
    ///                   slippage The amount of value-loss acceptable from
    ///                            swapping between tokens.
    ///                   call Swap instruction calldata.
    /// @param expectedShares The minimum expected amount of shares received
    ///                       from depositing `amount` of
    ///                       `swapAction.outputToken` into `cToken` position.
    /// @param collateralizeFor Whether the zapped deposit should be
    ///                         collateralized afterwards.
    /// @param receiver Address that should receive `cToken` shares.
    /// @return outAmount The `cToken` output shares received by `receiver`.
    function swapAndDeposit(
        address cToken,
        bool /* depositAsWrappedNative */,
        SwapperLib.Swap memory swapAction,
        uint256 expectedShares,
        bool collateralizeFor,
        address receiver
    ) external override payable nonReentrant returns (uint256 outAmount) {
        _prepareSwap(swapAction.inputToken, swapAction.inputAmount, false);

        if (!CommonLib._isNative(swapAction.outputToken)) {
            revert BaseZapper__UnderlyingTokenIsNotInputToken();
        }

        if (CommonLib._isMatchingToken(swapAction.inputToken, swapAction.outputToken)) {
            outAmount = swapAction.inputAmount;        
        } else if (swapAction.inputToken == wrappedNative) {
            // Unwrap native
            IWETH(wrappedNative).withdraw(swapAction.inputAmount);
            outAmount = swapAction.inputAmount;
        } else {
            // Execute swap into cToken asset.
            outAmount = SwapperLib._swapUnsafe(centralRegistry, swapAction);
        }

        address vault = ICToken(cToken).asset();

        // Deposit into vault.
        outAmount = IVault(vault)
            .deposit{value: outAmount}(outAmount, address(this));
        
        // Enter Curvance position.
        outAmount = _enterCurvance(
            cToken,
            vault,
            outAmount,
            expectedShares,
            collateralizeFor,
            receiver
        );
    }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"contract ICentralRegistry","name":"cr","type":"address"},{"internalType":"address","name":"wNative","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BaseZapper__ExecutionError","type":"error"},{"inputs":[],"name":"BaseZapper__InsufficientToRepay","type":"error"},{"inputs":[],"name":"BaseZapper__Unauthorized","type":"error"},{"inputs":[],"name":"BaseZapper__UnderlyingTokenIsNotInputToken","type":"error"},{"inputs":[],"name":"CentralRegistryLib__InvalidCentralRegistry","type":"error"},{"inputs":[],"name":"LowLevelCallsHelper__CallFailed","type":"error"},{"inputs":[],"name":"LowLevelCallsHelper__InsufficientBalance","type":"error"},{"inputs":[],"name":"Multicall__InvalidTarget","type":"error"},{"inputs":[],"name":"Multicall__UnknownCalldata","type":"error"},{"inputs":[],"name":"Reentrancy","type":"error"},{"inputs":[],"name":"SwapperLib__SameTokens","type":"error"},{"inputs":[],"name":"SwapperLib__UnknownCalldata","type":"error"},{"inputs":[],"name":"centralRegistry","outputs":[{"internalType":"contract ICentralRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bool","name":"isPriceUpdate","type":"bool"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Multicall.MulticallAction[]","name":"calls","type":"tuple[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"bool","name":"forceRedeemCollateral","type":"bool"}],"internalType":"struct BaseZapper.RedeemAction","name":"redeemAction","type":"tuple"},{"components":[{"internalType":"address","name":"inputToken","type":"address"},{"internalType":"uint256","name":"inputAmount","type":"uint256"},{"internalType":"address","name":"outputToken","type":"address"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"slippage","type":"uint256"},{"internalType":"bytes","name":"call","type":"bytes"}],"internalType":"struct SwapperLib.Swap","name":"swapAction","type":"tuple"},{"internalType":"address","name":"receiver","type":"address"}],"name":"redeemAndSwap","outputs":[{"internalType":"uint256","name":"outAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"components":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"bool","name":"forceRedeemCollateral","type":"bool"}],"internalType":"struct BaseZapper.RedeemAction","name":"redeemAction","type":"tuple"},{"components":[{"internalType":"address","name":"inputToken","type":"address"},{"internalType":"uint256","name":"inputAmount","type":"uint256"},{"internalType":"address","name":"outputToken","type":"address"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"slippage","type":"uint256"},{"internalType":"bytes","name":"call","type":"bytes"}],"internalType":"struct SwapperLib.Swap","name":"swapAction","type":"tuple"},{"internalType":"uint256","name":"expectedShares","type":"uint256"},{"internalType":"bool","name":"collateralizeFor","type":"bool"},{"internalType":"address","name":"receiver","type":"address"}],"name":"redeemSwapAndDeposit","outputs":[{"internalType":"uint256","name":"outAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"bool","name":"","type":"bool"},{"components":[{"internalType":"address","name":"inputToken","type":"address"},{"internalType":"uint256","name":"inputAmount","type":"uint256"},{"internalType":"address","name":"outputToken","type":"address"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"slippage","type":"uint256"},{"internalType":"bytes","name":"call","type":"bytes"}],"internalType":"struct SwapperLib.Swap","name":"swapAction","type":"tuple"},{"internalType":"uint256","name":"expectedShares","type":"uint256"},{"internalType":"bool","name":"collateralizeFor","type":"bool"},{"internalType":"address","name":"receiver","type":"address"}],"name":"swapAndDeposit","outputs":[{"internalType":"uint256","name":"outAmount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"borrowableCToken","type":"address"},{"internalType":"bool","name":"depositAsWrappedNative","type":"bool"},{"components":[{"internalType":"address","name":"inputToken","type":"address"},{"internalType":"uint256","name":"inputAmount","type":"uint256"},{"internalType":"address","name":"outputToken","type":"address"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"slippage","type":"uint256"},{"internalType":"bytes","name":"call","type":"bytes"}],"internalType":"struct SwapperLib.Swap","name":"swapAction","type":"tuple"},{"internalType":"uint256","name":"repayAssets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"swapAndRepay","outputs":[{"internalType":"uint256","name":"outAmount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"wrappedNative","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

60c060405234801561000f575f5ffd5b50604051611fe9380380611fe983398101604081905261002e91610177565b8181818161003b82610057565b6001600160a01b039182166080521660a052506101af92505050565b610068816399011ef160e01b610088565b610085576040516369b5e45b60e11b815260040160405180910390fd5b50565b5f610092836100aa565b80156100a357506100a383836100dd565b9392505050565b5f6100bc826301ffc9a760e01b6100dd565b80156100d757506100d5826001600160e01b03196100dd565b155b92915050565b6040516001600160e01b0319821660248201525f90819060440160408051601f19818403018152919052602080820180516001600160e01b03166301ffc9a760e01b17815282519293505f9283928392909183918a617530fa92503d91505f51905082801561014d575060208210155b801561015857505f81115b979650505050505050565b6001600160a01b0381168114610085575f5ffd5b5f5f60408385031215610188575f5ffd5b825161019381610163565b60208401519092506101a481610163565b809150509250929050565b60805160a051611dc66102235f395f818161017b015281816101fc015281816103280152818161036c015281816109360152818161106a01526110da01525f818160c601528181610245015281816103dc0152818161058501528181610654015281816106a2015261148d0152611dc65ff3fe608060405260043610610071575f3560e01c80639d2c4fe31161004c5780639d2c4fe314610100578063d4b386d11461011f578063e8bbf5d71461013e578063eb6d3a111461016a575f5ffd5b806367a3a4841461007c578063801c2e9f146100a25780638f73dcfa146100b5575f5ffd5b3661007857005b5f5ffd5b61008f61008a36600461187f565b61019d565b6040519081526020015b60405180910390f35b61008f6100b03660046118fa565b610295565b3480156100c0575f5ffd5b506100e87f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610099565b34801561010b575f5ffd5b5061008f61011a36600461199c565b610502565b34801561012a575f5ffd5b5061008f610139366004611a1a565b6105d7565b348015610149575f5ffd5b5061015d610158366004611a78565b61069e565b6040516100999190611b15565b348015610175575f5ffd5b506100e87f000000000000000000000000000000000000000000000000000000000000000081565b5f688000000000ab143c065c156101bb5763ab143c065f526004601cfd5b30688000000000ab143c065d6101d9845f0151856020015187610900565b83516101e4906109d5565b80156101ed5750845b1561021f576001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001684525b610230845f01518560400151610a0e565b156102405750602083015161026d565b61026a7f000000000000000000000000000000000000000000000000000000000000000085610a5e565b90505b61027e868560400151838686610c00565b90505f688000000000ab143c065d95945050505050565b5f688000000000ab143c065c156102b35763ab143c065f526004601cfd5b30688000000000ab143c065d6102d1855f015186602001515f610900565b6102de85604001516109d5565b6102fb5760405163ecaf3a9760e01b815260040160405180910390fd5b61030c855f01518660400151610a0e565b1561031c57506020840151610404565b84516001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169116036103d7576020850151604051632e1a7d4d60e01b815260048101919091527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d906024015f604051808303815f87803b1580156103b5575f5ffd5b505af11580156103c7573d5f5f3e3d5ffd5b5050505084602001519050610404565b6104017f000000000000000000000000000000000000000000000000000000000000000086610a5e565b90505b5f876001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610441573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104659190611b78565b604051636e553f6560e01b8152600481018490523060248201529091506001600160a01b03821690636e553f6590849060440160206040518083038185885af11580156104b4573d5f5f3e3d5ffd5b50505050506040513d601f19601f820116820180604052508101906104d99190611b93565b91506104e9888284888888610d38565b9150505f688000000000ab143c065d9695505050505050565b5f688000000000ab143c065c156105205763ab143c065f526004601cfd5b30688000000000ab143c065d61055f61053c6020880188611baa565b8651602080890151908a01359061055960608c0160408d01611bc5565b87610f11565b610570855f01518660400151610a0e565b15610580575060208401516105ad565b6105aa7f000000000000000000000000000000000000000000000000000000000000000086610a5e565b90505b6105bf87866040015183878787610d38565b90505f688000000000ab143c065d9695505050505050565b5f688000000000ab143c065c156105f55763ab143c065f526004601cfd5b30688000000000ab143c065d61062e6106116020860186611baa565b8451602080870151908801359061055960608a0160408b01611bc5565b61063f835f01518460400151610a0e565b1561064f5750602082015161067c565b6106797f000000000000000000000000000000000000000000000000000000000000000084610a5e565b90505b61068b8360400151838361105a565b5f688000000000ab143c065d9392505050565b60607f000000000000000000000000000000000000000000000000000000000000000082806001600160401b038111156106da576106da611729565b60405190808252806020026020018201604052801561070d57816020015b60608152602001906001900390816106f85790505b5060408051606080820183525f80835260208301819052928201529194505b828110156108f65786868281811061074657610746611be0565b90506020028101906107589190611bf4565b61076190611c12565b915081602001511561089857815160405163191d0cc560e11b81526001600160a01b0391821660048201525f9186169063323a198a90602401602060405180830381865afa1580156107b5573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107d99190611b78565b90506001600160a01b03811661080257604051632f3285fb60e21b815260040160405180910390fd5b8251604080850151905163bd0226d760e01b81526001600160a01b0384169263bd0226d7926108379233929190600401611c97565b5f604051808303815f87803b15801561084e575f5ffd5b505af1158015610860573d5f5f3e3d5ffd5b50505050610875835f01518460400151611107565b86838151811061088757610887611be0565b6020026020010181905250506108ee565b81516001600160a01b031630146108c257604051637720ccd960e01b815260040160405180910390fd5b6108d030836040015161117c565b8582815181106108e2576108e2611be0565b60200260200101819052505b60010161072c565b5050505092915050565b610909836109d5565b156109aa5734821461092e57604051630fc1653d60e11b815260040160405180910390fd5b80156109a5577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004015f604051808303818588803b15801561098d575f5ffd5b505af115801561099f573d5f5f3e3d5ffd5b50505050505b505050565b34156109c957604051630fc1653d60e11b815260040160405180910390fd5b6109a5833330856111d0565b5f6001600160a01b0382161580610a08575073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b038316145b92915050565b5f816001600160a01b0316836001600160a01b031603610a3057506001610a08565b610a39836109d5565b8015610a495750610a49826109d5565b15610a5657506001610a08565b505f92915050565b604081015181515f9190610a728183610a0e565b15610a9057604051636991e51560e11b815260040160405180910390fd5b6060840151604051631d4686fd60e31b81526001600160a01b0391821660048201525f9187169063ea3437e890602401602060405180830381865afa158015610adb573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610aff9190611b78565b90506001600160a01b038116610b2857604051637409771560e11b815260040160405180910390fd5b60405163383d5bf360e11b81526001600160a01b0382169063707ab7e690610b569088903090600401611cc2565b5f604051808303815f87803b158015610b6d575f5ffd5b505af1158015610b7f573d5f5f3e3d5ffd5b50505050610b96828660600151876020015161121f565b5f610ba084611237565b90505f610bac846109d5565b610bb6575f610bbc565b86602001515b9050610bd187606001518860a00151836112b7565b50610be0848860600151611350565b81610bea86611237565b610bf49190611d40565b98975050505050505050565b5f610c0b86866113e3565b825f03610c7e576040516357d159d560e01b81526001600160a01b0383811660048301528716906357d159d5906024016020604051808303815f875af1158015610c57573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c7b9190611b93565b92505b82841015610c9f576040516367d8a00f60e01b815260040160405180910390fd5b610caa85878561121f565b604051632796469160e21b8152600481018490526001600160a01b038381166024830152871690639e591a44906044015f604051808303815f87803b158015610cf1575f5ffd5b505af1158015610d03573d5f5f3e3d5ffd5b50505050610d118587611350565b610d1b8385611d40565b93508315610d2e57610d2e85338661105a565b5091949350505050565b5f610d4387876113e3565b610d4e86888761121f565b8215610e6957336001600160a01b0383161480610dd45750604051635fec5d0b60e01b81526001600160a01b038381166004830152336024830152881690635fec5d0b90604401602060405180830381865afa158015610db0573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610dd49190611d5f565b15610e505760405163b3bffb4560e01b8152600481018690526001600160a01b03838116602483015288169063b3bffb45906044016020604051808303815f875af1158015610e25573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e499190611b93565b9050610edc565b604051630ba2198760e21b815260040160405180910390fd5b604051636e553f6560e01b8152600481018690526001600160a01b038381166024830152881690636e553f65906044016020604051808303815f875af1158015610eb5573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ed99190611b93565b90505b83811015610efd57604051630fc1653d60e11b815260040160405180910390fd5b610f078688611350565b9695505050505050565b610f1b86866113e3565b5f8215610f9d57604051636779db5b60e01b8152600481018690523060248201523360448201526001600160a01b03881690636779db5b906064016020604051808303815f875af1158015610f72573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f969190611b93565b9050611014565b604051630b817f5160e31b8152600481018690523060248201523360448201526001600160a01b03881690635c0bfa88906064016020604051808303815f875af1158015610fed573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110119190611b93565b90505b8381101561103557604051630fc1653d60e11b815260040160405180910390fd5b8381111561105157611051868361104c8785611d40565b61105a565b50505050505050565b611063836109d5565b156110fc577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004015f604051808303818588803b1580156110c1575f5ffd5b505af11580156110d3573d5f5f3e3d5ffd5b50505050507f000000000000000000000000000000000000000000000000000000000000000092505b6109a5838383611618565b60605f5f846001600160a01b03165f856040516111249190611d7a565b5f6040518083038185875af1925050503d805f811461115e576040519150601f19603f3d011682016040523d82523d5f602084013e611163565b606091505b5091509150611173858383611658565b95945050505050565b60605f5f846001600160a01b0316846040516111989190611d7a565b5f60405180830381855af49150503d805f811461115e576040519150601f19603f3d011682016040523d82523d5f602084013e611163565b60405181606052826040528360601b602c526323b872dd60601b600c5260205f6064601c5f895af13d1560015f5114171661121257637939f4245f526004601cfd5b5f60605260405250505050565b611228836109d5565b6109a5576109a58383836116a0565b5f611241826109d5565b6112b0576040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa158015611287573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112ab9190611b93565b610a08565b4792915050565b6060814710156112da5760405163595909b560e11b815260040160405180910390fd5b5f5f856001600160a01b031684866040516112f59190611d7a565b5f6040518083038185875af1925050503d805f811461132f576040519150601f19603f3d011682016040523d82523d5f602084013e611334565b606091505b5091509150611344868383611658565b925050505b9392505050565b611359826109d5565b6113df57604051636eb1769f60e11b81523060048201526001600160a01b0382811660248301525f919084169063dd62ed3e90604401602060405180830381865afa1580156113aa573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113ce9190611b93565b11156113df576113df82825f6116a0565b5050565b6001600160a01b03821661140a57604051630fc1653d60e11b815260040160405180910390fd5b5f826001600160a01b03166341ed2c126040518163ffffffff1660e01b8152600401602060405180830381865afa158015611447573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061146b9190611b78565b604051637d5528bd60e01b81526001600160a01b0380831660048301529192507f000000000000000000000000000000000000000000000000000000000000000090911690637d5528bd90602401602060405180830381865afa1580156114d4573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114f89190611d5f565b15806115695750604051637bca031760e11b81526001600160a01b03848116600483015282169063f794062e90602401602060405180830381865afa158015611543573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115679190611d5f565b155b1561158757604051630ba2198760e21b815260040160405180910390fd5b826001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115c3573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115e79190611b78565b6001600160a01b0316826001600160a01b0316146109a55760405163ecaf3a9760e01b815260040160405180910390fd5b816014528060345263a9059cbb60601b5f5260205f604460105f875af13d1560015f5114171661164f576390b8ec185f526004601cfd5b5f603452505050565b606061166483836116d7565b815115801561167b57506001600160a01b0384163b155b15611699576040516314859aeb60e21b815260040160405180910390fd5b5092915050565b816014528060345263095ea7b360601b5f5260205f604460105f875af13d1560015f5114171661164f57633e3f8f735f526004601cfd5b816113df5780515f036116fd576040516314859aeb60e21b815260040160405180910390fd5b805181602001fd5b6001600160a01b0381168114611719575f5ffd5b50565b8015158114611719575f5ffd5b634e487b7160e01b5f52604160045260245ffd5b60405160c081016001600160401b038111828210171561175f5761175f611729565b60405290565b5f82601f830112611774575f5ffd5b81356001600160401b0381111561178d5761178d611729565b604051601f8201601f19908116603f011681016001600160401b03811182821017156117bb576117bb611729565b6040528181528382016020018510156117d2575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f60c082840312156117fe575f5ffd5b61180661173d565b9050813561181381611705565b815260208281013590820152604082013561182d81611705565b6040820152606082013561184081611705565b60608201526080828101359082015260a08201356001600160401b03811115611867575f5ffd5b61187384828501611765565b60a08301525092915050565b5f5f5f5f5f60a08688031215611893575f5ffd5b853561189e81611705565b945060208601356118ae8161171c565b935060408601356001600160401b038111156118c8575f5ffd5b6118d4888289016117ee565b9350506060860135915060808601356118ec81611705565b809150509295509295909350565b5f5f5f5f5f5f60c0878903121561190f575f5ffd5b863561191a81611705565b9550602087013561192a8161171c565b945060408701356001600160401b03811115611944575f5ffd5b61195089828a016117ee565b9450506060870135925060808701356119688161171c565b915060a087013561197881611705565b809150509295509295509295565b5f60608284031215611996575f5ffd5b50919050565b5f5f5f5f5f5f61010087890312156119b2575f5ffd5b86356119bd81611705565b95506119cc8860208901611986565b945060808701356001600160401b038111156119e6575f5ffd5b6119f289828a016117ee565b94505060a0870135925060c0870135611a0a8161171c565b915060e087013561197881611705565b5f5f5f60a08486031215611a2c575f5ffd5b611a368585611986565b925060608401356001600160401b03811115611a50575f5ffd5b611a5c868287016117ee565b9250506080840135611a6d81611705565b809150509250925092565b5f5f60208385031215611a89575f5ffd5b82356001600160401b03811115611a9e575f5ffd5b8301601f81018513611aae575f5ffd5b80356001600160401b03811115611ac3575f5ffd5b8560208260051b8401011115611ad7575f5ffd5b6020919091019590945092505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b82811015611b6c57603f19878603018452611b57858351611ae7565b94506020938401939190910190600101611b3b565b50929695505050505050565b5f60208284031215611b88575f5ffd5b815161134981611705565b5f60208284031215611ba3575f5ffd5b5051919050565b5f60208284031215611bba575f5ffd5b813561134981611705565b5f60208284031215611bd5575f5ffd5b81356113498161171c565b634e487b7160e01b5f52603260045260245ffd5b5f8235605e19833603018112611c08575f5ffd5b9190910192915050565b5f60608236031215611c22575f5ffd5b604051606081016001600160401b0381118282101715611c4457611c44611729565b6040528235611c5281611705565b81526020830135611c628161171c565b602082015260408301356001600160401b03811115611c7f575f5ffd5b611c8b36828601611765565b60408301525092915050565b6001600160a01b038481168252831660208201526060604082018190525f9061117390830184611ae7565b6040815260018060a01b0383511660408201526020830151606082015260018060a01b03604084015116608082015260018060a01b0360608401511660a0820152608083015160c08201525f60a084015160c060e0840152611d28610100840182611ae7565b91505061134960208301846001600160a01b03169052565b81810381811115610a0857634e487b7160e01b5f52601160045260245ffd5b5f60208284031215611d6f575f5ffd5b81516113498161171c565b5f82518060208501845e5f92019182525091905056fea26469706673582212208de869caa2e008353a01f58886a1c17bd57fea9e7129e0511f178b38a70da77e64736f6c634300081c00330000000000000000000000001310f352f1389969ece6741671c4b919523912ff0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a

Deployed Bytecode

0x608060405260043610610071575f3560e01c80639d2c4fe31161004c5780639d2c4fe314610100578063d4b386d11461011f578063e8bbf5d71461013e578063eb6d3a111461016a575f5ffd5b806367a3a4841461007c578063801c2e9f146100a25780638f73dcfa146100b5575f5ffd5b3661007857005b5f5ffd5b61008f61008a36600461187f565b61019d565b6040519081526020015b60405180910390f35b61008f6100b03660046118fa565b610295565b3480156100c0575f5ffd5b506100e87f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff81565b6040516001600160a01b039091168152602001610099565b34801561010b575f5ffd5b5061008f61011a36600461199c565b610502565b34801561012a575f5ffd5b5061008f610139366004611a1a565b6105d7565b348015610149575f5ffd5b5061015d610158366004611a78565b61069e565b6040516100999190611b15565b348015610175575f5ffd5b506100e87f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a81565b5f688000000000ab143c065c156101bb5763ab143c065f526004601cfd5b30688000000000ab143c065d6101d9845f0151856020015187610900565b83516101e4906109d5565b80156101ed5750845b1561021f576001600160a01b037f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a1684525b610230845f01518560400151610a0e565b156102405750602083015161026d565b61026a7f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff85610a5e565b90505b61027e868560400151838686610c00565b90505f688000000000ab143c065d95945050505050565b5f688000000000ab143c065c156102b35763ab143c065f526004601cfd5b30688000000000ab143c065d6102d1855f015186602001515f610900565b6102de85604001516109d5565b6102fb5760405163ecaf3a9760e01b815260040160405180910390fd5b61030c855f01518660400151610a0e565b1561031c57506020840151610404565b84516001600160a01b037f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a81169116036103d7576020850151604051632e1a7d4d60e01b815260048101919091527f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a6001600160a01b031690632e1a7d4d906024015f604051808303815f87803b1580156103b5575f5ffd5b505af11580156103c7573d5f5f3e3d5ffd5b5050505084602001519050610404565b6104017f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff86610a5e565b90505b5f876001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610441573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104659190611b78565b604051636e553f6560e01b8152600481018490523060248201529091506001600160a01b03821690636e553f6590849060440160206040518083038185885af11580156104b4573d5f5f3e3d5ffd5b50505050506040513d601f19601f820116820180604052508101906104d99190611b93565b91506104e9888284888888610d38565b9150505f688000000000ab143c065d9695505050505050565b5f688000000000ab143c065c156105205763ab143c065f526004601cfd5b30688000000000ab143c065d61055f61053c6020880188611baa565b8651602080890151908a01359061055960608c0160408d01611bc5565b87610f11565b610570855f01518660400151610a0e565b15610580575060208401516105ad565b6105aa7f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff86610a5e565b90505b6105bf87866040015183878787610d38565b90505f688000000000ab143c065d9695505050505050565b5f688000000000ab143c065c156105f55763ab143c065f526004601cfd5b30688000000000ab143c065d61062e6106116020860186611baa565b8451602080870151908801359061055960608a0160408b01611bc5565b61063f835f01518460400151610a0e565b1561064f5750602082015161067c565b6106797f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff84610a5e565b90505b61068b8360400151838361105a565b5f688000000000ab143c065d9392505050565b60607f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff82806001600160401b038111156106da576106da611729565b60405190808252806020026020018201604052801561070d57816020015b60608152602001906001900390816106f85790505b5060408051606080820183525f80835260208301819052928201529194505b828110156108f65786868281811061074657610746611be0565b90506020028101906107589190611bf4565b61076190611c12565b915081602001511561089857815160405163191d0cc560e11b81526001600160a01b0391821660048201525f9186169063323a198a90602401602060405180830381865afa1580156107b5573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107d99190611b78565b90506001600160a01b03811661080257604051632f3285fb60e21b815260040160405180910390fd5b8251604080850151905163bd0226d760e01b81526001600160a01b0384169263bd0226d7926108379233929190600401611c97565b5f604051808303815f87803b15801561084e575f5ffd5b505af1158015610860573d5f5f3e3d5ffd5b50505050610875835f01518460400151611107565b86838151811061088757610887611be0565b6020026020010181905250506108ee565b81516001600160a01b031630146108c257604051637720ccd960e01b815260040160405180910390fd5b6108d030836040015161117c565b8582815181106108e2576108e2611be0565b60200260200101819052505b60010161072c565b5050505092915050565b610909836109d5565b156109aa5734821461092e57604051630fc1653d60e11b815260040160405180910390fd5b80156109a5577f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a6001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004015f604051808303818588803b15801561098d575f5ffd5b505af115801561099f573d5f5f3e3d5ffd5b50505050505b505050565b34156109c957604051630fc1653d60e11b815260040160405180910390fd5b6109a5833330856111d0565b5f6001600160a01b0382161580610a08575073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b038316145b92915050565b5f816001600160a01b0316836001600160a01b031603610a3057506001610a08565b610a39836109d5565b8015610a495750610a49826109d5565b15610a5657506001610a08565b505f92915050565b604081015181515f9190610a728183610a0e565b15610a9057604051636991e51560e11b815260040160405180910390fd5b6060840151604051631d4686fd60e31b81526001600160a01b0391821660048201525f9187169063ea3437e890602401602060405180830381865afa158015610adb573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610aff9190611b78565b90506001600160a01b038116610b2857604051637409771560e11b815260040160405180910390fd5b60405163383d5bf360e11b81526001600160a01b0382169063707ab7e690610b569088903090600401611cc2565b5f604051808303815f87803b158015610b6d575f5ffd5b505af1158015610b7f573d5f5f3e3d5ffd5b50505050610b96828660600151876020015161121f565b5f610ba084611237565b90505f610bac846109d5565b610bb6575f610bbc565b86602001515b9050610bd187606001518860a00151836112b7565b50610be0848860600151611350565b81610bea86611237565b610bf49190611d40565b98975050505050505050565b5f610c0b86866113e3565b825f03610c7e576040516357d159d560e01b81526001600160a01b0383811660048301528716906357d159d5906024016020604051808303815f875af1158015610c57573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c7b9190611b93565b92505b82841015610c9f576040516367d8a00f60e01b815260040160405180910390fd5b610caa85878561121f565b604051632796469160e21b8152600481018490526001600160a01b038381166024830152871690639e591a44906044015f604051808303815f87803b158015610cf1575f5ffd5b505af1158015610d03573d5f5f3e3d5ffd5b50505050610d118587611350565b610d1b8385611d40565b93508315610d2e57610d2e85338661105a565b5091949350505050565b5f610d4387876113e3565b610d4e86888761121f565b8215610e6957336001600160a01b0383161480610dd45750604051635fec5d0b60e01b81526001600160a01b038381166004830152336024830152881690635fec5d0b90604401602060405180830381865afa158015610db0573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610dd49190611d5f565b15610e505760405163b3bffb4560e01b8152600481018690526001600160a01b03838116602483015288169063b3bffb45906044016020604051808303815f875af1158015610e25573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e499190611b93565b9050610edc565b604051630ba2198760e21b815260040160405180910390fd5b604051636e553f6560e01b8152600481018690526001600160a01b038381166024830152881690636e553f65906044016020604051808303815f875af1158015610eb5573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ed99190611b93565b90505b83811015610efd57604051630fc1653d60e11b815260040160405180910390fd5b610f078688611350565b9695505050505050565b610f1b86866113e3565b5f8215610f9d57604051636779db5b60e01b8152600481018690523060248201523360448201526001600160a01b03881690636779db5b906064016020604051808303815f875af1158015610f72573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f969190611b93565b9050611014565b604051630b817f5160e31b8152600481018690523060248201523360448201526001600160a01b03881690635c0bfa88906064016020604051808303815f875af1158015610fed573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110119190611b93565b90505b8381101561103557604051630fc1653d60e11b815260040160405180910390fd5b8381111561105157611051868361104c8785611d40565b61105a565b50505050505050565b611063836109d5565b156110fc577f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a6001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004015f604051808303818588803b1580156110c1575f5ffd5b505af11580156110d3573d5f5f3e3d5ffd5b50505050507f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a92505b6109a5838383611618565b60605f5f846001600160a01b03165f856040516111249190611d7a565b5f6040518083038185875af1925050503d805f811461115e576040519150601f19603f3d011682016040523d82523d5f602084013e611163565b606091505b5091509150611173858383611658565b95945050505050565b60605f5f846001600160a01b0316846040516111989190611d7a565b5f60405180830381855af49150503d805f811461115e576040519150601f19603f3d011682016040523d82523d5f602084013e611163565b60405181606052826040528360601b602c526323b872dd60601b600c5260205f6064601c5f895af13d1560015f5114171661121257637939f4245f526004601cfd5b5f60605260405250505050565b611228836109d5565b6109a5576109a58383836116a0565b5f611241826109d5565b6112b0576040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa158015611287573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112ab9190611b93565b610a08565b4792915050565b6060814710156112da5760405163595909b560e11b815260040160405180910390fd5b5f5f856001600160a01b031684866040516112f59190611d7a565b5f6040518083038185875af1925050503d805f811461132f576040519150601f19603f3d011682016040523d82523d5f602084013e611334565b606091505b5091509150611344868383611658565b925050505b9392505050565b611359826109d5565b6113df57604051636eb1769f60e11b81523060048201526001600160a01b0382811660248301525f919084169063dd62ed3e90604401602060405180830381865afa1580156113aa573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113ce9190611b93565b11156113df576113df82825f6116a0565b5050565b6001600160a01b03821661140a57604051630fc1653d60e11b815260040160405180910390fd5b5f826001600160a01b03166341ed2c126040518163ffffffff1660e01b8152600401602060405180830381865afa158015611447573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061146b9190611b78565b604051637d5528bd60e01b81526001600160a01b0380831660048301529192507f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff90911690637d5528bd90602401602060405180830381865afa1580156114d4573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114f89190611d5f565b15806115695750604051637bca031760e11b81526001600160a01b03848116600483015282169063f794062e90602401602060405180830381865afa158015611543573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115679190611d5f565b155b1561158757604051630ba2198760e21b815260040160405180910390fd5b826001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115c3573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115e79190611b78565b6001600160a01b0316826001600160a01b0316146109a55760405163ecaf3a9760e01b815260040160405180910390fd5b816014528060345263a9059cbb60601b5f5260205f604460105f875af13d1560015f5114171661164f576390b8ec185f526004601cfd5b5f603452505050565b606061166483836116d7565b815115801561167b57506001600160a01b0384163b155b15611699576040516314859aeb60e21b815260040160405180910390fd5b5092915050565b816014528060345263095ea7b360601b5f5260205f604460105f875af13d1560015f5114171661164f57633e3f8f735f526004601cfd5b816113df5780515f036116fd576040516314859aeb60e21b815260040160405180910390fd5b805181602001fd5b6001600160a01b0381168114611719575f5ffd5b50565b8015158114611719575f5ffd5b634e487b7160e01b5f52604160045260245ffd5b60405160c081016001600160401b038111828210171561175f5761175f611729565b60405290565b5f82601f830112611774575f5ffd5b81356001600160401b0381111561178d5761178d611729565b604051601f8201601f19908116603f011681016001600160401b03811182821017156117bb576117bb611729565b6040528181528382016020018510156117d2575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f60c082840312156117fe575f5ffd5b61180661173d565b9050813561181381611705565b815260208281013590820152604082013561182d81611705565b6040820152606082013561184081611705565b60608201526080828101359082015260a08201356001600160401b03811115611867575f5ffd5b61187384828501611765565b60a08301525092915050565b5f5f5f5f5f60a08688031215611893575f5ffd5b853561189e81611705565b945060208601356118ae8161171c565b935060408601356001600160401b038111156118c8575f5ffd5b6118d4888289016117ee565b9350506060860135915060808601356118ec81611705565b809150509295509295909350565b5f5f5f5f5f5f60c0878903121561190f575f5ffd5b863561191a81611705565b9550602087013561192a8161171c565b945060408701356001600160401b03811115611944575f5ffd5b61195089828a016117ee565b9450506060870135925060808701356119688161171c565b915060a087013561197881611705565b809150509295509295509295565b5f60608284031215611996575f5ffd5b50919050565b5f5f5f5f5f5f61010087890312156119b2575f5ffd5b86356119bd81611705565b95506119cc8860208901611986565b945060808701356001600160401b038111156119e6575f5ffd5b6119f289828a016117ee565b94505060a0870135925060c0870135611a0a8161171c565b915060e087013561197881611705565b5f5f5f60a08486031215611a2c575f5ffd5b611a368585611986565b925060608401356001600160401b03811115611a50575f5ffd5b611a5c868287016117ee565b9250506080840135611a6d81611705565b809150509250925092565b5f5f60208385031215611a89575f5ffd5b82356001600160401b03811115611a9e575f5ffd5b8301601f81018513611aae575f5ffd5b80356001600160401b03811115611ac3575f5ffd5b8560208260051b8401011115611ad7575f5ffd5b6020919091019590945092505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b82811015611b6c57603f19878603018452611b57858351611ae7565b94506020938401939190910190600101611b3b565b50929695505050505050565b5f60208284031215611b88575f5ffd5b815161134981611705565b5f60208284031215611ba3575f5ffd5b5051919050565b5f60208284031215611bba575f5ffd5b813561134981611705565b5f60208284031215611bd5575f5ffd5b81356113498161171c565b634e487b7160e01b5f52603260045260245ffd5b5f8235605e19833603018112611c08575f5ffd5b9190910192915050565b5f60608236031215611c22575f5ffd5b604051606081016001600160401b0381118282101715611c4457611c44611729565b6040528235611c5281611705565b81526020830135611c628161171c565b602082015260408301356001600160401b03811115611c7f575f5ffd5b611c8b36828601611765565b60408301525092915050565b6001600160a01b038481168252831660208201526060604082018190525f9061117390830184611ae7565b6040815260018060a01b0383511660408201526020830151606082015260018060a01b03604084015116608082015260018060a01b0360608401511660a0820152608083015160c08201525f60a084015160c060e0840152611d28610100840182611ae7565b91505061134960208301846001600160a01b03169052565b81810381811115610a0857634e487b7160e01b5f52601160045260245ffd5b5f60208284031215611d6f575f5ffd5b81516113498161171c565b5f82518060208501845e5f92019182525091905056fea26469706673582212208de869caa2e008353a01f58886a1c17bd57fea9e7129e0511f178b38a70da77e64736f6c634300081c0033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000001310f352f1389969ece6741671c4b919523912ff0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a

-----Decoded View---------------
Arg [0] : cr (address): 0x1310f352f1389969Ece6741671c4B919523912fF
Arg [1] : wNative (address): 0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000001310f352f1389969ece6741671c4b919523912ff
Arg [1] : 0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a


Deployed Bytecode Sourcemap

156733:3261:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;149129:1397;;;;;;:::i;:::-;;:::i;:::-;;;3424:25:1;;;3412:2;3397:18;149129:1397:0;;;;;;;;158519:1472;;;;;;:::i;:::-;;:::i;132562:49::-;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;4661:32:1;;;4643:51;;4631:2;4616:18;132562:49:0;4473:227:1;154338:1194:0;;;;;;;;;;-1:-1:-1;154338:1194:0;;;;;:::i;:::-;;:::i;152146:814::-;;;;;;;;;;-1:-1:-1;152146:814:0;;;;;:::i;:::-;;:::i;80573:1590::-;;;;;;;;;;-1:-1:-1;80573:1590:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;132686:38::-;;;;;;;;;;;;;;;149129:1397;149371:17;54996:22;54990:29;54987:146;;;55052:10;55046:4;55039:24;55113:4;55107;55100:18;54987:146;55178:9;55154:22;55147:41;149401:133:::1;149428:10;:21;;;149464:10;:22;;;149501;149401:12;:133::i;:::-;149749:21:::0;;149729:42:::1;::::0;:19:::1;:42::i;:::-;:68;;;;;149775:22;149729:68;149725:214;;;-1:-1:-1::0;;;;;149913:13:0::1;149881:46;::::0;;149725:214:::1;149955:73;149982:10;:21;;;150005:10;:22;;;149955:26;:73::i;:::-;149951:284;;;-1:-1:-1::0;150057:22:0::1;::::0;::::1;::::0;149951:284:::1;;;150172:51;150195:15;150212:10;150172:22;:51::i;:::-;150160:63;;149951:284;150356:162;150381:16;150412:10;:22;;;150449:9;150473:11;150499:8;150356:10;:162::i;:::-;150344:174;;55320:1:::0;55296:22;55289:33;149129:1397;;;;;;;:::o;158519:1472::-;158803:17;54996:22;54990:29;54987:146;;;55052:10;55046:4;55039:24;55113:4;55107;55100:18;54987:146;55178:9;55154:22;55147:41;158833:66:::1;158846:10;:21;;;158869:10;:22;;;158893:5;158833:12;:66::i;:::-;158917:43;158937:10;:22;;;158917:19;:43::i;:::-;158912:128;;158984:44;;-1:-1:-1::0;;;158984:44:0::1;;;;;;;;;;;158912:128;159056:73;159083:10;:21;;;159106:10;:22;;;159056:26;:73::i;:::-;159052:501;;;-1:-1:-1::0;159158:22:0::1;::::0;::::1;::::0;159052:501:::1;;;159210:21:::0;;-1:-1:-1;;;;;159235:13:0::1;159210:38:::0;::::1;::::0;::::1;::::0;159206:347:::1;;159325:22;::::0;::::1;::::0;159295:53:::1;::::0;-1:-1:-1;;;159295:53:0;;::::1;::::0;::::1;3424:25:1::0;;;;159301:13:0::1;-1:-1:-1::0;;;;;159295:29:0::1;::::0;::::1;::::0;3397:18:1;;159295:53:0::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;159375:10;:22;;;159363:34;;159206:347;;;159490:51;159513:15;159530:10;159490:22;:51::i;:::-;159478:63;;159206:347;159565:13;159589:6;-1:-1:-1::0;;;;;159581:21:0::1;;:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;159661:79;::::0;-1:-1:-1;;;159661:79:0;;::::1;::::0;::::1;8977:25:1::0;;;159734:4:0::1;9018:18:1::0;;;9011:60;159565:39:0;;-1:-1:-1;;;;;;159661:35:0;::::1;::::0;::::1;::::0;159704:9;;8950:18:1;;159661:79:0::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;159649:91;;159810:173;159839:6;159860:5;159880:9;159904:14;159933:16;159964:8;159810:14;:173::i;:::-;159798:185;;158822:1169;55320:1:::0;55296:22;55289:33;158519:1472;;;;;;;;:::o;154338:1194::-;154612:17;54996:22;54990:29;54987:146;;;55052:10;55046:4;55039:24;55113:4;55107;55100:18;54987:146;55178:9;55154:22;55147:41;154678:237:::1;154706:19;;::::0;::::1;:12:::0;:19:::1;:::i;:::-;154740:21:::0;;154776:19:::1;154810:22:::0;;::::1;::::0;154776:19;;::::1;;::::0;154847:34:::1;::::0;;;::::1;::::0;::::1;;:::i;:::-;154896:8;154678:13;:237::i;:::-;154932:73;154959:10;:21;;;154982:10;:22;;;154932:26;:73::i;:::-;154928:345;;;-1:-1:-1::0;155034:22:0::1;::::0;::::1;::::0;154928:345:::1;;;155210:51;155233:15;155250:10;155210:22;:51::i;:::-;155198:63;;154928:345;155334:190;155363:6;155384:10;:22;;;155421:9;155445:14;155474:16;155505:8;155334:14;:190::i;:::-;155322:202;;55320:1:::0;55296:22;55289:33;154338:1194;;;;;;;;:::o;152146:814::-;152323:17;54996:22;54990:29;54987:146;;;55052:10;55046:4;55039:24;55113:4;55107;55100:18;54987:146;55178:9;55154:22;55147:41;152389:237:::1;152417:19;;::::0;::::1;:12:::0;:19:::1;:::i;:::-;152451:21:::0;;152487:19:::1;152521:22:::0;;::::1;::::0;152487:19;;::::1;;::::0;152558:34:::1;::::0;;;::::1;::::0;::::1;;:::i;152389:237::-;152643:73;152670:10;:21;;;152693:10;:22;;;152643:26;:73::i;:::-;152639:236;;;-1:-1:-1::0;152745:22:0::1;::::0;::::1;::::0;152639:236:::1;;;152812:51;152835:15;152852:10;152812:22;:51::i;:::-;152800:63;;152639:236;152887:65;152908:10;:22;;;152932:8;152942:9;152887:20;:65::i;:::-;55320:1:::0;55296:22;55289:33;152146:814;;;;;:::o;80573:1590::-;80660:22;143354:15;80768:5;;-1:-1:-1;;;;;80801:21:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;80791:31:0;;-1:-1:-1;80879:1277:0;80899:8;80895:1;:12;80879:1277;;;80942:5;;80948:1;80942:8;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;80929:21;;;:::i;:::-;;;80983:10;:24;;;80979:810;;;81211:17;;81191:38;;-1:-1:-1;;;81191:38:0;;-1:-1:-1;;;;;4661:32:1;;;81191:38:0;;;4643:51:1;81173:15:0;;81191:19;;;;;4616:18:1;;81191:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;81173:56;-1:-1:-1;;;;;;81320:21:0;;81316:105;;81373:28;;-1:-1:-1;;;81373:28:0;;;;;;;;;;;81316:105;81537:17;;81577:15;;;;;81441:170;;-1:-1:-1;;;81441:170:0;;-1:-1:-1;;;;;81441:40:0;;;;;:170;;81504:10;;81537:17;81577:15;81441:170;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;81645:83;81693:10;:17;;;81712:10;:15;;;81645:47;:83::i;:::-;81632:7;81640:1;81632:10;;;;;;;;:::i;:::-;;;;;;:96;;;;81765:8;;;80979:810;81945:17;;-1:-1:-1;;;;;81928:34:0;81936:4;81928:34;81924:108;;81990:26;;-1:-1:-1;;;81990:26:0;;;;;;;;;;;81924:108;82061:83;82121:4;82128:10;:15;;;82061:51;:83::i;:::-;82048:7;82056:1;82048:10;;;;;;;;:::i;:::-;;;;;;:96;;;;80879:1277;80909:3;;80879:1277;;;;80684:1479;;;80573:1590;;;;:::o;140445:863::-;140595:31;140615:10;140595:19;:31::i;:::-;140591:391;;;140738:9;140723:11;:24;140719:100;;140775:28;;-1:-1:-1;;;140775:28:0;;;;;;;;;;;140719:100;140839:22;140835:115;;;140888:13;-1:-1:-1;;;;;140882:28:0;;140919:11;140882:52;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;140835:115;140445:863;;;:::o;140591:391::-;141063:9;:14;141059:82;;141101:28;;-1:-1:-1;;;141101:28:0;;;;;;;;;;;141059:82;141153:147;141200:10;141225;141258:4;141278:11;141153:32;:147::i;83510:185::-;83567:11;-1:-1:-1;;;;;83600:19:0;;;;:87;;-1:-1:-1;83645:42:0;-1:-1:-1;;;;;83636:51:0;;;83600:87;83591:96;83510:185;-1:-1:-1;;83510:185:0:o;82942:309::-;83048:4;83079:6;-1:-1:-1;;;;;83069:16:0;:6;-1:-1:-1;;;;;83069:16:0;;83065:60;;-1:-1:-1;83109:4:0;83102:11;;83065:60;83141:17;83151:6;83141:9;:17::i;:::-;:38;;;;;83162:17;83172:6;83162:9;:17::i;:::-;83137:82;;;-1:-1:-1;83203:4:0;83196:11;;83137:82;-1:-1:-1;83238:5:0;82942:309;;;;:::o;125338:1555::-;125495:18;;;;125545:17;;125443;;125495:18;125643:51;125545:17;125495:18;125643:26;:51::i;:::-;125639:115;;;125718:24;;-1:-1:-1;;;125718:24:0;;;;;;;;;;;125639:115;125819:13;;;;125792:41;;-1:-1:-1;;;125792:41:0;;-1:-1:-1;;;;;4661:32:1;;;125792:41:0;;;4643:51:1;125766:23:0;;125792:26;;;;;4616:18:1;;125792:41:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;125766:67;-1:-1:-1;;;;;;125908:29:0;;125904:98;;125961:29;;-1:-1:-1;;;125961:29:0;;;;;;;;;;;125904:98;126053:92;;-1:-1:-1;;;126053:92:0;;-1:-1:-1;;;;;126053:69:0;;;;;:92;;126123:6;;126139:4;;126053:92;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;126232:63;126249:10;126261:6;:13;;;126276:6;:18;;;126232:16;:63::i;:::-;126382:21;126406:33;126427:11;126406:20;:33::i;:::-;126382:57;;126452:17;126472:31;126492:10;126472:19;:31::i;:::-;:69;;126540:1;126472:69;;;126519:6;:18;;;126472:69;126452:89;;126584:124;126634:6;:13;;;126662:6;:11;;;126688:9;126584:35;:124::i;:::-;;126761:50;126785:10;126797:6;:13;;;126761:23;:50::i;:::-;126872:13;126836:33;126857:11;126836:20;:33::i;:::-;:49;;;;:::i;:::-;126824:61;125338:1555;-1:-1:-1;;;;;;;;125338:1555:0:o;138396:1500::-;138590:7;138610:44;138626:16;138644:9;138610:15;:44::i;:::-;138671:11;138686:1;138671:16;138667:247;;138820:82;;-1:-1:-1;;;138820:82:0;;-1:-1:-1;;;;;4661:32:1;;;138820:82:0;;;4643:51:1;138820:72:0;;;;;4616:18:1;;138820:82:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;138806:96;;138667:247;139013:11;139000:10;:24;138996:97;;;139048:33;;-1:-1:-1;;;139048:33:0;;;;;;;;;;;138996:97;139177:69;139205:9;139216:16;139234:11;139177:27;:69::i;:::-;139310:67;;-1:-1:-1;;;139310:67:0;;;;;8977:25:1;;;-1:-1:-1;;;;;9038:32:1;;;9018:18;;;9011:60;139310:44:0;;;;;8950:18:1;;139310:67:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;139440:63;139475:9;139486:16;139440:34;:63::i;:::-;139514:25;139528:11;139514:25;;:::i;:::-;;-1:-1:-1;139761:14:0;;139757:102;;139792:55;139813:9;139824:10;139836;139792:20;:55::i;:::-;-1:-1:-1;139878:10:0;;138396:1500;-1:-1:-1;;;;138396:1500:0:o;134238:1855::-;134453:14;134480:30;134496:6;134504:5;134480:15;:30::i;:::-;134569:50;134597:5;134604:6;134612;134569:27;:50::i;:::-;134875:16;134871:925;;;135200:10;-1:-1:-1;;;;;135200:22:0;;;;:100;;-1:-1:-1;135243:57:0;;-1:-1:-1;;;135243:57:0;;-1:-1:-1;;;;;12788:32:1;;;135243:57:0;;;12770:51:1;135289:10:0;12837:18:1;;;12830:60;135243:35:0;;;;;12743:18:1;;135243:57:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;135178:373;;;135344:117;;-1:-1:-1;;;135344:117:0;;;;;8977:25:1;;;-1:-1:-1;;;;;9038:32:1;;;9018:18;;;9011:60;135344:38:0;;;;;8950:18:1;;135344:117:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;135335:126;;134871:925;;135178:373;135509:26;;-1:-1:-1;;;135509:26:0;;;;;;;;;;;134871:925;135743:41;;-1:-1:-1;;;135743:41:0;;;;;8977:25:1;;;-1:-1:-1;;;;;9038:32:1;;;9018:18;;;9011:60;135743:23:0;;;;;8950:18:1;;135743:41:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;135734:50;;134871:925;135896:14;135887:6;:23;135883:91;;;135934:28;;-1:-1:-1;;;135934:28:0;;;;;;;;;;;135883:91;136036:49;136071:5;136078:6;136036:34;:49::i;:::-;134238:1855;;;;;;;;:::o;136688:1089::-;136909:30;136925:6;136933:5;136909:15;:30::i;:::-;136950:14;137031:21;137027:367;;;137078:136;;-1:-1:-1;;;137078:136:0;;;;;13353:25:1;;;137165:4:0;13394:18:1;;;13387:60;137189:10:0;13463:18:1;;;13456:60;-1:-1:-1;;;;;137078:35:0;;;;;13326:18:1;;137078:136:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;137069:145;;137027:367;;;137256:126;;-1:-1:-1;;;137256:126:0;;;;;13353:25:1;;;137333:4:0;13394:18:1;;;13387:60;137357:10:0;13463:18:1;;;13456:60;-1:-1:-1;;;;;137256:25:0;;;;;13326:18:1;;137256:126:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;137247:135;;137027:367;137497:14;137488:6;:23;137484:91;;;137535:28;;-1:-1:-1;;;137535:28:0;;;;;;;;;;;137484:91;137665:14;137656:6;:23;137652:118;;;137696:62;137717:5;137724:8;137734:23;137743:14;137734:6;:23;:::i;:::-;137696:20;:62::i;:::-;136898:879;136688:1089;;;;;;:::o;142644:488::-;142921:26;142941:5;142921:19;:26::i;:::-;142917:142;;;142970:13;-1:-1:-1;;;;;142964:28:0;;143001:6;142964:47;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;143034:13;143026:21;;142917:142;143071:53;143100:5;143107:8;143117:6;143071:28;:53::i;49206:265::-;49299:12;49325;49339:23;49366:6;-1:-1:-1;;;;;49366:11:0;49385:1;49388:4;49366:27;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;49324:69;;;;49421:42;49435:6;49443:7;49452:10;49421:13;:42::i;:::-;49414:49;49206:265;-1:-1:-1;;;;;49206:265:0:o;51086:263::-;51187:12;51213;51227:23;51254:6;-1:-1:-1;;;;;51254:19:0;51274:4;51254:25;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;64891:1160;65077:4;65071:11;65143:6;65137:4;65130:20;65209:2;65203:4;65196:16;65275:4;65271:2;65267:13;65261:4;65254:27;-1:-1:-1;;;65332:4:0;65325:48;65744:4;65738;65732;65726;65723:1;65716:5;65709;65704:45;65637:16;65630:24;65626:1;65619:4;65613:11;65610:18;65607:48;65521:247;65493:412;;65816:10;65810:4;65803:24;65885:4;65879;65872:18;65493:412;65932:1;65926:4;65919:15;65989:4;65982:15;-1:-1:-1;;;;64891:1160:0:o;130016:246::-;130149:26;130169:5;130149:19;:26::i;:::-;130144:111;;130192:51;130220:5;130227:7;130236:6;130192:27;:51::i;83891:186::-;83949:9;83975:16;83985:5;83975:9;:16::i;:::-;:94;;84031:38;;-1:-1:-1;;;84031:38:0;;84063:4;84031:38;;;4643:51:1;-1:-1:-1;;;;;84031:23:0;;;;;4616:18:1;;84031:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;83975:94;;;83994:21;83971:98;83891:186;-1:-1:-1;;83891:186:0:o;50104:442::-;50231:12;50284:5;50260:21;:29;50256:111;;;50313:42;;-1:-1:-1;;;50313:42:0;;;;;;;;;;;50256:111;50380:12;50394:23;50421:6;-1:-1:-1;;;;;50421:11:0;50454:5;50471:4;50421:55;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;50379:97;;;;50496:42;50510:6;50518:7;50527:10;50496:13;:42::i;:::-;50489:49;;;;50104:442;;;;;;:::o;130439:289::-;130529:26;130549:5;130529:19;:26::i;:::-;130524:197;;130576:47;;-1:-1:-1;;;130576:47:0;;130608:4;130576:47;;;12770:51:1;-1:-1:-1;;;;;12857:32:1;;;12837:18;;;12830:60;130626:1:0;;130576:23;;;;;;12743:18:1;;130576:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:51;130572:138;;;130648:46;130676:5;130683:7;130692:1;130648:27;:46::i;:::-;130439:289;;:::o;141555:731::-;-1:-1:-1;;;;;141695:20:0;;141691:88;;141739:28;;-1:-1:-1;;;141739:28:0;;;;;;;;;;;141691:88;141854:17;141882:6;-1:-1:-1;;;;;141874:29:0;;:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;141935:44;;-1:-1:-1;;;141935:44:0;;-1:-1:-1;;;;;4661:32:1;;;141935:44:0;;;4643:51:1;141854::0;;-1:-1:-1;141935:15:0;:31;;;;;;4616:18:1;;141935:44:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;141934:45;:82;;;-1:-1:-1;141997:19:0;;-1:-1:-1;;;141997:19:0;;-1:-1:-1;;;;;4661:32:1;;;141997:19:0;;;4643:51:1;141997:11:0;;;;;4616:18:1;;141997:19:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;141996:20;141934:82;141916:172;;;142050:26;;-1:-1:-1;;;142050:26:0;;;;;;;;;;;141916:172;142184:6;-1:-1:-1;;;;;142176:21:0;;:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;142167:32:0;:5;-1:-1:-1;;;;;142167:32:0;;142163:116;;142223:44;;-1:-1:-1;;;142223:44:0;;;;;;;;;;;68152:957;68318:2;68312:4;68305:16;68376:6;68370:4;68363:20;-1:-1:-1;;;68436:4:0;68429:48;68836:4;68830;68824;68818;68815:1;68808:5;68801;68796:45;68729:16;68722:24;68718:1;68711:4;68705:11;68702:18;68699:48;68613:247;68585:408;;68908:10;68902:4;68895:24;68973:4;68967;68960:18;68585:408;69020:1;69014:4;69007:15;68152:957;;;:::o;51563:513::-;51698:12;51723:36;51739:7;51748:10;51723:15;:36::i;:::-;51921:17;;:22;:49;;;;-1:-1:-1;;;;;;51947:18:0;;;:23;51921:49;51917:122;;;51994:33;;-1:-1:-1;;;51994:33:0;;;;;;;;;;;51917:122;-1:-1:-1;52058:10:0;51563:513;-1:-1:-1;;51563:513:0:o;71004:954::-;71169:2;71163:4;71156:16;71227:6;71221:4;71214:20;-1:-1:-1;;;71287:4:0;71280:48;71686:4;71680;71674;71668;71665:1;71658:5;71651;71646:45;71579:16;71572:24;71568:1;71561:4;71555:11;71552:18;71549:48;71463:247;71435:407;;71758:10;71752:4;71745:24;71822:4;71816;71809:18;52252:425;52371:7;52366:304;;52399:10;:17;52420:1;52399:22;52395:103;;52449:33;;-1:-1:-1;;;52449:33:0;;;;;;;;;;;52395:103;52632:10;52626:17;52613:10;52609:2;52605:19;52598:46;14:131:1;-1:-1:-1;;;;;89:31:1;;79:42;;69:70;;135:1;132;125:12;69:70;14:131;:::o;150:118::-;236:5;229:13;222:21;215:5;212:32;202:60;;258:1;255;248:12;273:127;334:10;329:3;325:20;322:1;315:31;365:4;362:1;355:15;389:4;386:1;379:15;405:248;472:2;466:9;514:4;502:17;;-1:-1:-1;;;;;534:34:1;;570:22;;;531:62;528:88;;;596:18;;:::i;:::-;632:2;625:22;405:248;:::o;658:745::-;700:5;753:3;746:4;738:6;734:17;730:27;720:55;;771:1;768;761:12;720:55;811:6;798:20;-1:-1:-1;;;;;833:6:1;830:30;827:56;;;863:18;;:::i;:::-;932:2;926:9;1024:2;986:17;;-1:-1:-1;;982:31:1;;;1015:2;978:40;974:54;962:67;;-1:-1:-1;;;;;1044:34:1;;1080:22;;;1041:62;1038:88;;;1106:18;;:::i;:::-;1142:2;1135:22;1166;;;1207:19;;;1228:4;1203:30;1200:39;-1:-1:-1;1197:59:1;;;1252:1;1249;1242:12;1197:59;1316:6;1309:4;1301:6;1297:17;1290:4;1282:6;1278:17;1265:58;1371:1;1343:19;;;1364:4;1339:30;1332:41;;;;1347:6;658:745;-1:-1:-1;;;658:745:1:o;1408:988::-;1459:5;1507:4;1495:9;1490:3;1486:19;1482:30;1479:50;;;1525:1;1522;1515:12;1479:50;1547:17;;:::i;:::-;1538:26;;1601:9;1588:23;1620:33;1645:7;1620:33;:::i;:::-;1662:22;;1757:2;1742:18;;;1729:32;1777:14;;;1770:31;1853:2;1838:18;;1825:32;1866:33;1825:32;1866:33;:::i;:::-;1926:2;1915:14;;1908:31;1991:2;1976:18;;1963:32;2004:33;1963:32;2004:33;:::i;:::-;2064:2;2053:14;;2046:31;2150:3;2135:19;;;2122:33;2171:15;;;2164:32;2247:3;2232:19;;2219:33;-1:-1:-1;;;;;2264:30:1;;2261:50;;;2307:1;2304;2297:12;2261:50;2344:45;2385:3;2376:6;2365:9;2361:22;2344:45;:::i;:::-;2338:3;2331:5;2327:15;2320:70;;1408:988;;;;:::o;2401:872::-;2515:6;2523;2531;2539;2547;2600:3;2588:9;2579:7;2575:23;2571:33;2568:53;;;2617:1;2614;2607:12;2568:53;2656:9;2643:23;2675:31;2700:5;2675:31;:::i;:::-;2725:5;-1:-1:-1;2782:2:1;2767:18;;2754:32;2795:30;2754:32;2795:30;:::i;:::-;2844:7;-1:-1:-1;2902:2:1;2887:18;;2874:32;-1:-1:-1;;;;;2918:30:1;;2915:50;;;2961:1;2958;2951:12;2915:50;2984:55;3031:7;3022:6;3011:9;3007:22;2984:55;:::i;:::-;2974:65;-1:-1:-1;;3112:2:1;3097:18;;3084:32;;-1:-1:-1;3194:3:1;3179:19;;3166:33;3208;3166;3208;:::i;:::-;3260:7;3250:17;;;2401:872;;;;;;;;:::o;3460:1008::-;3580:6;3588;3596;3604;3612;3620;3673:3;3661:9;3652:7;3648:23;3644:33;3641:53;;;3690:1;3687;3680:12;3641:53;3729:9;3716:23;3748:31;3773:5;3748:31;:::i;:::-;3798:5;-1:-1:-1;3855:2:1;3840:18;;3827:32;3868:30;3827:32;3868:30;:::i;:::-;3917:7;-1:-1:-1;3975:2:1;3960:18;;3947:32;-1:-1:-1;;;;;3991:30:1;;3988:50;;;4034:1;4031;4024:12;3988:50;4057:55;4104:7;4095:6;4084:9;4080:22;4057:55;:::i;:::-;4047:65;-1:-1:-1;;4185:2:1;4170:18;;4157:32;;-1:-1:-1;4267:3:1;4252:19;;4239:33;4281:30;4239:33;4281:30;:::i;:::-;4330:7;-1:-1:-1;4389:3:1;4374:19;;4361:33;4403;4361;4403;:::i;:::-;4455:7;4445:17;;;3460:1008;;;;;;;;:::o;4705:160::-;4770:5;4815:2;4806:6;4801:3;4797:16;4793:25;4790:45;;;4831:1;4828;4821:12;4790:45;-1:-1:-1;4853:6:1;4705:160;-1:-1:-1;4705:160:1:o;4870:1011::-;5025:6;5033;5041;5049;5057;5065;5118:3;5106:9;5097:7;5093:23;5089:33;5086:53;;;5135:1;5132;5125:12;5086:53;5174:9;5161:23;5193:31;5218:5;5193:31;:::i;:::-;5243:5;-1:-1:-1;5267:68:1;5327:7;5322:2;5307:18;;5267:68;:::i;:::-;5257:78;;5386:3;5375:9;5371:19;5358:33;-1:-1:-1;;;;;5406:6:1;5403:30;5400:50;;;5446:1;5443;5436:12;5400:50;5469:55;5516:7;5507:6;5496:9;5492:22;5469:55;:::i;:::-;5459:65;-1:-1:-1;;5597:3:1;5582:19;;5569:33;;-1:-1:-1;5680:3:1;5665:19;;5652:33;5694:30;5652:33;5694:30;:::i;:::-;5743:7;-1:-1:-1;5802:3:1;5787:19;;5774:33;5816;5774;5816;:::i;5886:612::-;6017:6;6025;6033;6086:3;6074:9;6065:7;6061:23;6057:33;6054:53;;;6103:1;6100;6093:12;6054:53;6126:59;6177:7;6166:9;6126:59;:::i;:::-;6116:69;;6236:2;6225:9;6221:18;6208:32;-1:-1:-1;;;;;6255:6:1;6252:30;6249:50;;;6295:1;6292;6285:12;6249:50;6318:55;6365:7;6356:6;6345:9;6341:22;6318:55;:::i;:::-;6308:65;;;6423:3;6412:9;6408:19;6395:33;6437:31;6462:5;6437:31;:::i;:::-;6487:5;6477:15;;;5886:612;;;;;:::o;6503:645::-;6624:6;6632;6685:2;6673:9;6664:7;6660:23;6656:32;6653:52;;;6701:1;6698;6691:12;6653:52;6741:9;6728:23;-1:-1:-1;;;;;6766:6:1;6763:30;6760:50;;;6806:1;6803;6796:12;6760:50;6829:22;;6882:4;6874:13;;6870:27;-1:-1:-1;6860:55:1;;6911:1;6908;6901:12;6860:55;6951:2;6938:16;-1:-1:-1;;;;;6969:6:1;6966:30;6963:50;;;7009:1;7006;6999:12;6963:50;7062:7;7057:2;7047:6;7044:1;7040:14;7036:2;7032:23;7028:32;7025:45;7022:65;;;7083:1;7080;7073:12;7022:65;7114:2;7106:11;;;;;7136:6;;-1:-1:-1;6503:645:1;-1:-1:-1;;;6503:645:1:o;7153:288::-;7194:3;7232:5;7226:12;7259:6;7254:3;7247:19;7315:6;7308:4;7301:5;7297:16;7290:4;7285:3;7281:14;7275:47;7367:1;7360:4;7351:6;7346:3;7342:16;7338:27;7331:38;7430:4;7423:2;7419:7;7414:2;7406:6;7402:15;7398:29;7393:3;7389:39;7385:50;7378:57;;;7153:288;;;;:::o;7446:779::-;7606:4;7654:2;7643:9;7639:18;7684:2;7673:9;7666:21;7707:6;7742;7736:13;7773:6;7765;7758:22;7811:2;7800:9;7796:18;7789:25;;7873:2;7863:6;7860:1;7856:14;7845:9;7841:30;7837:39;7823:53;;7911:2;7903:6;7899:15;7932:1;7942:254;7956:6;7953:1;7950:13;7942:254;;;8049:2;8045:7;8033:9;8025:6;8021:22;8017:36;8012:3;8005:49;8077:39;8109:6;8100;8094:13;8077:39;:::i;:::-;8067:49;-1:-1:-1;8151:2:1;8174:12;;;;8139:15;;;;;7978:1;7971:9;7942:254;;;-1:-1:-1;8213:6:1;;7446:779;-1:-1:-1;;;;;;7446:779:1:o;8547:251::-;8617:6;8670:2;8658:9;8649:7;8645:23;8641:32;8638:52;;;8686:1;8683;8676:12;8638:52;8718:9;8712:16;8737:31;8762:5;8737:31;:::i;9082:184::-;9152:6;9205:2;9193:9;9184:7;9180:23;9176:32;9173:52;;;9221:1;9218;9211:12;9173:52;-1:-1:-1;9244:16:1;;9082:184;-1:-1:-1;9082:184:1:o;9271:247::-;9330:6;9383:2;9371:9;9362:7;9358:23;9354:32;9351:52;;;9399:1;9396;9389:12;9351:52;9438:9;9425:23;9457:31;9482:5;9457:31;:::i;9523:241::-;9579:6;9632:2;9620:9;9611:7;9607:23;9603:32;9600:52;;;9648:1;9645;9638:12;9600:52;9687:9;9674:23;9706:28;9728:5;9706:28;:::i;9769:127::-;9830:10;9825:3;9821:20;9818:1;9811:31;9861:4;9858:1;9851:15;9885:4;9882:1;9875:15;9901:332;10002:4;10060:11;10047:25;10154:2;10150:7;10139:8;10123:14;10119:29;10115:43;10095:18;10091:68;10081:96;;10173:1;10170;10163:12;10081:96;10194:33;;;;;9901:332;-1:-1:-1;;9901:332:1:o;10238:902::-;10356:9;10415:4;10407:5;10391:14;10387:26;10383:37;10380:57;;;10433:1;10430;10423:12;10380:57;10486:2;10480:9;10528:4;10516:17;;-1:-1:-1;;;;;10548:34:1;;10584:22;;;10545:62;10542:88;;;10610:18;;:::i;:::-;10646:2;10639:22;10685:19;;10713:33;10685:19;10713:33;:::i;:::-;10755:23;;10826:2;10815:14;;10802:28;10839:30;10802:28;10839:30;:::i;:::-;10897:2;10885:15;;10878:32;10957:2;10946:14;;10933:28;-1:-1:-1;;;;;10973:30:1;;10970:50;;;11016:1;11013;11006:12;10970:50;11053:52;11090:14;11081:6;11074:5;11070:18;11053:52;:::i;:::-;11048:2;11036:15;;11029:77;-1:-1:-1;11040:6:1;10238:902;-1:-1:-1;;10238:902:1:o;11145:411::-;-1:-1:-1;;;;;11348:32:1;;;11330:51;;11417:32;;11412:2;11397:18;;11390:60;11486:2;11481;11466:18;;11459:30;;;-1:-1:-1;;11506:44:1;;11531:18;;11523:6;11506:44;:::i;11561:800::-;11762:2;11751:9;11744:21;11837:1;11833;11828:3;11824:11;11820:19;11811:6;11805:13;11801:39;11796:2;11785:9;11781:18;11774:67;11895:4;11887:6;11883:17;11877:24;11872:2;11861:9;11857:18;11850:52;11984:1;11980;11975:3;11971:11;11967:19;11961:2;11953:6;11949:15;11943:22;11939:48;11933:3;11922:9;11918:19;11911:77;12070:1;12066;12061:3;12057:11;12053:19;12047:2;12039:6;12035:15;12029:22;12025:48;12019:3;12008:9;12004:19;11997:77;12130:3;12122:6;12118:16;12112:23;12105:4;12094:9;12090:20;12083:53;11725:4;12183:3;12175:6;12171:16;12165:23;12225:4;12219:3;12208:9;12204:19;12197:33;12247:51;12293:3;12282:9;12278:19;12264:12;12247:51;:::i;:::-;12239:59;;;12307:48;12349:4;12338:9;12334:20;12326:6;-1:-1:-1;;;;;8296:31:1;8284:44;;8230:104;12366:225;12433:9;;;12454:11;;;12451:134;;;12507:10;12502:3;12498:20;12495:1;12488:31;12542:4;12539:1;12532:15;12570:4;12567:1;12560:15;12901:245;12968:6;13021:2;13009:9;13000:7;12996:23;12992:32;12989:52;;;13037:1;13034;13027:12;12989:52;13069:9;13063:16;13088:28;13110:5;13088:28;:::i;13527:301::-;13656:3;13694:6;13688:13;13740:6;13733:4;13725:6;13721:17;13716:3;13710:37;13802:1;13766:16;;13791:13;;;-1:-1:-1;13766:16:1;13527:301;-1:-1:-1;13527:301:1:o

Swarm Source

ipfs://8de869caa2e008353a01f58886a1c17bd57fea9e7129e0511f178b38a70da77e

Block Transaction Gas Used Reward
view all blocks produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.