ETH Price: $3,052.75 (+2.01%)

Token

Wrapped Arcadia Recovery Tokens (wART)
 

Overview

Max Total Supply

460,444.676084 wART

Holders

232

Market

Price

$0.00 @ 0.000000 ETH

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 6 Decimals)

Balance
17.514457 wART

Value
$0.00
0x458b40d2bfa35dec1b0da9b5749a62143f5df7ff
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information

Contract Source Code Verified (Exact Match)

Contract Name:
RecoveryController

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 8 : RecoveryController.sol
/**
 * Created by Pragma Labs
 * SPDX-License-Identifier: MIT
 */
pragma solidity 0.8.19;

import {ERC20} from "../lib/solmate/src/tokens/ERC20.sol";
import {Owned} from "../lib/solmate/src/auth/Owned.sol";
import {FixedPointMathLib} from "../lib/solmate/src/utils/FixedPointMathLib.sol";
import {SafeTransferLib} from "../lib/solmate/src/utils/SafeTransferLib.sol";

import {IUSDC} from "./interfaces/IUSDC.sol";
import {RecoveryToken} from "./RecoveryToken.sol";

/**
 * @title Recovery Controller.
 * @author Pragma Labs
 * @notice Handles the accounting and redemption of Recovery Tokens for Underlying Tokens,
 * both if assets are redeemed via legal means, or if the lost assets are redeemed via other means.
 * In the second situation the underlying assets will be distributed pro-rata to all holders of
 * Wrapped Recovery Tokens in discrete batches.
 * @dev Recovery Tokens can be redeemed one-to-one for Underlying Tokens.
 * @dev Recovery Tokens will only be eligible for redemption to Underlying Tokens after they are
 * deposited (wrapped) in this Recovery contract. It uses a modification of the ERC20 standard (non-transferrable)
 * to do the accounting of deposited Recovery Token Balances.
 */
