ETH Price: $3,138.83 (-1.60%)

Contract

0xE6326d0d0a4fbD77a33b875f7024DeA369Ff90F1

Overview

ETH Balance

0 ETH

ETH Value

$0.00

Token Holdings

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Deposit180439242025-12-03 18:32:1528 hrs ago1764786735IN
0xE6326d0d...369Ff90F1
0 ETH0.000001830.00259926

Latest 10 internal transactions

Advanced mode:
Parent Transaction Hash Block From To
180439242025-12-03 18:32:1528 hrs ago1764786735
0xE6326d0d...369Ff90F1
0 ETH
180439242025-12-03 18:32:1528 hrs ago1764786735
0xE6326d0d...369Ff90F1
0 ETH
180439242025-12-03 18:32:1528 hrs ago1764786735
0xE6326d0d...369Ff90F1
0 ETH
180439242025-12-03 18:32:1528 hrs ago1764786735
0xE6326d0d...369Ff90F1
0 ETH
180436912025-12-03 18:28:2228 hrs ago1764786502
0xE6326d0d...369Ff90F1
0 ETH
180436912025-12-03 18:28:2228 hrs ago1764786502
0xE6326d0d...369Ff90F1
0 ETH
163939892025-11-14 16:13:2020 days ago1763136800
0xE6326d0d...369Ff90F1
0 ETH
163939892025-11-14 16:13:2020 days ago1763136800
0xE6326d0d...369Ff90F1
0 ETH
163939892025-11-14 16:13:2020 days ago1763136800
0xE6326d0d...369Ff90F1
0 ETH
163939892025-11-14 16:13:2020 days ago1763136800
0xE6326d0d...369Ff90F1
0 ETH

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
PermissionlessPSM

Compiler Version
v0.8.26+commit.8a97fa7a

Optimization Enabled:
Yes with 1 runs

Other Settings:
cancun EvmVersion
// SPDX-License-Identifier: MIT

pragma solidity 0.8.26;

