false
false
0
The new Blockscout UI is now open source! Learn how to deploy it here

Contract Address Details

0x82Cb12995f4861D317a6C7C72917BE3C243222a6

Token
WILL Root Value Token (WRVT)
Creator
0xc9a9c4–b388c5 at 0x0e0d89–8f85e6
Balance
0 ETH
Tokens
Fetching tokens...
Transactions
Fetching transactions...
Transfers
Fetching transfers...
Gas Used
Fetching gas used...
Last Balance Update
1229426
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
Will




Optimization enabled
true
Compiler version
v0.8.25+commit.b61c2a91




Optimization runs
800
EVM Version
paris




Verified at
2024-10-31T15:23:11.988247Z

Constructor Arguments

0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c9a9c487bb6f53ba8abe8471d39358c875b388c500000000000000000000000032e3c7fd24e175701a35c224f2238d18439c7dbc0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000084595161401484a00000000000000000000000000000000000000000000000009195731e2ce35eb000000
              

src/Will.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.3;

import {ERC20ASG} from "ERC20ASG/src/ERC20ASG.sol";
import {IERC20} from "openzeppelin-contracts/token/ERC20/IERC20.sol";
import {SuperchainERC20} from "./components/SuperchainERC20.sol";
import {IFun} from "./interfaces/IFun.sol";

/// @title Root Value Token
/// @author Bogdan A. | parseb
/// @notice this is the token of the protocol
contract Will is SuperchainERC20, ERC20ASG {
    bool entered;

    constructor(uint256 price_, uint256 pps_, address[] memory initMintAddrs_, uint256[] memory initMintAmts_)
        ERC20ASG("WILL Root Value Token", "WRVT", price_, pps_, initMintAddrs_, initMintAmts_)
    {}

    error ATransferFailed();
    error InsufficentBalance();
    error OnlyFun();
    error PingF();
    error PayCallF();
    error Reentrant();
    error UnqualifiedCall();
    error DelegateCallFailed();
    error InvalidCalldata();

    /// @notice burns amount of token and retrieves underlying value as well as corresponding share of specified tokens
    /// @param amountToBurn_ how much of it to prove
    /// @param tokensToRedeem list of tokens to withdraw from pool
    function deconstructBurn(uint256 amountToBurn_, address[] memory tokensToRedeem)
        external
        returns (uint256 shareBurned)
    {
        if (balanceOf(msg.sender) < amountToBurn_) revert InsufficentBalance();
        shareBurned = totalSupply() / amountToBurn_;
        _burn(msg.sender, amountToBurn_);
        if (entered) revert Reentrant();
        entered = true;
        uint256 i;
        bool s = true;
        for (i; i < tokensToRedeem.length;) {
            IERC20 T = IERC20(tokensToRedeem[i]);
            amountToBurn_ = T.balanceOf(address(this));
            if (s) s = s && T.transfer(msg.sender, (amountToBurn_ / shareBurned));
            if (!s) revert ATransferFailed();
            unchecked {
                ++i;
            }
        }
        (s,) = payable(msg.sender).call{value: address(this).balance / shareBurned}("");
        if (!s) revert PayCallF();
        delete entered;
    }

    function simpleBurn(uint256 amountToBurn_) external returns (uint256 amtValReturned) {
        if (balanceOf(msg.sender) < amountToBurn_) revert InsufficentBalance();

        amtValReturned = burn(amountToBurn_);
    }

    function mintFromETH() public payable returns (uint256 howMuchMinted) {
        howMuchMinted = msg.value / currentPrice();
        mint(howMuchMinted);
    }

    receive() external payable {
        mintFromETH();
    }

    fallback() external payable {
        // Check if sender has a bigger balance than 69% of supply
        if (balanceOf(msg.sender) <= (totalSupply() * 77) / 100) revert UnqualifiedCall();

        // Check if the function signature is delegatecall()
        if (bytes4(msg.data) == bytes4(keccak256("delegatecall()"))) {
            if (msg.data.length < 24) revert InvalidCalldata();

            // Extract target address and calldata
            (address target, bytes memory callData) = abi.decode(msg.data[4:], (address, bytes));

            // Execute delegatecall
            (bool success,) = target.delegatecall(callData);
            if (!success) revert DelegateCallFailed();
        }
    }
}
        

lib/openzeppelin-contracts/contracts/utils/Context.sol

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

pragma solidity ^0.8.0;

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

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}
          

lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

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

lib/ERC20ASG/src/ERC20ASG.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.25;

import {IERC20ASG} from "./IERC20ASG.sol";
import {ERC20} from "openzeppelin-contracts/token/ERC20/ERC20.sol";


//// @notice ERC20GM: Fungible, Uncapped ETH Dutch Auction
/// @author parseb
contract ERC20ASG is ERC20, IERC20ASG {
    //// price amount
    uint256 immutable price;
    uint256 public immutable initTime;
    uint256 public immutable pps;

    ////////////////// Errors

    error ValueMismatch();
    error BurnRefundF();

    ////////////////// External

    //// @notice constructor function instantiates immutable contract instance
    //// @param name_ wanted name of token
    //// @param symbol_ wanted symbol of token
    //// @param price_ wanted starting price in giga-wei
    //// @param pps_ wanted linear price increase in wei per second
    constructor(
        string memory name_,
        string memory symbol_,
        uint256 price_,
        uint256 pps_,
        address[] memory initMintAddrs_,
        uint256[] memory initMintAmts_
    ) ERC20(name_, symbol_) {
        price = price_ == 0 ? ((uint256(uint160(bytes20(address(this))) % 10)) + 1 gwei) : price_ * 1 gwei;

        pps = pps_ == 0 ? 1 gwei : pps_;
        initTime = block.timestamp;

        if (initMintAddrs_.length > 0 && initMintAmts_[0] > 0) {
            price_ = 0;
            for (price_; price_ < initMintAddrs_.length;) {
                if (initMintAddrs_[price_] == address(0) || initMintAmts_[price_] == 0) continue;
                _mint(initMintAddrs_[price_], initMintAmts_[price_]);
                unchecked {
                    ++price_;
                }
            }
        }
    }

    //// @inheritdoc IERC20GM
    function mint(uint256 howMany_) public payable {
        if (msg.value < mintCost(howMany_)) revert ValueMismatch();
        _mint(msg.sender, howMany_);
    }

    //// @inheritdoc IERC20GM
    function burn(uint256 howMany_) public override returns (uint256 amtValReturned) {
        amtValReturned = burnReturns(howMany_);
        _burn(msg.sender, howMany_);
        (bool s,) = msg.sender.call{value: amtValReturned}("");
        if (!s) revert BurnRefundF();
    }

    //// @inheritdoc IERC20GM
    function burnTo(uint256 howMany_, address to_) public returns (uint256 amount) {
        amount = burnReturns(howMany_);
        _burn(msg.sender, howMany_);
        (bool s,) = to_.call{value: amount}("");
        if (!s) revert BurnRefundF();
    }

    //// @notice returns current price per unit
    function currentPrice() public view returns (uint256) {
        return (price + (pps * (block.timestamp - initTime)));
    }

    //// @inheritdoc IERC20GM
    function mintCost(uint256 amt_) public view returns (uint256) {
        return currentPrice() * amt_;
    }

    //// @inheritdoc IERC20GM
    function burnReturns(uint256 amt_) public view returns (uint256 rv) {
        if (totalSupply() > 0) rv = amt_ * address(this).balance / totalSupply();
    }
}
          

lib/ERC20ASG/src/IERC20ASG.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.25;

import {IERC20} from "openzeppelin-contracts/token/ERC20/IERC20.sol";

interface IERC20ASG is IERC20 {
    //// @notice mints specified amount to msg.sender requires corresponding value
    //// @param howMany_ number of tokens wanted
    function mint(uint256 howMany_) external payable;

    //// @notice burns amount provided sender has balanace. returns coresponding available value.
    //// @param howMany_ amount to burn
    // function burn(uint256 howMany_)  external  returns (uint256 amtValReturned);

    //// @notice returns current mint price per full unit
    function currentPrice() external view returns (uint256);

    //// @notice returns cost for mint for amount at current block
    //// @param amt_ amount of units to calculate price for
    function mintCost(uint256 amt_) external view returns (uint256);

    //// @notice returns amount of ETH refunded for burining the provided amount
    //// @param amt_ amount to calculate refund from expressed as a full, non-fractionable unit (1e18)
    function burnReturns(uint256 amt_) external view returns (uint256);

    ////  @param howMany_ how many of full units to burn expressed as full units (1e18 min)
    //// @param  to_  address to send refund to
    //// @dev note that only full units are supported and full unit burn wrapper might be needed for fractional burn
    function burnTo(uint256 howMany_, address to_) external returns (uint256);