contract RecoveryController is ERC20, Owned {
    using FixedPointMathLib for uint256;
    using SafeTransferLib for ERC20;

    /*//////////////////////////////////////////////////////////////
                               CONSTANTS
    //////////////////////////////////////////////////////////////*/

    // Minimum cooldown period between the termination initiation and finalisation.
    uint256 internal constant COOLDOWN_PERIOD = 1 weeks;

    /*//////////////////////////////////////////////////////////////
                               STORAGE
    //////////////////////////////////////////////////////////////*/

    // The contract address of the Underlying Token.
    address internal immutable underlying;

    // The (unwrapped) Recovery Token contract.
    RecoveryToken public immutable recoveryToken;

    // Bool indicating if the contract is activated or not.
    bool public active;

    // Timestamp that the termination of the contract is initiated.
    uint32 public terminationTimestamp;

    // The growth of Underlying Tokens redeemed per Wrapped Recovery Token for the entire life of the contract.
    uint256 public redeemablePerRTokenGlobal;

    // Map tokenHolder => Growth of Underlying Tokens redeemed per Wrapped Recovery Token at the owner last interaction.
    mapping(address => uint256) public redeemablePerRTokenLast;
    // Map tokenHolder => Amount of Recovery Tokens redeemed for Underlying Tokens.
    mapping(address => uint256) public redeemed;

    /* //////////////////////////////////////////////////////////////
                                EVENTS
    ////////////////////////////////////////////////////////////// */

    /**
     * @notice Emitted when a value for the activity of the Controller is set.
     * @param active Bool indicating if the contract is activated or not.
     */
    event ActivationSet(bool active);

    /**
     * @notice Emitted when the termination of the Controller is initiated.
     */
    event TerminationInitiated();

    /*//////////////////////////////////////////////////////////////
                               ERRORS
    //////////////////////////////////////////////////////////////*/

    // Thrown if the Contract is terminated.
    error ControllerTerminated();

    // Thrown if the Contract is not active.
    error NotActive();

    // Thrown if the Contract is active.
    error Active();

    // Thrown on transfers.
    error NoTransfersAllowed();

    // Thrown if arrays are not equal in length..
    error LengthMismatch();

    // Thrown when trying to deposit zero assets.
    error DepositAmountZero();

    // Thrown when trying to withdraw zero assets.
    error WithdrawAmountZero();

    // Thrown when less time as the cooldown period passed between the termination initiation and finalisation.
    error TerminationCoolDownPeriodNotPassed();

    /*//////////////////////////////////////////////////////////////
                               MODIFIERS
    //////////////////////////////////////////////////////////////*/

    /**
     * @dev Throws if the contract is not active.
     */
    modifier isActive() {
        if (!active) revert NotActive();

        _;
    }

    /**
     * @dev Throws if the contract is active.
     */
    modifier notActive() {
        if (active) revert Active();

        _;
    }

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    /**
     * @param underlying_ The contract address of the Underlying Token.
     */
    constructor(address underlying_)
        ERC20("Wrapped Arcadia Recovery Tokens", "wART", ERC20(underlying_).decimals())
        Owned(msg.sender)
    {
        underlying = underlying_;
        recoveryToken = new RecoveryToken(address(this), decimals);

        emit ActivationSet(false);
    }

    /*//////////////////////////////////////////////////////////////
                        ACTIVATION LOGIC
    //////////////////////////////////////////////////////////////*/

    /**
     * @notice Sets contract to active.
     * @dev After the contract is active, token holders can withdraw, deposit and interact with the contract,
     * and no new recoveryTokens can be minted.
     */
    function activate() external onlyOwner {
        if (terminationTimestamp != 0) revert ControllerTerminated();

        active = true;

        emit ActivationSet(true);
    }

    /*//////////////////////////////////////////////////////////////
                               ERC20 LOGIC
    //////////////////////////////////////////////////////////////*/
    /**
     * @notice Modification of the ERC-20 transfer implementation.
     * @dev No transfer allowed.
     */
    function transfer(address, uint256) public pure override returns (bool) {
        revert NoTransfersAllowed();
    }

    /**
     * @notice Modification of the ERC-20 transferFrom implementation.
     * @dev No transferFrom allowed.
     */
    function transferFrom(address, address, uint256) public pure override returns (bool) {
        revert NoTransfersAllowed();
    }

    /*//////////////////////////////////////////////////////////////
                            MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    /**
     * @notice Mints Wrapped Recovery Tokens.
     * @param to The address that receives the minted tokens.
     * @param amount The amount of tokens minted.
     * @dev Mints an amount of Recovery Tokens to the controller,
     * equal to the minted Wrapped Recovery Tokens.
     */
    function mint(address to, uint256 amount) external onlyOwner notActive {
        _mint(to, amount);
        recoveryToken.mint(amount);
    }

    /**
     * @notice Batch mints Wrapped Recovery Tokens.
     * @param tos Array with addresses that receive the minted tokens.
     * @param amounts Array with amounts of tokens minted.
     * @dev Mints an amount of Recovery Tokens to the controller,
     * equal to the sum of all minted Wrapped Recovery Tokens.
     */
    function batchMint(address[] calldata tos, uint256[] calldata amounts) external onlyOwner notActive {
        uint256 length = tos.length;
        uint256 totalAmount;

        if (length != amounts.length) revert LengthMismatch();

        uint256 amount;
        for (uint256 i; i < length;) {
            amount = amounts[i];
            _mint(tos[i], amount);

            unchecked {
                ++i;
                totalAmount += amount;
            }
        }

        recoveryToken.mint(totalAmount);
    }

    /**
     * @notice Burns Wrapped Recovery Tokens.
     * @param from The address from which the tokens are burned.
     * @param amount The amount of tokens burned.
     * @dev Burns an amount of Recovery Tokens, held by the controller,
     * equal to the burned unredeemed Wrapped Recovery Tokens.
     */
    function burn(address from, uint256 amount) external onlyOwner notActive {
        uint256 openPosition = balanceOf[from];

        // Burn the Wrapped Recovery Tokens.
        if (amount >= openPosition) amount = openPosition;
        _burn(from, amount);

        // Burn the corresponding Recovery Tokens held by the controller.
        recoveryToken.burn(amount);
    }

    /**
     * @notice Batch burns Wrapped Recovery Tokens.
     * @param froms Array with addresses from which the tokens are burned.
     * @param amounts Array with amounts of tokens burned.
     * @dev Burns an amount of Recovery Tokens, held by the controller,
     * equal to the sum of all burned unredeemed Wrapped Recovery Tokens.
     */
    function batchBurn(address[] calldata froms, uint256[] calldata amounts) external onlyOwner notActive {
        uint256 length = froms.length;

        if (length != amounts.length) revert LengthMismatch();

        address from;
        uint256 openPosition;
        uint256 amount;
        uint256 totalAmount;
        for (uint256 i; i < length;) {
            from = froms[i];
            openPosition = balanceOf[from];
            amount = amounts[i];

            // Burn the Wrapped Recovery Tokens.
            if (amount >= openPosition) amount = openPosition;
            _burn(from, amount);

            unchecked {
                ++i;
                totalAmount += amount;
            }
        }

        // Burn the corresponding Recovery Tokens held by the controller.
        recoveryToken.burn(totalAmount);
    }

    /*//////////////////////////////////////////////////////////////
                        RECOVERY TOKEN LOGIC
    //////////////////////////////////////////////////////////////*/

    /**
     * @notice Deposits the underlying assets to this contract.
     * Deposited assets become redeemable pro-rata by the Wrapped Recovery Token Holders.
     * @param amount The amount of underlying tokens deposited.
     */
    function depositUnderlying(uint256 amount) external isActive {
        if (amount == 0) revert DepositAmountZero();

        _distributeUnderlying(amount);
        ERC20(underlying).safeTransferFrom(msg.sender, address(this), amount);
    }

    /**
     * @notice Redeems Recovery Tokens for Underlying Tokens.
     * @param owner_ The owner of the wrapped Recovery Tokens.
     * @dev Everyone can call the redeem function for any address.
     */
    function redeemUnderlying(address owner_) external isActive {
        // Cache token balances.
        uint256 initialBalance = balanceOf[owner_];
        uint256 redeemedLast = redeemed[owner_];
        uint256 openPosition = initialBalance - redeemedLast;

        // Calculate the redeemable underlying tokens since the last redemption.
        uint256 redeemable =
            initialBalance.mulDivDown(redeemablePerRTokenGlobal - redeemablePerRTokenLast[owner_], 1e18);

        if (openPosition <= redeemable) {
            // Updated balance of redeemed Underlying Tokens exceeds the non-redeemed rTokens.
            // -> Close the position and settle surplus rTokens.
            _closePosition(owner_);
            uint256 surplus = redeemable - openPosition;
            redeemable = openPosition;
            _settleSurplus(surplus, redeemable);
        } else {
            // Position not fully recovered, update accounting for total redeemed Underlying Tokens.
            redeemed[owner_] = redeemedLast + redeemable;
            redeemablePerRTokenLast[owner_] = redeemablePerRTokenGlobal;
        }

        // Reentrancy: Transfer the Underlying Tokens after logic.
        _redeemUnderlying(owner_, redeemable);
    }

    /**
     * @notice Deposits (wraps) Recovery Tokens.
     * @param amount The non-redeemed rTokens deposited.
     * @dev Holders of Recovery Tokens need to deposit the tokens in this contract before
     * they can redeem the Recovery Tokens for redeemed Underlying Tokens.
     */
    function depositRecoveryTokens(uint256 amount) external isActive {
        if (amount == 0) revert DepositAmountZero();

        // Cache token balances.
        uint256 initialBalance = balanceOf[msg.sender];
        uint256 redeemedLast;
        uint256 redeemable;

        // Reentrancy: recoveryToken is a trusted contract without hooks or external calls.
        // Recovery Tokens need to be transferred to Controller before a position can be closed.
        recoveryToken.transferFrom(msg.sender, address(this), amount);

        if (initialBalance != 0) {
            redeemedLast = redeemed[msg.sender];
            // Calculate the redeemable underlying tokens since the last redemption.
            redeemable =
                initialBalance.mulDivDown(redeemablePerRTokenGlobal - redeemablePerRTokenLast[msg.sender], 1e18);
        }

        uint256 openPosition = initialBalance + amount - redeemedLast;

        if (openPosition <= redeemable) {
            // Updated balance of redeemed Underlying Tokens exceeds the non-redeemed rTokens.
            // Close the position and distribute the surplus to other rToken-Holders.
            _closePosition(msg.sender);
            uint256 surplus = redeemable - openPosition;
            redeemable = openPosition;
            // Settle surplus to other rToken-Holders or the Protocol Owner.
            _settleSurplus(surplus, redeemable);
        } else {
            // Update accounting for total redeemed Underlying Tokens.
            redeemed[msg.sender] = redeemedLast + redeemable;
            redeemablePerRTokenLast[msg.sender] = redeemablePerRTokenGlobal;

            // Update accounting for newly deposited rTokens.
            _mint(msg.sender, amount);
        }

        // Reentrancy: Transfer the Underlying Tokens after logic.
        _redeemUnderlying(msg.sender, redeemable);
    }

    /**
     * @notice Withdraws (unwraps) Recovery Tokens.
     * @param amount The non-redeemed rTokens withdrawn.
     * @dev Holders of Recovery Tokens need to deposit the tokens in this contract before
     * they can redeem the Recovery Tokens for redeemed Underlying Tokens.
     */
    function withdrawRecoveryTokens(uint256 amount) external isActive {
        if (amount == 0) revert WithdrawAmountZero();

        // Cache token balances.
        uint256 initialBalance = balanceOf[msg.sender];
        uint256 redeemedLast = redeemed[msg.sender];
        uint256 openPosition = initialBalance - redeemedLast;

        // Calculate the redeemable underlying tokens since the last redemption.
        uint256 redeemable =
            initialBalance.mulDivDown(redeemablePerRTokenGlobal - redeemablePerRTokenLast[msg.sender], 1e18);

        if (openPosition <= redeemable) {
            // Updated balance of redeemed Underlying Tokens, even before withdrawing rTokens,
            // exceeds the non-redeemed rTokens.
            // -> Close the position and settle surplus rTokens.
            _closePosition(msg.sender);
            uint256 surplus = redeemable - openPosition;
            redeemable = openPosition;
            // Settle surplus to other rToken-Holders or the Protocol Owner.
            _settleSurplus(surplus, redeemable);
        } else {
            if (openPosition - redeemable <= amount) {
                // Updated balance of redeemed Underlying Tokens, after withdrawing rTokens
                // exceeds the non-redeemed rTokens.
                // -> Close the position and withdraw the remaining rTokens.
                _closePosition(msg.sender);
                amount = openPosition - redeemable;
                // Check if there is surplus to settle to the Protocol Owner.
                _settleSurplus(0, redeemable);
            } else {
                // Update accounting for total redeemed Underlying Tokens.
                redeemed[msg.sender] = redeemedLast + redeemable;
                redeemablePerRTokenLast[msg.sender] = redeemablePerRTokenGlobal;

                // Update accounting for withdrawn rTokens.
                _burn(msg.sender, amount);
            }

            // Withdraw the Recovery Tokens to the owner.
            recoveryToken.transfer(msg.sender, amount);
        }

        // Reentrancy: Transfer the Underlying Tokens after logic.
        _redeemUnderlying(msg.sender, redeemable);
    }

    /**
     * @notice Returns the current maximum amount of Recovery Tokens that can be redeemed for Underlying Tokens.
     * @param owner_ The owner of the wrapped Recovery Tokens.
     */
    function maxRedeemable(address owner_) public view returns (uint256 redeemable) {
        // Calculate the redeemable underlying tokens since the last redemption.
        redeemable = balanceOf[owner_].mulDivDown(redeemablePerRTokenGlobal - redeemablePerRTokenLast[owner_], 1e18);

        // Calculate the open position.
        uint256 openPosition = balanceOf[owner_] - redeemed[owner_];

        // Return Minimum.
        redeemable = openPosition <= redeemable ? openPosition : redeemable;
    }

    /**
     * @notice Returns the amount of Recovery Tokens that can be redeemed for Underlying Tokens without taking into account restrictions.
     * @param owner_ The owner of the wrapped Recovery Tokens.
     */
    function previewRedeemable(address owner_) public view returns (uint256 redeemable) {
        // Calculate the redeemable underlying tokens since the last redemption.
        redeemable = balanceOf[owner_].mulDivDown(redeemablePerRTokenGlobal - redeemablePerRTokenLast[owner_], 1e18);
    }

    /**
     * @notice Logic to close a fully recovered position.
     * @param owner_ The owner of the fully recovered position.
     */
    function _closePosition(address owner_) internal {
        redeemed[owner_] = 0;
        redeemablePerRTokenLast[owner_] = 0;
        _burn(owner_, balanceOf[owner_]);
    }

    /**
     * @notice Logic to redeem Recovery Tokens for Underlying Tokens.
     * @param to The receiver of the Underlying Tokens.
     * @param amount The amount of tokens redeemed.
     * @dev Recovery Tokens are redeemed one-to-one for Underlying Tokens.
     */
    function _redeemUnderlying(address to, uint256 amount) internal {
        // Burn the redeemed recovery tokens.
        recoveryToken.burn(amount);
        // Send equal amount of underlying assets.
        // Reentrancy: Transfer the Underlying Tokens after logic.
        if (IUSDC(underlying).isBlacklisted(to)) {
            // Very unrealistic flow, to be settled outside of this contract.
            ERC20(underlying).safeTransfer(owner, amount);
        } else {
            ERC20(underlying).safeTransfer(to, amount);
        }
    }

    /**
     * @notice Logic to settle any surplus Recovery Tokens after a position is closed.
     * @param surplus The amount of surplus Recovery Tokens.
     * @param redeemable The amount of Underlying Tokens that are redeemed.
     */
    function _settleSurplus(uint256 surplus, uint256 redeemable) internal {
        if (totalSupply != 0) {
            // Not all positions are recovered, distribute the surplus to other rToken-Holders.
            _distributeUnderlying(surplus);
        } else {
            // All positions are recovered, send any remaining Underlying Tokens back to the Protocol Owner.
            ERC20(underlying).safeTransfer(owner, ERC20(underlying).balanceOf(address(this)) - redeemable);
        }
    }

    /**
     * @notice Calculates and updates the growth of Underlying Tokens redeemed per Wrapped Recovery Token.
     * @param amount The amount of redeemed Underlying Tokens.
     */
    function _distributeUnderlying(uint256 amount) internal {
        if (amount != 0) redeemablePerRTokenGlobal += amount.mulDivDown(1e18, totalSupply);
    }

    /*//////////////////////////////////////////////////////////////
                        CONTRACT TERMINATION
    //////////////////////////////////////////////////////////////*/

    /**
     * @notice Starts the termination process.
     * @dev The termination process is a two step process, a fixed 'COOLDOWN_PERIOD' should pass between initiation and finalisation.
     * @dev during the 'COOLDOWN_PERIOD' all Wrapped Recovery Token Holders should claim their redeemable balances.
     */
    function initiateTermination() external onlyOwner {
        terminationTimestamp = uint32(block.timestamp);

        emit TerminationInitiated();
    }

    /**
     * @notice Finalises the termination process.
     * @dev The termination process is a two step process, a fixed 'COOLDOWN_PERIOD' should pass between initiation and finalisation.
     * @dev After the 'COOLDOWN_PERIOD' the 'owner' of the Controller can withdraw the remaining balance of Underlying Tokens.
     * When the termination is finalised, the Controller will cease to operate and cannot be restarted.
     */
    function finaliseTermination() external onlyOwner {
        if (terminationTimestamp == 0 || terminationTimestamp + COOLDOWN_PERIOD > uint32(block.timestamp)) {
            revert TerminationCoolDownPeriodNotPassed();
        }

        active = false;

        // Withdraw any remaining Underlying Tokens back to the Protocol Owner.
        ERC20(underlying).safeTransfer(owner, ERC20(underlying).balanceOf(address(this)));

        emit ActivationSet(false);
    }
}