import {SafeERC20, IERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {FeeLib} from "src/libraries/FeeLib.sol";
import {IMetaCore} from "src/interfaces/core/IMetaCore.sol";
import {IDebtToken} from "src/interfaces/core/IDebtToken.sol";
import {IFeeHook} from "src/interfaces/utils/integrations/IFeeHook.sol";

/**
 * @title PermissionlessPSM
 * @author Spinnaker Labs
 * @notice Multi-stablecoin Permissionless Peg Stability Module, dynamic entry/exit fees with mint caps
 * @dev Granted mint and burn permissions by DEBT_TOKEN
 * @dev Inspired by IERC4626, but not strictly compliant
 */
contract PermissionlessPSM {
    using Math for uint;
    using SafeERC20 for IERC20;
    using FeeLib for uint;

    uint16 constant BP = 1e4;

    IMetaCore public metaCore;
    IDebtToken public debtToken;
    IFeeHook public feeHook;
    address public feeReceiver;
    bool public paused;
    mapping(address stable => uint) public debtTokenMinted;
    mapping(address stable => uint) public mintCap;

    /// @dev Scale factor to DEBT_TOKEN
    mapping(address => uint64 wadOffset) public stables;

    error OnlyOwner(address caller);
    error AddressZero();
    error AmountZero();
    error Paused();
    error NotListedToken(address token);
    error AlreadyListed(address token);
    error PassedMintCap(uint mintCap, uint minted);
    error SurpassedFeePercentage(uint feePercentage, uint maxFeePercentage);

    event DebtTokenMinted(uint debtTokenMinted, address stable);
    event DebtTokenBurned(uint debtTokenBurned, address stable);
    event FeeHookSet(address feeHook);
    event PausedSet(bool paused);
    event MintCap(uint mintCap);
    event Deposit(address indexed caller, address indexed stable, uint stableAmount, uint mintedDebtToken, uint fee);
    event Withdraw(address indexed caller, address indexed stable, uint stableAmount, uint burnedDebtToken, uint fee);
    event FeeReceiverSet(address feeReceiver);

    modifier onlyOwner() {
        if (msg.sender != metaCore.owner()) revert OnlyOwner(msg.sender);
        _;
    }

    modifier notPaused() {
        if (paused) revert Paused();
        _;
    }

    constructor(address _metaCore, address _debtToken, address[] memory _stables, address _feeHook, address _feeReceiver) {
        if (_metaCore == address(0) || _debtToken == address(0) || _feeHook == address(0)) revert AddressZero();

        metaCore = IMetaCore(_metaCore);
        debtToken = IDebtToken(_debtToken);
        feeHook = IFeeHook(_feeHook);
        feeReceiver = _feeReceiver;

        for (uint i; i < _stables.length; i++) {
            if (_stables[i] == address(0)) revert AddressZero();

            _whitelistStable(_stables[i]);
        }
    }

    function deposit(address stable, uint stableAmount, address receiver, uint16 maxFeePercentage) public notPaused returns (uint mintedDebtToken) {
        if (stableAmount == 0) revert AmountZero();

        uint debtTokenFee;
        (mintedDebtToken, debtTokenFee) = previewDeposit(stable, stableAmount, maxFeePercentage);

        uint cap = mintCap[stable];
        uint _debtTokenMinted = debtTokenMinted[stable] + mintedDebtToken + debtTokenFee;
        if (_debtTokenMinted > cap) revert PassedMintCap(cap, _debtTokenMinted);

        debtTokenMinted[stable] = _debtTokenMinted;

        debtToken.mint(receiver, mintedDebtToken);
        debtToken.mint(feeReceiver, debtTokenFee);

        IERC20(stable).safeTransferFrom(msg.sender, address(this), stableAmount);

        emit Deposit(msg.sender, stable, stableAmount, mintedDebtToken, debtTokenFee);
    }

    function mint(address stable, uint debtTokenAmount, address receiver, uint16 maxFeePercentage) public notPaused returns (uint stableAmount) {
        uint debtTokenFee;
        (stableAmount, debtTokenFee) = previewMint(stable, debtTokenAmount, maxFeePercentage);

        if (stableAmount == 0) revert AmountZero();

        uint cap = mintCap[stable];
        uint _debtTokenMinted = debtTokenMinted[stable] + debtTokenAmount + debtTokenFee;
        if (_debtTokenMinted > cap) revert PassedMintCap(cap, _debtTokenMinted);

        debtTokenMinted[stable] = _debtTokenMinted;

        debtToken.mint(receiver, debtTokenAmount);
        debtToken.mint(feeReceiver, debtTokenFee);

        IERC20(stable).safeTransferFrom(msg.sender, address(this), stableAmount);

        emit Deposit(msg.sender, stable, stableAmount, debtTokenAmount, debtTokenFee);
    }

    function withdraw(address stable, uint stableAmount, address receiver, uint16 maxFeePercentage)
        public
        notPaused
        returns (uint burnedDebtToken)
    {
        uint stableFee;
        (burnedDebtToken, stableFee) = previewWithdraw(stable, stableAmount, maxFeePercentage);

        if (burnedDebtToken == 0) revert AmountZero();

        debtToken.burn(msg.sender, burnedDebtToken);

        debtTokenMinted[stable] -= burnedDebtToken;

        IERC20(stable).safeTransfer(receiver, stableAmount);
        IERC20(stable).safeTransfer(feeReceiver, stableFee);

        emit Withdraw(msg.sender, stable, stableAmount, burnedDebtToken, stableFee);
    }

    function redeem(address stable, uint debtTokenAmount, address receiver, uint16 maxFeePercentage)
        public
        notPaused
        returns (uint stableAmount)
    {
        if (debtTokenAmount == 0) revert AmountZero();

        uint stableFee;
        (stableAmount, stableFee) = previewRedeem(stable, debtTokenAmount, maxFeePercentage);

        debtToken.burn(msg.sender, debtTokenAmount);

        debtTokenMinted[stable] -= debtTokenAmount;

        IERC20(stable).safeTransfer(receiver, stableAmount);
        IERC20(stable).safeTransfer(feeReceiver, stableFee);

        emit Withdraw(msg.sender, stable, stableAmount, debtTokenAmount, stableFee);
    }

    /**
     * @dev Takes DEBT_TOKEN as fee, returns the amount of DEBT_TOKEN that would be minted
     */
    function previewDeposit(address stable, uint stableAmount, uint16 maxFeePercentage) public view returns (uint mintedDebtToken, uint debtTokenFee) {
        uint64 wadOffset = stables[stable];

        if (wadOffset == 0) revert NotListedToken(stable);

        uint grossMintedDebtToken = stableAmount * wadOffset;

        uint fee = feeHook.calcFee(msg.sender, stable, grossMintedDebtToken, IFeeHook.Action.DEPOSIT);
        if (fee > maxFeePercentage) revert SurpassedFeePercentage(fee, maxFeePercentage);

        debtTokenFee = grossMintedDebtToken.feeOnRaw(fee);
        mintedDebtToken = grossMintedDebtToken - debtTokenFee;
    }

    /**
     * @dev Takes DEBT_TOKEN as fee, returns the amount of stable needed to mint DEBT_TOKEN
     */
    function previewMint(address stable, uint debtTokenAmount, uint16 maxFeePercentage) public view returns (uint stableAmount, uint debtTokenFee) {
        uint64 wadOffset = stables[stable];

        if (wadOffset == 0) revert NotListedToken(stable);

        uint fee = feeHook.calcFee(msg.sender, stable, debtTokenAmount, IFeeHook.Action.MINT);
        if (fee > maxFeePercentage) revert SurpassedFeePercentage(fee, maxFeePercentage);

        debtTokenFee = debtTokenAmount.mulDiv(fee, BP - fee, Math.Rounding.Up);        
        stableAmount = (debtTokenAmount + debtTokenFee).ceilDiv(wadOffset);
    }

    /**
     * @dev Takes stable as fee, returns the amount of DEBT_TOKEN that would be burned
     */
    function previewWithdraw(address stable, uint stableAmount, uint16 maxFeePercentage) public view returns (uint burnedDebtToken, uint stableFee) {
        uint64 wadOffset = stables[stable];

        if (wadOffset == 0) revert NotListedToken(stable);

        uint grossBurnedDebtToken = stableAmount * wadOffset;

        uint fee = feeHook.calcFee(msg.sender, stable, grossBurnedDebtToken, IFeeHook.Action.WITHDRAW);
        if (fee > maxFeePercentage) revert SurpassedFeePercentage(fee, maxFeePercentage);

        stableFee = stableAmount.mulDiv(fee, BP - fee, Math.Rounding.Up);
        burnedDebtToken = grossBurnedDebtToken + stableFee * wadOffset;
    }

    /**
     * @dev Takes stable as fee, returns the amount of stable given for redeeming DEBT_TOKEN
     */
    function previewRedeem(address stable, uint debtTokenAmount, uint16 maxFeePercentage) public view returns (uint stableAmount, uint stableFee) {
        uint64 wadOffset = stables[stable];

        if (wadOffset == 0) revert NotListedToken(stable);

        uint grossStable = debtTokenAmount / wadOffset;

        uint fee = feeHook.calcFee(msg.sender, stable, debtTokenAmount, IFeeHook.Action.REDEEM);
        if (fee > maxFeePercentage) revert SurpassedFeePercentage(fee, maxFeePercentage);

        stableFee = grossStable.mulDiv(fee, BP, Math.Rounding.Up);
        stableAmount = grossStable - stableFee;
    }

    function whitelistStable(address _stable) external onlyOwner {
        if (stables[_stable] != 0) revert AlreadyListed(_stable);

        _whitelistStable(_stable);
    }

    function blacklistStable(address _stable) external onlyOwner {
        delete stables[_stable];
    }

    function setFeeHook(address _feeHook) external onlyOwner {
        if (_feeHook == address(0)) revert AddressZero();
        
        feeHook = IFeeHook(_feeHook);

        emit FeeHookSet(_feeHook);
    }

    function setPaused(bool _paused) external onlyOwner {
        paused = _paused;

        emit PausedSet(_paused);
    }

    function setMintCap(address stable, uint _mintCap) external onlyOwner {
        mintCap[stable] = _mintCap;

        emit MintCap(_mintCap);
    }

    function setFeeReceiver(address _feeReceiver) external onlyOwner {
        feeReceiver = _feeReceiver;

        emit FeeReceiverSet(_feeReceiver);
    }

    function _whitelistStable(address _stable) private {
        IERC20Metadata stable = IERC20Metadata(_stable);

        uint64 wadOffset = uint64(10 ** (debtToken.decimals() - stable.decimals()));

        stables[_stable] = wadOffset;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";

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

    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

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

    function safeIncreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
     * with further edits by Uniswap Labs also under MIT license.
     */
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod0 := mul(x, y)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1);

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
            // See https://cs.stackexchange.com/q/138556/92363.

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the 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.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator,
        Rounding rounding
    ) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10**64) {
                value /= 10**64;
                result += 64;
            }
            if (value >= 10**32) {
                value /= 10**32;
                result += 32;
            }
            if (value >= 10**16) {
                value /= 10**16;
                result += 16;
            }
            if (value >= 10**8) {
                value /= 10**8;
                result += 8;
            }
            if (value >= 10**4) {
                value /= 10**4;
                result += 4;
            }
            if (value >= 10**2) {
                value /= 10**2;
                result += 2;
            }
            if (value >= 10**1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256, rounded down, of a positive value.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

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

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

// SPDX-License-Identifier: MIT

pragma solidity 0.8.26;

import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";

library FeeLib {
    using Math for uint;

    uint private constant BP = 1e4;

    /// @dev Calculates the fees that should be added to an amount `shares` that does already include fees.
    /// Used in {IERC4626-deposit}, {IERC4626-mint}, {IERC4626-withdraw} and {IERC4626-previewRedeem} operations.
    function feeOnRaw(
        uint shares,
        uint feeBP
    ) internal pure returns (uint) {
        return shares.mulDiv(feeBP, BP, Math.Rounding.Up);
    }

    /// @dev Calculates the fee part of an amount `shares` that deoes not includes fees.
    /// Used in {IERC4626-previewDeposit} and {IERC4626-previewRedeem} operations.
    function feeOnTotal(
        uint shares,
        uint feeBP
    ) internal pure returns (uint) {
        return shares.mulDiv(feeBP, feeBP + BP, Math.Rounding.Up);
    }
}

// SPDX-License-Identifier: MIT

pragma solidity 0.8.26;

interface IMetaCore {
    // ---------------------------------
    // Structures
    // ---------------------------------
    struct FeeInfo {
        bool existsForDebtToken;
        uint16 debtTokenFee;
    }

    struct RebalancerFeeInfo {
        bool exists;
        uint16 entryFee;
        uint16 exitFee;
    }

    // ---------------------------------
    // Public constants
    // ---------------------------------
    function OWNERSHIP_TRANSFER_DELAY() external view returns (uint256);
    function DEFAULT_FLASH_LOAN_FEE() external view returns (uint16);

    // ---------------------------------
    // Public state variables
    // ---------------------------------
    function debtToken() external view returns (address);
    function lspEntryFee() external view returns (uint16);
    function lspExitFee() external view returns (uint16);
    function interestProtocolShare() external view returns (uint16);
    /// @dev Default interest receiver for all PositionManagers, unless overriden in the respective PM
    function defaultInterestReceiver() external view returns (address);

    function feeReceiver() external view returns (address);
    function priceFeed() external view returns (address);
    function owner() external view returns (address);
    function pendingOwner() external view returns (address);
    function ownershipTransferDeadline() external view returns (uint256);
    function guardian() external view returns (address);
    function paused() external view returns (bool);
    function lspBootstrapPeriod() external view returns (uint64);

    // ---------------------------------
    // External functions
    // ---------------------------------
    function setFeeReceiver(address _feeReceiver) external;
    function setPriceFeed(address _priceFeed) external;
    function setGuardian(address _guardian) external;

    /**
     * @notice Global pause/unpause
     *         Pausing halts new deposits/borrowing across the protocol
     */
    function setPaused(bool _paused) external;

    /**
     * @notice Extend or change the LSP bootstrap period,
     *         after which certain protocol mechanics change
     */
    function setLspBootstrapPeriod(uint64 _bootstrapPeriod) external;

    /**
     * @notice Set a custom flash-loan fee for a given periphery contract
     * @param _periphery Target contract that will get this custom fee
     * @param _debtTokenFee Fee in basis points (bp)
     * @param _existsForDebtToken Whether this custom fee is used when the caller = `debtToken`
     */
    function setPeripheryFlashLoanFee(address _periphery, uint16 _debtTokenFee, bool _existsForDebtToken) external;

    /**
     * @notice Begin the ownership transfer process
     * @param newOwner The address proposed to be the new owner
     */
    function commitTransferOwnership(address newOwner) external;

    /**
     * @notice Finish the ownership transfer, after the mandatory delay
     */
    function acceptTransferOwnership() external;

    /**
     * @notice Revoke a pending ownership transfer
     */
    function revokeTransferOwnership() external;

    /**
     * @notice Look up a custom flash-loan fee for a specific periphery contract
     * @param peripheryContract The contract that might have a custom fee
     * @return The flash-loan fee in basis points
     */
    function getPeripheryFlashLoanFee(address peripheryContract) external view returns (uint16);

    /**
     * @notice Set / override entry & exit fees for a special rebalancer contract
     */
    function setRebalancerFee(address _rebalancer, uint16 _entryFee, uint16 _exitFee) external;

    /**
     * @notice Set the LSP entry fee globally
     * @param _fee Fee in basis points
     */
    function setEntryFee(uint16 _fee) external;

    /**
     * @notice Set the LSP exit fee globally
     * @param _fee Fee in basis points
     */
    function setExitFee(uint16 _fee) external;

    /**
     * @notice Set the interest protocol share globally to all PositionManagers
     * @param _interestProtocolShare Share in basis points
     */
    function setInterestProtocolShare(uint16 _interestProtocolShare) external;

    /**
     * @notice Look up the LSP entry fee for a rebalancer
     * @param rebalancer Possibly has a special fee
     * @return The entry fee in basis points
     */
    function getLspEntryFee(address rebalancer) external view returns (uint16);

    /**
     * @notice Look up the LSP exit fee for a rebalancer
     * @param rebalancer Possibly has a special fee
     * @return The exit fee in basis points
     */
    function getLspExitFee(address rebalancer) external view returns (uint16);

    // ---------------------------------
    // Events
    // ---------------------------------
    event NewOwnerCommitted(address indexed owner, address indexed pendingOwner, uint256 deadline);
    event NewOwnerAccepted(address indexed oldOwner, address indexed newOwner);
    event NewOwnerRevoked(address indexed owner, address indexed revokedOwner);

    event FeeReceiverSet(address indexed feeReceiver);
    event PriceFeedSet(address indexed priceFeed);
    event GuardianSet(address indexed guardian);
    event PeripheryFlashLoanFee(address indexed periphery, uint16 debtTokenFee);
    event LSPBootstrapPeriodSet(uint64 bootstrapPeriod);
    event RebalancerFees(address indexed rebalancer, uint16 entryFee, uint16 exitFee);
    event EntryFeeSet(uint16 fee);
    event ExitFeeSet(uint16 fee);
    event InterestProtocolShareSet(uint16 interestProtocolShare);
    event DefaultInterestReceiverSet(address indexed defaultInterestReceiver);
    event Paused();
    event Unpaused();
}

File 7 of 13 : IDebtToken.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.26;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 
import { IERC3156FlashBorrower } from "@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol";
import "./ICore.sol";

interface IDebtToken is IERC20 {
    // --- Events ---
    event FlashLoanFeeUpdated(uint256 newFee);

    // --- Public constants ---
    function version() external view returns (string memory);
    function permitTypeHash() external view returns (bytes32);

    // --- Public immutables ---
    function gasPool() external view returns (address);
    function DEBT_GAS_COMPENSATION() external view returns (uint256);

    // --- Public mappings ---
    function liquidStabilityPools(address) external view returns (bool);
    function borrowerOperations(address) external view returns (bool);
    function factories(address) external view returns (bool);
    function peripheries(address) external view returns (bool);
    function positionManagers(address) external view returns (bool);

    // --- External functions ---

    function enablePositionManager(address _positionManager) external;
    function mintWithGasCompensation(address _account, uint256 _amount) external returns (bool);
    function burnWithGasCompensation(address _account, uint256 _amount) external returns (bool);
    function mint(address _account, uint256 _amount) external;
    function burn(address _account, uint256 _amount) external;
    function decimals() external view returns (uint8);
    function sendToPeriphery(address _sender, uint256 _amount) external;
    function sendToSP(address _sender, uint256 _amount) external;
    function returnFromPool(address _poolAddress, address _receiver, uint256 _amount) external;
    function transfer(address recipient, uint256 amount) external returns (bool);
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
    function maxFlashLoan(address token) external view returns (uint256);
    function flashFee(address token, uint256 amount) external view returns (uint256);
    function flashLoan(
        IERC3156FlashBorrower receiver,
        address token,
        uint256 amount,
        bytes calldata data
    ) external returns (bool);
    function whitelistLiquidStabilityPoolAddress(address _liquidStabilityPool, bool active) external;
    function whitelistBorrowerOperationsAddress(address _borrowerOperations, bool active) external;
    function whitelistFactoryAddress(address _factory, bool active) external;
    function whitelistPeripheryAddress(address _periphery, bool active) external;
    function whitelistPSM(address, bool) external;
    function setDebtGasCompensation(uint256 _gasCompensation, bool _isFinalValue) external;
    function setFlashLoanFee(uint256 _fee) external;
    function DOMAIN_SEPARATOR() external view returns (bytes32);
    function permit(
        address owner,
        address spender,
        uint256 amount,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;
    function nonces(address owner) external view returns (uint256);
}

// SPDX-License-Identifier: MIT

pragma solidity 0.8.26;

interface IFeeHook {
    enum Action {
        DEPOSIT,
        MINT,
        WITHDRAW,
        REDEEM
    }

    function calcFee(address caller, address token, uint amount, Action action) external view returns (uint feeInBP);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)

pragma solidity ^0.8.0;

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

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

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)

pragma solidity ^0.8.1;

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

        return account.code.length > 0;
    }

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

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

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

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

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

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

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

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

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

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

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

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

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