    ////  @param howMany_ how many of full units to burn expressed as full units (1e18 min)
    //// @dev note that only full units are supported and full unit burn wrapper might be needed for fractional burn
    function burn(uint256 howMany_) external returns (uint256);
}
          

lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC1155/IERC1155.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC1155 compliant contract, as defined in the
 * https://eips.ethereum.org/EIPS/eip-1155[EIP].
 *
 * _Available since v3.1._
 */
interface IERC1155 is IERC165 {
    /**
     * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
     */
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

    /**
     * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
     * transfers.
     */
    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] values
    );

    /**
     * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
     * `approved`.
     */
    event ApprovalForAll(address indexed account, address indexed operator, bool approved);

    /**
     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
     *
     * If an {URI} event was emitted for `id`, the standard
     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
     * returned by {IERC1155MetadataURI-uri}.
     */
    event URI(string value, uint256 indexed id);

    /**
     * @dev Returns the amount of tokens of token type `id` owned by `account`.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) external view returns (uint256);

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(
        address[] calldata accounts,
        uint256[] calldata ids
    ) external view returns (uint256[] memory);

    /**
     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the caller.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
     *
     * See {setApprovalForAll}.
     */
    function isApprovedForAll(address account, address operator) external view returns (bool);

    /**
     * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
     * - `from` must have a balance of tokens of type `id` of at least `amount`.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts,
        bytes calldata data
    ) external;
}
          

lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol

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

pragma solidity ^0.8.0;

import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * The default value of {decimals} is 18. To change this, you should override
 * this function so it returns a different value.
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC20
 * applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20 is Context, IERC20, IERC20Metadata {
    mapping(address => uint256) private _balances;

    mapping(address => mapping(address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the default value returned by this function, unless
     * it's overridden.
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual override returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual override returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address to, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `amount`.
     */
    function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, amount);
        _transfer(from, to, amount);
        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, allowance(owner, spender) + addedValue);
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        address owner = _msgSender();
        uint256 currentAllowance = allowance(owner, spender);
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        unchecked {
            _approve(owner, spender, currentAllowance - subtractedValue);
        }

        return true;
    }

    /**
     * @dev Moves `amount` of tokens from `from` to `to`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     */
    function _transfer(address from, address to, uint256 amount) internal virtual {
        require(from != address(0), "ERC20: transfer from the zero address");
        require(to != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(from, to, amount);

        uint256 fromBalance = _balances[from];
        require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
        unchecked {
            _balances[from] = fromBalance - amount;
            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
            // decrementing then incrementing.
            _balances[to] += amount;
        }

        emit Transfer(from, to, amount);

        _afterTokenTransfer(from, to, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        _beforeTokenTransfer(address(0), account, amount);

        _totalSupply += amount;
        unchecked {
            // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
            _balances[account] += amount;
        }
        emit Transfer(address(0), account, amount);

        _afterTokenTransfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        _beforeTokenTransfer(account, address(0), amount);

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        unchecked {
            _balances[account] = accountBalance - amount;
            // Overflow not possible: amount <= accountBalance <= totalSupply.
            _totalSupply -= amount;
        }

        emit Transfer(account, address(0), amount);

        _afterTokenTransfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(address owner, address spender, uint256 amount) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.
     *
     * Does not update the allowance amount in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Might emit an {Approval} event.
     */
    function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            require(currentAllowance >= amount, "ERC20: insufficient allowance");
            unchecked {
                _approve(owner, spender, currentAllowance - amount);
            }
        }
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}

    /**
     * @dev Hook that is called after any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * has been transferred to `to`.
     * - when `from` is zero, `amount` tokens have been minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}
}
          

lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol

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

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol

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

pragma solidity ^0.8.0;

import "../IERC20.sol";

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

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

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

lib/optimism/packages/contracts-bedrock/src/L2/interfaces/IL2ToL2CrossDomainMessenger.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @title IL2ToL2CrossDomainMessenger
/// @notice Interface for the L2ToL2CrossDomainMessenger contract.
interface IL2ToL2CrossDomainMessenger {
    /// @notice Mapping of message hashes to boolean receipt values. Note that a message will only
    ///         be present in this mapping if it has successfully been relayed on this chain, and
    ///         can therefore not be relayed again.
    /// @param _msgHash message hash to check.
    /// @return Returns true if the message corresponding to the `_msgHash` was successfully relayed.
    function successfulMessages(bytes32 _msgHash) external view returns (bool);

    /// @notice Retrieves the next message nonce. Message version will be added to the upper two
    ///         bytes of the message nonce. Message version allows us to treat messages as having
    ///         different structures.
    /// @return Nonce of the next message to be sent, with added message version.
    function messageNonce() external view returns (uint256);

    /// @notice Retrieves the sender of the current cross domain message.
    /// @return _sender Address of the sender of the current cross domain message.
    function crossDomainMessageSender() external view returns (address _sender);

    /// @notice Retrieves the source of the current cross domain message.
    /// @return _source Chain ID of the source of the current cross domain message.
    function crossDomainMessageSource() external view returns (uint256 _source);

    /// @notice Sends a message to some target address on a destination chain. Note that if the call
    ///         always reverts, then the message will be unrelayable, and any ETH sent will be
    ///         permanently locked. The same will occur if the target on the other chain is
    ///         considered unsafe (see the _isUnsafeTarget() function).
    /// @param _destination Chain ID of the destination chain.
    /// @param _target      Target contract or wallet address.
    /// @param _message     Message to trigger the target address with.
    function sendMessage(uint256 _destination, address _target, bytes calldata _message) external;

    /// @notice Relays a message that was sent by the other CrossDomainMessenger contract. Can only
    ///         be executed via cross-chain call from the other messenger OR if the message was
    ///         already received once and is currently being replayed.
    /// @param _destination Chain ID of the destination chain.
    /// @param _nonce       Nonce of the message being relayed.
    /// @param _sender      Address of the user who sent the message.
    /// @param _source      Chain ID of the source chain.
    /// @param _target      Address that the message is targeted at.
    /// @param _message     Message to send to the target.
    function relayMessage(
        uint256 _destination,
        uint256 _source,
        uint256 _nonce,
        address _sender,
        address _target,
        bytes calldata _message
    )
        external
        payable;
}
          

lib/optimism/packages/contracts-bedrock/src/L2/interfaces/ISuperchainERC20.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Interfaces
import { IERC20Solady } from "src/vendor/interfaces/IERC20Solady.sol";

/// @title ISuperchainERC20Extensions
/// @notice Interface for the extensions to the ERC20 standard that are used by SuperchainERC20.
///         Exists in case developers are already importing the ERC20 interface separately and
///         importing the full SuperchainERC20 interface would cause conflicting imports.
interface ISuperchainERC20Extensions {
    /// @notice Emitted when tokens are sent from one chain to another.
    /// @param from         Address of the sender.
    /// @param to           Address of the recipient.
    /// @param amount       Number of tokens sent.
    /// @param destination  Chain ID of the destination chain.
    event SendERC20(address indexed from, address indexed to, uint256 amount, uint256 destination);

    /// @notice Emitted whenever tokens are successfully relayed on this chain.
    /// @param from     Address of the msg.sender of sendERC20 on the source chain.
    /// @param to       Address of the recipient.
    /// @param amount   Amount of tokens relayed.
    /// @param source   Chain ID of the source chain.
    event RelayERC20(address indexed from, address indexed to, uint256 amount, uint256 source);

    /// @notice Sends tokens to some target address on another chain.
    /// @param _to      Address to send tokens to.
    /// @param _amount  Amount of tokens to send.
    /// @param _chainId Chain ID of the destination chain.
    function sendERC20(address _to, uint256 _amount, uint256 _chainId) external;

    /// @notice Relays tokens received from another chain.
    /// @param _from    Address of the msg.sender of sendERC20 on the source chain.
    /// @param _to      Address to relay tokens to.
    /// @param _amount  Amount of tokens to relay.
    function relayERC20(address _from, address _to, uint256 _amount) external;
}

/// @title ISuperchainERC20Errors
/// @notice Interface containing the errors added in the SuperchainERC20 implementation.
interface ISuperchainERC20Errors {
    /// @notice Thrown when attempting to relay a message and the function caller (msg.sender) is not
    /// L2ToL2CrossDomainMessenger.
    error CallerNotL2ToL2CrossDomainMessenger();

    /// @notice Thrown when attempting to relay a message and the cross domain message sender is not this
    /// SuperchainERC20.
    error InvalidCrossDomainSender();

    /// @notice Thrown when attempting to perform an operation and the account is the zero address.
    error ZeroAddress();
}

/// @title ISuperchainERC20
/// @notice Combines Solady's ERC20 interface with the SuperchainERC20Extensions interface.
interface ISuperchainERC20 is IERC20Solady, ISuperchainERC20Extensions, ISuperchainERC20Errors { }
          

lib/optimism/packages/contracts-bedrock/src/libraries/Predeploys.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @title Predeploys
/// @notice Contains constant addresses for protocol contracts that are pre-deployed to the L2 system.
//          This excludes the preinstalls (non-protocol contracts).
library Predeploys {
    /// @notice Number of predeploy-namespace addresses reserved for protocol usage.
    uint256 internal constant PREDEPLOY_COUNT = 2048;

    /// @custom:legacy
    /// @notice Address of the LegacyMessagePasser predeploy. Deprecate. Use the updated
    ///         L2ToL1MessagePasser contract instead.
    address internal constant LEGACY_MESSAGE_PASSER = 0x4200000000000000000000000000000000000000;

    /// @custom:legacy
    /// @notice Address of the L1MessageSender predeploy. Deprecated. Use L2CrossDomainMessenger
    ///         or access tx.origin (or msg.sender) in a L1 to L2 transaction instead.
    ///         Not embedded into new OP-Stack chains.
    address internal constant L1_MESSAGE_SENDER = 0x4200000000000000000000000000000000000001;

    /// @custom:legacy
    /// @notice Address of the DeployerWhitelist predeploy. No longer active.
    address internal constant DEPLOYER_WHITELIST = 0x4200000000000000000000000000000000000002;

    /// @notice Address of the canonical WETH contract.
    address internal constant WETH = 0x4200000000000000000000000000000000000006;

    /// @notice Address of the L2CrossDomainMessenger predeploy.
    address internal constant L2_CROSS_DOMAIN_MESSENGER = 0x4200000000000000000000000000000000000007;

    /// @notice Address of the GasPriceOracle predeploy. Includes fee information
    ///         and helpers for computing the L1 portion of the transaction fee.
    address internal constant GAS_PRICE_ORACLE = 0x420000000000000000000000000000000000000F;

    /// @notice Address of the L2StandardBridge predeploy.
    address internal constant L2_STANDARD_BRIDGE = 0x4200000000000000000000000000000000000010;

    //// @notice Address of the SequencerFeeWallet predeploy.
    address internal constant SEQUENCER_FEE_WALLET = 0x4200000000000000000000000000000000000011;

    /// @notice Address of the OptimismMintableERC20Factory predeploy.
    address internal constant OPTIMISM_MINTABLE_ERC20_FACTORY = 0x4200000000000000000000000000000000000012;

    /// @custom:legacy
    /// @notice Address of the L1BlockNumber predeploy. Deprecated. Use the L1Block predeploy
    ///         instead, which exposes more information about the L1 state.
    address internal constant L1_BLOCK_NUMBER = 0x4200000000000000000000000000000000000013;

    /// @notice Address of the L2ERC721Bridge predeploy.
    address internal constant L2_ERC721_BRIDGE = 0x4200000000000000000000000000000000000014;

    /// @notice Address of the L1Block predeploy.
    address internal constant L1_BLOCK_ATTRIBUTES = 0x4200000000000000000000000000000000000015;

    /// @notice Address of the L2ToL1MessagePasser predeploy.
    address internal constant L2_TO_L1_MESSAGE_PASSER = 0x4200000000000000000000000000000000000016;

    /// @notice Address of the OptimismMintableERC721Factory predeploy.
    address internal constant OPTIMISM_MINTABLE_ERC721_FACTORY = 0x4200000000000000000000000000000000000017;

    /// @notice Address of the ProxyAdmin predeploy.
    address internal constant PROXY_ADMIN = 0x4200000000000000000000000000000000000018;

    /// @notice Address of the BaseFeeVault predeploy.
    address internal constant BASE_FEE_VAULT = 0x4200000000000000000000000000000000000019;

    /// @notice Address of the L1FeeVault predeploy.
    address internal constant L1_FEE_VAULT = 0x420000000000000000000000000000000000001A;

    /// @notice Address of the SchemaRegistry predeploy.
    address internal constant SCHEMA_REGISTRY = 0x4200000000000000000000000000000000000020;

    /// @notice Address of the EAS predeploy.
    address internal constant EAS = 0x4200000000000000000000000000000000000021;

    /// @notice Address of the GovernanceToken predeploy.
    address internal constant GOVERNANCE_TOKEN = 0x4200000000000000000000000000000000000042;

    /// @custom:legacy
    /// @notice Address of the LegacyERC20ETH predeploy. Deprecated. Balances are migrated to the
    ///         state trie as of the Bedrock upgrade. Contract has been locked and write functions
    ///         can no longer be accessed.
    address internal constant LEGACY_ERC20_ETH = 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000;

    /// @notice Address of the CrossL2Inbox predeploy.
    address internal constant CROSS_L2_INBOX = 0x4200000000000000000000000000000000000022;

    /// @notice Address of the L2ToL2CrossDomainMessenger predeploy.
    address internal constant L2_TO_L2_CROSS_DOMAIN_MESSENGER = 0x4200000000000000000000000000000000000023;

    /// @notice Address of the SuperchainWETH predeploy.
    address internal constant SUPERCHAIN_WETH = 0x4200000000000000000000000000000000000024;

    /// @notice Address of the ETHLiquidity predeploy.
    address internal constant ETH_LIQUIDITY = 0x4200000000000000000000000000000000000025;

    /// @notice Address of the OptimismSuperchainERC20Factory predeploy.
    address internal constant OPTIMISM_SUPERCHAIN_ERC20_FACTORY = 0x4200000000000000000000000000000000000026;

    /// @notice Address of the OptimismSuperchainERC20Beacon predeploy.
    address internal constant OPTIMISM_SUPERCHAIN_ERC20_BEACON = 0x4200000000000000000000000000000000000027;

    // TODO: Precalculate the address of the implementation contract
    /// @notice Arbitrary address of the OptimismSuperchainERC20 implementation contract.
    address internal constant OPTIMISM_SUPERCHAIN_ERC20 = 0xB9415c6cA93bdC545D4c5177512FCC22EFa38F28;

    /// @notice Returns the name of the predeploy at the given address.
    function getName(address _addr) internal pure returns (string memory out_) {
        require(isPredeployNamespace(_addr), "Predeploys: address must be a predeploy");
        if (_addr == LEGACY_MESSAGE_PASSER) return "LegacyMessagePasser";
        if (_addr == L1_MESSAGE_SENDER) return "L1MessageSender";
        if (_addr == DEPLOYER_WHITELIST) return "DeployerWhitelist";
        if (_addr == WETH) return "WETH";
        if (_addr == L2_CROSS_DOMAIN_MESSENGER) return "L2CrossDomainMessenger";
        if (_addr == GAS_PRICE_ORACLE) return "GasPriceOracle";
        if (_addr == L2_STANDARD_BRIDGE) return "L2StandardBridge";
        if (_addr == SEQUENCER_FEE_WALLET) return "SequencerFeeVault";
        if (_addr == OPTIMISM_MINTABLE_ERC20_FACTORY) return "OptimismMintableERC20Factory";
        if (_addr == L1_BLOCK_NUMBER) return "L1BlockNumber";
        if (_addr == L2_ERC721_BRIDGE) return "L2ERC721Bridge";
        if (_addr == L1_BLOCK_ATTRIBUTES) return "L1Block";
        if (_addr == L2_TO_L1_MESSAGE_PASSER) return "L2ToL1MessagePasser";
        if (_addr == OPTIMISM_MINTABLE_ERC721_FACTORY) return "OptimismMintableERC721Factory";
        if (_addr == PROXY_ADMIN) return "ProxyAdmin";
        if (_addr == BASE_FEE_VAULT) return "BaseFeeVault";
        if (_addr == L1_FEE_VAULT) return "L1FeeVault";
        if (_addr == SCHEMA_REGISTRY) return "SchemaRegistry";
        if (_addr == EAS) return "EAS";
        if (_addr == GOVERNANCE_TOKEN) return "GovernanceToken";
        if (_addr == LEGACY_ERC20_ETH) return "LegacyERC20ETH";
        if (_addr == CROSS_L2_INBOX) return "CrossL2Inbox";
        if (_addr == L2_TO_L2_CROSS_DOMAIN_MESSENGER) return "L2ToL2CrossDomainMessenger";
        if (_addr == SUPERCHAIN_WETH) return "SuperchainWETH";
        if (_addr == ETH_LIQUIDITY) return "ETHLiquidity";
        if (_addr == OPTIMISM_SUPERCHAIN_ERC20_FACTORY) return "OptimismSuperchainERC20Factory";
        if (_addr == OPTIMISM_SUPERCHAIN_ERC20_BEACON) return "OptimismSuperchainERC20Beacon";
        revert("Predeploys: unnamed predeploy");
    }

    /// @notice Returns true if the predeploy is not proxied.
    function notProxied(address _addr) internal pure returns (bool) {
        return _addr == GOVERNANCE_TOKEN || _addr == WETH;
    }

    /// @notice Returns true if the address is a defined predeploy that is embedded into new OP-Stack chains.
    function isSupportedPredeploy(address _addr, bool _useInterop) internal pure returns (bool) {
        return _addr == LEGACY_MESSAGE_PASSER || _addr == DEPLOYER_WHITELIST || _addr == WETH
            || _addr == L2_CROSS_DOMAIN_MESSENGER || _addr == GAS_PRICE_ORACLE || _addr == L2_STANDARD_BRIDGE
            || _addr == SEQUENCER_FEE_WALLET || _addr == OPTIMISM_MINTABLE_ERC20_FACTORY || _addr == L1_BLOCK_NUMBER
            || _addr == L2_ERC721_BRIDGE || _addr == L1_BLOCK_ATTRIBUTES || _addr == L2_TO_L1_MESSAGE_PASSER
            || _addr == OPTIMISM_MINTABLE_ERC721_FACTORY || _addr == PROXY_ADMIN || _addr == BASE_FEE_VAULT
            || _addr == L1_FEE_VAULT || _addr == SCHEMA_REGISTRY || _addr == EAS || _addr == GOVERNANCE_TOKEN
            || (_useInterop && _addr == CROSS_L2_INBOX) || (_useInterop && _addr == L2_TO_L2_CROSS_DOMAIN_MESSENGER)
            || (_useInterop && _addr == SUPERCHAIN_WETH) || (_useInterop && _addr == ETH_LIQUIDITY)
            || (_useInterop && _addr == OPTIMISM_SUPERCHAIN_ERC20_FACTORY)
            || (_useInterop && _addr == OPTIMISM_SUPERCHAIN_ERC20_BEACON);
    }

    function isPredeployNamespace(address _addr) internal pure returns (bool) {
        return uint160(_addr) >> 11 == uint160(0x4200000000000000000000000000000000000000) >> 11;
    }

    /// @notice Function to compute the expected address of the predeploy implementation
    ///         in the genesis state.
    function predeployToCodeNamespace(address _addr) internal pure returns (address) {
        require(
            isPredeployNamespace(_addr), "Predeploys: can only derive code-namespace address for predeploy addresses"
        );
        return address(
            uint160(uint256(uint160(_addr)) & 0xffff | uint256(uint160(0xc0D3C0d3C0d3C0D3c0d3C0d3c0D3C0d3c0d30000)))
        );
    }
}
          

lib/optimism/packages/contracts-bedrock/src/vendor/interfaces/IERC20Solady.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IERC20Solady {
    /// @dev The total supply has overflowed.
    error TotalSupplyOverflow();

    /// @dev The allowance has overflowed.
    error AllowanceOverflow();

    /// @dev The allowance has underflowed.
    error AllowanceUnderflow();

    /// @dev Insufficient balance.
    error InsufficientBalance();

    /// @dev Insufficient allowance.
    error InsufficientAllowance();

    /// @dev The permit is invalid.
    error InvalidPermit();

    /// @dev The permit has expired.
    error PermitExpired();

    /// @dev Emitted when `amount` tokens is transferred from `from` to `to`.
    event Transfer(address indexed from, address indexed to, uint256 amount);

    /// @dev Emitted when `amount` tokens is approved by `owner` to be used by `spender`.
    event Approval(address indexed owner, address indexed spender, uint256 amount);

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

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

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

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

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

    /// @dev Returns the amount of tokens that `spender` can spend on behalf of `owner`.
    function allowance(address owner, address spender) external view returns (uint256 result);

    /// @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
    ///
    /// Emits a {Approval} event.
    function approve(address spender, uint256 amount) external returns (bool);

    /// @dev Transfer `amount` tokens from the caller to `to`.
    ///
    /// Requirements:
    /// - `from` must at least have `amount`.
    ///
    /// Emits a {Transfer} event.
    function transfer(address to, uint256 amount) external returns (bool);

    /// @dev Transfers `amount` tokens from `from` to `to`.
    ///
    /// Note: Does not update the allowance if it is the maximum uint256 value.
    ///
    /// Requirements:
    /// - `from` must at least have `amount`.
    /// - The caller must have at least `amount` of allowance to transfer the tokens of `from`.
    ///
    /// Emits a {Transfer} event.
    function transferFrom(address from, address to, uint256 amount) external returns (bool);

    /// @dev Returns the current nonce for `owner`.
    /// This value is used to compute the signature for EIP-2612 permit.
    function nonces(address owner) external view returns (uint256 result);

    /// @dev Sets `value` as the allowance of `spender` over the tokens of `owner`,
    /// authorized by a signed approval by `owner`.
    ///
    /// Emits a {Approval} event.
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    )
        external;

    /// @dev Returns the EIP-712 domain separator for the EIP-2612 permit.
    function DOMAIN_SEPARATOR() external view returns (bytes32 result);
}
          

src/components/SuperchainERC20.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

import {
    ISuperchainERC20Extensions,
    ISuperchainERC20Errors
} from "optimism/packages/contracts-bedrock/src/L2/interfaces/ISuperchainERC20.sol";
// import { ERC20 } from "@solady/tokens/ERC20.sol";
import {IL2ToL2CrossDomainMessenger} from
    "optimism/packages/contracts-bedrock/src/L2/interfaces/IL2ToL2CrossDomainMessenger.sol";
import {Predeploys} from "optimism/packages/contracts-bedrock/src/libraries/Predeploys.sol";
import {ERC20} from "openzeppelin-contracts/token/ERC20/ERC20.sol";

/// @title SuperchainERC20
/// @notice SuperchainERC20 is a standard extension of the base ERC20 token contract that unifies ERC20 token
///         bridging to make it fungible across the Superchain. It builds on top of the L2ToL2CrossDomainMessenger for
///         both replay protection and domain binding.
abstract contract SuperchainERC20 is ISuperchainERC20Extensions, ISuperchainERC20Errors, ERC20 {
    /// @notice Address of the L2ToL2CrossDomainMessenger Predeploy.
    address internal constant MESSENGER = Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER;

    /// @notice Sends tokens to some target address on another chain.
    /// @param _to      Address to send tokens to.
    /// @param _amount  Amount of tokens to send.
    /// @param _chainId Chain ID of the destination chain.
    function sendERC20(address _to, uint256 _amount, uint256 _chainId) external virtual {
        if (_to == address(0)) revert ZeroAddress();

        _burn(msg.sender, _amount);

        bytes memory _message = abi.encodeCall(this.relayERC20, (msg.sender, _to, _amount));
        IL2ToL2CrossDomainMessenger(MESSENGER).sendMessage(_chainId, address(this), _message);

        emit SendERC20(msg.sender, _to, _amount, _chainId);
    }

    /// @notice Relays tokens received from another chain.
    /// @param _from   Address of the msg.sender of sendERC20 on the source chain.
    /// @param _to     Address to relay tokens to.
    /// @param _amount Amount of tokens to relay.
    function relayERC20(address _from, address _to, uint256 _amount) external virtual {
        if (msg.sender != MESSENGER) revert CallerNotL2ToL2CrossDomainMessenger();

        if (IL2ToL2CrossDomainMessenger(MESSENGER).crossDomainMessageSender() != address(this)) {
            revert InvalidCrossDomainSender();
        }

        uint256 source = IL2ToL2CrossDomainMessenger(MESSENGER).crossDomainMessageSource();

        _mint(_to, _amount);

        emit RelayERC20(_from, _to, _amount, source);
    }
}
          

src/interfaces/IExecution.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.3;

enum SQState {
    None,
    Initialized,
    Valid,
    Executed,
    Stale
}

enum MovementType {
    Revert,
    AgentMajority,
    EnergeticMajority
}

struct Call {
    address target;
    bytes callData;
}

struct Movement {
    MovementType category;
    address initiatior;
    address exeAccount;
    uint256 viaNode;
    uint256 expiresAt;
    bytes32 descriptionHash;
    bytes executedPayload;
}

struct SignatureQueue {
    SQState state;
    Movement Action;
    address[] Signers;
    bytes[] Sigs;
    bytes32 exeSig;
}

struct UserSignal {
    string[2][] MembraneInflation;
    string[] lastRedistSignal;
}

struct NodeState {
    string[9] basicInfo; // [nodeId, inflation, balanceAnchor, balanceBudget, value, membraneId, balanceOfUser, childParentEligibilityPerSec, lastParentRedistribution ]
    string membraneMeta;
    address[] membersOfNode;
    string[] childrenNodes;
    string[] rootPath;
    UserSignal[] signals;
}

interface IExecution {
    function createEndpointForOwner(address origin, uint256 nodeId_, address owner)
        external
        returns (address endpoint);

    function executeQueue(bytes32 SignatureQueueHash_) external returns (bool s);

    function submitSignatures(bytes32 sigHash, address[] memory signers, bytes[] memory signatures) external;

    function startMovement(
        address origin,
        uint8 typeOfMovement,
        uint256 node_,
        uint256 expiresInDays,
        address executingAccount,
        bytes32 descriptionHash,
        bytes memory data
    ) external returns (bytes32 movementHash);

    function setWillWe(address WillWeImplementationAddress) external;

    /// View

    function isQueueValid(bytes32 sigHash) external view returns (bool);

    function FoundingAgent() external returns (address);

    function WillToken() external view returns (address);

    function getSigQueue(bytes32 hash_) external view returns (SignatureQueue memory);

    /// @notice retrieves the node or agent  that owns the execution account
    /// @param endpointAddress execution account for which to retrieve owner
    /// @dev in case of user-driven endpoints the returned value is uint160( address of endpoint creator )
    function endpointOwner(address endpointAddress) external view returns (uint256);

    function isValidSignature(bytes32 _hash, bytes memory _signature) external view returns (bytes4);

    function hashMessage(Movement memory movement) external view returns (bytes32);

    //// cleanup functions

    function removeSignature(bytes32 sigHash_, uint256 index_, address who_) external;

    function removeLatentAction(bytes32 actionHash_, uint256 index) external;
}
          

src/interfaces/IFun.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.3;

import {IERC1155} from "openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol";
import {IExecution, SignatureQueue, NodeState} from "./IExecution.sol";

interface IFun is IERC1155, IExecution {
    function spawnRootBranch(address fungible20_) external returns (uint256 fID);

    function spawnBranch(uint256 fid_) external returns (uint256 newID);

    function spawnBranchWithMembrane(uint256 fid_, uint256 membraneID_) external returns (uint256 newID);

    function mintMembership(uint256 fid_, address to_) external returns (uint256 mID);

    function membershipEnforce(address target, uint256 fid_) external returns (bool s);
    function burn(uint256 fid_, uint256 amount_) external;
    function allMembersOf(uint256 fid_) external view returns (address[] memory);
    function mint(uint256 fid_, uint256 amount_) external;
    function toID(address x) external view returns (uint256);
    function toAddress(uint256 x) external view returns (address);
    function isMember(address whoabout_, uint256 whereabout_) external view returns (bool);
    function getInUseMemberaneID(uint256 fid_) external view returns (uint256 membraneID_);
    function getMembraneOf(uint256 fid_) external view returns (uint256);
    function getChildrenOf(uint256 fid_) external view returns (uint256[] memory);
    function getParentOf(uint256 fid_) external view returns (uint256);
    function membershipID(uint256 fid_) external pure returns (uint256);
    function getRootId(uint256 fid_) external view returns (uint256);
    function getRootToken(uint256 fid_) external view returns (address);
    function fungo() external returns (address);
    function createEndpointForOwner(uint256 nodeId_, address owner) external returns (address endpoint);
    function localizeEndpoint(address endpointAddress, uint256 endpointParent_, address endpointOwner_) external;
    function getSigQueue(bytes32 hash_) external view returns (SignatureQueue memory);
    function totalSupply(uint256 nodeId) external view returns (uint256);
    function executionEngineAddress() external view returns (address);
    function rule() external;
    function Will() external view returns (address);
    function getUserInteractions(address user_) external view returns (uint256[][2] memory);
    function removeSignature(bytes32 sigHash_, uint256 index_) external;

    function inParentDenomination(uint256 amt_, uint256 id_) external view returns (uint256);
    function getFidPath(uint256 fid_) external view returns (uint256[] memory fids);
    function burnPath(uint256 target_, uint256 amount) external;
    function mintPath(uint256 target_, uint256 amount) external;
    function sendSignal(uint256 targetNode_, uint256[] memory signals) external;
    function initSelfControl() external returns (address controlingAgent);

    //// Data
    function getNodeData(uint256 n) external view returns (NodeState memory N);
    function getNodes(uint256[] memory nodeIds) external view returns (NodeState[] memory nodes);
    function getAllNodesForRoot(address rootAddress, address userIfAny)
        external
        view
        returns (NodeState[] memory nodes);
}
          

Compiler Settings

{"viaIR":false,"remappings":["openzeppelin-contracts/token/=lib/openzeppelin-contracts/contracts/token/","openzeppelin-contracts/contracts/=lib/openzeppelin-contracts/contracts/","@solady/=lib/solady/src/","src/vendor/interfaces/=lib/optimism/packages/contracts-bedrock/src/vendor/interfaces/","@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/","@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/","ERC20ASG/=lib/ERC20ASG/","automate/=lib/optimism/packages/contracts-bedrock/lib/automate/contracts/","ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/","erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/","forge-std/=lib/forge-std/src/","halmos-cheatcodes/=lib/halmos-cheatcodes/src/","kontrol-cheatcodes/=lib/optimism/packages/contracts-bedrock/lib/kontrol-cheatcodes/src/","lib-keccak/=lib/optimism/packages/contracts-bedrock/lib/lib-keccak/contracts/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/","openzeppelin-contracts-v5/=lib/optimism/packages/contracts-bedrock/lib/openzeppelin-contracts-v5/","openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/","openzeppelin/=lib/openzeppelin-contracts/contracts/","optimism/=lib/optimism/","prb-test/=lib/optimism/packages/contracts-bedrock/lib/automate/lib/prb-test/src/","safe-contracts/=lib/optimism/packages/contracts-bedrock/lib/safe-contracts/contracts/","solady/=lib/solady/src/","solidity-stringutils/=lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/","solmate/=lib/optimism/packages/contracts-bedrock/lib/solmate/src/"],"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata","storageLayout"],"":["ast"]}},"optimizer":{"runs":800,"enabled":true},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"libraries":{},"evmVersion":"paris"}
              

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"uint256","name":"price_","internalType":"uint256"},{"type":"uint256","name":"pps_","internalType":"uint256"},{"type":"address[]","name":"initMintAddrs_","internalType":"address[]"},{"type":"uint256[]","name":"initMintAmts_","internalType":"uint256[]"}]},{"type":"error","name":"ATransferFailed","inputs":[]},{"type":"error","name":"BurnRefundF","inputs":[]},{"type":"error","name":"CallerNotL2ToL2CrossDomainMessenger","inputs":[]},{"type":"error","name":"DelegateCallFailed","inputs":[]},{"type":"error","name":"InsufficentBalance","inputs":[]},{"type":"error","name":"InvalidCalldata","inputs":[]},{"type":"error","name":"InvalidCrossDomainSender","inputs":[]},{"type":"error","name":"OnlyFun","inputs":[]},{"type":"error","name":"PayCallF","inputs":[]},{"type":"error","name":"PingF","inputs":[]},{"type":"error","name":"Reentrant","inputs":[]},{"type":"error","name":"UnqualifiedCall","inputs":[]},{"type":"error","name":"ValueMismatch","inputs":[]},{"type":"error","name":"ZeroAddress","inputs":[]},{"type":"event","name":"Approval","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"address","name":"spender","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RelayERC20","inputs":[{"type":"address","name":"from","internalType":"address","indexed":true},{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"uint256","name":"source","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SendERC20","inputs":[{"type":"address","name":"from","internalType":"address","indexed":true},{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"uint256","name":"destination","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Transfer","inputs":[{"type":"address","name":"from","internalType":"address","indexed":true},{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"fallback","stateMutability":"payable"},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"allowance","inputs":[{"type":"address","name":"owner","internalType":"address"},{"type":"address","name":"spender","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"approve","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"balanceOf","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"amtValReturned","internalType":"uint256"}],"name":"burn","inputs":[{"type":"uint256","name":"howMany_","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"rv","internalType":"uint256"}],"name":"burnReturns","inputs":[{"type":"uint256","name":"amt_","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"amount","internalType":"uint256"}],"name":"burnTo","inputs":[{"type":"uint256","name":"howMany_","internalType":"uint256"},{"type":"address","name":"to_","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"currentPrice","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"decimals","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"shareBurned","internalType":"uint256"}],"name":"deconstructBurn","inputs":[{"type":"uint256","name":"amountToBurn_","internalType":"uint256"},{"type":"address[]","name":"tokensToRedeem","internalType":"address[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"decreaseAllowance","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"subtractedValue","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"increaseAllowance","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"addedValue","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"initTime","inputs":[]},{"type":"function","stateMutability":"payable","outputs":[],"name":"mint","inputs":[{"type":"uint256","name":"howMany_","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"mintCost","inputs":[{"type":"uint256","name":"amt_","internalType":"uint256"}]},{"type":"function","stateMutability":"payable","outputs":[{"type":"uint256","name":"howMuchMinted","internalType":"uint256"}],"name":"mintFromETH","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"name","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"pps","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"relayERC20","inputs":[{"type":"address","name":"_from","internalType":"address"},{"type":"address","name":"_to","internalType":"address"},{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"sendERC20","inputs":[{"type":"address","name":"_to","internalType":"address"},{"type":"uint256","name":"_amount","internalType":"uint256"},{"type":"uint256","name":"_chainId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"amtValReturned","internalType":"uint256"}],"name":"simpleBurn","inputs":[{"type":"uint256","name":"amountToBurn_","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"symbol","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalSupply","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transfer","inputs":[{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transferFrom","inputs":[{"type":"address","name":"from","internalType":"address"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"receive","stateMutability":"payable"}]
              

Contract Creation Code

0x60e060405234801561001057600080fd5b506040516120d53803806120d583398101604081905261002f91610390565b6040518060400160405280601581526020017f57494c4c20526f6f742056616c756520546f6b656e00000000000000000000008152506040518060400160405280600481526020016315d4959560e21b81525085858585858581600390816100979190610500565b5060046100a48282610500565b505050836000146100c2576100bd84633b9aca006105d5565b6100e4565b6100cd600a306105f2565b6100e4906001600160a01b0316633b9aca00610626565b60805282156100f357826100f9565b633b9aca005b60c0524260a05281511580159061012a575060008160008151811061012057610120610639565b6020026020010151115b156101e157600093505b81518410156101e15760006001600160a01b031682858151811061015a5761015a610639565b60200260200101516001600160a01b03161480610190575080848151811061018457610184610639565b60200260200101516000145b610134576101d68285815181106101a9576101a9610639565b60200260200101518286815181106101c3576101c3610639565b60200260200101516101f060201b60201c565b836001019350610134565b5050505050505050505061064f565b6001600160a01b03821661024a5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015260640160405180910390fd5b806002600082825461025c9190610626565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156102f6576102f66102b8565b604052919050565b60006001600160401b03821115610317576103176102b8565b5060051b60200190565b600082601f83011261033257600080fd5b81516020610347610342836102fe565b6102ce565b8083825260208201915060208460051b87010193508684111561036957600080fd5b602086015b84811015610385578051835291830191830161036e565b509695505050505050565b600080600080608085870312156103a657600080fd5b845160208087015160408801519296509450906001600160401b03808211156103ce57600080fd5b818801915088601f8301126103e257600080fd5b81516103f0610342826102fe565b81815260059190911b8301840190848101908b83111561040f57600080fd5b938501935b828510156104435784516001600160a01b03811681146104345760008081fd5b82529385019390850190610414565b60608b0151909750945050508083111561045c57600080fd5b505061046a87828801610321565b91505092959194509250565b600181811c9082168061048a57607f821691505b6020821081036104aa57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156102b3576000816000526020600020601f850160051c810160208610156104d95750805b601f850160051c820191505b818110156104f8578281556001016104e5565b505050505050565b81516001600160401b03811115610519576105196102b8565b61052d816105278454610476565b846104b0565b602080601f831160018114610562576000841561054a5750858301515b600019600386901b1c1916600185901b1785556104f8565b600085815260208120601f198616915b8281101561059157888601518255948401946001909101908401610572565b50858210156105af5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176105ec576105ec6105bf565b92915050565b60006001600160a01b038381168061061a57634e487b7160e01b600052601260045260246000fd5b92169190910692915050565b808201808211156105ec576105ec6105bf565b634e487b7160e01b600052603260045260246000fd5b60805160a05160c051611a4961068c600039600081816102de0152610a520152600081816103250152610a2701526000610a7c0152611a496000f3fe60806040526004361061018e5760003560e01c8063571ff20d116100d6578063a0712d681161007f578063b623890111610059578063b623890114610585578063d9f50046146105a5578063dd62ed3e146105c55761019d565b8063a0712d6814610532578063a457c2d714610545578063a9059cbb146105655761019d565b80637db802ca116100b05780637db802ca1461050057806395d89b41146105085780639d1b464a1461051d5761019d565b8063571ff20d1461048a57806370a08231146104aa57806378a3727b146104e05761019d565b806318160ddd11610138578063313ce56711610112578063313ce5671461042e578063395093511461044a57806342966c681461046a5761019d565b806318160ddd146103d957806323b872dd146103ee57806327de8f271461040e5761019d565b8063095ea7b311610169578063095ea7b3146103695780630dc561ba1461039957806313467092146103b95761019d565b806218b1d3146102cc578063041151871461031357806306fdde03146103475761019d565b3661019d5761019b61060b565b005b60646101a860025490565b6101b390604d611509565b6101bd9190611520565b33600090815260208190526040902054116101eb5760405163742b13ff60e11b815260040160405180910390fd5b635e4abfed60e11b6101fe366000611542565b6001600160e01b0319160361019b57601836101561022f57604051638129bbcd60e01b815260040160405180910390fd5b60008061023f3660048184611572565b81019061024c91906115f8565b915091506000826001600160a01b03168260405161026a91906116c4565b600060405180830381855af49150503d80600081146102a5576040519150601f19603f3d011682016040523d82523d6000602084013e6102aa565b606091505b505090508061019b576040516318cecad560e01b815260040160405180910390fd5b3480156102d857600080fd5b506103007f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020015b60405180910390f35b34801561031f57600080fd5b506103007f000000000000000000000000000000000000000000000000000000000000000081565b34801561035357600080fd5b5061035c61062d565b60405161030a919061170c565b34801561037557600080fd5b50610389610384366004611726565b6106bf565b604051901515815260200161030a565b3480156103a557600080fd5b506103006103b4366004611752565b6106d9565b3480156103c557600080fd5b506103006103d4366004611752565b61070a565b3480156103e557600080fd5b50600254610300565b3480156103fa57600080fd5b5061038961040936600461176b565b610743565b34801561041a57600080fd5b50610300610429366004611752565b610767565b34801561043a57600080fd5b506040516012815260200161030a565b34801561045657600080fd5b50610389610465366004611726565b61077c565b34801561047657600080fd5b50610300610485366004611752565b6107bb565b34801561049657600080fd5b506103006104a53660046117ac565b610841565b3480156104b657600080fd5b506103006104c53660046117dc565b6001600160a01b031660009081526020819052604090205490565b3480156104ec57600080fd5b5061019b6104fb3660046117f9565b6108d3565b61030061060b565b34801561051457600080fd5b5061035c610a11565b34801561052957600080fd5b50610300610a20565b61019b610540366004611752565b610aa5565b34801561055157600080fd5b50610389610560366004611726565b610adb565b34801561057157600080fd5b50610389610580366004611726565b610b8a565b34801561059157600080fd5b506103006105a036600461182e565b610b98565b3480156105b157600080fd5b5061019b6105c036600461176b565b610dfb565b3480156105d157600080fd5b506103006105e03660046118ec565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6000610615610a20565b61061f9034611520565b905061062a81610aa5565b90565b60606003805461063c9061191a565b80601f01602080910402602001604051908101604052809291908181526020018280546106689061191a565b80156106b55780601f1061068a576101008083540402835291602001916106b5565b820191906000526020600020905b81548152906001019060200180831161069857829003601f168201915b5050505050905090565b6000336106cd818585610f80565b60019150505b92915050565b6000806106e560025490565b1115610705576002546106f84784611509565b6107029190611520565b90505b919050565b3360009081526020819052604081205482111561073a5760405163064c392760e21b815260040160405180910390fd5b610702826107bb565b6000336107518582856110a5565b61075c858585611137565b506001949350505050565b600081610772610a20565b6107029190611509565b3360008181526001602090815260408083206001600160a01b03871684529091528120549091906106cd90829086906107b690879061194e565b610f80565b60006107c6826106d9565b90506107d2338361130a565b604051600090339083908381818185875af1925050503d8060008114610814576040519150601f19603f3d011682016040523d82523d6000602084013e610819565b606091505b505090508061083b57604051630958b5bb60e41b815260040160405180910390fd5b50919050565b600061084c836106d9565b9050610858338461130a565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146108a5576040519150601f19603f3d011682016040523d82523d6000602084013e6108aa565b606091505b50509050806108cc57604051630958b5bb60e41b815260040160405180910390fd5b5092915050565b6001600160a01b0383166108fa5760405163d92e233d60e01b815260040160405180910390fd5b610904338361130a565b604080513360248201526001600160a01b0385166044820152606480820185905282518083039091018152608490910182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16636cfa802360e11b1790529051637056f41f60e01b81526023602160991b0190637056f41f9061099290859030908690600401611961565b600060405180830381600087803b1580156109ac57600080fd5b505af11580156109c0573d6000803e3d6000fd5b505060408051868152602081018690526001600160a01b03881693503392507ffcea3600a13c757f2758710b089cc9752781c35d2a9d6804370ed18cd82f0bb691015b60405180910390a350505050565b60606004805461063c9061191a565b6000610a4c7f000000000000000000000000000000000000000000000000000000000000000042611992565b610a76907f0000000000000000000000000000000000000000000000000000000000000000611509565b610aa0907f000000000000000000000000000000000000000000000000000000000000000061194e565b905090565b610aae81610767565b341015610ace5760405163dd8e4af760e01b815260040160405180910390fd5b610ad83382611434565b50565b3360008181526001602090815260408083206001600160a01b038716845290915281205490919083811015610b7d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f00000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61075c8286868403610f80565b6000336106cd818585611137565b33600090815260208190526040812054831115610bc85760405163064c392760e21b815260040160405180910390fd5b82610bd260025490565b610bdc9190611520565b9050610be8338461130a565b60055460ff1615610c0c5760405163769dd35360e11b815260040160405180910390fd5b6005805460ff191660019081179091556000905b8351821015610d79576000848381518110610c3d57610c3d6119a5565b60209081029190910101516040516370a0823160e01b81523060048201529091506001600160a01b038216906370a0823190602401602060405180830381865afa158015610c8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cb391906119bb565b95508115610d4f57818015610d4c57506001600160a01b03811663a9059cbb33610cdd878a611520565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af1158015610d28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d4c91906119d4565b91505b81610d6d576040516301fd421760e71b815260040160405180910390fd5b82600101925050610c20565b33610d848447611520565b604051600081818185875af1925050503d8060008114610dc0576040519150601f19603f3d011682016040523d82523d6000602084013e610dc5565b606091505b50508091505080610de9576040516365a1711b60e01b815260040160405180910390fd5b50506005805460ff1916905592915050565b336023602160991b0114610e21576040516265d51560e41b815260040160405180910390fd5b306001600160a01b03166023602160991b016001600160a01b03166338ffde186040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e9491906119f6565b6001600160a01b031614610ebb57604051635e11715560e11b815260040160405180910390fd5b60006023602160991b016001600160a01b031663247944626040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f2691906119bb565b9050610f328383611434565b826001600160a01b0316846001600160a01b03167fc75e22a0b57fb7740dbfc0caa5c6b7a82a2139964e7f1b7be7ac4e8be0f719ba8484604051610a03929190918252602082015260400190565b6001600160a01b038316610fe25760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610b74565b6001600160a01b0382166110435760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610b74565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b6001600160a01b03838116600090815260016020908152604080832093861683529290522054600019811461113157818110156111245760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610b74565b6111318484848403610f80565b50505050565b6001600160a01b0383166111b35760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610b74565b6001600160a01b0382166112155760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610b74565b6001600160a01b038316600090815260208190526040902054818110156112a45760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610b74565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3611131565b6001600160a01b03821661136a5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610b74565b6001600160a01b038216600090815260208190526040902054818110156113de5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610b74565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9101611098565b6001600160a01b03821661148a5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610b74565b806002600082825461149c919061194e565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176106d3576106d36114f3565b60008261153d57634e487b7160e01b600052601260045260246000fd5b500490565b6001600160e01b0319813581811691600485101561156a5780818660040360031b1b83161692505b505092915050565b6000808585111561158257600080fd5b8386111561158f57600080fd5b5050820193919092039150565b6001600160a01b0381168114610ad857600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156115f0576115f06115b1565b604052919050565b6000806040838503121561160b57600080fd5b82356116168161159c565b915060208381013567ffffffffffffffff8082111561163457600080fd5b818601915086601f83011261164857600080fd5b81358181111561165a5761165a6115b1565b61166c601f8201601f191685016115c7565b9150808252878482850101111561168257600080fd5b80848401858401376000848284010152508093505050509250929050565b60005b838110156116bb5781810151838201526020016116a3565b50506000910152565b600082516116d68184602087016116a0565b9190910192915050565b600081518084526116f88160208601602086016116a0565b601f01601f19169290920160200192915050565b60208152600061171f60208301846116e0565b9392505050565b6000806040838503121561173957600080fd5b82356117448161159c565b946020939093013593505050565b60006020828403121561176457600080fd5b5035919050565b60008060006060848603121561178057600080fd5b833561178b8161159c565b9250602084013561179b8161159c565b929592945050506040919091013590565b600080604083850312156117bf57600080fd5b8235915060208301356117d18161159c565b809150509250929050565b6000602082840312156117ee57600080fd5b813561171f8161159c565b60008060006060848603121561180e57600080fd5b83356118198161159c565b95602085013595506040909401359392505050565b6000806040838503121561184157600080fd5b8235915060208084013567ffffffffffffffff8082111561186157600080fd5b818601915086601f83011261187557600080fd5b813581811115611887576118876115b1565b8060051b91506118988483016115c7565b81815291830184019184810190898411156118b257600080fd5b938501935b838510156118dc57843592506118cc8361159c565b82825293850193908501906118b7565b8096505050505050509250929050565b600080604083850312156118ff57600080fd5b823561190a8161159c565b915060208301356117d18161159c565b600181811c9082168061192e57607f821691505b60208210810361083b57634e487b7160e01b600052602260045260246000fd5b808201808211156106d3576106d36114f3565b8381526001600160a01b038316602082015260606040820152600061198960608301846116e0565b95945050505050565b818103818111156106d3576106d36114f3565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156119cd57600080fd5b5051919050565b6000602082840312156119e657600080fd5b8151801515811461171f57600080fd5b600060208284031215611a0857600080fd5b815161171f8161159c56fea26469706673582212202ef304b025ba03afe21c70eacbd98224525b0eba6d5a322131a2c5b4dee46b9f64736f6c6343000819003300000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c9a9c487bb6f53ba8abe8471d39358c875b388c500000000000000000000000032e3c7fd24e175701a35c224f2238d18439c7dbc0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000084595161401484a00000000000000000000000000000000000000000000000009195731e2ce35eb000000

Deployed ByteCode

0x60806040526004361061018e5760003560e01c8063571ff20d116100d6578063a0712d681161007f578063b623890111610059578063b623890114610585578063d9f50046146105a5578063dd62ed3e146105c55761019d565b8063a0712d6814610532578063a457c2d714610545578063a9059cbb146105655761019d565b80637db802ca116100b05780637db802ca1461050057806395d89b41146105085780639d1b464a1461051d5761019d565b8063571ff20d1461048a57806370a08231146104aa57806378a3727b146104e05761019d565b806318160ddd11610138578063313ce56711610112578063313ce5671461042e578063395093511461044a57806342966c681461046a5761019d565b806318160ddd146103d957806323b872dd146103ee57806327de8f271461040e5761019d565b8063095ea7b311610169578063095ea7b3146103695780630dc561ba1461039957806313467092146103b95761019d565b806218b1d3146102cc578063041151871461031357806306fdde03146103475761019d565b3661019d5761019b61060b565b005b60646101a860025490565b6101b390604d611509565b6101bd9190611520565b33600090815260208190526040902054116101eb5760405163742b13ff60e11b815260040160405180910390fd5b635e4abfed60e11b6101fe366000611542565b6001600160e01b0319160361019b57601836101561022f57604051638129bbcd60e01b815260040160405180910390fd5b60008061023f3660048184611572565b81019061024c91906115f8565b915091506000826001600160a01b03168260405161026a91906116c4565b600060405180830381855af49150503d80600081146102a5576040519150601f19603f3d011682016040523d82523d6000602084013e6102aa565b606091505b505090508061019b576040516318cecad560e01b815260040160405180910390fd5b3480156102d857600080fd5b506103007f000000000000000000000000000000000000000000000000000000000000000181565b6040519081526020015b60405180910390f35b34801561031f57600080fd5b506103007f000000000000000000000000000000000000000000000000000000006723a0d481565b34801561035357600080fd5b5061035c61062d565b60405161030a919061170c565b34801561037557600080fd5b50610389610384366004611726565b6106bf565b604051901515815260200161030a565b3480156103a557600080fd5b506103006103b4366004611752565b6106d9565b3480156103c557600080fd5b506103006103d4366004611752565b61070a565b3480156103e557600080fd5b50600254610300565b3480156103fa57600080fd5b5061038961040936600461176b565b610743565b34801561041a57600080fd5b50610300610429366004611752565b610767565b34801561043a57600080fd5b506040516012815260200161030a565b34801561045657600080fd5b50610389610465366004611726565b61077c565b34801561047657600080fd5b50610300610485366004611752565b6107bb565b34801561049657600080fd5b506103006104a53660046117ac565b610841565b3480156104b657600080fd5b506103006104c53660046117dc565b6001600160a01b031660009081526020819052604090205490565b3480156104ec57600080fd5b5061019b6104fb3660046117f9565b6108d3565b61030061060b565b34801561051457600080fd5b5061035c610a11565b34801561052957600080fd5b50610300610a20565b61019b610540366004611752565b610aa5565b34801561055157600080fd5b50610389610560366004611726565b610adb565b34801561057157600080fd5b50610389610580366004611726565b610b8a565b34801561059157600080fd5b506103006105a036600461182e565b610b98565b3480156105b157600080fd5b5061019b6105c036600461176b565b610dfb565b3480156105d157600080fd5b506103006105e03660046118ec565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6000610615610a20565b61061f9034611520565b905061062a81610aa5565b90565b60606003805461063c9061191a565b80601f01602080910402602001604051908101604052809291908181526020018280546106689061191a565b80156106b55780601f1061068a576101008083540402835291602001916106b5565b820191906000526020600020905b81548152906001019060200180831161069857829003601f168201915b5050505050905090565b6000336106cd818585610f80565b60019150505b92915050565b6000806106e560025490565b1115610705576002546106f84784611509565b6107029190611520565b90505b919050565b3360009081526020819052604081205482111561073a5760405163064c392760e21b815260040160405180910390fd5b610702826107bb565b6000336107518582856110a5565b61075c858585611137565b506001949350505050565b600081610772610a20565b6107029190611509565b3360008181526001602090815260408083206001600160a01b03871684529091528120549091906106cd90829086906107b690879061194e565b610f80565b60006107c6826106d9565b90506107d2338361130a565b604051600090339083908381818185875af1925050503d8060008114610814576040519150601f19603f3d011682016040523d82523d6000602084013e610819565b606091505b505090508061083b57604051630958b5bb60e41b815260040160405180910390fd5b50919050565b600061084c836106d9565b9050610858338461130a565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146108a5576040519150601f19603f3d011682016040523d82523d6000602084013e6108aa565b606091505b50509050806108cc57604051630958b5bb60e41b815260040160405180910390fd5b5092915050565b6001600160a01b0383166108fa5760405163d92e233d60e01b815260040160405180910390fd5b610904338361130a565b604080513360248201526001600160a01b0385166044820152606480820185905282518083039091018152608490910182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16636cfa802360e11b1790529051637056f41f60e01b81526023602160991b0190637056f41f9061099290859030908690600401611961565b600060405180830381600087803b1580156109ac57600080fd5b505af11580156109c0573d6000803e3d6000fd5b505060408051868152602081018690526001600160a01b03881693503392507ffcea3600a13c757f2758710b089cc9752781c35d2a9d6804370ed18cd82f0bb691015b60405180910390a350505050565b60606004805461063c9061191a565b6000610a4c7f000000000000000000000000000000000000000000000000000000006723a0d442611992565b610a76907f0000000000000000000000000000000000000000000000000000000000000001611509565b610aa0907f000000000000000000000000000000000000000000000000000000003b9aca0061194e565b905090565b610aae81610767565b341015610ace5760405163dd8e4af760e01b815260040160405180910390fd5b610ad83382611434565b50565b3360008181526001602090815260408083206001600160a01b038716845290915281205490919083811015610b7d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f00000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61075c8286868403610f80565b6000336106cd818585611137565b33600090815260208190526040812054831115610bc85760405163064c392760e21b815260040160405180910390fd5b82610bd260025490565b610bdc9190611520565b9050610be8338461130a565b60055460ff1615610c0c5760405163769dd35360e11b815260040160405180910390fd5b6005805460ff191660019081179091556000905b8351821015610d79576000848381518110610c3d57610c3d6119a5565b60209081029190910101516040516370a0823160e01b81523060048201529091506001600160a01b038216906370a0823190602401602060405180830381865afa158015610c8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cb391906119bb565b95508115610d4f57818015610d4c57506001600160a01b03811663a9059cbb33610cdd878a611520565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af1158015610d28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d4c91906119d4565b91505b81610d6d576040516301fd421760e71b815260040160405180910390fd5b82600101925050610c20565b33610d848447611520565b604051600081818185875af1925050503d8060008114610dc0576040519150601f19603f3d011682016040523d82523d6000602084013e610dc5565b606091505b50508091505080610de9576040516365a1711b60e01b815260040160405180910390fd5b50506005805460ff1916905592915050565b336023602160991b0114610e21576040516265d51560e41b815260040160405180910390fd5b306001600160a01b03166023602160991b016001600160a01b03166338ffde186040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e9491906119f6565b6001600160a01b031614610ebb57604051635e11715560e11b815260040160405180910390fd5b60006023602160991b016001600160a01b031663247944626040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f2691906119bb565b9050610f328383611434565b826001600160a01b0316846001600160a01b03167fc75e22a0b57fb7740dbfc0caa5c6b7a82a2139964e7f1b7be7ac4e8be0f719ba8484604051610a03929190918252602082015260400190565b6001600160a01b038316610fe25760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610b74565b6001600160a01b0382166110435760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610b74565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b6001600160a01b03838116600090815260016020908152604080832093861683529290522054600019811461113157818110156111245760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610b74565b6111318484848403610f80565b50505050565b6001600160a01b0383166111b35760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610b74565b6001600160a01b0382166112155760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610b74565b6001600160a01b038316600090815260208190526040902054818110156112a45760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610b74565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3611131565b6001600160a01b03821661136a5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610b74565b6001600160a01b038216600090815260208190526040902054818110156113de5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610b74565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9101611098565b6001600160a01b03821661148a5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610b74565b806002600082825461149c919061194e565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176106d3576106d36114f3565b60008261153d57634e487b7160e01b600052601260045260246000fd5b500490565b6001600160e01b0319813581811691600485101561156a5780818660040360031b1b83161692505b505092915050565b6000808585111561158257600080fd5b8386111561158f57600080fd5b5050820193919092039150565b6001600160a01b0381168114610ad857600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156115f0576115f06115b1565b604052919050565b6000806040838503121561160b57600080fd5b82356116168161159c565b915060208381013567ffffffffffffffff8082111561163457600080fd5b818601915086601f83011261164857600080fd5b81358181111561165a5761165a6115b1565b61166c601f8201601f191685016115c7565b9150808252878482850101111561168257600080fd5b80848401858401376000848284010152508093505050509250929050565b60005b838110156116bb5781810151838201526020016116a3565b50506000910152565b600082516116d68184602087016116a0565b9190910192915050565b600081518084526116f88160208601602086016116a0565b601f01601f19169290920160200192915050565b60208152600061171f60208301846116e0565b9392505050565b6000806040838503121561173957600080fd5b82356117448161159c565b946020939093013593505050565b60006020828403121561176457600080fd5b5035919050565b60008060006060848603121561178057600080fd5b833561178b8161159c565b9250602084013561179b8161159c565b929592945050506040919091013590565b600080604083850312156117bf57600080fd5b8235915060208301356117d18161159c565b809150509250929050565b6000602082840312156117ee57600080fd5b813561171f8161159c565b60008060006060848603121561180e57600080fd5b83356118198161159c565b95602085013595506040909401359392505050565b6000806040838503121561184157600080fd5b8235915060208084013567ffffffffffffffff8082111561186157600080fd5b818601915086601f83011261187557600080fd5b813581811115611887576118876115b1565b8060051b91506118988483016115c7565b81815291830184019184810190898411156118b257600080fd5b938501935b838510156118dc57843592506118cc8361159c565b82825293850193908501906118b7565b8096505050505050509250929050565b600080604083850312156118ff57600080fd5b823561190a8161159c565b915060208301356117d18161159c565b600181811c9082168061192e57607f821691505b60208210810361083b57634e487b7160e01b600052602260045260246000fd5b808201808211156106d3576106d36114f3565b8381526001600160a01b038316602082015260606040820152600061198960608301846116e0565b95945050505050565b818103818111156106d3576106d36114f3565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156119cd57600080fd5b5051919050565b6000602082840312156119e657600080fd5b8151801515811461171f57600080fd5b600060208284031215611a0857600080fd5b815161171f8161159c56fea26469706673582212202ef304b025ba03afe21c70eacbd98224525b0eba6d5a322131a2c5b4dee46b9f64736f6c63430008190033