File 2 of 8 : ERC20.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Transfer(address indexed from, address indexed to, uint256 amount);

    event Approval(address indexed owner, address indexed spender, uint256 amount);

    /*//////////////////////////////////////////////////////////////
                            METADATA STORAGE
    //////////////////////////////////////////////////////////////*/

    string public name;

    string public symbol;

    uint8 public immutable decimals;

    /*//////////////////////////////////////////////////////////////
                              ERC20 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 public totalSupply;

    mapping(address => uint256) public balanceOf;

    mapping(address => mapping(address => uint256)) public allowance;

    /*//////////////////////////////////////////////////////////////
                            EIP-2612 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 internal immutable INITIAL_CHAIN_ID;

    bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;

    mapping(address => uint256) public nonces;

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(
        string memory _name,
        string memory _symbol,
        uint8 _decimals
    ) {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;

        INITIAL_CHAIN_ID = block.chainid;
        INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
    }

    /*//////////////////////////////////////////////////////////////
                               ERC20 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 amount) public virtual returns (bool) {
        allowance[msg.sender][spender] = amount;

        emit Approval(msg.sender, spender, amount);

        return true;
    }

    function transfer(address to, uint256 amount) public virtual returns (bool) {
        balanceOf[msg.sender] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(msg.sender, to, amount);

        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual returns (bool) {
        uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.

        if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;

        balanceOf[from] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(from, to, amount);

        return true;
    }

    /*//////////////////////////////////////////////////////////////
                             EIP-2612 LOGIC
    //////////////////////////////////////////////////////////////*/

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual {
        require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");

        // Unchecked because the only math done is incrementing
        // the owner's nonce which cannot realistically overflow.
        unchecked {
            address recoveredAddress = ecrecover(
                keccak256(
                    abi.encodePacked(
                        "\x19\x01",
                        DOMAIN_SEPARATOR(),
                        keccak256(
                            abi.encode(
                                keccak256(
                                    "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
                                ),
                                owner,
                                spender,
                                value,
                                nonces[owner]++,
                                deadline
                            )
                        )
                    )
                ),
                v,
                r,
                s
            );

            require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");

            allowance[recoveredAddress][spender] = value;
        }

        emit Approval(owner, spender, value);
    }

    function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
        return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
    }

    function computeDomainSeparator() internal view virtual returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                    keccak256(bytes(name)),
                    keccak256("1"),
                    block.chainid,
                    address(this)
                )
            );
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(address to, uint256 amount) internal virtual {
        totalSupply += amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(address(0), to, amount);
    }

    function _burn(address from, uint256 amount) internal virtual {
        balanceOf[from] -= amount;

        // Cannot underflow because a user's balance
        // will never be larger than the total supply.
        unchecked {
            totalSupply -= amount;
        }

        emit Transfer(from, address(0), amount);
    }
}

File 3 of 8 : Owned.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Simple single owner authorization mixin.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Owned.sol)
abstract contract Owned {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

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

    /*//////////////////////////////////////////////////////////////
                            OWNERSHIP STORAGE
    //////////////////////////////////////////////////////////////*/

    address public owner;

    modifier onlyOwner() virtual {
        require(msg.sender == owner, "UNAUTHORIZED");

        _;
    }

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(address _owner) {
        owner = _owner;

        emit OwnershipTransferred(address(0), _owner);
    }

    /*//////////////////////////////////////////////////////////////
                             OWNERSHIP LOGIC
    //////////////////////////////////////////////////////////////*/

    function transferOwnership(address newOwner) public virtual onlyOwner {
        owner = newOwner;

        emit OwnershipTransferred(msg.sender, newOwner);
    }
}

File 4 of 8 : FixedPointMathLib.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)
library FixedPointMathLib {
    /*//////////////////////////////////////////////////////////////
                    SIMPLIFIED FIXED POINT OPERATIONS
    //////////////////////////////////////////////////////////////*/

    uint256 internal constant MAX_UINT256 = 2**256 - 1;

    uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.

    function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.
    }

    function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.
    }

    function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.
    }

    function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.
    }

    /*//////////////////////////////////////////////////////////////
                    LOW LEVEL FIXED POINT OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function mulDivDown(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
            if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
                revert(0, 0)
            }

            // Divide x * y by the denominator.
            z := div(mul(x, y), denominator)
        }
    }

    function mulDivUp(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
            if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
                revert(0, 0)
            }

            // If x * y modulo the denominator is strictly greater than 0,
            // 1 is added to round up the division of x * y by the denominator.
            z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator))
        }
    }

    function rpow(
        uint256 x,
        uint256 n,
        uint256 scalar
    ) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            switch x
            case 0 {
                switch n
                case 0 {
                    // 0 ** 0 = 1
                    z := scalar
                }
                default {
                    // 0 ** n = 0
                    z := 0
                }
            }
            default {
                switch mod(n, 2)
                case 0 {
                    // If n is even, store scalar in z for now.
                    z := scalar
                }
                default {
                    // If n is odd, store x in z for now.
                    z := x
                }

                // Shifting right by 1 is like dividing by 2.
                let half := shr(1, scalar)

                for {
                    // Shift n right by 1 before looping to halve it.
                    n := shr(1, n)
                } n {
                    // Shift n right by 1 each iteration to halve it.
                    n := shr(1, n)
                } {
                    // Revert immediately if x ** 2 would overflow.
                    // Equivalent to iszero(eq(div(xx, x), x)) here.
                    if shr(128, x) {
                        revert(0, 0)
                    }

                    // Store x squared.
                    let xx := mul(x, x)

                    // Round to the nearest number.
                    let xxRound := add(xx, half)

                    // Revert if xx + half overflowed.
                    if lt(xxRound, xx) {
                        revert(0, 0)
                    }

                    // Set x to scaled xxRound.
                    x := div(xxRound, scalar)

                    // If n is even:
                    if mod(n, 2) {
                        // Compute z * x.
                        let zx := mul(z, x)

                        // If z * x overflowed:
                        if iszero(eq(div(zx, x), z)) {
                            // Revert if x is non-zero.
                            if iszero(iszero(x)) {
                                revert(0, 0)
                            }
                        }

                        // Round to the nearest number.
                        let zxRound := add(zx, half)

                        // Revert if zx + half overflowed.
                        if lt(zxRound, zx) {
                            revert(0, 0)
                        }

                        // Return properly scaled zxRound.
                        z := div(zxRound, scalar)
                    }
                }
            }
        }
    }

    /*//////////////////////////////////////////////////////////////
                        GENERAL NUMBER UTILITIES
    //////////////////////////////////////////////////////////////*/

    function sqrt(uint256 x) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            let y := x // We start y at x, which will help us make our initial estimate.

            z := 181 // The "correct" value is 1, but this saves a multiplication later.

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

            // We check y >= 2^(k + 8) but shift right by k bits
            // each branch to ensure that if x >= 256, then y >= 256.
            if iszero(lt(y, 0x10000000000000000000000000000000000)) {
                y := shr(128, y)
                z := shl(64, z)
            }
            if iszero(lt(y, 0x1000000000000000000)) {
                y := shr(64, y)
                z := shl(32, z)
            }
            if iszero(lt(y, 0x10000000000)) {
                y := shr(32, y)
                z := shl(16, z)
            }
            if iszero(lt(y, 0x1000000)) {
                y := shr(16, y)
                z := shl(8, z)
            }

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

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

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

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

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

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

            // If x+1 is a perfect square, the Babylonian method cycles between
            // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor.
            // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
            // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.
            // If you don't care whether the floor or ceil square root is returned, you can remove this statement.
            z := sub(z, lt(div(x, z), z))
        }
    }

    function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Mod x by y. Note this will return
            // 0 instead of reverting if y is zero.
            z := mod(x, y)
        }
    }

    function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) {
        /// @solidity memory-safe-assembly
        assembly {
            // Divide x by y. Note this will return
            // 0 instead of reverting if y is zero.
            r := div(x, y)
        }
    }

    function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Add 1 to x * y if x % y > 0. Note this will
            // return 0 instead of reverting if y is zero.
            z := add(gt(mod(x, y), 0), div(x, y))
        }
    }
}