File 12 of 13 : IERC3156FlashBorrower.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (interfaces/IERC3156FlashBorrower.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC3156 FlashBorrower, as defined in
 * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156].
 *
 * _Available since v4.1._
 */
interface IERC3156FlashBorrower {
    /**
     * @dev Receive a flash loan.
     * @param initiator The initiator of the loan.
     * @param token The loan currency.
     * @param amount The amount of tokens lent.
     * @param fee The additional amount of tokens to repay.
     * @param data Arbitrary data structure, intended to contain user-defined parameters.
     * @return The keccak256 hash of "IERC3156FlashBorrower.onFlashLoan"
     */
    function onFlashLoan(
        address initiator,
        address token,
        uint256 amount,
        uint256 fee,
        bytes calldata data
    ) external returns (bytes32);
}

// SPDX-License-Identifier: MIT

pragma solidity 0.8.26;

import {IMetaCore} from "src/interfaces/core/IMetaCore.sol";

interface ICore {

    // --- Public variables ---
    function metaCore() external view returns (IMetaCore);
    function startTime() external view returns (uint256);
    function CCR() external view returns (uint256);
    function dmBootstrapPeriod() external view returns (uint64);
    function isPeriphery(address peripheryContract) external view returns (bool);

    // --- External functions ---

    function setPeripheryEnabled(address _periphery, bool _enabled) external;
    function setPMBootstrapPeriod(address dm, uint64 _bootstrapPeriod) external;
    function setNewCCR(uint256 _CCR) external;

    function priceFeed() external view returns (address);
    function owner() external view returns (address);
    function pendingOwner() external view returns (address);
    function guardian() external view returns (address);
    function feeReceiver() external view returns (address);
    function paused() external view returns (bool);
    function lspBootstrapPeriod() external view returns (uint64);
    function getLspEntryFee(address rebalancer) external view returns (uint16);
    function getLspExitFee(address rebalancer) external view returns (uint16);
    function interestProtocolShare() external view returns (uint16);
    function defaultInterestReceiver() external view returns (address);

    // --- Events ---
    event CCRSet(uint256 initialCCR);
    event PMBootstrapPeriodSet(address dm, uint64 bootstrapPeriod);
    event PeripheryEnabled(address indexed periphery, bool enabled);
}

Settings
{
  "remappings": [
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "@openzeppelin-upgradeable/contracts/=lib/openzeppelin-contracts-upgradeable/contracts/",
    "solady/=lib/solady/src/",
    "@solmate/=lib/solmate/src/",
    "@chimera/=lib/chimera/src/",
    "forge-std/=lib/forge-std/src/",
    "@uniswap/v3-core/=lib/v3-core/",
    "@uniswap/v3-periphery/=lib/v3-periphery/",
    "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
    "chimera/=lib/chimera/src/",
    "ds-test/=lib/solmate/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
    "halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
    "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "rewards/=lib/rewards/",
    "solmate/=lib/solmate/src/",
    "uniswap/=lib/uniswap/",
    "v3-core/=lib/v3-core/contracts/",
    "v3-periphery/=lib/v3-periphery/contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 1
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": false
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_metaCore","type":"address"},{"internalType":"address","name":"_debtToken","type":"address"},{"internalType":"address[]","name":"_stables","type":"address[]"},{"internalType":"address","name":"_feeHook","type":"address"},{"internalType":"address","name":"_feeReceiver","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AddressZero","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"AlreadyListed","type":"error"},{"inputs":[],"name":"AmountZero","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"NotListedToken","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"OnlyOwner","type":"error"},{"inputs":[{"internalType":"uint256","name":"mintCap","type":"uint256"},{"internalType":"uint256","name":"minted","type":"uint256"}],"name":"PassedMintCap","type":"error"},{"inputs":[],"name":"Paused","type":"error"},{"inputs":[{"internalType":"uint256","name":"feePercentage","type":"uint256"},{"internalType":"uint256","name":"maxFeePercentage","type":"uint256"}],"name":"SurpassedFeePercentage","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"debtTokenBurned","type":"uint256"},{"indexed":false,"internalType":"address","name":"stable","type":"address"}],"name":"DebtTokenBurned","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"debtTokenMinted","type":"uint256"},{"indexed":false,"internalType":"address","name":"stable","type":"address"}],"name":"DebtTokenMinted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"stable","type":"address"},{"indexed":false,"internalType":"uint256","name":"stableAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mintedDebtToken","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"feeHook","type":"address"}],"name":"FeeHookSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"feeReceiver","type":"address"}],"name":"FeeReceiverSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"mintCap","type":"uint256"}],"name":"MintCap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"paused","type":"bool"}],"name":"PausedSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"stable","type":"address"},{"indexed":false,"internalType":"uint256","name":"stableAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"burnedDebtToken","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[{"internalType":"address","name":"_stable","type":"address"}],"name":"blacklistStable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"debtToken","outputs":[{"internalType":"contract IDebtToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"stable","type":"address"}],"name":"debtTokenMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"stable","type":"address"},{"internalType":"uint256","name":"stableAmount","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint16","name":"maxFeePercentage","type":"uint16"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"mintedDebtToken","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeHook","outputs":[{"internalType":"contract IFeeHook","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeReceiver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metaCore","outputs":[{"internalType":"contract IMetaCore","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"stable","type":"address"},{"internalType":"uint256","name":"debtTokenAmount","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint16","name":"maxFeePercentage","type":"uint16"}],"name":"mint","outputs":[{"internalType":"uint256","name":"stableAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"stable","type":"address"}],"name":"mintCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"stable","type":"address"},{"internalType":"uint256","name":"stableAmount","type":"uint256"},{"internalType":"uint16","name":"maxFeePercentage","type":"uint16"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"mintedDebtToken","type":"uint256"},{"internalType":"uint256","name":"debtTokenFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"stable","type":"address"},{"internalType":"uint256","name":"debtTokenAmount","type":"uint256"},{"internalType":"uint16","name":"maxFeePercentage","type":"uint16"}],"name":"previewMint","outputs":[{"internalType":"uint256","name":"stableAmount","type":"uint256"},{"internalType":"uint256","name":"debtTokenFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"stable","type":"address"},{"internalType":"uint256","name":"debtTokenAmount","type":"uint256"},{"internalType":"uint16","name":"maxFeePercentage","type":"uint16"}],"name":"previewRedeem","outputs":[{"internalType":"uint256","name":"stableAmount","type":"uint256"},{"internalType":"uint256","name":"stableFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"stable","type":"address"},{"internalType":"uint256","name":"stableAmount","type":"uint256"},{"internalType":"uint16","name":"maxFeePercentage","type":"uint16"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"burnedDebtToken","type":"uint256"},{"internalType":"uint256","name":"stableFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"stable","type":"address"},{"internalType":"uint256","name":"debtTokenAmount","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint16","name":"maxFeePercentage","type":"uint16"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"stableAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeHook","type":"address"}],"name":"setFeeHook","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeReceiver","type":"address"}],"name":"setFeeReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"stable","type":"address"},{"internalType":"uint256","name":"_mintCap","type":"uint256"}],"name":"setMintCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_paused","type":"bool"}],"name":"setPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"stables","outputs":[{"internalType":"uint64","name":"wadOffset","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_stable","type":"address"}],"name":"whitelistStable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"stable","type":"address"},{"internalType":"uint256","name":"stableAmount","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint16","name":"maxFeePercentage","type":"uint16"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"burnedDebtToken","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]