File 5 of 8 : SafeTransferLib.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

import {ERC20} from "../tokens/ERC20.sol";

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.
library SafeTransferLib {
    /*//////////////////////////////////////////////////////////////
                             ETH OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferETH(address to, uint256 amount) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Transfer the ETH and store if it succeeded or not.
            success := call(gas(), to, amount, 0, 0, 0, 0)
        }

        require(success, "ETH_TRANSFER_FAILED");
    }

    /*//////////////////////////////////////////////////////////////
                            ERC20 OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferFrom(
        ERC20 token,
        address from,
        address to,
        uint256 amount
    ) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "from" argument.
            mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
            mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
            )
        }

        require(success, "TRANSFER_FROM_FAILED");
    }

    function safeTransfer(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
            )
        }

        require(success, "TRANSFER_FAILED");
    }

    function safeApprove(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
            )
        }

        require(success, "APPROVE_FAILED");
    }
}

File 6 of 8 : IUSDC.sol
/**
 * Created by Pragma Labs
 * SPDX-License-Identifier: MIT
 */
pragma solidity 0.8.19;

interface IUSDC {
    /**
     * @dev Checks if account is blacklisted
     * @param _account The address to check
     */
    function isBlacklisted(address _account) external view returns (bool);
}

File 7 of 8 : RecoveryToken.sol
/**
 * Created by Pragma Labs
 * SPDX-License-Identifier: MIT
 */
pragma solidity 0.8.19;

import {ERC20} from "../lib/solmate/src/tokens/ERC20.sol";

import {IRecoveryToken} from "./interfaces/IRecoveryToken.sol";

/**
 * @title Arcadia Recovery Tokens.
 * @author Pragma Labs
 * @notice ERC20 contract for the accounting of the Recovery of lost Underlying Tokens.
 * @dev The one-to-one redemption of Recovery Tokens for Underlying Tokens,
 * is handled by the Recovery Controller.
 */
contract RecoveryToken is IRecoveryToken, ERC20 {
    /*//////////////////////////////////////////////////////////////
                               STORAGE
    //////////////////////////////////////////////////////////////*/

    // The contract address of the Recovery Controller.
    address public immutable recoveryController;

    /*//////////////////////////////////////////////////////////////
                               ERRORS
    //////////////////////////////////////////////////////////////*/

    // Thrown when 'msg.sender" is not the 'recoveryController'.
    error NotRecoveryController();

    /*//////////////////////////////////////////////////////////////
                               MODIFIERS
    //////////////////////////////////////////////////////////////*/

    /**
     * @dev Throws if called by any account other than the Recovery Controller.
     */
    modifier onlyRecoveryController() {
        if (msg.sender != recoveryController) revert NotRecoveryController();

        _;
    }

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    /**
     * @param recoveryController_ The contract address of the Recovery Controller.
     * @param decimals_ Must be identical to decimals of the Underlying Token.
     */
    constructor(address recoveryController_, uint8 decimals_) ERC20("Arcadia Recovery Token", "ART", decimals_) {
        recoveryController = recoveryController_;
    }

    /*//////////////////////////////////////////////////////////////
                            MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    /**
     * @notice Mints Recovery Tokens.
     * @param amount The amount of Recovery Tokens minted.
     * @dev Only the Recovery Controller can mint tokens before it is activated.
     */
    function mint(uint256 amount) external onlyRecoveryController {
        _mint(msg.sender, amount);
    }

    /**
     * @notice Burns Recovery Tokens.
     * @param amount The amount of Recovery Tokens burned.
     */
    function burn(uint256 amount) external {
        _burn(msg.sender, amount);
    }

    /**
     * @notice Burns Recovery Tokens.
     * @param from The address from which the tokens are burned.
     * @param amount The amount of Recovery Tokens burned.
     */
    function burn(address from, uint256 amount) external onlyRecoveryController {
        _burn(from, amount);
    }
}

File 8 of 8 : IRecoveryToken.sol
/**
 * Created by Pragma Labs
 * SPDX-License-Identifier: MIT
 */
pragma solidity 0.8.19;

interface IRecoveryToken {
    /**
     * @notice Mints Recovery Tokens.
     * @param amount The amount of Recovery Tokens minted.
     */
    function mint(uint256 amount) external;

    /**
     * @notice Burns Recovery Tokens.
     * @param amount The amount of Recovery Tokens burned.
     */
    function burn(uint256 amount) external;
}

Settings
{
  "remappings": [
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "solmate/=lib/solmate/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"underlying_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"Active","type":"error"},{"inputs":[],"name":"ControllerTerminated","type":"error"},{"inputs":[],"name":"DepositAmountZero","type":"error"},{"inputs":[],"name":"LengthMismatch","type":"error"},{"inputs":[],"name":"NoTransfersAllowed","type":"error"},{"inputs":[],"name":"NotActive","type":"error"},{"inputs":[],"name":"TerminationCoolDownPeriodNotPassed","type":"error"},{"inputs":[],"name":"WithdrawAmountZero","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"active","type":"bool"}],"name":"ActivationSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[],"name":"TerminationInitiated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"activate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"active","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"froms","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"batchBurn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"tos","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"batchMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"depositRecoveryTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"depositUnderlying","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"finaliseTermination","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initiateTermination","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"maxRedeemable","outputs":[{"internalType":"uint256","name":"redeemable","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"previewRedeemable","outputs":[{"internalType":"uint256","name":"redeemable","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"recoveryToken","outputs":[{"internalType":"contract RecoveryToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"redeemUnderlying","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"redeemablePerRTokenGlobal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"redeemablePerRTokenLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"redeemed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"terminationTimestamp","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawRecoveryTokens","outputs":[],"stateMutability":"nonpayable","type":"function"}]

6101206040523480156200001257600080fd5b50604051620036a6380380620036a68339810160408190526200003591620002bc565b336040518060400160405280601f81526020017f577261707065642041726361646961205265636f7665727920546f6b656e7300815250604051806040016040528060048152602001631dd0549560e21b815250836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000c8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000ee9190620002ee565b6000620000fc8482620003b8565b5060016200010b8382620003b8565b5060ff81166080524660a0526200012162000212565b60c0525050600680546001600160a01b0319166001600160a01b0384169081179091556040519091506000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3506001600160a01b03811660e0526080516040513091906200019490620002ae565b6001600160a01b03909216825260ff166020820152604001604051809103906000f080158015620001c9573d6000803e3d6000fd5b506001600160a01b031661010052604051600081527fda8d093060d8bb4ec62c308766e6aff7be6a9a04c3d4a920517503311855b4ec9060200160405180910390a15062000502565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f600060405162000246919062000484565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b6110d880620025ce83390190565b600060208284031215620002cf57600080fd5b81516001600160a01b0381168114620002e757600080fd5b9392505050565b6000602082840312156200030157600080fd5b815160ff81168114620002e757600080fd5b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200033e57607f821691505b6020821081036200035f57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620003b357600081815260208120601f850160051c810160208610156200038e5750805b601f850160051c820191505b81811015620003af578281556001016200039a565b5050505b505050565b81516001600160401b03811115620003d457620003d462000313565b620003ec81620003e5845462000329565b8462000365565b602080601f8311600181146200042457600084156200040b5750858301515b600019600386901b1c1916600185901b178555620003af565b600085815260208120601f198616915b82811015620004555788860151825594840194600190910190840162000434565b5085821015620004745787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000808354620004948162000329565b60018281168015620004af5760018114620004c557620004f6565b60ff1984168752821515830287019450620004f6565b8760005260208060002060005b85811015620004ed5781548a820152908401908201620004d2565b50505082870194505b50929695505050505050565b60805160a05160c05160e0516101005161202c620005a2600039600081816102b60152818161092901528181610a7a01528181610c0401528181610f3f0152818161113a0152818161122d01526117da015260008181610d7b01528181610df2015281816113d20152818161174f0152818161185b015281816118de0152611914015260006109e3015260006109ae01526000610324015261202c6000f3fe608060405234801561001057600080fd5b50600436106101fb5760003560e01c80635de8697d1161011a5780639dc29fac116100ad578063b9f5be411161007c578063b9f5be411461047e578063d505accf14610491578063dd62ed3e146104a4578063e5ad693e146104cf578063f2fde38b146104ef57600080fd5b80639dc29fac1461042a5780639f4568ef1461043d5780639fba4aab1461045d578063a9059cbb1461047057600080fd5b80637ecebe00116100e95780637ecebe00146103e75780638da5cb5b1461040757806395d89b411461041a57806398a8d41e1461042257600080fd5b80635de8697d1461039957806368573107146103a15780636f9a31f4146103b457806370a08231146103c757600080fd5b806323b872dd116101925780633644e515116101615780633644e5151461035857806340c10f19146103605780634a6cc677146103735780635af1e0c61461038657600080fd5b806323b872dd146102f0578063293f19ca146103035780632c7392bb14610316578063313ce5671461031f57600080fd5b80630bbfc833116101ce5780630bbfc833146102665780630f15f4c01461029257806318160ddd1461029a57806319133877146102b157600080fd5b806302fb0c5e1461020057806303579dca1461022957806306fdde031461023e578063095ea7b314610253575b600080fd5b60065461021490600160a01b900460ff1681565b60405190151581526020015b60405180910390f35b61023c610237366004611c24565b610502565b005b610246610614565b6040516102209190611c3f565b610214610261366004611c8d565b6106a2565b60065461027d90600160a81b900463ffffffff1681565b60405163ffffffff9091168152602001610220565b61023c61070f565b6102a360025481565b604051908152602001610220565b6102d87f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610220565b6102146102fe366004611cb7565b6107ba565b61023c610311366004611cf3565b6107d5565b6102a360075481565b6103467f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff9091168152602001610220565b6102a36109aa565b61023c61036e366004611c8d565b610a05565b61023c610381366004611d58565b610ae2565b6102a3610394366004611c24565b610c73565b61023c610cc4565b61023c6103af366004611d58565b610e4a565b6102a36103c2366004611c24565b610fac565b6102a36103d5366004611c24565b60036020526000908152604090205481565b6102a36103f5366004611c24565b60056020526000908152604090205481565b6006546102d8906001600160a01b031681565b610246611021565b61023c61102e565b61023c610438366004611c8d565b6110a1565b6102a361044b366004611c24565b60096020526000908152604090205481565b61023c61046b366004611cf3565b6111a3565b6102146102fe366004611c8d565b61023c61048c366004611cf3565b611371565b61023c61049f366004611dc4565b6113fd565b6102a36104b2366004611e37565b600460209081526000928352604080842090915290825290205481565b6102a36104dd366004611c24565b60086020526000908152604090205481565b61023c6104fd366004611c24565b611641565b600654600160a01b900460ff1661052c57604051634065aaf160e11b815260040160405180910390fd5b6001600160a01b0381166000908152600360209081526040808320546009909252822054909161055c8284611e80565b6001600160a01b038516600090815260086020526040812054600754929350909161059a9161058a91611e80565b8590670de0b6b3a76400006116b7565b90508082116105cd576105ac856116d5565b60006105b88383611e80565b90508291506105c78183611710565b50610603565b6105d78184611e93565b6001600160a01b0386166000908152600960209081526040808320939093556007546008909152919020555b61060d85826117c4565b5050505050565b6000805461062190611ea6565b80601f016020809104026020016040519081016040528092919081815260200182805461064d90611ea6565b801561069a5780601f1061066f5761010080835404028352916020019161069a565b820191906000526020600020905b81548152906001019060200180831161067d57829003601f168201915b505050505081565b3360008181526004602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906106fd9086815260200190565b60405180910390a35060015b92915050565b6006546001600160a01b031633146107425760405162461bcd60e51b815260040161073990611ee0565b60405180910390fd5b600654600160a81b900463ffffffff161561077057604051633193e6ef60e21b815260040160405180910390fd5b6006805460ff60a01b1916600160a01b179055604051600181527fda8d093060d8bb4ec62c308766e6aff7be6a9a04c3d4a920517503311855b4ec906020015b60405180910390a1565b6000604051631de81c7b60e01b815260040160405180910390fd5b600654600160a01b900460ff166107ff57604051634065aaf160e11b815260040160405180910390fd5b806000036108205760405163375bfb0160e11b815260040160405180910390fd5b33600090815260036020908152604080832054600990925282205490916108478284611e80565b33600090815260086020526040812054600754929350909161086c9161058a91611e80565b905080821161089f5761087e336116d5565b600061088a8383611e80565b90508291506108998183611710565b506109a0565b846108aa8284611e80565b116108d4576108b8336116d5565b6108c28183611e80565b94506108cf600082611710565b61090d565b6108de8184611e93565b3360008181526009602090815260408083209490945560075460089091529290209190915561090d908661193b565b60405163a9059cbb60e01b8152336004820152602481018690527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a9059cbb906044016020604051808303816000875af115801561097a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061099e9190611f06565b505b61060d33826117c4565b60007f000000000000000000000000000000000000000000000000000000000000000046146109e0576109db6119b7565b905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b6006546001600160a01b03163314610a2f5760405162461bcd60e51b815260040161073990611ee0565b600654600160a01b900460ff1615610a5a5760405163c9b0a2a760e01b815260040160405180910390fd5b610a648282611a51565b60405163140e25ad60e31b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a0712d6890602401600060405180830381600087803b158015610ac657600080fd5b505af1158015610ada573d6000803e3d6000fd5b505050505050565b6006546001600160a01b03163314610b0c5760405162461bcd60e51b815260040161073990611ee0565b600654600160a01b900460ff1615610b375760405163c9b0a2a760e01b815260040160405180910390fd5b82818114610b5b576040516001621398b960e31b0319815260040160405180910390fd5b60008060008060005b85811015610bed57898982818110610b7e57610b7e611f28565b9050602002016020810190610b939190611c24565b6001600160a01b0381166000908152600360205260409020549095509350878782818110610bc357610bc3611f28565b905060200201359250838310610bd7578392505b610be1858461193b565b90820190600101610b64565b50604051630852cd8d60e31b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906342966c6890602401600060405180830381600087803b158015610c5057600080fd5b505af1158015610c64573d6000803e3d6000fd5b50505050505050505050505050565b6001600160a01b03811660009081526008602052604081205460075461070991610c9c91611e80565b6001600160a01b03841660009081526003602052604090205490670de0b6b3a76400006116b7565b6006546001600160a01b03163314610cee5760405162461bcd60e51b815260040161073990611ee0565b600654600160a81b900463ffffffff161580610d29575060065463ffffffff42811691610d279162093a8091600160a81b900416611e93565b115b15610d47576040516341bc68d960e11b815260040160405180910390fd5b6006805460ff60a01b1981169091556040516370a0823160e01b8152306004820152610e19916001600160a01b03908116917f0000000000000000000000000000000000000000000000000000000000000000909116906370a0823190602401602060405180830381865afa158015610dc4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610de89190611f3e565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169190611ab5565b604051600081527fda8d093060d8bb4ec62c308766e6aff7be6a9a04c3d4a920517503311855b4ec906020016107b0565b6006546001600160a01b03163314610e745760405162461bcd60e51b815260040161073990611ee0565b600654600160a01b900460ff1615610e9f5760405163c9b0a2a760e01b815260040160405180910390fd5b826000828214610ec5576040516001621398b960e31b0319815260040160405180910390fd5b6000805b83811015610f2857858582818110610ee357610ee3611f28565b905060200201359150610f1c888883818110610f0157610f01611f28565b9050602002016020810190610f169190611c24565b83611a51565b91810191600101610ec9565b5060405163140e25ad60e31b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a0712d6890602401600060405180830381600087803b158015610f8b57600080fd5b505af1158015610f9f573d6000803e3d6000fd5b5050505050505050505050565b6001600160a01b038116600090815260086020526040812054600754610fd591610c9c91611e80565b6001600160a01b038316600090815260096020908152604080832054600390925282205492935090916110089190611e80565b905081811115611018578161101a565b805b9392505050565b6001805461062190611ea6565b6006546001600160a01b031633146110585760405162461bcd60e51b815260040161073990611ee0565b6006805463ffffffff60a81b1916600160a81b4263ffffffff16021790556040517f815e0521f8ed896d67f1c40f81925d244ce8a40a26205d8c6e12597a1e3ef17590600090a1565b6006546001600160a01b031633146110cb5760405162461bcd60e51b815260040161073990611ee0565b600654600160a01b900460ff16156110f65760405163c9b0a2a760e01b815260040160405180910390fd5b6001600160a01b03821660009081526003602052604090205480821061111a578091505b611124838361193b565b604051630852cd8d60e31b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906342966c6890602401600060405180830381600087803b15801561118657600080fd5b505af115801561119a573d6000803e3d6000fd5b50505050505050565b600654600160a01b900460ff166111cd57604051634065aaf160e11b815260040160405180910390fd5b806000036111ee57604051635d66204960e11b815260040160405180910390fd5b336000818152600360205260408082205490516323b872dd60e01b81526004810193909352306024840152604483018490529181906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906323b872dd906064016020604051808303816000875af1158015611276573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061129a9190611f06565b5082156112e457336000908152600960209081526040808320546008909252909120546007549193506112e1916112d19190611e80565b8490670de0b6b3a76400006116b7565b90505b6000826112f18686611e93565b6112fb9190611e80565b905081811161132e5761130d336116d5565b60006113198284611e80565b90508192506113288184611710565b50611367565b6113388284611e93565b336000818152600960209081526040808320949094556007546008909152929020919091556113679086611a51565b61060d33836117c4565b600654600160a01b900460ff1661139b57604051634065aaf160e11b815260040160405180910390fd5b806000036113bc57604051635d66204960e11b815260040160405180910390fd5b6113c581611b3c565b6113fa6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016333084611b73565b50565b4284101561144d5760405162461bcd60e51b815260206004820152601760248201527f5045524d49545f444541444c494e455f455850495245440000000000000000006044820152606401610739565b600060016114596109aa565b6001600160a01b038a811660008181526005602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa158015611565573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381161580159061159b5750876001600160a01b0316816001600160a01b0316145b6115d85760405162461bcd60e51b815260206004820152600e60248201526d24a72b20a624a22fa9a4a3a722a960911b6044820152606401610739565b6001600160a01b0390811660009081526004602090815260408083208a8516808552908352928190208990555188815291928a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b6006546001600160a01b0316331461166b5760405162461bcd60e51b815260040161073990611ee0565b600680546001600160a01b0319166001600160a01b03831690811790915560405133907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b60008260001904841183021582026116ce57600080fd5b5091020490565b6001600160a01b03811660009081526009602090815260408083208390556008825280832083905560039091529020546113fa90829061193b565b600254156117255761172182611b3c565b5050565b6006546040516370a0823160e01b8152306004820152611721916001600160a01b039081169184917f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015611796573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117ba9190611f3e565b610de89190611e80565b604051630852cd8d60e31b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906342966c6890602401600060405180830381600087803b15801561182657600080fd5b505af115801561183a573d6000803e3d6000fd5b505060405163fe575a8760e01b81526001600160a01b0385811660048301527f000000000000000000000000000000000000000000000000000000000000000016925063fe575a879150602401602060405180830381865afa1580156118a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118c89190611f06565b1561190757600654611721906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911683611ab5565b6117216001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168383611ab5565b6001600160a01b03821660009081526003602052604081208054839290611963908490611e80565b90915550506002805482900390556040518181526000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020015b60405180910390a35050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60006040516119e99190611f57565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b8060026000828254611a639190611e93565b90915550506001600160a01b0382166000818152600360209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91016119ab565b600060405163a9059cbb60e01b81526001600160a01b0384166004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080611b365760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b6044820152606401610739565b50505050565b80156113fa57600254611b5a908290670de0b6b3a7640000906116b7565b60076000828254611b6b9190611e93565b909155505050565b60006040516323b872dd60e01b81526001600160a01b03851660048201526001600160a01b03841660248201528260448201526020600060648360008a5af13d15601f3d116001600051141617169150508061060d5760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b6044820152606401610739565b80356001600160a01b0381168114611c1f57600080fd5b919050565b600060208284031215611c3657600080fd5b61101a82611c08565b600060208083528351808285015260005b81811015611c6c57858101830151858201604001528201611c50565b506000604082860101526040601f19601f8301168501019250505092915050565b60008060408385031215611ca057600080fd5b611ca983611c08565b946020939093013593505050565b600080600060608486031215611ccc57600080fd5b611cd584611c08565b9250611ce360208501611c08565b9150604084013590509250925092565b600060208284031215611d0557600080fd5b5035919050565b60008083601f840112611d1e57600080fd5b50813567ffffffffffffffff811115611d3657600080fd5b6020830191508360208260051b8501011115611d5157600080fd5b9250929050565b60008060008060408587031215611d6e57600080fd5b843567ffffffffffffffff80821115611d8657600080fd5b611d9288838901611d0c565b90965094506020870135915080821115611dab57600080fd5b50611db887828801611d0c565b95989497509550505050565b600080600080600080600060e0888a031215611ddf57600080fd5b611de888611c08565b9650611df660208901611c08565b95506040880135945060608801359350608088013560ff81168114611e1a57600080fd5b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215611e4a57600080fd5b611e5383611c08565b9150611e6160208401611c08565b90509250929050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561070957610709611e6a565b8082018082111561070957610709611e6a565b600181811c90821680611eba57607f821691505b602082108103611eda57634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252600c908201526b15539055551213d49256915160a21b604082015260600190565b600060208284031215611f1857600080fd5b8151801515811461101a57600080fd5b634e487b7160e01b600052603260045260246000fd5b600060208284031215611f5057600080fd5b5051919050565b600080835481600182811c915080831680611f7357607f831692505b60208084108203611f9257634e487b7160e01b86526022600452602486fd5b818015611fa65760018114611fbb57611fe8565b60ff1986168952841515850289019650611fe8565b60008a81526020902060005b86811015611fe05781548b820152908501908301611fc7565b505084890196505b50949897505050505050505056fea26469706673582212203b558a27ec2fc3e6d5d9d8a9028db7f1a703ca5f4ce332ac4d5a24bf646e620b64736f6c634300081300336101006040523480156200001257600080fd5b50604051620010d8380380620010d8833981016040819052620000359162000173565b6040518060400160405280601681526020017f41726361646961205265636f7665727920546f6b656e000000000000000000008152506040518060400160405280600381526020016210549560ea1b81525082826000908162000099919062000267565b506001620000a8838262000267565b5060ff81166080524660a052620000be620000d7565b60c052505050506001600160a01b031660e052620003b1565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60006040516200010b919062000333565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b600080604083850312156200018757600080fd5b82516001600160a01b03811681146200019f57600080fd5b602084015190925060ff81168114620001b757600080fd5b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620001ed57607f821691505b6020821081036200020e57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200026257600081815260208120601f850160051c810160208610156200023d5750805b601f850160051c820191505b818110156200025e5782815560010162000249565b5050505b505050565b81516001600160401b03811115620002835762000283620001c2565b6200029b81620002948454620001d8565b8462000214565b602080601f831160018114620002d35760008415620002ba5750858301515b600019600386901b1c1916600185901b1785556200025e565b600085815260208120601f198616915b828110156200030457888601518255948401946001909101908401620002e3565b5085821015620003235787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60008083546200034381620001d8565b600182811680156200035e57600181146200037457620003a5565b60ff1984168752821515830287019450620003a5565b8760005260208060002060005b858110156200039c5781548a82015290840190820162000381565b50505082870194505b50929695505050505050565b60805160a05160c05160e051610cdf620003f96000396000818161028a0152818161051f0152610576015260006104d8015260006104a3015260006101750152610cdf6000f3fe608060405234801561001057600080fd5b50600436106101005760003560e01c80637ecebe0011610097578063a9059cbb11610066578063a9059cbb14610234578063d505accf14610247578063dd62ed3e1461025a578063f48da4751461028557600080fd5b80637ecebe00146101e657806395d89b41146102065780639dc29fac1461020e578063a0712d681461022157600080fd5b8063313ce567116100d3578063313ce567146101705780633644e515146101a957806342966c68146101b157806370a08231146101c657600080fd5b806306fdde0314610105578063095ea7b31461012357806318160ddd1461014657806323b872dd1461015d575b600080fd5b61010d6102c4565b60405161011a91906109c3565b60405180910390f35b610136610131366004610a2d565b610352565b604051901515815260200161011a565b61014f60025481565b60405190815260200161011a565b61013661016b366004610a57565b6103bf565b6101977f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff909116815260200161011a565b61014f61049f565b6101c46101bf366004610a93565b6104fa565b005b61014f6101d4366004610aac565b60036020526000908152604090205481565b61014f6101f4366004610aac565b60056020526000908152604090205481565b61010d610507565b6101c461021c366004610a2d565b610514565b6101c461022f366004610a93565b61056b565b610136610242366004610a2d565b6105be565b6101c4610255366004610ace565b610624565b61014f610268366004610b41565b600460209081526000928352604080842090915290825290205481565b6102ac7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161011a565b600080546102d190610b74565b80601f01602080910402602001604051908101604052809291908181526020018280546102fd90610b74565b801561034a5780601f1061031f5761010080835404028352916020019161034a565b820191906000526020600020905b81548152906001019060200180831161032d57829003601f168201915b505050505081565b3360008181526004602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906103ad9086815260200190565b60405180910390a35060015b92915050565b6001600160a01b0383166000908152600460209081526040808320338452909152812054600019811461041b576103f68382610bc4565b6001600160a01b03861660009081526004602090815260408083203384529091529020555b6001600160a01b03851660009081526003602052604081208054859290610443908490610bc4565b90915550506001600160a01b0380851660008181526003602052604090819020805487019055519091871690600080516020610c8a8339815191529061048c9087815260200190565b60405180910390a3506001949350505050565b60007f000000000000000000000000000000000000000000000000000000000000000046146104d5576104d061086d565b905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b6105043382610907565b50565b600180546102d190610b74565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461055d57604051634f161bfb60e01b815260040160405180910390fd5b6105678282610907565b5050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146105b457604051634f161bfb60e01b815260040160405180910390fd5b6105043382610971565b336000908152600360205260408120805483919083906105df908490610bc4565b90915550506001600160a01b03831660008181526003602052604090819020805485019055513390600080516020610c8a833981519152906103ad9086815260200190565b428410156106795760405162461bcd60e51b815260206004820152601760248201527f5045524d49545f444541444c494e455f4558504952454400000000000000000060448201526064015b60405180910390fd5b6000600161068561049f565b6001600160a01b038a811660008181526005602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa158015610791573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116158015906107c75750876001600160a01b0316816001600160a01b0316145b6108045760405162461bcd60e51b815260206004820152600e60248201526d24a72b20a624a22fa9a4a3a722a960911b6044820152606401610670565b6001600160a01b0390811660009081526004602090815260408083208a8516808552908352928190208990555188815291928a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f600060405161089f9190610bd7565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b6001600160a01b0382166000908152600360205260408120805483929061092f908490610bc4565b90915550506002805482900390556040518181526000906001600160a01b03841690600080516020610c8a833981519152906020015b60405180910390a35050565b80600260008282546109839190610c76565b90915550506001600160a01b038216600081815260036020908152604080832080548601905551848152600080516020610c8a8339815191529101610965565b600060208083528351808285015260005b818110156109f0578581018301518582016040015282016109d4565b506000604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b0381168114610a2857600080fd5b919050565b60008060408385031215610a4057600080fd5b610a4983610a11565b946020939093013593505050565b600080600060608486031215610a6c57600080fd5b610a7584610a11565b9250610a8360208501610a11565b9150604084013590509250925092565b600060208284031215610aa557600080fd5b5035919050565b600060208284031215610abe57600080fd5b610ac782610a11565b9392505050565b600080600080600080600060e0888a031215610ae957600080fd5b610af288610a11565b9650610b0060208901610a11565b95506040880135945060608801359350608088013560ff81168114610b2457600080fd5b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215610b5457600080fd5b610b5d83610a11565b9150610b6b60208401610a11565b90509250929050565b600181811c90821680610b8857607f821691505b602082108103610ba857634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b818103818111156103b9576103b9610bae565b600080835481600182811c915080831680610bf357607f831692505b60208084108203610c1257634e487b7160e01b86526022600452602486fd5b818015610c265760018114610c3b57610c68565b60ff1986168952841515850289019650610c68565b60008a81526020902060005b86811015610c605781548b820152908501908301610c47565b505084890196505b509498975050505050505050565b808201808211156103b9576103b9610bae56feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212203f7d86e2f44a25662b9d113cb9a731dcd6f0df09a121ca704b069dc361e86e7564736f6c634300081300330000000000000000000000007f5c764cbc14f9669b88837ca1490cca17c31607

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101fb5760003560e01c80635de8697d1161011a5780639dc29fac116100ad578063b9f5be411161007c578063b9f5be411461047e578063d505accf14610491578063dd62ed3e146104a4578063e5ad693e146104cf578063f2fde38b146104ef57600080fd5b80639dc29fac1461042a5780639f4568ef1461043d5780639fba4aab1461045d578063a9059cbb1461047057600080fd5b80637ecebe00116100e95780637ecebe00146103e75780638da5cb5b1461040757806395d89b411461041a57806398a8d41e1461042257600080fd5b80635de8697d1461039957806368573107146103a15780636f9a31f4146103b457806370a08231146103c757600080fd5b806323b872dd116101925780633644e515116101615780633644e5151461035857806340c10f19146103605780634a6cc677146103735780635af1e0c61461038657600080fd5b806323b872dd146102f0578063293f19ca146103035780632c7392bb14610316578063313ce5671461031f57600080fd5b80630bbfc833116101ce5780630bbfc833146102665780630f15f4c01461029257806318160ddd1461029a57806319133877146102b157600080fd5b806302fb0c5e1461020057806303579dca1461022957806306fdde031461023e578063095ea7b314610253575b600080fd5b60065461021490600160a01b900460ff1681565b60405190151581526020015b60405180910390f35b61023c610237366004611c24565b610502565b005b610246610614565b6040516102209190611c3f565b610214610261366004611c8d565b6106a2565b60065461027d90600160a81b900463ffffffff1681565b60405163ffffffff9091168152602001610220565b61023c61070f565b6102a360025481565b604051908152602001610220565b6102d87f000000000000000000000000939c1a951070fb9074d69916756643c90e6633a781565b6040516001600160a01b039091168152602001610220565b6102146102fe366004611cb7565b6107ba565b61023c610311366004611cf3565b6107d5565b6102a360075481565b6103467f000000000000000000000000000000000000000000000000000000000000000681565b60405160ff9091168152602001610220565b6102a36109aa565b61023c61036e366004611c8d565b610a05565b61023c610381366004611d58565b610ae2565b6102a3610394366004611c24565b610c73565b61023c610cc4565b61023c6103af366004611d58565b610e4a565b6102a36103c2366004611c24565b610fac565b6102a36103d5366004611c24565b60036020526000908152604090205481565b6102a36103f5366004611c24565b60056020526000908152604090205481565b6006546102d8906001600160a01b031681565b610246611021565b61023c61102e565b61023c610438366004611c8d565b6110a1565b6102a361044b366004611c24565b60096020526000908152604090205481565b61023c61046b366004611cf3565b6111a3565b6102146102fe366004611c8d565b61023c61048c366004611cf3565b611371565b61023c61049f366004611dc4565b6113fd565b6102a36104b2366004611e37565b600460209081526000928352604080842090915290825290205481565b6102a36104dd366004611c24565b60086020526000908152604090205481565b61023c6104fd366004611c24565b611641565b600654600160a01b900460ff1661052c57604051634065aaf160e11b815260040160405180910390fd5b6001600160a01b0381166000908152600360209081526040808320546009909252822054909161055c8284611e80565b6001600160a01b038516600090815260086020526040812054600754929350909161059a9161058a91611e80565b8590670de0b6b3a76400006116b7565b90508082116105cd576105ac856116d5565b60006105b88383611e80565b90508291506105c78183611710565b50610603565b6105d78184611e93565b6001600160a01b0386166000908152600960209081526040808320939093556007546008909152919020555b61060d85826117c4565b5050505050565b6000805461062190611ea6565b80601f016020809104026020016040519081016040528092919081815260200182805461064d90611ea6565b801561069a5780601f1061066f5761010080835404028352916020019161069a565b820191906000526020600020905b81548152906001019060200180831161067d57829003601f168201915b505050505081565b3360008181526004602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906106fd9086815260200190565b60405180910390a35060015b92915050565b6006546001600160a01b031633146107425760405162461bcd60e51b815260040161073990611ee0565b60405180910390fd5b600654600160a81b900463ffffffff161561077057604051633193e6ef60e21b815260040160405180910390fd5b6006805460ff60a01b1916600160a01b179055604051600181527fda8d093060d8bb4ec62c308766e6aff7be6a9a04c3d4a920517503311855b4ec906020015b60405180910390a1565b6000604051631de81c7b60e01b815260040160405180910390fd5b600654600160a01b900460ff166107ff57604051634065aaf160e11b815260040160405180910390fd5b806000036108205760405163375bfb0160e11b815260040160405180910390fd5b33600090815260036020908152604080832054600990925282205490916108478284611e80565b33600090815260086020526040812054600754929350909161086c9161058a91611e80565b905080821161089f5761087e336116d5565b600061088a8383611e80565b90508291506108998183611710565b506109a0565b846108aa8284611e80565b116108d4576108b8336116d5565b6108c28183611e80565b94506108cf600082611710565b61090d565b6108de8184611e93565b3360008181526009602090815260408083209490945560075460089091529290209190915561090d908661193b565b60405163a9059cbb60e01b8152336004820152602481018690527f000000000000000000000000939c1a951070fb9074d69916756643c90e6633a76001600160a01b03169063a9059cbb906044016020604051808303816000875af115801561097a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061099e9190611f06565b505b61060d33826117c4565b60007f000000000000000000000000000000000000000000000000000000000000000a46146109e0576109db6119b7565b905090565b507f8ffb4630c82cf9417b0644cecb137d5781d69dda93480c405445146e9112681090565b6006546001600160a01b03163314610a2f5760405162461bcd60e51b815260040161073990611ee0565b600654600160a01b900460ff1615610a5a5760405163c9b0a2a760e01b815260040160405180910390fd5b610a648282611a51565b60405163140e25ad60e31b8152600481018290527f000000000000000000000000939c1a951070fb9074d69916756643c90e6633a76001600160a01b03169063a0712d6890602401600060405180830381600087803b158015610ac657600080fd5b505af1158015610ada573d6000803e3d6000fd5b505050505050565b6006546001600160a01b03163314610b0c5760405162461bcd60e51b815260040161073990611ee0565b600654600160a01b900460ff1615610b375760405163c9b0a2a760e01b815260040160405180910390fd5b82818114610b5b576040516001621398b960e31b0319815260040160405180910390fd5b60008060008060005b85811015610bed57898982818110610b7e57610b7e611f28565b9050602002016020810190610b939190611c24565b6001600160a01b0381166000908152600360205260409020549095509350878782818110610bc357610bc3611f28565b905060200201359250838310610bd7578392505b610be1858461193b565b90820190600101610b64565b50604051630852cd8d60e31b8152600481018290527f000000000000000000000000939c1a951070fb9074d69916756643c90e6633a76001600160a01b0316906342966c6890602401600060405180830381600087803b158015610c5057600080fd5b505af1158015610c64573d6000803e3d6000fd5b50505050505050505050505050565b6001600160a01b03811660009081526008602052604081205460075461070991610c9c91611e80565b6001600160a01b03841660009081526003602052604090205490670de0b6b3a76400006116b7565b6006546001600160a01b03163314610cee5760405162461bcd60e51b815260040161073990611ee0565b600654600160a81b900463ffffffff161580610d29575060065463ffffffff42811691610d279162093a8091600160a81b900416611e93565b115b15610d47576040516341bc68d960e11b815260040160405180910390fd5b6006805460ff60a01b1981169091556040516370a0823160e01b8152306004820152610e19916001600160a01b03908116917f0000000000000000000000007f5c764cbc14f9669b88837ca1490cca17c31607909116906370a0823190602401602060405180830381865afa158015610dc4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610de89190611f3e565b6001600160a01b037f0000000000000000000000007f5c764cbc14f9669b88837ca1490cca17c31607169190611ab5565b604051600081527fda8d093060d8bb4ec62c308766e6aff7be6a9a04c3d4a920517503311855b4ec906020016107b0565b6006546001600160a01b03163314610e745760405162461bcd60e51b815260040161073990611ee0565b600654600160a01b900460ff1615610e9f5760405163c9b0a2a760e01b815260040160405180910390fd5b826000828214610ec5576040516001621398b960e31b0319815260040160405180910390fd5b6000805b83811015610f2857858582818110610ee357610ee3611f28565b905060200201359150610f1c888883818110610f0157610f01611f28565b9050602002016020810190610f169190611c24565b83611a51565b91810191600101610ec9565b5060405163140e25ad60e31b8152600481018390527f000000000000000000000000939c1a951070fb9074d69916756643c90e6633a76001600160a01b03169063a0712d6890602401600060405180830381600087803b158015610f8b57600080fd5b505af1158015610f9f573d6000803e3d6000fd5b5050505050505050505050565b6001600160a01b038116600090815260086020526040812054600754610fd591610c9c91611e80565b6001600160a01b038316600090815260096020908152604080832054600390925282205492935090916110089190611e80565b905081811115611018578161101a565b805b9392505050565b6001805461062190611ea6565b6006546001600160a01b031633146110585760405162461bcd60e51b815260040161073990611ee0565b6006805463ffffffff60a81b1916600160a81b4263ffffffff16021790556040517f815e0521f8ed896d67f1c40f81925d244ce8a40a26205d8c6e12597a1e3ef17590600090a1565b6006546001600160a01b031633146110cb5760405162461bcd60e51b815260040161073990611ee0565b600654600160a01b900460ff16156110f65760405163c9b0a2a760e01b815260040160405180910390fd5b6001600160a01b03821660009081526003602052604090205480821061111a578091505b611124838361193b565b604051630852cd8d60e31b8152600481018390527f000000000000000000000000939c1a951070fb9074d69916756643c90e6633a76001600160a01b0316906342966c6890602401600060405180830381600087803b15801561118657600080fd5b505af115801561119a573d6000803e3d6000fd5b50505050505050565b600654600160a01b900460ff166111cd57604051634065aaf160e11b815260040160405180910390fd5b806000036111ee57604051635d66204960e11b815260040160405180910390fd5b336000818152600360205260408082205490516323b872dd60e01b81526004810193909352306024840152604483018490529181906001600160a01b037f000000000000000000000000939c1a951070fb9074d69916756643c90e6633a716906323b872dd906064016020604051808303816000875af1158015611276573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061129a9190611f06565b5082156112e457336000908152600960209081526040808320546008909252909120546007549193506112e1916112d19190611e80565b8490670de0b6b3a76400006116b7565b90505b6000826112f18686611e93565b6112fb9190611e80565b905081811161132e5761130d336116d5565b60006113198284611e80565b90508192506113288184611710565b50611367565b6113388284611e93565b336000818152600960209081526040808320949094556007546008909152929020919091556113679086611a51565b61060d33836117c4565b600654600160a01b900460ff1661139b57604051634065aaf160e11b815260040160405180910390fd5b806000036113bc57604051635d66204960e11b815260040160405180910390fd5b6113c581611b3c565b6113fa6001600160a01b037f0000000000000000000000007f5c764cbc14f9669b88837ca1490cca17c3160716333084611b73565b50565b4284101561144d5760405162461bcd60e51b815260206004820152601760248201527f5045524d49545f444541444c494e455f455850495245440000000000000000006044820152606401610739565b600060016114596109aa565b6001600160a01b038a811660008181526005602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa158015611565573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381161580159061159b5750876001600160a01b0316816001600160a01b0316145b6115d85760405162461bcd60e51b815260206004820152600e60248201526d24a72b20a624a22fa9a4a3a722a960911b6044820152606401610739565b6001600160a01b0390811660009081526004602090815260408083208a8516808552908352928190208990555188815291928a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b6006546001600160a01b0316331461166b5760405162461bcd60e51b815260040161073990611ee0565b600680546001600160a01b0319166001600160a01b03831690811790915560405133907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b60008260001904841183021582026116ce57600080fd5b5091020490565b6001600160a01b03811660009081526009602090815260408083208390556008825280832083905560039091529020546113fa90829061193b565b600254156117255761172182611b3c565b5050565b6006546040516370a0823160e01b8152306004820152611721916001600160a01b039081169184917f0000000000000000000000007f5c764cbc14f9669b88837ca1490cca17c3160716906370a0823190602401602060405180830381865afa158015611796573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117ba9190611f3e565b610de89190611e80565b604051630852cd8d60e31b8152600481018290527f000000000000000000000000939c1a951070fb9074d69916756643c90e6633a76001600160a01b0316906342966c6890602401600060405180830381600087803b15801561182657600080fd5b505af115801561183a573d6000803e3d6000fd5b505060405163fe575a8760e01b81526001600160a01b0385811660048301527f0000000000000000000000007f5c764cbc14f9669b88837ca1490cca17c3160716925063fe575a879150602401602060405180830381865afa1580156118a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118c89190611f06565b1561190757600654611721906001600160a01b037f0000000000000000000000007f5c764cbc14f9669b88837ca1490cca17c316078116911683611ab5565b6117216001600160a01b037f0000000000000000000000007f5c764cbc14f9669b88837ca1490cca17c31607168383611ab5565b6001600160a01b03821660009081526003602052604081208054839290611963908490611e80565b90915550506002805482900390556040518181526000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020015b60405180910390a35050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60006040516119e99190611f57565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b8060026000828254611a639190611e93565b90915550506001600160a01b0382166000818152600360209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91016119ab565b600060405163a9059cbb60e01b81526001600160a01b0384166004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080611b365760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b6044820152606401610739565b50505050565b80156113fa57600254611b5a908290670de0b6b3a7640000906116b7565b60076000828254611b6b9190611e93565b909155505050565b60006040516323b872dd60e01b81526001600160a01b03851660048201526001600160a01b03841660248201528260448201526020600060648360008a5af13d15601f3d116001600051141617169150508061060d5760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b6044820152606401610739565b80356001600160a01b0381168114611c1f57600080fd5b919050565b600060208284031215611c3657600080fd5b61101a82611c08565b600060208083528351808285015260005b81811015611c6c57858101830151858201604001528201611c50565b506000604082860101526040601f19601f8301168501019250505092915050565b60008060408385031215611ca057600080fd5b611ca983611c08565b946020939093013593505050565b600080600060608486031215611ccc57600080fd5b611cd584611c08565b9250611ce360208501611c08565b9150604084013590509250925092565b600060208284031215611d0557600080fd5b5035919050565b60008083601f840112611d1e57600080fd5b50813567ffffffffffffffff811115611d3657600080fd5b6020830191508360208260051b8501011115611d5157600080fd5b9250929050565b60008060008060408587031215611d6e57600080fd5b843567ffffffffffffffff80821115611d8657600080fd5b611d9288838901611d0c565b90965094506020870135915080821115611dab57600080fd5b50611db887828801611d0c565b95989497509550505050565b600080600080600080600060e0888a031215611ddf57600080fd5b611de888611c08565b9650611df660208901611c08565b95506040880135945060608801359350608088013560ff81168114611e1a57600080fd5b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215611e4a57600080fd5b611e5383611c08565b9150611e6160208401611c08565b90509250929050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561070957610709611e6a565b8082018082111561070957610709611e6a565b600181811c90821680611eba57607f821691505b602082108103611eda57634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252600c908201526b15539055551213d49256915160a21b604082015260600190565b600060208284031215611f1857600080fd5b8151801515811461101a57600080fd5b634e487b7160e01b600052603260045260246000fd5b600060208284031215611f5057600080fd5b5051919050565b600080835481600182811c915080831680611f7357607f831692505b60208084108203611f9257634e487b7160e01b86526022600452602486fd5b818015611fa65760018114611fbb57611fe8565b60ff1986168952841515850289019650611fe8565b60008a81526020902060005b86811015611fe05781548b820152908501908301611fc7565b505084890196505b50949897505050505050505056fea26469706673582212203b558a27ec2fc3e6d5d9d8a9028db7f1a703ca5f4ce332ac4d5a24bf646e620b64736f6c63430008130033

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

0000000000000000000000007f5c764cbc14f9669b88837ca1490cca17c31607

-----Decoded View---------------
Arg [0] : underlying_ (address): 0x7F5c764cBc14f9669B88837ca1490cCa17c31607

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000007f5c764cbc14f9669b88837ca1490cca17c31607


[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.