608060405234801561000f575f80fd5b506040516122e03803806122e083398101604081905261002e916102a8565b6001600160a01b038516158061004b57506001600160a01b038416155b8061005d57506001600160a01b038216155b1561007b57604051639fabe1c160e01b815260040160405180910390fd5b5f80546001600160a01b038088166001600160a01b0319928316178355600180548883169084161790556002805486831690841617905560038054918516919092161790555b8351811015610145575f6001600160a01b03168482815181106100e6576100e66103b5565b60200260200101516001600160a01b03160361011557604051639fabe1c160e01b815260040160405180910390fd5b61013d84828151811061012a5761012a6103b5565b602002602001015161015060201b60201c565b6001016100c1565b505050505050610514565b5f8190505f816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610191573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101b591906103c9565b60015f9054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610205573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061022991906103c9565b6102339190610404565b61023e90600a610506565b6001600160a01b03939093165f90815260066020526040902080546001600160401b0319166001600160401b03909416939093179092555050565b80516001600160a01b038116811461028f575f80fd5b919050565b634e487b7160e01b5f52604160045260245ffd5b5f805f805f60a086880312156102bc575f80fd5b6102c586610279565b94506102d360208701610279565b60408701519094506001600160401b038111156102ee575f80fd5b8601601f810188136102fe575f80fd5b80516001600160401b0381111561031757610317610294565b604051600582901b90603f8201601f191681016001600160401b038111828210171561034557610345610294565b60405291825260208184018101929081018b841115610362575f80fd5b6020850194505b838510156103885761037a85610279565b815260209485019401610369565b50955061039b9250505060608701610279565b91506103a960808701610279565b90509295509295909350565b634e487b7160e01b5f52603260045260245ffd5b5f602082840312156103d9575f80fd5b815160ff811681146103e9575f80fd5b9392505050565b634e487b7160e01b5f52601160045260245ffd5b60ff828116828216039081111561041d5761041d6103f0565b92915050565b6001815b600184111561045e57808504811115610442576104426103f0565b600184161561045057908102905b60019390931c928002610427565b935093915050565b5f826104745750600161041d565b8161048057505f61041d565b816001811461049657600281146104a0576104bc565b600191505061041d565b60ff8411156104b1576104b16103f0565b50506001821b61041d565b5060208310610133831016604e8410600b84101617156104df575081810a61041d565b6104eb5f198484610423565b805f19048211156104fe576104fe6103f0565b029392505050565b5f6103e960ff841683610466565b611dbf806105215f395ff3fe608060405234801561000f575f80fd5b5060043610610110575f3560e01c80630c1f1e141461011457806316c38b3c146101295780632f6196b71461013c578063327b6d161461016257806337e7f9eb1461018157806344f1d38b146101a95780634743a510146101bc578063474566c6146101fc5780635c975abb1461021b57806361db42711461023f57806361fc03681461025e5780637c16de13146102715780638b4af4521461028457806392c18454146102975780639ccc6eb4146102aa578063aa3b89b2146102bd578063b3f00674146102d0578063c06abe77146102e3578063e8eda9df146102f6578063efdcd97414610309578063f11f44611461031c578063f8d898981461032f575b5f80fd5b610127610122366004611944565b610342565b005b61012761013736600461196c565b610416565b61014f61014a36600461199d565b610513565b6040519081526020015b60405180910390f35b61014f610170366004611944565b60046020525f908152604090205481565b61019461018f3660046119eb565b610711565b60408051928352602083019190915201610159565b6101946101b73660046119eb565b610854565b6101e46101ca366004611944565b60066020525f90815260409020546001600160401b031681565b6040516001600160401b039091168152602001610159565b5f5461020e906001600160a01b031681565b6040516101599190611a26565b60035461022f90600160a01b900460ff1681565b6040519015158152602001610159565b61014f61024d366004611944565b60056020525f908152604090205481565b61014f61026c36600461199d565b610968565b61019461027f3660046119eb565b610ac4565b61014f61029236600461199d565b610bd2565b6101276102a5366004611944565b610d1f565b6101946102b83660046119eb565b610e36565b6101276102cb366004611944565b610f61565b60035461020e906001600160a01b031681565b6101276102f1366004611a3a565b611053565b61014f61030436600461199d565b611150565b610127610317366004611944565b61133a565b60025461020e906001600160a01b031681565b60015461020e906001600160a01b031681565b5f8054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610390573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103b49190611a64565b6001600160a01b0316336001600160a01b0316146103f05733604051630543601560e11b81526004016103e79190611a26565b60405180910390fd5b6001600160a01b03165f90815260066020526040902080546001600160401b0319169055565b5f8054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610464573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104889190611a64565b6001600160a01b0316336001600160a01b0316146104bb5733604051630543601560e11b81526004016103e79190611a26565b60038054821515600160a01b0260ff60a01b199091161790556040517f40db37ff5c0bdc2c427fbb2078c8f24afea940abac0e3c23bb4ea3bf2da2b2129061050890831515815260200190565b60405180910390a150565b6003545f90600160a01b900460ff1615610540576040516313d0ff5960e31b815260040160405180910390fd5b5f61054c868685610e36565b90925090505f829003610572576040516365e52d5160e11b815260040160405180910390fd5b6001600160a01b0386165f90815260056020908152604080832054600490925282205490919083906105a5908990611a93565b6105af9190611a93565b9050818111156105dc576040516319f62e8960e01b815260048101839052602481018290526044016103e7565b6001600160a01b038089165f9081526004602081905260409182902084905560015491516340c10f1960e01b815291909216916340c10f1991610623918a918c9101611aa6565b5f604051808303815f87803b15801561063a575f80fd5b505af115801561064c573d5f803e3d5ffd5b50506001546003546040516340c10f1960e01b81526001600160a01b0392831694506340c10f19935061068792909116908790600401611aa6565b5f604051808303815f87803b15801561069e575f80fd5b505af11580156106b0573d5f803e3d5ffd5b506106ca925050506001600160a01b03891633308761142a565b876001600160a01b0316336001600160a01b03165f80516020611d6a833981519152868a876040516106fe93929190611abf565b60405180910390a3505050949350505050565b6001600160a01b0383165f9081526006602052604081205481906001600160401b0316808203610756578560405163914662e560e01b81526004016103e79190611a26565b5f61076a6001600160401b03831687611ad5565b60028054604051631c2e957160e11b81529293505f926001600160a01b039091169163385d2ae2916107a49133918d918891600401611b00565b602060405180830381865afa1580156107bf573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107e39190611b4a565b90508561ffff1681111561080e57808660405163a89e26b760e01b81526004016103e7929190611b61565b6108288161081e81612710611b73565b899190600161149b565b935061083d6001600160401b03841685611ad5565b6108479083611a93565b9450505050935093915050565b6001600160a01b0383165f9081526006602052604081205481906001600160401b0316808203610899578560405163914662e560e01b81526004016103e79190611a26565b5f6108ad6001600160401b03831687611ad5565b600254604051631c2e957160e11b81529192505f916001600160a01b039091169063385d2ae2906108e89033908c9087908790600401611b00565b602060405180830381865afa158015610903573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109279190611b4a565b90508561ffff1681111561095257808660405163a89e26b760e01b81526004016103e7929190611b61565b61095c82826114f8565b93506108478483611b73565b6003545f90600160a01b900460ff1615610995576040516313d0ff5960e31b815260040160405180910390fd5b835f036109b5576040516365e52d5160e11b815260040160405180910390fd5b5f6109c1868685610ac4565b600154604051632770a7eb60e21b81529294509092506001600160a01b031690639dc29fac906109f79033908990600401611aa6565b5f604051808303815f87803b158015610a0e575f80fd5b505af1158015610a20573d5f803e3d5ffd5b505050506001600160a01b0386165f9081526004602052604081208054879290610a4b908490611b73565b90915550610a6590506001600160a01b0387168584611511565b600354610a7f906001600160a01b03888116911683611511565b856001600160a01b0316336001600160a01b03165f80516020611d4a833981519152848885604051610ab393929190611abf565b60405180910390a350949350505050565b6001600160a01b0383165f9081526006602052604081205481906001600160401b0316808203610b09578560405163914662e560e01b81526004016103e79190611a26565b5f610b1d6001600160401b03831687611b9a565b600254604051631c2e957160e11b81529192505f916001600160a01b039091169063385d2ae290610b599033908c908c90600390600401611b00565b602060405180830381865afa158015610b74573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b989190611b4a565b90508561ffff16811115610bc357808660405163a89e26b760e01b81526004016103e7929190611b61565b61095c8282612710600161149b565b6003545f90600160a01b900460ff1615610bff576040516313d0ff5960e31b815260040160405180910390fd5b5f610c0b868685610711565b90925090505f829003610c31576040516365e52d5160e11b815260040160405180910390fd5b600154604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac90610c639033908690600401611aa6565b5f604051808303815f87803b158015610c7a575f80fd5b505af1158015610c8c573d5f803e3d5ffd5b505050506001600160a01b0386165f9081526004602052604081208054849290610cb7908490611b73565b90915550610cd190506001600160a01b0387168587611511565b600354610ceb906001600160a01b03888116911683611511565b856001600160a01b0316336001600160a01b03165f80516020611d4a833981519152878585604051610ab393929190611abf565b5f8054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d6d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d919190611a64565b6001600160a01b0316336001600160a01b031614610dc45733604051630543601560e11b81526004016103e79190611a26565b6001600160a01b038116610deb57604051639fabe1c160e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0383161790556040517fd6e2f80c31feccfd7c896d69ad9963871021131ff84f2a9828b40bad60dd8cb490610508908390611a26565b6001600160a01b0383165f9081526006602052604081205481906001600160401b0316808203610e7b578560405163914662e560e01b81526004016103e79190611a26565b600254604051631c2e957160e11b81525f916001600160a01b03169063385d2ae290610eb29033908b908b90600190600401611b00565b602060405180830381865afa158015610ecd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ef19190611b4a565b90508461ffff16811115610f1c57808560405163a89e26b760e01b81526004016103e7929190611b61565b610f3681610f2c81612710611b73565b889190600161149b565b9250610f556001600160401b038316610f4f8589611a93565b90611535565b93505050935093915050565b5f8054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610faf573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fd39190611a64565b6001600160a01b0316336001600160a01b0316146110065733604051630543601560e11b81526004016103e79190611a26565b6001600160a01b0381165f908152600660205260409020546001600160401b03161561104757806040516319cd459560e01b81526004016103e79190611a26565b6110508161156a565b50565b5f8054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110a1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110c59190611a64565b6001600160a01b0316336001600160a01b0316146110f85733604051630543601560e11b81526004016103e79190611a26565b6001600160a01b0382165f9081526005602052604090819020829055517ffb004db797f030699766afa59af1098f1fb21a289537c4fde9614cdf2298066f906111449083815260200190565b60405180910390a15050565b6003545f90600160a01b900460ff161561117d576040516313d0ff5960e31b815260040160405180910390fd5b835f0361119d576040516365e52d5160e11b815260040160405180910390fd5b5f6111a9868685610854565b6001600160a01b0388165f908152600560209081526040808320546004909252822054939550919350909183906111e1908690611a93565b6111eb9190611a93565b905081811115611218576040516319f62e8960e01b815260048101839052602481018290526044016103e7565b6001600160a01b038089165f9081526004602081905260409182902084905560015491516340c10f1960e01b815291909216916340c10f199161125f918a91899101611aa6565b5f604051808303815f87803b158015611276575f80fd5b505af1158015611288573d5f803e3d5ffd5b50506001546003546040516340c10f1960e01b81526001600160a01b0392831694506340c10f1993506112c392909116908790600401611aa6565b5f604051808303815f87803b1580156112da575f80fd5b505af11580156112ec573d5f803e3d5ffd5b50611306925050506001600160a01b03891633308a61142a565b876001600160a01b0316336001600160a01b03165f80516020611d6a8339815191528987876040516106fe93929190611abf565b5f8054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611388573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113ac9190611a64565b6001600160a01b0316336001600160a01b0316146113df5733604051630543601560e11b81526004016103e79190611a26565b600380546001600160a01b0319166001600160a01b0383161790556040517fbdf37c276f641820b141429d245add2552b4118c0866e5a78638e3de5ef18d9d90610508908390611a26565b6040516001600160a01b03808516602483015283166044820152606481018290526114959085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611693565b50505050565b5f806114a8868686611764565b905060018360028111156114be576114be611aec565b1480156114da57505f84806114d5576114d5611b86565b868809115b156114ed576114ea600182611a93565b90505b90505b949350505050565b5f6115088383612710600161149b565b90505b92915050565b6115308363a9059cbb60e01b848460405160240161145e929190611aa6565b505050565b5f82156115625781611548600185611b73565b6115529190611b9a565b61155d906001611a93565b611508565b505f92915050565b5f8190505f816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115ab573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115cf9190611bb9565b60015f9054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561161f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116439190611bb9565b61164d9190611bd9565b61165890600a611cd5565b6001600160a01b03939093165f90815260066020526040902080546001600160401b0319166001600160401b03909416939093179092555050565b5f6116e7826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166118139092919063ffffffff16565b80519091501561153057808060200190518101906117059190611ce3565b6115305760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016103e7565b5f80805f19858709858702925082811083820303915050805f0361179b5783828161179157611791611b86565b049250505061180c565b8084116117a6575f80fd5b5f848688098519600190810187169687900496828603819004959092119093035f82900391909104909201919091029190911760038402600290811880860282030280860282030280860282030280860282030280860282030280860290910302029150505b9392505050565b60606114f084845f85855f80866001600160a01b031685876040516118389190611cfe565b5f6040518083038185875af1925050503d805f8114611872576040519150601f19603f3d011682016040523d82523d5f602084013e611877565b606091505b509150915061188887838387611893565b979650505050505050565b606083156119015782515f036118fa576001600160a01b0385163b6118fa5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016103e7565b50816114f0565b6114f083838151156119165781518083602001fd5b8060405162461bcd60e51b81526004016103e79190611d14565b6001600160a01b0381168114611050575f80fd5b5f60208284031215611954575f80fd5b813561180c81611930565b8015158114611050575f80fd5b5f6020828403121561197c575f80fd5b813561180c8161195f565b803561ffff81168114611998575f80fd5b919050565b5f805f80608085870312156119b0575f80fd5b84356119bb81611930565b93506020850135925060408501356119d281611930565b91506119e060608601611987565b905092959194509250565b5f805f606084860312156119fd575f80fd5b8335611a0881611930565b925060208401359150611a1d60408501611987565b90509250925092565b6001600160a01b0391909116815260200190565b5f8060408385031215611a4b575f80fd5b8235611a5681611930565b946020939093013593505050565b5f60208284031215611a74575f80fd5b815161180c81611930565b634e487b7160e01b5f52601160045260245ffd5b8082018082111561150b5761150b611a7f565b6001600160a01b03929092168252602082015260400190565b9283526020830191909152604082015260600190565b808202811582820484141761150b5761150b611a7f565b634e487b7160e01b5f52602160045260245ffd5b6001600160a01b03858116825284166020820152604081018390526080810160048310611b3b57634e487b7160e01b5f52602160045260245ffd5b82606083015295945050505050565b5f60208284031215611b5a575f80fd5b5051919050565b91825261ffff16602082015260400190565b8181038181111561150b5761150b611a7f565b634e487b7160e01b5f52601260045260245ffd5b5f82611bb457634e487b7160e01b5f52601260045260245ffd5b500490565b5f60208284031215611bc9575f80fd5b815160ff8116811461180c575f80fd5b60ff828116828216039081111561150b5761150b611a7f565b6001815b6001841115611c2d57808504811115611c1157611c11611a7f565b6001841615611c1f57908102905b60019390931c928002611bf6565b935093915050565b5f82611c435750600161150b565b81611c4f57505f61150b565b8160018114611c655760028114611c6f57611c8b565b600191505061150b565b60ff841115611c8057611c80611a7f565b50506001821b61150b565b5060208310610133831016604e8410600b8410161715611cae575081810a61150b565b611cba5f198484611bf2565b805f1904821115611ccd57611ccd611a7f565b029392505050565b5f61150860ff841683611c35565b5f60208284031215611cf3575f80fd5b815161180c8161195f565b5f82518060208501845e5f920191825250919050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f8301168401019150509291505056feebff2602b3f468259e1e99f613fed6691f3a6526effe6ef3e768ba7ae7a36c4f4e2ca0515ed1aef1395f66b5303bb5d6f1bf9d61a353fa53f73f8ac9973fa9f6a26469706673582212201710f9f3a14ef9934bb3477e760ef32019ed84998e81e494498e9465693c7d8a64736f6c634300081a00330000000000000000000000008700af942be2a6e5566306d0ee7bcc5a3a6e0ce80000000000000000000000000f26bbb8962d73bc891327f14db5162d5279899f00000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000d431abc566a2b82bfb6fbea94ac22cae4065486c000000000000000000000000686ed0d7840dbd41cdacd37c26e68e13ed317d340000000000000000000000000000000000000000000000000000000000000002000000000000000000000000203a662b0bd271a6ed5a60edfbd04bfce608fd3600000000000000000000000000000000efe302beaa2b3e6e1b18d08d69a9012a

Deployed Bytecode

0x608060405234801561000f575f80fd5b5060043610610110575f3560e01c80630c1f1e141461011457806316c38b3c146101295780632f6196b71461013c578063327b6d161461016257806337e7f9eb1461018157806344f1d38b146101a95780634743a510146101bc578063474566c6146101fc5780635c975abb1461021b57806361db42711461023f57806361fc03681461025e5780637c16de13146102715780638b4af4521461028457806392c18454146102975780639ccc6eb4146102aa578063aa3b89b2146102bd578063b3f00674146102d0578063c06abe77146102e3578063e8eda9df146102f6578063efdcd97414610309578063f11f44611461031c578063f8d898981461032f575b5f80fd5b610127610122366004611944565b610342565b005b61012761013736600461196c565b610416565b61014f61014a36600461199d565b610513565b6040519081526020015b60405180910390f35b61014f610170366004611944565b60046020525f908152604090205481565b61019461018f3660046119eb565b610711565b60408051928352602083019190915201610159565b6101946101b73660046119eb565b610854565b6101e46101ca366004611944565b60066020525f90815260409020546001600160401b031681565b6040516001600160401b039091168152602001610159565b5f5461020e906001600160a01b031681565b6040516101599190611a26565b60035461022f90600160a01b900460ff1681565b6040519015158152602001610159565b61014f61024d366004611944565b60056020525f908152604090205481565b61014f61026c36600461199d565b610968565b61019461027f3660046119eb565b610ac4565b61014f61029236600461199d565b610bd2565b6101276102a5366004611944565b610d1f565b6101946102b83660046119eb565b610e36565b6101276102cb366004611944565b610f61565b60035461020e906001600160a01b031681565b6101276102f1366004611a3a565b611053565b61014f61030436600461199d565b611150565b610127610317366004611944565b61133a565b60025461020e906001600160a01b031681565b60015461020e906001600160a01b031681565b5f8054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610390573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103b49190611a64565b6001600160a01b0316336001600160a01b0316146103f05733604051630543601560e11b81526004016103e79190611a26565b60405180910390fd5b6001600160a01b03165f90815260066020526040902080546001600160401b0319169055565b5f8054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610464573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104889190611a64565b6001600160a01b0316336001600160a01b0316146104bb5733604051630543601560e11b81526004016103e79190611a26565b60038054821515600160a01b0260ff60a01b199091161790556040517f40db37ff5c0bdc2c427fbb2078c8f24afea940abac0e3c23bb4ea3bf2da2b2129061050890831515815260200190565b60405180910390a150565b6003545f90600160a01b900460ff1615610540576040516313d0ff5960e31b815260040160405180910390fd5b5f61054c868685610e36565b90925090505f829003610572576040516365e52d5160e11b815260040160405180910390fd5b6001600160a01b0386165f90815260056020908152604080832054600490925282205490919083906105a5908990611a93565b6105af9190611a93565b9050818111156105dc576040516319f62e8960e01b815260048101839052602481018290526044016103e7565b6001600160a01b038089165f9081526004602081905260409182902084905560015491516340c10f1960e01b815291909216916340c10f1991610623918a918c9101611aa6565b5f604051808303815f87803b15801561063a575f80fd5b505af115801561064c573d5f803e3d5ffd5b50506001546003546040516340c10f1960e01b81526001600160a01b0392831694506340c10f19935061068792909116908790600401611aa6565b5f604051808303815f87803b15801561069e575f80fd5b505af11580156106b0573d5f803e3d5ffd5b506106ca925050506001600160a01b03891633308761142a565b876001600160a01b0316336001600160a01b03165f80516020611d6a833981519152868a876040516106fe93929190611abf565b60405180910390a3505050949350505050565b6001600160a01b0383165f9081526006602052604081205481906001600160401b0316808203610756578560405163914662e560e01b81526004016103e79190611a26565b5f61076a6001600160401b03831687611ad5565b60028054604051631c2e957160e11b81529293505f926001600160a01b039091169163385d2ae2916107a49133918d918891600401611b00565b602060405180830381865afa1580156107bf573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107e39190611b4a565b90508561ffff1681111561080e57808660405163a89e26b760e01b81526004016103e7929190611b61565b6108288161081e81612710611b73565b899190600161149b565b935061083d6001600160401b03841685611ad5565b6108479083611a93565b9450505050935093915050565b6001600160a01b0383165f9081526006602052604081205481906001600160401b0316808203610899578560405163914662e560e01b81526004016103e79190611a26565b5f6108ad6001600160401b03831687611ad5565b600254604051631c2e957160e11b81529192505f916001600160a01b039091169063385d2ae2906108e89033908c9087908790600401611b00565b602060405180830381865afa158015610903573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109279190611b4a565b90508561ffff1681111561095257808660405163a89e26b760e01b81526004016103e7929190611b61565b61095c82826114f8565b93506108478483611b73565b6003545f90600160a01b900460ff1615610995576040516313d0ff5960e31b815260040160405180910390fd5b835f036109b5576040516365e52d5160e11b815260040160405180910390fd5b5f6109c1868685610ac4565b600154604051632770a7eb60e21b81529294509092506001600160a01b031690639dc29fac906109f79033908990600401611aa6565b5f604051808303815f87803b158015610a0e575f80fd5b505af1158015610a20573d5f803e3d5ffd5b505050506001600160a01b0386165f9081526004602052604081208054879290610a4b908490611b73565b90915550610a6590506001600160a01b0387168584611511565b600354610a7f906001600160a01b03888116911683611511565b856001600160a01b0316336001600160a01b03165f80516020611d4a833981519152848885604051610ab393929190611abf565b60405180910390a350949350505050565b6001600160a01b0383165f9081526006602052604081205481906001600160401b0316808203610b09578560405163914662e560e01b81526004016103e79190611a26565b5f610b1d6001600160401b03831687611b9a565b600254604051631c2e957160e11b81529192505f916001600160a01b039091169063385d2ae290610b599033908c908c90600390600401611b00565b602060405180830381865afa158015610b74573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b989190611b4a565b90508561ffff16811115610bc357808660405163a89e26b760e01b81526004016103e7929190611b61565b61095c8282612710600161149b565b6003545f90600160a01b900460ff1615610bff576040516313d0ff5960e31b815260040160405180910390fd5b5f610c0b868685610711565b90925090505f829003610c31576040516365e52d5160e11b815260040160405180910390fd5b600154604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac90610c639033908690600401611aa6565b5f604051808303815f87803b158015610c7a575f80fd5b505af1158015610c8c573d5f803e3d5ffd5b505050506001600160a01b0386165f9081526004602052604081208054849290610cb7908490611b73565b90915550610cd190506001600160a01b0387168587611511565b600354610ceb906001600160a01b03888116911683611511565b856001600160a01b0316336001600160a01b03165f80516020611d4a833981519152878585604051610ab393929190611abf565b5f8054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d6d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d919190611a64565b6001600160a01b0316336001600160a01b031614610dc45733604051630543601560e11b81526004016103e79190611a26565b6001600160a01b038116610deb57604051639fabe1c160e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0383161790556040517fd6e2f80c31feccfd7c896d69ad9963871021131ff84f2a9828b40bad60dd8cb490610508908390611a26565b6001600160a01b0383165f9081526006602052604081205481906001600160401b0316808203610e7b578560405163914662e560e01b81526004016103e79190611a26565b600254604051631c2e957160e11b81525f916001600160a01b03169063385d2ae290610eb29033908b908b90600190600401611b00565b602060405180830381865afa158015610ecd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ef19190611b4a565b90508461ffff16811115610f1c57808560405163a89e26b760e01b81526004016103e7929190611b61565b610f3681610f2c81612710611b73565b889190600161149b565b9250610f556001600160401b038316610f4f8589611a93565b90611535565b93505050935093915050565b5f8054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610faf573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fd39190611a64565b6001600160a01b0316336001600160a01b0316146110065733604051630543601560e11b81526004016103e79190611a26565b6001600160a01b0381165f908152600660205260409020546001600160401b03161561104757806040516319cd459560e01b81526004016103e79190611a26565b6110508161156a565b50565b5f8054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110a1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110c59190611a64565b6001600160a01b0316336001600160a01b0316146110f85733604051630543601560e11b81526004016103e79190611a26565b6001600160a01b0382165f9081526005602052604090819020829055517ffb004db797f030699766afa59af1098f1fb21a289537c4fde9614cdf2298066f906111449083815260200190565b60405180910390a15050565b6003545f90600160a01b900460ff161561117d576040516313d0ff5960e31b815260040160405180910390fd5b835f0361119d576040516365e52d5160e11b815260040160405180910390fd5b5f6111a9868685610854565b6001600160a01b0388165f908152600560209081526040808320546004909252822054939550919350909183906111e1908690611a93565b6111eb9190611a93565b905081811115611218576040516319f62e8960e01b815260048101839052602481018290526044016103e7565b6001600160a01b038089165f9081526004602081905260409182902084905560015491516340c10f1960e01b815291909216916340c10f199161125f918a91899101611aa6565b5f604051808303815f87803b158015611276575f80fd5b505af1158015611288573d5f803e3d5ffd5b50506001546003546040516340c10f1960e01b81526001600160a01b0392831694506340c10f1993506112c392909116908790600401611aa6565b5f604051808303815f87803b1580156112da575f80fd5b505af11580156112ec573d5f803e3d5ffd5b50611306925050506001600160a01b03891633308a61142a565b876001600160a01b0316336001600160a01b03165f80516020611d6a8339815191528987876040516106fe93929190611abf565b5f8054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611388573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113ac9190611a64565b6001600160a01b0316336001600160a01b0316146113df5733604051630543601560e11b81526004016103e79190611a26565b600380546001600160a01b0319166001600160a01b0383161790556040517fbdf37c276f641820b141429d245add2552b4118c0866e5a78638e3de5ef18d9d90610508908390611a26565b6040516001600160a01b03808516602483015283166044820152606481018290526114959085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611693565b50505050565b5f806114a8868686611764565b905060018360028111156114be576114be611aec565b1480156114da57505f84806114d5576114d5611b86565b868809115b156114ed576114ea600182611a93565b90505b90505b949350505050565b5f6115088383612710600161149b565b90505b92915050565b6115308363a9059cbb60e01b848460405160240161145e929190611aa6565b505050565b5f82156115625781611548600185611b73565b6115529190611b9a565b61155d906001611a93565b611508565b505f92915050565b5f8190505f816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115ab573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115cf9190611bb9565b60015f9054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561161f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116439190611bb9565b61164d9190611bd9565b61165890600a611cd5565b6001600160a01b03939093165f90815260066020526040902080546001600160401b0319166001600160401b03909416939093179092555050565b5f6116e7826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166118139092919063ffffffff16565b80519091501561153057808060200190518101906117059190611ce3565b6115305760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016103e7565b5f80805f19858709858702925082811083820303915050805f0361179b5783828161179157611791611b86565b049250505061180c565b8084116117a6575f80fd5b5f848688098519600190810187169687900496828603819004959092119093035f82900391909104909201919091029190911760038402600290811880860282030280860282030280860282030280860282030280860282030280860290910302029150505b9392505050565b60606114f084845f85855f80866001600160a01b031685876040516118389190611cfe565b5f6040518083038185875af1925050503d805f8114611872576040519150601f19603f3d011682016040523d82523d5f602084013e611877565b606091505b509150915061188887838387611893565b979650505050505050565b606083156119015782515f036118fa576001600160a01b0385163b6118fa5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016103e7565b50816114f0565b6114f083838151156119165781518083602001fd5b8060405162461bcd60e51b81526004016103e79190611d14565b6001600160a01b0381168114611050575f80fd5b5f60208284031215611954575f80fd5b813561180c81611930565b8015158114611050575f80fd5b5f6020828403121561197c575f80fd5b813561180c8161195f565b803561ffff81168114611998575f80fd5b919050565b5f805f80608085870312156119b0575f80fd5b84356119bb81611930565b93506020850135925060408501356119d281611930565b91506119e060608601611987565b905092959194509250565b5f805f606084860312156119fd575f80fd5b8335611a0881611930565b925060208401359150611a1d60408501611987565b90509250925092565b6001600160a01b0391909116815260200190565b5f8060408385031215611a4b575f80fd5b8235611a5681611930565b946020939093013593505050565b5f60208284031215611a74575f80fd5b815161180c81611930565b634e487b7160e01b5f52601160045260245ffd5b8082018082111561150b5761150b611a7f565b6001600160a01b03929092168252602082015260400190565b9283526020830191909152604082015260600190565b808202811582820484141761150b5761150b611a7f565b634e487b7160e01b5f52602160045260245ffd5b6001600160a01b03858116825284166020820152604081018390526080810160048310611b3b57634e487b7160e01b5f52602160045260245ffd5b82606083015295945050505050565b5f60208284031215611b5a575f80fd5b5051919050565b91825261ffff16602082015260400190565b8181038181111561150b5761150b611a7f565b634e487b7160e01b5f52601260045260245ffd5b5f82611bb457634e487b7160e01b5f52601260045260245ffd5b500490565b5f60208284031215611bc9575f80fd5b815160ff8116811461180c575f80fd5b60ff828116828216039081111561150b5761150b611a7f565b6001815b6001841115611c2d57808504811115611c1157611c11611a7f565b6001841615611c1f57908102905b60019390931c928002611bf6565b935093915050565b5f82611c435750600161150b565b81611c4f57505f61150b565b8160018114611c655760028114611c6f57611c8b565b600191505061150b565b60ff841115611c8057611c80611a7f565b50506001821b61150b565b5060208310610133831016604e8410600b8410161715611cae575081810a61150b565b611cba5f198484611bf2565b805f1904821115611ccd57611ccd611a7f565b029392505050565b5f61150860ff841683611c35565b5f60208284031215611cf3575f80fd5b815161180c8161195f565b5f82518060208501845e5f920191825250919050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f8301168401019150509291505056feebff2602b3f468259e1e99f613fed6691f3a6526effe6ef3e768ba7ae7a36c4f4e2ca0515ed1aef1395f66b5303bb5d6f1bf9d61a353fa53f73f8ac9973fa9f6a26469706673582212201710f9f3a14ef9934bb3477e760ef32019ed84998e81e494498e9465693c7d8a64736f6c634300081a0033

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

0000000000000000000000008700af942be2a6e5566306d0ee7bcc5a3a6e0ce80000000000000000000000000f26bbb8962d73bc891327f14db5162d5279899f00000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000d431abc566a2b82bfb6fbea94ac22cae4065486c000000000000000000000000686ed0d7840dbd41cdacd37c26e68e13ed317d340000000000000000000000000000000000000000000000000000000000000002000000000000000000000000203a662b0bd271a6ed5a60edfbd04bfce608fd3600000000000000000000000000000000efe302beaa2b3e6e1b18d08d69a9012a

-----Decoded View---------------
Arg [0] : _metaCore (address): 0x8700AF942BE2A6E5566306D0eE7Bcc5a3A6E0ce8
Arg [1] : _debtToken (address): 0x0F26bBb8962d73bC891327F14dB5162D5279899F
Arg [2] : _stables (address[]): 0x203A662b0BD271A6ed5a60EdFbd04bFce608FD36,0x00000000eFE302BEAA2b3e6e1b18d08D69a9012a
Arg [3] : _feeHook (address): 0xD431aBC566a2B82BFb6FBea94ac22CAE4065486C
Arg [4] : _feeReceiver (address): 0x686Ed0d7840dbd41cdaCD37C26E68E13eD317D34

-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 0000000000000000000000008700af942be2a6e5566306d0ee7bcc5a3a6e0ce8
Arg [1] : 0000000000000000000000000f26bbb8962d73bc891327f14db5162d5279899f
Arg [2] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [3] : 000000000000000000000000d431abc566a2b82bfb6fbea94ac22cae4065486c
Arg [4] : 000000000000000000000000686ed0d7840dbd41cdacd37c26e68e13ed317d34
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [6] : 000000000000000000000000203a662b0bd271a6ed5a60edfbd04bfce608fd36
Arg [7] : 00000000000000000000000000000000efe302beaa2b3e6e1b18d08d69a9012a


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ 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.