ETH Price: $2,513.05 (-0.02%)

Contract

0x66dcc49c47ebc505a4b560fD14Dc143f0098407f
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Confirm Transact...218795332025-02-19 9:31:236 days ago1739957483IN
ENS Nameweb3innovationlab.eth
0 ETH0.000210771.17650048
Submit Transacti...218795092025-02-19 9:26:356 days ago1739957195IN
ENS Nameweb3innovationlab.eth
0 ETH0.000251781.1450247

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
MultisigWallet

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion
File 1 of 6 : MultisigWallet.sol
// SPDX-License-Identifier: MIT
// This file is part of the MultisigWallet project.
// Portions of this code are derived from the OpenZeppelin Contracts library.
// OpenZeppelin Contracts are licensed under the MIT License.
// See the LICENSE and NOTICE files for more details.
pragma solidity ^0.8.7;

import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";

/**
 * @title MultisigWallet
 * @dev A multisig wallet contract that requires multiple confirmations for transactions, including managing owners.
 */
contract MultisigWallet is ReentrancyGuard, IERC721Receiver {
    /**
     * @notice Emitted when a deposit is made.
     * @param sender The address that sent the deposit.
     * @param amountOrTokenId The amount of Ether or the token ID for ERC721 deposits.
     * @param balance The new balance of the wallet after the deposit.
     */
    event Deposit(address indexed sender, uint256 indexed amountOrTokenId, uint256 indexed balance);

    /**
     * @notice Emitted when a transaction is submitted.
     * @param _transactionType The type of the submitted transaction.
     * @param txIndex The index of the submitted transaction.
     * @param to The address to which the transaction is directed.
     * @param value The amount of Ether sent in the transaction.
     * @param tokenAddress The address of the token contract (if applicable).
     * @param amountOrTokenId The amount of tokens or the token ID (if applicable).
     * @param owner The address of the owner who submitted the transaction.
     * @param data The data payload of the transaction.
     */
    event SubmitTransaction(
        TransactionType indexed _transactionType,
        uint256 indexed txIndex,
        address indexed to,
        uint256 value,
        address tokenAddress,
        uint256 amountOrTokenId,
        address owner,
        bytes data
    );

    /**
     * @notice Emitted when a transaction is confirmed by an owner.
     * @param owner The address of the owner who confirmed the transaction.
     * @param txIndex The index of the confirmed transaction.
     */
    event ConfirmTransaction(address indexed owner, uint256 indexed txIndex);

    /**
     * @notice Emitted when a confirmation for a transaction is revoked by an owner.
     * @param owner The address of the owner who revoked the confirmation.
     * @param txIndex The index of the transaction for which the confirmation was revoked.
     */
    event RevokeConfirmation(address indexed owner, uint256 indexed txIndex);

    /**
     * @notice Emitted when a transaction is executed.
     * @param _transactionType The type of the executed transaction.
     * @param txIndex The index of the executed transaction.
     * @param to The address to which the transaction was sent.
     * @param value The amount of Ether sent in the transaction.
     * @param tokenAddress The address of the token contract (if applicable).
     * @param amountOrTokenId The amount of tokens or the token ID (if applicable).
     * @param owner The address of the owner who executed the transaction.
     * @param data The data payload of the transaction.
     */
    event ExecuteTransaction(
        TransactionType indexed _transactionType,
        uint256 indexed txIndex,
        address indexed to,
        uint256 value,
        address tokenAddress,
        uint256 amountOrTokenId,
        address owner,
        bytes data
    );

    /**
     * @notice Emitted for each transfer within a batch transaction.
     * @param recipient The recipient address of the transfer.
     * @param tokenAddress The token contract address (if applicable, `address(0)` for Ether).
     * @param value The amount of Ether or ERC20 tokens transferred.
     * @param tokenId The ID of the ERC721 token transferred (if applicable).
     * @notice Test a large BatchTransfer on a local testnet first to check if the gascosts are within the EVM constraint
     */
    event BatchTransferExecuted(
        address indexed recipient, address indexed tokenAddress, uint256 value, uint256 indexed tokenId
    );

    /**
     * @notice Emitted when a new owner is added to the multisig wallet.
     * @param owner The address of the owner that was added.
     */
    event OwnerAdded(address indexed owner);

    /**
     * @notice Emitted when an owner is removed from the multisig wallet.
     * @param owner The address of the owner that was removed.
     */
    event OwnerRemoved(address indexed owner);

    /**
     * @notice Emitted when all pending transactions are deactivated.
     */
    event PendingTransactionsDeactivated();

    /**
     * @notice Emitted when an owner deactivates their own pending transaction.
     * @param txIndex The index of the transaction that was deactivated.
     * @param owner The address of the owner who deactivated the transaction.
     */
    event DeactivatedMyPendingTransaction(uint256 indexed txIndex, address indexed owner);

    /**
     * @notice Emitted when the contract receives an ERC721 token.
     * @param operator The address which initiated the transfer (i.e., msg.sender).
     * @param from The address which previously owned the token.
     * @param tokenId The identifier of the token being transferred.
     * @param data Additional data with no specified format.
     */
    event ERC721Received(address indexed operator, address indexed from, uint256 indexed tokenId, bytes data);

    /**
     * @enum TransactionType
     * @dev Represents the type of transaction in the multisig wallet.
     * @param ETH Ether transfer.
     * @param ERC20 ERC20 token transfer.
     * @param ERC721 ERC721 token transfer.
     * @param AddOwner Adding a new owner.
     * @param RemoveOwner Removing an existing owner.
     * @param BatchTransaction multiple transfers in one ransaction.
     * @param Other Any other transaction type.
     */
    enum TransactionType {
        ETH, // 0
        ERC20, // 1
        ERC721, // 2
        AddOwner, // 3
        RemoveOwner, // 4
        BatchTransaction, // 5
        Other // 6

    }

    /**
     * @struct Transaction
     * @dev Represents a transaction within the multisig wallet.
     * @param transactionType The type of the transaction.
     * @param isActive Indicates if the transaction is active.
     * @param numConfirmations The number of confirmations the transaction has received.
     * @param owner The address of the owner who submitted the transaction.
     * @param to The destination address of the transaction.
     * @param value The amount of Ether involved in the transaction.
     * @param data The data payload of the transaction.
     */
    struct Transaction {
        TransactionType transactionType;
        bool isActive;
        uint64 numConfirmations;
        address owner;
        address to;
        uint256 value;
        bytes data;
    }

    /// @notice Struct to represent individual bulk transfer details
    struct BatchTransaction {
        address to; // Recipient address
        address tokenAddress; // Token contract address (address(0) for ETH)
        uint256 value; // Ether amount (if ETH) or token amount
        uint256 tokenId; // Token ID (for ERC721)
    }

    /// @notice Array of multisig wallet owners.
    address[] public owners;

    /// @notice Mapping to check if an address is an owner.
    mapping(address => bool) public isOwner;

    /// @notice Nested mapping to track confirmations: transaction index => owner => confirmation status.
    mapping(uint256 => mapping(address => bool)) public isConfirmed;

    /// @notice Array of all submitted transactions.
    Transaction[] public transactions;

    /**
     * @notice Modifier to restrict access to only multisig owners.
     * @dev Reverts if the caller is not an owner.
     */
    modifier onlyMultisigOwner() {
        require(isOwner[msg.sender], "MultisigWallet: Not a multisig owner");
        _;
    }

    /**
     * @notice Modifier to check if a transaction exists.
     * @dev Reverts if the transaction does not exist.
     * @param _txIndex The index of the transaction.
     */
    modifier txExists(uint256 _txIndex) {
        require(_txIndex < transactions.length, "MultisigWallet: Transaction does not exist");
        _;
    }

    /**
     * @notice Modifier to check if a transaction is active.
     * @dev Reverts if the transaction is not active.
     * @param _txIndex The index of the transaction.
     */
    modifier isActive(uint256 _txIndex) {
        require(transactions[_txIndex].isActive, "MultisigWallet: Transaction not active");
        _;
    }

    /**
     * @notice Modifier to ensure the transaction has not been confirmed by the caller.
     * @dev Reverts if the transaction is already confirmed by the caller.
     * @param _txIndex The index of the transaction.
     */
    modifier notConfirmed(uint256 _txIndex) {
        require(!isConfirmed[_txIndex][msg.sender], "MultisigWallet: transaction already confirmed by this owner");
        _;
    }

    /**
     * @notice Initializes the multisig wallet with a list of owners.
     * @dev The constructor sets the initial owners and ensures no duplicates or zero addresses.
     * @param _owners The array of addresses to be set as initial owners.
     */
    constructor(address[] memory _owners) {
        require(_owners.length > 0, "MultisigWallet: at least one owner required");

        for (uint256 i = 0; i < _owners.length; i++) {
            address owner = _owners[i];
            require(owner != address(0), "MultisigWallet: owner address cannot be zero");
            require(!isOwner[owner], "MultisigWallet: duplicate owner address");

            isOwner[owner] = true;
            owners.push(owner);
        }
    }

    /**
     * @notice Fallback function to receive Ether.
     * @dev Emits a {Deposit} event upon receiving Ether.
     */
    receive() external payable {
        emit Deposit(msg.sender, msg.value, address(this).balance);
    }

    /**
     * @notice Submits a transaction to be confirmed by the owners.
     * @dev Depending on the transaction type, it decodes the data and emits a {SubmitTransaction} event. Once submitted the transaction gets directly confirmed for that owner by calling the confirmTransaction funcion.
     * @param _transactionType The type of the transaction.
     * @param _to The address to send the transaction to.
     * @param _value The amount of Ether to send (if applicable).
     * @param _data The data payload of the transaction.
     */
    function submitTransaction(TransactionType _transactionType, address _to, uint256 _value, bytes memory _data)
        public
        onlyMultisigOwner
    {
        uint256 txIndex = transactions.length;

        transactions.push(
            Transaction({
                transactionType: _transactionType,
                to: _to,
                value: _value,
                data: _data,
                isActive: true,
                numConfirmations: 0,
                owner: msg.sender
            })
        );

        address recipient = _to;
        address tokenAddress = address(0);
        uint256 _amountOrTokenId = 0;

        if (_transactionType == TransactionType.ERC20 || _transactionType == TransactionType.ERC721) {
            // Decode the data to extract the token address and amount / tokenId
            (address to, uint256 amountOrTokenId) = decodeTransactionData(_transactionType, _data);
            recipient = to;
            tokenAddress = _to;
            _amountOrTokenId = amountOrTokenId;
        }

        emit SubmitTransaction(
            _transactionType, txIndex, recipient, _value, tokenAddress, _amountOrTokenId, msg.sender, _data
        );

        confirmTransaction(txIndex);
    }

    /**
     * @notice Confirms a submitted transaction.
     * @dev Increments the confirmation count and executes the transaction if enough confirmations are reached.
     * @param _txIndex The index of the transaction to confirm.
     */
    function confirmTransaction(uint256 _txIndex)
        public
        onlyMultisigOwner
        txExists(_txIndex)
        isActive(_txIndex)
        notConfirmed(_txIndex)
    {
        Transaction storage transaction = transactions[_txIndex];
        isConfirmed[_txIndex][msg.sender] = true;
        uint64 newNumConfirmations = transaction.numConfirmations + 1; // doing that to safe gas
        transaction.numConfirmations = newNumConfirmations;

        TransactionType txType = transaction.transactionType; // doing that to safe gas in the hasEnoughConfirmations function

        emit ConfirmTransaction(msg.sender, _txIndex);

        if (hasEnoughConfirmations(newNumConfirmations, txType)) {
            executeTransaction(_txIndex); // this means that the owner who gives the last needed confirmation has to pay for the execution gas fees
        }
    }

    /**
     * @notice Executes a confirmed transaction.
     * @dev Performs the actual transaction based on its type and marks it as inactive after execution. For adding or removing multisig owners, the respective internal function get called.
     * @param _txIndex The index of the transaction to execute.
     */
    function executeTransaction(uint256 _txIndex)
        public
        txExists(_txIndex)
        isActive(_txIndex)
        nonReentrant
        onlyMultisigOwner
    {
        Transaction storage transaction = transactions[_txIndex];

        uint64 numConfirmations = transaction.numConfirmations;
        TransactionType txType = transaction.transactionType;

        require(
            hasEnoughConfirmations(numConfirmations, txType), "MultisigWallet: insufficient confirmations to execute"
        );

        address to = transaction.to;
        uint256 value = transaction.value;
        bytes memory data = transaction.data;
        address recipient = to;
        address tokenAddress = address(0);
        uint256 amountOrTokenId = 0;

        if (txType == TransactionType.BatchTransaction) {
            BatchTransaction[] memory transfers = abi.decode(data, (BatchTransaction[]));
            uint256 len = transfers.length;

            for (uint256 i = 0; i < len; i++) {
                BatchTransaction memory transfer = transfers[i];
                if (transfer.tokenAddress == address(0)) {
                    // Ether transfer
                    require((transfer.tokenId == 0), "BatchTransfer: ETH transfer with TokenId doesn't make sense");
                    (bool success,) = transfer.to.call{value: transfer.value}("");
                    require(success, "BatchTransfer: Ether transfer failed");
                } else if (transfer.tokenId == 0) {
                    // ERC20 transfer
                    require(
                        IERC20(transfer.tokenAddress).transfer(transfer.to, transfer.value),
                        "BatchTransfer: ERC20 transfer failed"
                    );
                } else {
                    // ERC721 transfer
                    IERC721(transfer.tokenAddress).safeTransferFrom(address(this), transfer.to, transfer.tokenId);
                }
                // Emit BatchTransferExecuted event
                emit BatchTransferExecuted(transfer.to, transfer.tokenAddress, transfer.value, transfer.tokenId);
            }
        }

        if (txType == TransactionType.AddOwner) {
            addOwnerInternal(to, _txIndex);
        } else if (txType == TransactionType.RemoveOwner) {
            removeOwnerInternal(to, _txIndex);
        }

        if (txType == TransactionType.ETH || txType == TransactionType.Other) {
            require(to != address(this), "MultisigWallet: cannot call internal functions");
            (bool success,) = to.call{value: value}(data);
            require(success, "MultisigWallet: external call failed");
        }

        if (txType == TransactionType.ERC20 || txType == TransactionType.ERC721) {
            require(to != address(this), "MultisigWallet: cannot call internal functions");
            (bool success,) = to.call{value: value}(data);
            require(success, "MultisigWallet: external call failed");
            // Decode the data to extract the token address and amount / tokenId
            (address _to, uint256 _amountOrTokenId) = decodeTransactionData(txType, data);
            recipient = _to;
            tokenAddress = to;
            amountOrTokenId = _amountOrTokenId;
        }

        transaction.isActive = false;

        emit ExecuteTransaction(txType, _txIndex, recipient, value, tokenAddress, amountOrTokenId, msg.sender, data);
    }

    /**
     * @notice Revokes a confirmation for a transaction.
     * @dev Decrements the confirmation count.
     * @param _txIndex The index of the transaction to revoke confirmation for.
     */
    function revokeConfirmation(uint256 _txIndex) public onlyMultisigOwner txExists(_txIndex) isActive(_txIndex) {
        Transaction storage transaction = transactions[_txIndex];
        require(transaction.isActive, "MultisigWallet: Transaction is not active");
        require(isConfirmed[_txIndex][msg.sender], "MultisigWallet: Transaction has not been confirmed");

        transaction.numConfirmations -= 1;
        isConfirmed[_txIndex][msg.sender] = false;

        emit RevokeConfirmation(msg.sender, _txIndex);
    }

    /**
     * @notice Submits a transaction to send Ether to a specified address.
     * @dev Utilizes {submitTransaction} with `TransactionType.ETH`.
     * @param _to The recipient address.
     * @param _amount The amount of Ether to send (in Wei).
     */
    function sendETH(address _to, uint256 _amount) public onlyMultisigOwner {
        require(_to != address(0), "MultisigWallet: receiver address required");
        require(_amount > 0, "MultisigWallet: Ether (Wei) amount required");
        submitTransaction(TransactionType.ETH, _to, _amount, "");
    }

    /**
     * @notice Adds a new owner to the multisig wallet.
     * @dev Submits a transaction of type `AddOwner` which requires confirmations.
     * @param _newOwner The address of the new owner to be added.
     */
    function addOwner(address _newOwner) public onlyMultisigOwner {
        require(_newOwner != address(0), "MultisigWallet: new owner address required");
        require(!isOwner[_newOwner], "MultisigWallet: owner already exists");
        submitTransaction(TransactionType.AddOwner, _newOwner, 0, "");
    }

    /**
     * @notice Internal function to add a new owner after sufficient confirmations.
     * @dev Adds the new owner, updates mappings, and emits an {OwnerAdded} event.
     * @param _newOwner The address of the new owner to be added.
     * @param _txIndex The index of the transaction that triggered the addition.
     */
    function addOwnerInternal(address _newOwner, uint256 _txIndex)
        internal
        onlyMultisigOwner
        txExists(_txIndex)
        isActive(_txIndex)
    {
        Transaction storage transaction = transactions[_txIndex];
        require(
            transaction.numConfirmations * 3 >= owners.length * 2,
            "MultisigWallet: insufficient confirmations to add owner"
        );

        require(!isOwner[_newOwner], "MultisigWallet: address is already an owner");

        // Clear pending transactions before adding the new owner
        deactivatePendingTransactions();

        isOwner[_newOwner] = true;
        owners.push(_newOwner);

        emit OwnerAdded(_newOwner);
    }

    /**
     * @notice Removes an existing owner from the multisig wallet.
     * @dev Submits a transaction of type `RemoveOwner` which requires confirmations.
     * @param _owner The address of the owner to be removed.
     */
    function removeOwner(address _owner) public onlyMultisigOwner {
        require(_owner != address(0), "MultisigWallet: owner Address that is to be removed is required");
        require(isOwner[_owner], "MultisigWallet: address is not an owner");
        submitTransaction(TransactionType.RemoveOwner, _owner, 0, "");
    }

    /**
     * @notice Internal function to remove an owner after sufficient confirmations.
     * @dev Removes the owner, updates mappings, and emits an {OwnerRemoved} event.
     * @param _owner The address of the owner to be removed.
     * @param _txIndex The index of the transaction that triggered the removal.
     */
    function removeOwnerInternal(address _owner, uint256 _txIndex)
        internal
        onlyMultisigOwner
        txExists(_txIndex)
        isActive(_txIndex)
    {
        Transaction storage transaction = transactions[_txIndex];
        require(
            transaction.numConfirmations * 3 >= owners.length * 2,
            "MultisigWallet: insufficient confirmations to remove owner"
        );

        require(isOwner[_owner], "MultisigWallet: address is not an owner");

        require(owners.length > 1, "MultisigWallet: cannot remove the last owner");

        // Clear pending transactions before adding the new owner
        deactivatePendingTransactions();

        isOwner[_owner] = false;
        for (uint256 i = 0; i < owners.length; i++) {
            if (owners[i] == _owner) {
                owners[i] = owners[owners.length - 1];
                owners.pop();
                break;
            }
        }

        emit OwnerRemoved(_owner);
    }

    /**
     * @notice Submits a transaction to transfer ERC20 tokens.
     * @dev Encodes the ERC20 `transfer` function call and submits it as a transaction.
     * @param _token The ERC20 token contract.
     * @param _to The recipient address.
     * @param _amount The amount of tokens to transfer.
     */
    function transferERC20(IERC20 _token, address _to, uint256 _amount) public onlyMultisigOwner {
        require(address(_token) != address(0), "MultisigWallet: token address required");
        require(_to != address(0), "MultisigWallet: receiver address required");
        require(_amount > 0, "MultisigWallet: token amount required");
        // Encode the transfer data
        bytes memory data = abi.encodeWithSelector(_token.transfer.selector, _to, _amount);
        // Submit the transaction for confirmation
        submitTransaction(TransactionType.ERC20, address(_token), 0, data);
    }

    /**
     * @notice Submits a transaction to transfer ERC20 tokens using `transferFrom`.
     * @dev Encodes the ERC20 `transferFrom` function call and submits it as a transaction.
     * @param _token The ERC20 token contract.
     * @param _from The address from which tokens will be transferred.
     * @param _to The recipient address.
     * @param _amount The amount of tokens to transfer.
     */
    function transferFromERC20(IERC20 _token, address _from, address _to, uint256 _amount) public onlyMultisigOwner {
        require(address(_token) != address(0), "MultisigWallet: token address required");
        require(_from != address(0), "MultisigWallet: the token-owners address is required");
        require(_to != address(0), "MultisigWallet: receiver address required");
        require(_amount > 0, "MultisigWallet: token amount required");
        // Encode the transferFrom data
        bytes memory data = abi.encodeWithSelector(_token.transferFrom.selector, _from, _to, _amount);
        // Submit the transaction for confirmation
        submitTransaction(TransactionType.ERC20, address(_token), 0, data);
    }

    /**
     * @notice Submits a transaction to transfer an ERC721 token.
     * @dev Encodes the ERC721 `safeTransferFrom` function call and submits it as a transaction.
     * @param _token The ERC721 token contract.
     * @param _from The current owner of the token.
     * @param _to The recipient address.
     * @param _tokenId The ID of the token to transfer.
     */
    function safeTransferFromERC721(address _token, address _from, address _to, uint256 _tokenId)
        public
        onlyMultisigOwner
    {
        require(address(_token) != address(0), "MultisigWallet: token address required");
        require(_from != address(0), "MultisigWallet: the tokenowners address is required");
        require(_to != address(0), "MultisigWallet: receiver address required");
        // Encode the transferFrom data
        bytes memory data = abi.encodeWithSignature("safeTransferFrom(address,address,uint256)", _from, _to, _tokenId);
        submitTransaction(TransactionType.ERC721, _token, 0, data);
    }

    /**
     * @notice Submits a BulkTransfer transaction
     * @dev Encodes an array of BulkTransfer structs into the data payload
     * @param transfers Array of BulkTransfer structs representing the transfers
     */
    function batchTransfer(BatchTransaction[] memory transfers) public onlyMultisigOwner {
        bytes memory data = abi.encode(transfers);
        submitTransaction(TransactionType.BatchTransaction, address(this), 0, data);
    }

    /**
     * @notice Deactivates all pending (active) transactions.
     * @dev Iterates through all transactions and marks them as inactive.
     * Emits a {PendingTransactionsDeactivated} event upon completion.
     */
    function deactivatePendingTransactions() internal {
        uint256 length = transactions.length;
        for (uint256 i = 0; i < length;) {
            Transaction storage txn = transactions[i];
            if (txn.isActive) {
                txn.isActive = false;
            }
            unchecked {
                ++i;
            }
        }
        emit PendingTransactionsDeactivated();
    }

    /**
     * @notice Allows an owner to deactivate their own pending transaction.
     * @dev Marks the specified transaction as inactive if it was submitted by the caller.
     * @param _txIndex The index of the transaction to deactivate.
     */
    function deactivateMyPendingTransaction(uint256 _txIndex)
        public
        txExists(_txIndex)
        isActive(_txIndex)
        onlyMultisigOwner
    {
        require(
            transactions[_txIndex].owner == msg.sender,
            "MultisigWallet: only the owner can clear their submitted transaction"
        );

        // Deactivate Transaction
        transactions[_txIndex].isActive = false;

        emit DeactivatedMyPendingTransaction(_txIndex, msg.sender);
    }

    /**
     * @notice Checks if a transaction has received enough confirmations to be executed.
     * @dev The required number of confirmations varies based on the transaction type.
     * @param numConfirmations The current number of confirmations.
     * @param transactionType The type of the transaction.
     * @return True if the transaction has enough confirmations, false otherwise.
     */
    function hasEnoughConfirmations(uint64 numConfirmations, TransactionType transactionType)
        internal
        view
        returns (bool)
    {
        if (transactionType == TransactionType.AddOwner || transactionType == TransactionType.RemoveOwner) {
            // Important decisions require 2/3 or more confirmations
            return numConfirmations * 3 >= owners.length * 2;
        } else {
            // Normal decisions require more than 50% confirmations
            return numConfirmations * 2 > owners.length;
        }
    }

    /**
     * @notice Decodes the transaction data based on the transaction type.
     * @dev Extracts relevant parameters from the data payload for ERC20 and ERC721 transactions.
     * @param transactionType The type of the transaction.
     * @param data The data payload of the transaction.
     * @return to The recipient address extracted from the data.
     * @return amountOrTokenId The amount of tokens or token ID extracted from the data.
     */
    function decodeTransactionData(TransactionType transactionType, bytes memory data)
        internal
        pure
        returns (address to, uint256 amountOrTokenId)
    {
        if (transactionType == TransactionType.ERC20) {
            // ERC20 transfer(address recipient, uint256 amount)
            require(data.length == 68 || data.length == 100, "MultisigWallet: invalid data length for ERC20 transfer");

            // Use assembly to extract parameters directly
            if (data.length == 68) {
                // Handle ERC20 transfer(address to, uint256 amount)
                assembly {
                    // data points to the bytes array in memory
                    // Skip the first 32 bytes (length) and 4 bytes (selector)
                    let paramsOffset := add(data, 36)
                    to := mload(paramsOffset) // Load address (to) at data + 36
                    amountOrTokenId := mload(add(paramsOffset, 32)) // Load uint256 (amount) at data + 68
                }
                return (to, amountOrTokenId);
            } else if (data.length == 100) {
                // Handle ERC20 transferFrom(address from, address to, uint256 amount)
                assembly {
                    // Skip the first 32 bytes (length) and 4 bytes (selector)
                    let paramsOffset := add(data, 36)
                    // from is at data + 36, but we don't need to use it
                    let toAddr := mload(add(paramsOffset, 32)) // Load address (to) at data + 68
                    let amount := mload(add(paramsOffset, 64)) // Load uint256 (amount) at data + 100
                    to := toAddr
                    amountOrTokenId := amount
                }
                return (to, amountOrTokenId);
            }
        } else if (transactionType == TransactionType.ERC721) {
            // ERC721 safeTransferFrom(address from, address to, uint256 tokenId)
            require(data.length == 100, "MultisigWallet: invalid data length for ERC721 transfer");

            // Use assembly to extract parameters directly
            assembly {
                let paramsOffset := add(data, 36)
                // Skipping 'from' address (we don't need it for the return value)
                to := mload(add(paramsOffset, 32)) // Load address (to)
                amountOrTokenId := mload(add(paramsOffset, 64)) // Load uint256 (tokenId)
            }
            return (to, amountOrTokenId);
        } else {
            revert("MultisigWallet: unsupported transaction type for data decoding");
        }
    }

    /**
     * @notice Handles the receipt of an ERC721 token.
     * @dev This function is called whenever an ERC721 `safeTransfer` is performed to this contract.
     * It must return the function selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented, the transfer will be reverted.
     * @param operator The address which called `safeTransferFrom`.
     * @param from The address which previously owned the token.
     * @param tokenId The NFT identifier which is being transferred.
     * @param data Additional data with no specified format.
     * @return bytes4 Returns `IERC721Receiver.onERC721Received.selector` to confirm the token transfer.
     */
    function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data)
        external
        override
        returns (bytes4)
    {
        emit ERC721Received(operator, from, tokenId, data);
        return this.onERC721Received.selector;
    }

    /**
     * @notice Retrieves the total number of owners.
     * @return ownerCount The number of current owners in the multisig wallet.
     */
    function getOwnerCount() public view returns (uint256) {
        uint256 ownerCount = owners.length;
        return ownerCount;
    }

    /**
     * @notice Retrieves the list of all owners.
     * @return ownersList An array containing the addresses of all current owners.
     */
    function getOwners() public view returns (address[] memory) {
        return owners;
    }
}

File 2 of 6 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    uint256 private _status;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    constructor() {
        _status = NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if (_status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        _status = ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == ENTERED;
    }
}

File 3 of 6 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @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 value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

    /**
     * @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` 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 value) external returns (bool);
}

File 4 of 6 : IERC721.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
     *   a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or
     *   {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
     *   a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the address zero.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}

File 5 of 6 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.20;

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721Receiver {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be
     * reverted.
     *
     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

File 6 of 6 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

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

Settings
{
  "remappings": [
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/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/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "viaIR": false,
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address[]","name":"_owners","type":"address[]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":true,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"BatchTransferExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"uint256","name":"txIndex","type":"uint256"}],"name":"ConfirmTransaction","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"txIndex","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"DeactivatedMyPendingTransaction","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"uint256","name":"amountOrTokenId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"balance","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"ERC721Received","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum MultisigWallet.TransactionType","name":"_transactionType","type":"uint8"},{"indexed":true,"internalType":"uint256","name":"txIndex","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOrTokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"ExecuteTransaction","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"OwnerAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"OwnerRemoved","type":"event"},{"anonymous":false,"inputs":[],"name":"PendingTransactionsDeactivated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"uint256","name":"txIndex","type":"uint256"}],"name":"RevokeConfirmation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum MultisigWallet.TransactionType","name":"_transactionType","type":"uint8"},{"indexed":true,"internalType":"uint256","name":"txIndex","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOrTokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"SubmitTransaction","type":"event"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"addOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"internalType":"struct MultisigWallet.BatchTransaction[]","name":"transfers","type":"tuple[]"}],"name":"batchTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_txIndex","type":"uint256"}],"name":"confirmTransaction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_txIndex","type":"uint256"}],"name":"deactivateMyPendingTransaction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_txIndex","type":"uint256"}],"name":"executeTransaction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getOwnerCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOwners","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"isConfirmed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"owners","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"removeOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_txIndex","type":"uint256"}],"name":"revokeConfirmation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"safeTransferFromERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"sendETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum MultisigWallet.TransactionType","name":"_transactionType","type":"uint8"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"submitTransaction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"transactions","outputs":[{"internalType":"enum MultisigWallet.TransactionType","name":"transactionType","type":"uint8"},{"internalType":"bool","name":"isActive","type":"bool"},{"internalType":"uint64","name":"numConfirmations","type":"uint64"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"},{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferFromERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

608060405234801561001057600080fd5b5060405161361838038061361883398101604081905261002f9161025a565b6001600055805161009b5760405162461bcd60e51b815260206004820152602b60248201527f4d756c746973696757616c6c65743a206174206c65617374206f6e65206f776e60448201526a195c881c995c5d5a5c995960aa1b60648201526084015b60405180910390fd5b60005b81518110156102215760008282815181106100bb576100bb610329565b6020026020010151905060006001600160a01b0316816001600160a01b03160361013c5760405162461bcd60e51b815260206004820152602c60248201527f4d756c746973696757616c6c65743a206f776e6572206164647265737320636160448201526b6e6e6f74206265207a65726f60a01b6064820152608401610092565b6001600160a01b03811660009081526002602052604090205460ff16156101b55760405162461bcd60e51b815260206004820152602760248201527f4d756c746973696757616c6c65743a206475706c6963617465206f776e6572206044820152666164647265737360c81b6064820152608401610092565b6001600160a01b03166000818152600260205260408120805460ff1916600190811790915580548082018255918190527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf690910180546001600160a01b0319169092179091550161009e565b505061033f565b634e487b7160e01b600052604160045260246000fd5b80516001600160a01b038116811461025557600080fd5b919050565b60006020828403121561026c57600080fd5b81516001600160401b0381111561028257600080fd5b8201601f8101841361029357600080fd5b80516001600160401b038111156102ac576102ac610228565b604051600582901b90603f8201601f191681016001600160401b03811182821017156102da576102da610228565b6040529182526020818401810192908101878411156102f857600080fd5b6020850194505b8385101561031e576103108561023e565b8152602094850194016102ff565b509695505050505050565b634e487b7160e01b600052603260045260246000fd5b6132ca8061034e6000396000f3fe6080604052600436106101185760003560e01c80638dbcc2e0116100a0578063d47a1a2711610064578063d47a1a271461039b578063d59dafd0146103bb578063dd71105d146103db578063ee22610b146103fb578063ef18374a1461041b57600080fd5b80638dbcc2e0146102e65780639ace38c2146103065780639db5dbe414610339578063a0e67e2b14610359578063c01a8c841461037b57600080fd5b806320ea8d86116100e757806320ea8d861461020b5780632f54bf6e1461022b57806364a197f31461026b5780637065cb481461028b57806380f59a65146102ab57600080fd5b8063025e7c2714610153578063150b7a0214610190578063173825d9146101c95780631afecd1c146101eb57600080fd5b3661014e576040514790349033907f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a1590600090a4005b600080fd5b34801561015f57600080fd5b5061017361016e3660046126bb565b610439565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561019c57600080fd5b506101b06101ab3660046126e9565b610463565b6040516001600160e01b03199091168152602001610187565b3480156101d557600080fd5b506101e96101e4366004612788565b6104c5565b005b3480156101f757600080fd5b506101e96102063660046126bb565b6105d1565b34801561021757600080fd5b506101e96102263660046126bb565b610796565b34801561023757600080fd5b5061025b610246366004612788565b60026020526000908152604090205460ff1681565b6040519015158152602001610187565b34801561027757600080fd5b506101e96102863660046127ac565b6109da565b34801561029757600080fd5b506101e96102a6366004612788565b610ab3565b3480156102b757600080fd5b5061025b6102c63660046127d8565b600360209081526000928352604080842090915290825290205460ff1681565b3480156102f257600080fd5b506101e9610301366004612876565b610bd9565b34801561031257600080fd5b506103266103213660046126bb565b610e28565b60405161018797969594939291906129a7565b34801561034557600080fd5b506101e9610354366004612a21565b610f1c565b34801561036557600080fd5b5061036e611012565b6040516101879190612a62565b34801561038757600080fd5b506101e96103963660046126bb565b611074565b3480156103a757600080fd5b506101e96103b6366004612ad1565b611287565b3480156103c757600080fd5b506101e96103d6366004612bbb565b6112e8565b3480156103e757600080fd5b506101e96103f6366004612bbb565b61143d565b34801561040757600080fd5b506101e96104163660046126bb565b6115a8565b34801561042757600080fd5b50600154604051908152602001610187565b6001818154811061044957600080fd5b6000918252602090912001546001600160a01b0316905081565b600083856001600160a01b0316876001600160a01b03167fa05d90f300156ad1b545bc5d8197024456f21d22a708f5af04dd293e3d60525186866040516104ab929190612c0c565b60405180910390a450630a85bd0160e11b95945050505050565b3360009081526002602052604090205460ff166104fd5760405162461bcd60e51b81526004016104f490612c3b565b60405180910390fd5b6001600160a01b0381166105795760405162461bcd60e51b815260206004820152603f60248201527f4d756c746973696757616c6c65743a206f776e6572204164647265737320746860448201527f617420697320746f2062652072656d6f7665642069732072657175697265640060648201526084016104f4565b6001600160a01b03811660009081526002602052604090205460ff166105b15760405162461bcd60e51b81526004016104f490612c7f565b6105ce600482600060405180602001604052806000815250610bd9565b50565b600454819081106105f45760405162461bcd60e51b81526004016104f490612cc6565b816004818154811061060857610608612d10565b6000918252602090912060049091020154610100900460ff1661063d5760405162461bcd60e51b81526004016104f490612d26565b3360009081526002602052604090205460ff1661066c5760405162461bcd60e51b81526004016104f490612c3b565b336001600160a01b03166004848154811061068957610689612d10565b6000918252602090912060049091020154600160501b90046001600160a01b03161461072b5760405162461bcd60e51b8152602060048201526044602482018190527f4d756c746973696757616c6c65743a206f6e6c7920746865206f776e65722063908201527f616e20636c656172207468656972207375626d6974746564207472616e7361636064820152633a34b7b760e11b608482015260a4016104f4565b60006004848154811061074057610740612d10565b60009182526020822060049091020180549215156101000261ff001990931692909217909155604051339185917f2c8d5957f60f56ae0608f50dbce4cda251ec4ed938d7d2ef7e10297719fdf2539190a3505050565b3360009081526002602052604090205460ff166107c55760405162461bcd60e51b81526004016104f490612c3b565b600454819081106107e85760405162461bcd60e51b81526004016104f490612cc6565b81600481815481106107fc576107fc612d10565b6000918252602090912060049091020154610100900460ff166108315760405162461bcd60e51b81526004016104f490612d26565b60006004848154811061084657610846612d10565b600091825260209091206004909102018054909150610100900460ff166108c15760405162461bcd60e51b815260206004820152602960248201527f4d756c746973696757616c6c65743a205472616e73616374696f6e206973206e6044820152686f742061637469766560b81b60648201526084016104f4565b600084815260036020908152604080832033845290915290205460ff166109455760405162461bcd60e51b815260206004820152603260248201527f4d756c746973696757616c6c65743a205472616e73616374696f6e20686173206044820152711b9bdd081899595b8818dbdb999a5c9b595960721b60648201526084016104f4565b805460019082906002906109699084906201000090046001600160401b0316612d82565b82546001600160401b039182166101009390930a9283029190920219909116179055506000848152600360209081526040808320338085529252808320805460ff191690555186927ff0dca620e2e81f7841d07bcc105e1704fb01475b278a9d4c236e1c62945edd5591a350505050565b3360009081526002602052604090205460ff16610a095760405162461bcd60e51b81526004016104f490612c3b565b6001600160a01b038216610a2f5760405162461bcd60e51b81526004016104f490612da1565b60008111610a935760405162461bcd60e51b815260206004820152602b60248201527f4d756c746973696757616c6c65743a20457468657220285765692920616d6f7560448201526a1b9d081c995c5d5a5c995960aa1b60648201526084016104f4565b610aaf6000838360405180602001604052806000815250610bd9565b5050565b3360009081526002602052604090205460ff16610ae25760405162461bcd60e51b81526004016104f490612c3b565b6001600160a01b038116610b4b5760405162461bcd60e51b815260206004820152602a60248201527f4d756c746973696757616c6c65743a206e6577206f776e6572206164647265736044820152691cc81c995c5d5a5c995960b21b60648201526084016104f4565b6001600160a01b03811660009081526002602052604090205460ff1615610bc05760405162461bcd60e51b8152602060048201526024808201527f4d756c746973696757616c6c65743a206f776e657220616c72656164792065786044820152636973747360e01b60648201526084016104f4565b6105ce6003826000604051806020016040528060008152505b3360009081526002602052604090205460ff16610c085760405162461bcd60e51b81526004016104f490612c3b565b600480546040805160e0810190915290919080876006811115610c2d57610c2d612941565b8152600160208083018290526000604084018190523360608501526001600160a01b038a16608085015260a0840189905260c09093018790528454808301865594835290912082516004909402018054929390929091839160ff191690836006811115610c9c57610c9c612941565b021790555060208201518154604084015160608501516001600160a01b03908116600160501b027fffff0000000000000000000000000000000000000000ffffffffffffffffffff6001600160401b03909316620100000269ffffffffffffffff000019951515610100029590951669ffffffffffffffffff00199094169390931793909317161782556080830151600183018054919092166001600160a01b031990911617905560a0820151600282015560c08201516003820190610d629082612e6b565b5085915060009050806001886006811115610d7f57610d7f612941565b1480610d9c57506002886006811115610d9a57610d9a612941565b145b15610db957600080610dae8a88611dbe565b909550899450925050505b826001600160a01b031684896006811115610dd657610dd6612941565b7f7a9333d5a9c2b79797bf46d7626bd8cda468b400f501bc0ed09cdef2d294c9dd898686338c604051610e0d959493929190612f29565b60405180910390a4610e1e84611074565b5050505050505050565b60048181548110610e3857600080fd5b6000918252602090912060049091020180546001820154600283015460038401805460ff8086169750610100860416956001600160401b0362010000870416956001600160a01b03600160501b9091048116951693929091610e9990612dea565b80601f0160208091040260200160405190810160405280929190818152602001828054610ec590612dea565b8015610f125780601f10610ee757610100808354040283529160200191610f12565b820191906000526020600020905b815481529060010190602001808311610ef557829003601f168201915b5050505050905087565b3360009081526002602052604090205460ff16610f4b5760405162461bcd60e51b81526004016104f490612c3b565b6001600160a01b038316610f715760405162461bcd60e51b81526004016104f490612f6d565b6001600160a01b038216610f975760405162461bcd60e51b81526004016104f490612da1565b60008111610fb75760405162461bcd60e51b81526004016104f490612fb3565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b17905261100c600185600084610bd9565b50505050565b6060600180548060200260200160405190810160405280929190818152602001828054801561106a57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161104c575b5050505050905090565b3360009081526002602052604090205460ff166110a35760405162461bcd60e51b81526004016104f490612c3b565b600454819081106110c65760405162461bcd60e51b81526004016104f490612cc6565b81600481815481106110da576110da612d10565b6000918252602090912060049091020154610100900460ff1661110f5760405162461bcd60e51b81526004016104f490612d26565b6000838152600360209081526040808320338452909152902054839060ff16156111a15760405162461bcd60e51b815260206004820152603b60248201527f4d756c746973696757616c6c65743a207472616e73616374696f6e20616c726560448201527f61647920636f6e6669726d65642062792074686973206f776e6572000000000060648201526084016104f4565b6000600485815481106111b6576111b6612d10565b600091825260208083208884526003825260408085203386529092529083208054600160ff19909116811790915560049290920201805490935061120a91620100009091046001600160401b031690612ff8565b82546001600160401b038216620100000269ffffffffffffffff00001982168117855560405192935060ff90811691161790879033907f5cbe105e36805f7820e291f799d5794ff948af2a5f664e580382defb6339004190600090a36112708282611fa5565b1561127e5761127e876115a8565b50505050505050565b3360009081526002602052604090205460ff166112b65760405162461bcd60e51b81526004016104f490612c3b565b6000816040516020016112c99190613017565b6040516020818303038152906040529050610aaf600530600084610bd9565b3360009081526002602052604090205460ff166113175760405162461bcd60e51b81526004016104f490612c3b565b6001600160a01b03841661133d5760405162461bcd60e51b81526004016104f490612f6d565b6001600160a01b0383166113af5760405162461bcd60e51b815260206004820152603360248201527f4d756c746973696757616c6c65743a2074686520746f6b656e6f776e657273206044820152721859191c995cdcc81a5cc81c995c5d5a5c9959606a1b60648201526084016104f4565b6001600160a01b0382166113d55760405162461bcd60e51b81526004016104f490612da1565b6040516001600160a01b038085166024830152831660448201526064810182905260009060840160408051601f198184030181529190526020810180516001600160e01b0316632142170760e11b1790529050611436600286600084610bd9565b5050505050565b3360009081526002602052604090205460ff1661146c5760405162461bcd60e51b81526004016104f490612c3b565b6001600160a01b0384166114925760405162461bcd60e51b81526004016104f490612f6d565b6001600160a01b0383166115055760405162461bcd60e51b815260206004820152603460248201527f4d756c746973696757616c6c65743a2074686520746f6b656e2d6f776e657273604482015273081859191c995cdcc81a5cc81c995c5d5a5c995960621b60648201526084016104f4565b6001600160a01b03821661152b5760405162461bcd60e51b81526004016104f490612da1565b6000811161154b5760405162461bcd60e51b81526004016104f490612fb3565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052611436600186600084610bd9565b600454819081106115cb5760405162461bcd60e51b81526004016104f490612cc6565b81600481815481106115df576115df612d10565b6000918252602090912060049091020154610100900460ff166116145760405162461bcd60e51b81526004016104f490612d26565b61161c612029565b3360009081526002602052604090205460ff1661164b5760405162461bcd60e51b81526004016104f490612c3b565b60006004848154811061166057611660612d10565b6000918252602090912060049091020180549091506001600160401b03620100008204169060ff166116928282611fa5565b6116fc5760405162461bcd60e51b815260206004820152603560248201527f4d756c746973696757616c6c65743a20696e73756666696369656e7420636f6e6044820152746669726d6174696f6e7320746f206578656375746560581b60648201526084016104f4565b600183015460028401546003850180546001600160a01b03909316926000919061172590612dea565b80601f016020809104026020016040519081016040528092919081815260200182805461175190612dea565b801561179e5780601f106117735761010080835404028352916020019161179e565b820191906000526020600020905b81548152906001019060200180831161178157829003601f168201915b5093945086935060009250829150600590508760068111156117c2576117c2612941565b03611b23576000848060200190518101906117dd9190613080565b805190915060005b81811015611b1f57600083828151811061180157611801612d10565b6020026020010151905060006001600160a01b031681602001516001600160a01b031603611959576060810151156118a15760405162461bcd60e51b815260206004820152603b60248201527f42617463685472616e736665723a20455448207472616e73666572207769746860448201527f20546f6b656e496420646f65736e2774206d616b652073656e7365000000000060648201526084016104f4565b805160408083015190516000926001600160a01b031691908381818185875af1925050503d80600081146118f1576040519150601f19603f3d011682016040523d82523d6000602084013e6118f6565b606091505b50509050806119535760405162461bcd60e51b8152602060048201526024808201527f42617463685472616e736665723a204574686572207472616e736665722066616044820152631a5b195960e21b60648201526084016104f4565b50611ab8565b8060600151600003611a425760208101518151604080840151905163a9059cbb60e01b81526001600160a01b039283166004820152602481019190915291169063a9059cbb906044016020604051808303816000875af11580156119c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119e5919061315b565b611a3d5760405162461bcd60e51b8152602060048201526024808201527f42617463685472616e736665723a204552433230207472616e736665722066616044820152631a5b195960e21b60648201526084016104f4565b611ab8565b602081015181516060830151604051632142170760e11b81523060048201526001600160a01b03928316602482015260448101919091529116906342842e0e90606401600060405180830381600087803b158015611a9f57600080fd5b505af1158015611ab3573d6000803e3d6000fd5b505050505b806060015181602001516001600160a01b031682600001516001600160a01b03167f11545b22e85dd851103fdaeff84f4db960c8ea9ef39898c3f2b32b8e14913bfd8460400151604051611b0e91815260200190565b60405180910390a4506001016117e5565b5050505b6003876006811115611b3757611b37612941565b03611b4b57611b46868d612053565b611b6e565b6004876006811115611b5f57611b5f612941565b03611b6e57611b6e868d6122d0565b6000876006811115611b8257611b82612941565b1480611b9f57506006876006811115611b9d57611b9d612941565b145b15611c4c57306001600160a01b03871603611bcc5760405162461bcd60e51b81526004016104f49061317d565b6000866001600160a01b03168686604051611be791906131cb565b60006040518083038185875af1925050503d8060008114611c24576040519150601f19603f3d011682016040523d82523d6000602084013e611c29565b606091505b5050905080611c4a5760405162461bcd60e51b81526004016104f4906131e7565b505b6001876006811115611c6057611c60612941565b1480611c7d57506002876006811115611c7b57611c7b612941565b145b15611d4157306001600160a01b03871603611caa5760405162461bcd60e51b81526004016104f49061317d565b6000866001600160a01b03168686604051611cc591906131cb565b60006040518083038185875af1925050503d8060008114611d02576040519150601f19603f3d011682016040523d82523d6000602084013e611d07565b606091505b5050905080611d285760405162461bcd60e51b81526004016104f4906131e7565b600080611d358a88611dbe565b90965089955093505050505b885461ff00191689556001600160a01b0383168c886006811115611d6757611d67612941565b7f8486d3d18fdaaf4d3cd166a7275bd95df5e8087a2cc662f6c33164f3052ea6be888686338b604051611d9e959493929190612f29565b60405180910390a4505050505050505050611db96001600055565b505050565b6000806001846006811115611dd557611dd5612941565b03611e8f57825160441480611deb575082516064145b611e565760405162461bcd60e51b815260206004820152603660248201527f4d756c746973696757616c6c65743a20696e76616c69642064617461206c656e60448201527533ba34103337b91022a9219918103a3930b739b332b960511b60648201526084016104f4565b8251604403611e7057505060248101516044820151611f9e565b8251606403611e8a57505060448101516064820151611f9e565b611f9e565b6002846006811115611ea357611ea3612941565b03611f30578251606414611f1f5760405162461bcd60e51b815260206004820152603760248201527f4d756c746973696757616c6c65743a20696e76616c69642064617461206c656e60448201527f67746820666f7220455243373231207472616e7366657200000000000000000060648201526084016104f4565b505060448101516064820151611f9e565b60405162461bcd60e51b815260206004820152603e60248201527f4d756c746973696757616c6c65743a20756e737570706f72746564207472616e60448201527f73616374696f6e207479706520666f722064617461206465636f64696e67000060648201526084016104f4565b9250929050565b60006003826006811115611fbb57611fbb612941565b1480611fd857506004826006811115611fd657611fd6612941565b145b1561200857600154611feb90600261322b565b611ff6846003613242565b6001600160401b031610159050612023565b600154612016846002613242565b6001600160401b03161190505b92915050565b60026000540361204c57604051633ee5aeb560e01b815260040160405180910390fd5b6002600055565b3360009081526002602052604090205460ff166120825760405162461bcd60e51b81526004016104f490612c3b565b600454819081106120a55760405162461bcd60e51b81526004016104f490612cc6565b81600481815481106120b9576120b9612d10565b6000918252602090912060049091020154610100900460ff166120ee5760405162461bcd60e51b81526004016104f490612d26565b60006004848154811061210357612103612d10565b60009182526020909120600154600490920201915061212390600261322b565b815461213f906201000090046001600160401b03166003613242565b6001600160401b031610156121bc5760405162461bcd60e51b815260206004820152603760248201527f4d756c746973696757616c6c65743a20696e73756666696369656e7420636f6e60448201527f6669726d6174696f6e7320746f20616464206f776e657200000000000000000060648201526084016104f4565b6001600160a01b03851660009081526002602052604090205460ff16156122395760405162461bcd60e51b815260206004820152602b60248201527f4d756c746973696757616c6c65743a206164647265737320697320616c72656160448201526a323c9030b71037bbb732b960a91b60648201526084016104f4565b612241612636565b6001600160a01b038516600081815260026020526040808220805460ff19166001908117909155805480820182559083527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60180546001600160a01b03191684179055517f994a936646fe87ffe4f1e469d3d6aa417d6b855598397f323de5b449f765f0c39190a25050505050565b3360009081526002602052604090205460ff166122ff5760405162461bcd60e51b81526004016104f490612c3b565b600454819081106123225760405162461bcd60e51b81526004016104f490612cc6565b816004818154811061233657612336612d10565b6000918252602090912060049091020154610100900460ff1661236b5760405162461bcd60e51b81526004016104f490612d26565b60006004848154811061238057612380612d10565b6000918252602090912060015460049092020191506123a090600261322b565b81546123bc906201000090046001600160401b03166003613242565b6001600160401b031610156124395760405162461bcd60e51b815260206004820152603a60248201527f4d756c746973696757616c6c65743a20696e73756666696369656e7420636f6e60448201527f6669726d6174696f6e7320746f2072656d6f7665206f776e657200000000000060648201526084016104f4565b6001600160a01b03851660009081526002602052604090205460ff166124715760405162461bcd60e51b81526004016104f490612c7f565b60018054116124d75760405162461bcd60e51b815260206004820152602c60248201527f4d756c746973696757616c6c65743a2063616e6e6f742072656d6f766520746860448201526b32903630b9ba1037bbb732b960a11b60648201526084016104f4565b6124df612636565b6001600160a01b0385166000908152600260205260408120805460ff191690555b6001548110156125fa57856001600160a01b03166001828154811061252757612527612d10565b6000918252602090912001546001600160a01b0316036125f2576001805461255090829061326b565b8154811061256057612560612d10565b600091825260209091200154600180546001600160a01b03909216918390811061258c5761258c612d10565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060018054806125cb576125cb61327e565b600082815260209020810160001990810180546001600160a01b03191690550190556125fa565b600101612500565b506040516001600160a01b038616907f58619076adf5bb0943d100ef88d52d7c3fd691b19d3a9071b555b651fbf418da90600090a25050505050565b60045460005b8181101561268e5760006004828154811061265957612659612d10565b600091825260209091206004909102018054909150610100900460ff161561268557805461ff00191681555b5060010161263c565b506040517fbbb8e378f092289f6721a3c81d4263fcbfee5d004ba72a2f80ac4c118c3975cc90600090a150565b6000602082840312156126cd57600080fd5b5035919050565b6001600160a01b03811681146105ce57600080fd5b60008060008060006080868803121561270157600080fd5b853561270c816126d4565b9450602086013561271c816126d4565b93506040860135925060608601356001600160401b0381111561273e57600080fd5b8601601f8101881361274f57600080fd5b80356001600160401b0381111561276557600080fd5b88602082840101111561277757600080fd5b959894975092955050506020019190565b60006020828403121561279a57600080fd5b81356127a5816126d4565b9392505050565b600080604083850312156127bf57600080fd5b82356127ca816126d4565b946020939093013593505050565b600080604083850312156127eb57600080fd5b8235915060208301356127fd816126d4565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b038111828210171561284057612840612808565b60405290565b604051601f8201601f191681016001600160401b038111828210171561286e5761286e612808565b604052919050565b6000806000806080858703121561288c57600080fd5b84356007811061289b57600080fd5b935060208501356128ab816126d4565b92506040850135915060608501356001600160401b038111156128cd57600080fd5b8501601f810187136128de57600080fd5b80356001600160401b038111156128f7576128f7612808565b61290a601f8201601f1916602001612846565b81815288602083850101111561291f57600080fd5b8160208401602083013760006020838301015280935050505092959194509250565b634e487b7160e01b600052602160045260246000fd5b60005b8381101561297257818101518382015260200161295a565b50506000910152565b60008151808452612993816020860160208601612957565b601f01601f19169290920160200192915050565b6000600789106129c757634e487b7160e01b600052602160045260246000fd5b88825287151560208301526001600160401b03871660408301526001600160a01b0386811660608401528516608083015260a0820184905260e060c08301819052612a149083018461297b565b9998505050505050505050565b600080600060608486031215612a3657600080fd5b8335612a41816126d4565b92506020840135612a51816126d4565b929592945050506040919091013590565b602080825282518282018190526000918401906040840190835b81811015612aa35783516001600160a01b0316835260209384019390920191600101612a7c565b509095945050505050565b60006001600160401b03821115612ac757612ac7612808565b5060051b60200190565b600060208284031215612ae357600080fd5b81356001600160401b03811115612af957600080fd5b8201601f81018413612b0a57600080fd5b8035612b1d612b1882612aae565b612846565b8082825260208201915060208360071b850101925086831115612b3f57600080fd5b6020840193505b82841015612bb15760808488031215612b5e57600080fd5b612b6661281e565b8435612b71816126d4565b81526020850135612b81816126d4565b60208281019190915260408681013590830152606080870135908301529083526080909401939190910190612b46565b9695505050505050565b60008060008060808587031215612bd157600080fd5b8435612bdc816126d4565b93506020850135612bec816126d4565b92506040850135612bfc816126d4565b9396929550929360600135925050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b60208082526024908201527f4d756c746973696757616c6c65743a204e6f742061206d756c7469736967206f6040820152633bb732b960e11b606082015260800190565b60208082526027908201527f4d756c746973696757616c6c65743a2061646472657373206973206e6f742061604082015266371037bbb732b960c91b606082015260800190565b6020808252602a908201527f4d756c746973696757616c6c65743a205472616e73616374696f6e20646f6573604082015269081b9bdd08195e1a5cdd60b21b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b60208082526026908201527f4d756c746973696757616c6c65743a205472616e73616374696f6e206e6f742060408201526561637469766560d01b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b6001600160401b03828116828216039081111561202357612023612d6c565b60208082526029908201527f4d756c746973696757616c6c65743a2072656365697665722061646472657373604082015268081c995c5d5a5c995960ba1b606082015260800190565b600181811c90821680612dfe57607f821691505b602082108103612e1e57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115611db957806000526020600020601f840160051c81016020851015612e4b5750805b601f840160051c820191505b818110156114365760008155600101612e57565b81516001600160401b03811115612e8457612e84612808565b612e9881612e928454612dea565b84612e24565b6020601f821160018114612ecc5760008315612eb45750848201515b600019600385901b1c1916600184901b178455611436565b600084815260208120601f198516915b82811015612efc5787850151825560209485019460019092019101612edc565b5084821015612f1a5786840151600019600387901b60f8161c191681555b50505050600190811b01905550565b8581526001600160a01b038581166020830152604082018590528316606082015260a060808201819052600090612f629083018461297b565b979650505050505050565b60208082526026908201527f4d756c746973696757616c6c65743a20746f6b656e20616464726573732072656040820152651c5d5a5c995960d21b606082015260800190565b60208082526025908201527f4d756c746973696757616c6c65743a20746f6b656e20616d6f756e74207265716040820152641d5a5c995960da1b606082015260800190565b6001600160401b03818116838216019081111561202357612023612d6c565b602080825282518282018190526000918401906040840190835b81811015612aa357835180516001600160a01b03908116855260208083015190911681860152604080830151908601526060918201519185019190915290930192608090920191600101613031565b60006020828403121561309257600080fd5b81516001600160401b038111156130a857600080fd5b8201601f810184136130b957600080fd5b80516130c7612b1882612aae565b8082825260208201915060208360071b8501019250868311156130e957600080fd5b6020840193505b82841015612bb1576080848803121561310857600080fd5b61311061281e565b845161311b816126d4565b8152602085015161312b816126d4565b602082810191909152604086810151908301526060808701519083015290835260809094019391909101906130f0565b60006020828403121561316d57600080fd5b815180151581146127a557600080fd5b6020808252602e908201527f4d756c746973696757616c6c65743a2063616e6e6f742063616c6c20696e746560408201526d726e616c2066756e6374696f6e7360901b606082015260800190565b600082516131dd818460208701612957565b9190910192915050565b60208082526024908201527f4d756c746973696757616c6c65743a2065787465726e616c2063616c6c2066616040820152631a5b195960e21b606082015260800190565b808202811582820484141761202357612023612d6c565b6001600160401b03818116838216029081169081811461326457613264612d6c565b5092915050565b8181038181111561202357612023612d6c565b634e487b7160e01b600052603160045260246000fdfea2646970667358221220f5393edd02b5cfb950699c3d9c82962c92d3c1a3d65cd41314b18472faaad8d664736f6c634300081c003300000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000d5a4ed9d14bc273ce995b4e7e8fa0a21e59f8f3b000000000000000000000000bae2957b8c6cc7d39b7fdf5e82cf8c467b86be400000000000000000000000005a7c04218942c1c9baed35289a9b3edfed6f216f

Deployed Bytecode

0x6080604052600436106101185760003560e01c80638dbcc2e0116100a0578063d47a1a2711610064578063d47a1a271461039b578063d59dafd0146103bb578063dd71105d146103db578063ee22610b146103fb578063ef18374a1461041b57600080fd5b80638dbcc2e0146102e65780639ace38c2146103065780639db5dbe414610339578063a0e67e2b14610359578063c01a8c841461037b57600080fd5b806320ea8d86116100e757806320ea8d861461020b5780632f54bf6e1461022b57806364a197f31461026b5780637065cb481461028b57806380f59a65146102ab57600080fd5b8063025e7c2714610153578063150b7a0214610190578063173825d9146101c95780631afecd1c146101eb57600080fd5b3661014e576040514790349033907f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a1590600090a4005b600080fd5b34801561015f57600080fd5b5061017361016e3660046126bb565b610439565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561019c57600080fd5b506101b06101ab3660046126e9565b610463565b6040516001600160e01b03199091168152602001610187565b3480156101d557600080fd5b506101e96101e4366004612788565b6104c5565b005b3480156101f757600080fd5b506101e96102063660046126bb565b6105d1565b34801561021757600080fd5b506101e96102263660046126bb565b610796565b34801561023757600080fd5b5061025b610246366004612788565b60026020526000908152604090205460ff1681565b6040519015158152602001610187565b34801561027757600080fd5b506101e96102863660046127ac565b6109da565b34801561029757600080fd5b506101e96102a6366004612788565b610ab3565b3480156102b757600080fd5b5061025b6102c63660046127d8565b600360209081526000928352604080842090915290825290205460ff1681565b3480156102f257600080fd5b506101e9610301366004612876565b610bd9565b34801561031257600080fd5b506103266103213660046126bb565b610e28565b60405161018797969594939291906129a7565b34801561034557600080fd5b506101e9610354366004612a21565b610f1c565b34801561036557600080fd5b5061036e611012565b6040516101879190612a62565b34801561038757600080fd5b506101e96103963660046126bb565b611074565b3480156103a757600080fd5b506101e96103b6366004612ad1565b611287565b3480156103c757600080fd5b506101e96103d6366004612bbb565b6112e8565b3480156103e757600080fd5b506101e96103f6366004612bbb565b61143d565b34801561040757600080fd5b506101e96104163660046126bb565b6115a8565b34801561042757600080fd5b50600154604051908152602001610187565b6001818154811061044957600080fd5b6000918252602090912001546001600160a01b0316905081565b600083856001600160a01b0316876001600160a01b03167fa05d90f300156ad1b545bc5d8197024456f21d22a708f5af04dd293e3d60525186866040516104ab929190612c0c565b60405180910390a450630a85bd0160e11b95945050505050565b3360009081526002602052604090205460ff166104fd5760405162461bcd60e51b81526004016104f490612c3b565b60405180910390fd5b6001600160a01b0381166105795760405162461bcd60e51b815260206004820152603f60248201527f4d756c746973696757616c6c65743a206f776e6572204164647265737320746860448201527f617420697320746f2062652072656d6f7665642069732072657175697265640060648201526084016104f4565b6001600160a01b03811660009081526002602052604090205460ff166105b15760405162461bcd60e51b81526004016104f490612c7f565b6105ce600482600060405180602001604052806000815250610bd9565b50565b600454819081106105f45760405162461bcd60e51b81526004016104f490612cc6565b816004818154811061060857610608612d10565b6000918252602090912060049091020154610100900460ff1661063d5760405162461bcd60e51b81526004016104f490612d26565b3360009081526002602052604090205460ff1661066c5760405162461bcd60e51b81526004016104f490612c3b565b336001600160a01b03166004848154811061068957610689612d10565b6000918252602090912060049091020154600160501b90046001600160a01b03161461072b5760405162461bcd60e51b8152602060048201526044602482018190527f4d756c746973696757616c6c65743a206f6e6c7920746865206f776e65722063908201527f616e20636c656172207468656972207375626d6974746564207472616e7361636064820152633a34b7b760e11b608482015260a4016104f4565b60006004848154811061074057610740612d10565b60009182526020822060049091020180549215156101000261ff001990931692909217909155604051339185917f2c8d5957f60f56ae0608f50dbce4cda251ec4ed938d7d2ef7e10297719fdf2539190a3505050565b3360009081526002602052604090205460ff166107c55760405162461bcd60e51b81526004016104f490612c3b565b600454819081106107e85760405162461bcd60e51b81526004016104f490612cc6565b81600481815481106107fc576107fc612d10565b6000918252602090912060049091020154610100900460ff166108315760405162461bcd60e51b81526004016104f490612d26565b60006004848154811061084657610846612d10565b600091825260209091206004909102018054909150610100900460ff166108c15760405162461bcd60e51b815260206004820152602960248201527f4d756c746973696757616c6c65743a205472616e73616374696f6e206973206e6044820152686f742061637469766560b81b60648201526084016104f4565b600084815260036020908152604080832033845290915290205460ff166109455760405162461bcd60e51b815260206004820152603260248201527f4d756c746973696757616c6c65743a205472616e73616374696f6e20686173206044820152711b9bdd081899595b8818dbdb999a5c9b595960721b60648201526084016104f4565b805460019082906002906109699084906201000090046001600160401b0316612d82565b82546001600160401b039182166101009390930a9283029190920219909116179055506000848152600360209081526040808320338085529252808320805460ff191690555186927ff0dca620e2e81f7841d07bcc105e1704fb01475b278a9d4c236e1c62945edd5591a350505050565b3360009081526002602052604090205460ff16610a095760405162461bcd60e51b81526004016104f490612c3b565b6001600160a01b038216610a2f5760405162461bcd60e51b81526004016104f490612da1565b60008111610a935760405162461bcd60e51b815260206004820152602b60248201527f4d756c746973696757616c6c65743a20457468657220285765692920616d6f7560448201526a1b9d081c995c5d5a5c995960aa1b60648201526084016104f4565b610aaf6000838360405180602001604052806000815250610bd9565b5050565b3360009081526002602052604090205460ff16610ae25760405162461bcd60e51b81526004016104f490612c3b565b6001600160a01b038116610b4b5760405162461bcd60e51b815260206004820152602a60248201527f4d756c746973696757616c6c65743a206e6577206f776e6572206164647265736044820152691cc81c995c5d5a5c995960b21b60648201526084016104f4565b6001600160a01b03811660009081526002602052604090205460ff1615610bc05760405162461bcd60e51b8152602060048201526024808201527f4d756c746973696757616c6c65743a206f776e657220616c72656164792065786044820152636973747360e01b60648201526084016104f4565b6105ce6003826000604051806020016040528060008152505b3360009081526002602052604090205460ff16610c085760405162461bcd60e51b81526004016104f490612c3b565b600480546040805160e0810190915290919080876006811115610c2d57610c2d612941565b8152600160208083018290526000604084018190523360608501526001600160a01b038a16608085015260a0840189905260c09093018790528454808301865594835290912082516004909402018054929390929091839160ff191690836006811115610c9c57610c9c612941565b021790555060208201518154604084015160608501516001600160a01b03908116600160501b027fffff0000000000000000000000000000000000000000ffffffffffffffffffff6001600160401b03909316620100000269ffffffffffffffff000019951515610100029590951669ffffffffffffffffff00199094169390931793909317161782556080830151600183018054919092166001600160a01b031990911617905560a0820151600282015560c08201516003820190610d629082612e6b565b5085915060009050806001886006811115610d7f57610d7f612941565b1480610d9c57506002886006811115610d9a57610d9a612941565b145b15610db957600080610dae8a88611dbe565b909550899450925050505b826001600160a01b031684896006811115610dd657610dd6612941565b7f7a9333d5a9c2b79797bf46d7626bd8cda468b400f501bc0ed09cdef2d294c9dd898686338c604051610e0d959493929190612f29565b60405180910390a4610e1e84611074565b5050505050505050565b60048181548110610e3857600080fd5b6000918252602090912060049091020180546001820154600283015460038401805460ff8086169750610100860416956001600160401b0362010000870416956001600160a01b03600160501b9091048116951693929091610e9990612dea565b80601f0160208091040260200160405190810160405280929190818152602001828054610ec590612dea565b8015610f125780601f10610ee757610100808354040283529160200191610f12565b820191906000526020600020905b815481529060010190602001808311610ef557829003601f168201915b5050505050905087565b3360009081526002602052604090205460ff16610f4b5760405162461bcd60e51b81526004016104f490612c3b565b6001600160a01b038316610f715760405162461bcd60e51b81526004016104f490612f6d565b6001600160a01b038216610f975760405162461bcd60e51b81526004016104f490612da1565b60008111610fb75760405162461bcd60e51b81526004016104f490612fb3565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b17905261100c600185600084610bd9565b50505050565b6060600180548060200260200160405190810160405280929190818152602001828054801561106a57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161104c575b5050505050905090565b3360009081526002602052604090205460ff166110a35760405162461bcd60e51b81526004016104f490612c3b565b600454819081106110c65760405162461bcd60e51b81526004016104f490612cc6565b81600481815481106110da576110da612d10565b6000918252602090912060049091020154610100900460ff1661110f5760405162461bcd60e51b81526004016104f490612d26565b6000838152600360209081526040808320338452909152902054839060ff16156111a15760405162461bcd60e51b815260206004820152603b60248201527f4d756c746973696757616c6c65743a207472616e73616374696f6e20616c726560448201527f61647920636f6e6669726d65642062792074686973206f776e6572000000000060648201526084016104f4565b6000600485815481106111b6576111b6612d10565b600091825260208083208884526003825260408085203386529092529083208054600160ff19909116811790915560049290920201805490935061120a91620100009091046001600160401b031690612ff8565b82546001600160401b038216620100000269ffffffffffffffff00001982168117855560405192935060ff90811691161790879033907f5cbe105e36805f7820e291f799d5794ff948af2a5f664e580382defb6339004190600090a36112708282611fa5565b1561127e5761127e876115a8565b50505050505050565b3360009081526002602052604090205460ff166112b65760405162461bcd60e51b81526004016104f490612c3b565b6000816040516020016112c99190613017565b6040516020818303038152906040529050610aaf600530600084610bd9565b3360009081526002602052604090205460ff166113175760405162461bcd60e51b81526004016104f490612c3b565b6001600160a01b03841661133d5760405162461bcd60e51b81526004016104f490612f6d565b6001600160a01b0383166113af5760405162461bcd60e51b815260206004820152603360248201527f4d756c746973696757616c6c65743a2074686520746f6b656e6f776e657273206044820152721859191c995cdcc81a5cc81c995c5d5a5c9959606a1b60648201526084016104f4565b6001600160a01b0382166113d55760405162461bcd60e51b81526004016104f490612da1565b6040516001600160a01b038085166024830152831660448201526064810182905260009060840160408051601f198184030181529190526020810180516001600160e01b0316632142170760e11b1790529050611436600286600084610bd9565b5050505050565b3360009081526002602052604090205460ff1661146c5760405162461bcd60e51b81526004016104f490612c3b565b6001600160a01b0384166114925760405162461bcd60e51b81526004016104f490612f6d565b6001600160a01b0383166115055760405162461bcd60e51b815260206004820152603460248201527f4d756c746973696757616c6c65743a2074686520746f6b656e2d6f776e657273604482015273081859191c995cdcc81a5cc81c995c5d5a5c995960621b60648201526084016104f4565b6001600160a01b03821661152b5760405162461bcd60e51b81526004016104f490612da1565b6000811161154b5760405162461bcd60e51b81526004016104f490612fb3565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052611436600186600084610bd9565b600454819081106115cb5760405162461bcd60e51b81526004016104f490612cc6565b81600481815481106115df576115df612d10565b6000918252602090912060049091020154610100900460ff166116145760405162461bcd60e51b81526004016104f490612d26565b61161c612029565b3360009081526002602052604090205460ff1661164b5760405162461bcd60e51b81526004016104f490612c3b565b60006004848154811061166057611660612d10565b6000918252602090912060049091020180549091506001600160401b03620100008204169060ff166116928282611fa5565b6116fc5760405162461bcd60e51b815260206004820152603560248201527f4d756c746973696757616c6c65743a20696e73756666696369656e7420636f6e6044820152746669726d6174696f6e7320746f206578656375746560581b60648201526084016104f4565b600183015460028401546003850180546001600160a01b03909316926000919061172590612dea565b80601f016020809104026020016040519081016040528092919081815260200182805461175190612dea565b801561179e5780601f106117735761010080835404028352916020019161179e565b820191906000526020600020905b81548152906001019060200180831161178157829003601f168201915b5093945086935060009250829150600590508760068111156117c2576117c2612941565b03611b23576000848060200190518101906117dd9190613080565b805190915060005b81811015611b1f57600083828151811061180157611801612d10565b6020026020010151905060006001600160a01b031681602001516001600160a01b031603611959576060810151156118a15760405162461bcd60e51b815260206004820152603b60248201527f42617463685472616e736665723a20455448207472616e73666572207769746860448201527f20546f6b656e496420646f65736e2774206d616b652073656e7365000000000060648201526084016104f4565b805160408083015190516000926001600160a01b031691908381818185875af1925050503d80600081146118f1576040519150601f19603f3d011682016040523d82523d6000602084013e6118f6565b606091505b50509050806119535760405162461bcd60e51b8152602060048201526024808201527f42617463685472616e736665723a204574686572207472616e736665722066616044820152631a5b195960e21b60648201526084016104f4565b50611ab8565b8060600151600003611a425760208101518151604080840151905163a9059cbb60e01b81526001600160a01b039283166004820152602481019190915291169063a9059cbb906044016020604051808303816000875af11580156119c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119e5919061315b565b611a3d5760405162461bcd60e51b8152602060048201526024808201527f42617463685472616e736665723a204552433230207472616e736665722066616044820152631a5b195960e21b60648201526084016104f4565b611ab8565b602081015181516060830151604051632142170760e11b81523060048201526001600160a01b03928316602482015260448101919091529116906342842e0e90606401600060405180830381600087803b158015611a9f57600080fd5b505af1158015611ab3573d6000803e3d6000fd5b505050505b806060015181602001516001600160a01b031682600001516001600160a01b03167f11545b22e85dd851103fdaeff84f4db960c8ea9ef39898c3f2b32b8e14913bfd8460400151604051611b0e91815260200190565b60405180910390a4506001016117e5565b5050505b6003876006811115611b3757611b37612941565b03611b4b57611b46868d612053565b611b6e565b6004876006811115611b5f57611b5f612941565b03611b6e57611b6e868d6122d0565b6000876006811115611b8257611b82612941565b1480611b9f57506006876006811115611b9d57611b9d612941565b145b15611c4c57306001600160a01b03871603611bcc5760405162461bcd60e51b81526004016104f49061317d565b6000866001600160a01b03168686604051611be791906131cb565b60006040518083038185875af1925050503d8060008114611c24576040519150601f19603f3d011682016040523d82523d6000602084013e611c29565b606091505b5050905080611c4a5760405162461bcd60e51b81526004016104f4906131e7565b505b6001876006811115611c6057611c60612941565b1480611c7d57506002876006811115611c7b57611c7b612941565b145b15611d4157306001600160a01b03871603611caa5760405162461bcd60e51b81526004016104f49061317d565b6000866001600160a01b03168686604051611cc591906131cb565b60006040518083038185875af1925050503d8060008114611d02576040519150601f19603f3d011682016040523d82523d6000602084013e611d07565b606091505b5050905080611d285760405162461bcd60e51b81526004016104f4906131e7565b600080611d358a88611dbe565b90965089955093505050505b885461ff00191689556001600160a01b0383168c886006811115611d6757611d67612941565b7f8486d3d18fdaaf4d3cd166a7275bd95df5e8087a2cc662f6c33164f3052ea6be888686338b604051611d9e959493929190612f29565b60405180910390a4505050505050505050611db96001600055565b505050565b6000806001846006811115611dd557611dd5612941565b03611e8f57825160441480611deb575082516064145b611e565760405162461bcd60e51b815260206004820152603660248201527f4d756c746973696757616c6c65743a20696e76616c69642064617461206c656e60448201527533ba34103337b91022a9219918103a3930b739b332b960511b60648201526084016104f4565b8251604403611e7057505060248101516044820151611f9e565b8251606403611e8a57505060448101516064820151611f9e565b611f9e565b6002846006811115611ea357611ea3612941565b03611f30578251606414611f1f5760405162461bcd60e51b815260206004820152603760248201527f4d756c746973696757616c6c65743a20696e76616c69642064617461206c656e60448201527f67746820666f7220455243373231207472616e7366657200000000000000000060648201526084016104f4565b505060448101516064820151611f9e565b60405162461bcd60e51b815260206004820152603e60248201527f4d756c746973696757616c6c65743a20756e737570706f72746564207472616e60448201527f73616374696f6e207479706520666f722064617461206465636f64696e67000060648201526084016104f4565b9250929050565b60006003826006811115611fbb57611fbb612941565b1480611fd857506004826006811115611fd657611fd6612941565b145b1561200857600154611feb90600261322b565b611ff6846003613242565b6001600160401b031610159050612023565b600154612016846002613242565b6001600160401b03161190505b92915050565b60026000540361204c57604051633ee5aeb560e01b815260040160405180910390fd5b6002600055565b3360009081526002602052604090205460ff166120825760405162461bcd60e51b81526004016104f490612c3b565b600454819081106120a55760405162461bcd60e51b81526004016104f490612cc6565b81600481815481106120b9576120b9612d10565b6000918252602090912060049091020154610100900460ff166120ee5760405162461bcd60e51b81526004016104f490612d26565b60006004848154811061210357612103612d10565b60009182526020909120600154600490920201915061212390600261322b565b815461213f906201000090046001600160401b03166003613242565b6001600160401b031610156121bc5760405162461bcd60e51b815260206004820152603760248201527f4d756c746973696757616c6c65743a20696e73756666696369656e7420636f6e60448201527f6669726d6174696f6e7320746f20616464206f776e657200000000000000000060648201526084016104f4565b6001600160a01b03851660009081526002602052604090205460ff16156122395760405162461bcd60e51b815260206004820152602b60248201527f4d756c746973696757616c6c65743a206164647265737320697320616c72656160448201526a323c9030b71037bbb732b960a91b60648201526084016104f4565b612241612636565b6001600160a01b038516600081815260026020526040808220805460ff19166001908117909155805480820182559083527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60180546001600160a01b03191684179055517f994a936646fe87ffe4f1e469d3d6aa417d6b855598397f323de5b449f765f0c39190a25050505050565b3360009081526002602052604090205460ff166122ff5760405162461bcd60e51b81526004016104f490612c3b565b600454819081106123225760405162461bcd60e51b81526004016104f490612cc6565b816004818154811061233657612336612d10565b6000918252602090912060049091020154610100900460ff1661236b5760405162461bcd60e51b81526004016104f490612d26565b60006004848154811061238057612380612d10565b6000918252602090912060015460049092020191506123a090600261322b565b81546123bc906201000090046001600160401b03166003613242565b6001600160401b031610156124395760405162461bcd60e51b815260206004820152603a60248201527f4d756c746973696757616c6c65743a20696e73756666696369656e7420636f6e60448201527f6669726d6174696f6e7320746f2072656d6f7665206f776e657200000000000060648201526084016104f4565b6001600160a01b03851660009081526002602052604090205460ff166124715760405162461bcd60e51b81526004016104f490612c7f565b60018054116124d75760405162461bcd60e51b815260206004820152602c60248201527f4d756c746973696757616c6c65743a2063616e6e6f742072656d6f766520746860448201526b32903630b9ba1037bbb732b960a11b60648201526084016104f4565b6124df612636565b6001600160a01b0385166000908152600260205260408120805460ff191690555b6001548110156125fa57856001600160a01b03166001828154811061252757612527612d10565b6000918252602090912001546001600160a01b0316036125f2576001805461255090829061326b565b8154811061256057612560612d10565b600091825260209091200154600180546001600160a01b03909216918390811061258c5761258c612d10565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060018054806125cb576125cb61327e565b600082815260209020810160001990810180546001600160a01b03191690550190556125fa565b600101612500565b506040516001600160a01b038616907f58619076adf5bb0943d100ef88d52d7c3fd691b19d3a9071b555b651fbf418da90600090a25050505050565b60045460005b8181101561268e5760006004828154811061265957612659612d10565b600091825260209091206004909102018054909150610100900460ff161561268557805461ff00191681555b5060010161263c565b506040517fbbb8e378f092289f6721a3c81d4263fcbfee5d004ba72a2f80ac4c118c3975cc90600090a150565b6000602082840312156126cd57600080fd5b5035919050565b6001600160a01b03811681146105ce57600080fd5b60008060008060006080868803121561270157600080fd5b853561270c816126d4565b9450602086013561271c816126d4565b93506040860135925060608601356001600160401b0381111561273e57600080fd5b8601601f8101881361274f57600080fd5b80356001600160401b0381111561276557600080fd5b88602082840101111561277757600080fd5b959894975092955050506020019190565b60006020828403121561279a57600080fd5b81356127a5816126d4565b9392505050565b600080604083850312156127bf57600080fd5b82356127ca816126d4565b946020939093013593505050565b600080604083850312156127eb57600080fd5b8235915060208301356127fd816126d4565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b038111828210171561284057612840612808565b60405290565b604051601f8201601f191681016001600160401b038111828210171561286e5761286e612808565b604052919050565b6000806000806080858703121561288c57600080fd5b84356007811061289b57600080fd5b935060208501356128ab816126d4565b92506040850135915060608501356001600160401b038111156128cd57600080fd5b8501601f810187136128de57600080fd5b80356001600160401b038111156128f7576128f7612808565b61290a601f8201601f1916602001612846565b81815288602083850101111561291f57600080fd5b8160208401602083013760006020838301015280935050505092959194509250565b634e487b7160e01b600052602160045260246000fd5b60005b8381101561297257818101518382015260200161295a565b50506000910152565b60008151808452612993816020860160208601612957565b601f01601f19169290920160200192915050565b6000600789106129c757634e487b7160e01b600052602160045260246000fd5b88825287151560208301526001600160401b03871660408301526001600160a01b0386811660608401528516608083015260a0820184905260e060c08301819052612a149083018461297b565b9998505050505050505050565b600080600060608486031215612a3657600080fd5b8335612a41816126d4565b92506020840135612a51816126d4565b929592945050506040919091013590565b602080825282518282018190526000918401906040840190835b81811015612aa35783516001600160a01b0316835260209384019390920191600101612a7c565b509095945050505050565b60006001600160401b03821115612ac757612ac7612808565b5060051b60200190565b600060208284031215612ae357600080fd5b81356001600160401b03811115612af957600080fd5b8201601f81018413612b0a57600080fd5b8035612b1d612b1882612aae565b612846565b8082825260208201915060208360071b850101925086831115612b3f57600080fd5b6020840193505b82841015612bb15760808488031215612b5e57600080fd5b612b6661281e565b8435612b71816126d4565b81526020850135612b81816126d4565b60208281019190915260408681013590830152606080870135908301529083526080909401939190910190612b46565b9695505050505050565b60008060008060808587031215612bd157600080fd5b8435612bdc816126d4565b93506020850135612bec816126d4565b92506040850135612bfc816126d4565b9396929550929360600135925050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b60208082526024908201527f4d756c746973696757616c6c65743a204e6f742061206d756c7469736967206f6040820152633bb732b960e11b606082015260800190565b60208082526027908201527f4d756c746973696757616c6c65743a2061646472657373206973206e6f742061604082015266371037bbb732b960c91b606082015260800190565b6020808252602a908201527f4d756c746973696757616c6c65743a205472616e73616374696f6e20646f6573604082015269081b9bdd08195e1a5cdd60b21b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b60208082526026908201527f4d756c746973696757616c6c65743a205472616e73616374696f6e206e6f742060408201526561637469766560d01b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b6001600160401b03828116828216039081111561202357612023612d6c565b60208082526029908201527f4d756c746973696757616c6c65743a2072656365697665722061646472657373604082015268081c995c5d5a5c995960ba1b606082015260800190565b600181811c90821680612dfe57607f821691505b602082108103612e1e57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115611db957806000526020600020601f840160051c81016020851015612e4b5750805b601f840160051c820191505b818110156114365760008155600101612e57565b81516001600160401b03811115612e8457612e84612808565b612e9881612e928454612dea565b84612e24565b6020601f821160018114612ecc5760008315612eb45750848201515b600019600385901b1c1916600184901b178455611436565b600084815260208120601f198516915b82811015612efc5787850151825560209485019460019092019101612edc565b5084821015612f1a5786840151600019600387901b60f8161c191681555b50505050600190811b01905550565b8581526001600160a01b038581166020830152604082018590528316606082015260a060808201819052600090612f629083018461297b565b979650505050505050565b60208082526026908201527f4d756c746973696757616c6c65743a20746f6b656e20616464726573732072656040820152651c5d5a5c995960d21b606082015260800190565b60208082526025908201527f4d756c746973696757616c6c65743a20746f6b656e20616d6f756e74207265716040820152641d5a5c995960da1b606082015260800190565b6001600160401b03818116838216019081111561202357612023612d6c565b602080825282518282018190526000918401906040840190835b81811015612aa357835180516001600160a01b03908116855260208083015190911681860152604080830151908601526060918201519185019190915290930192608090920191600101613031565b60006020828403121561309257600080fd5b81516001600160401b038111156130a857600080fd5b8201601f810184136130b957600080fd5b80516130c7612b1882612aae565b8082825260208201915060208360071b8501019250868311156130e957600080fd5b6020840193505b82841015612bb1576080848803121561310857600080fd5b61311061281e565b845161311b816126d4565b8152602085015161312b816126d4565b602082810191909152604086810151908301526060808701519083015290835260809094019391909101906130f0565b60006020828403121561316d57600080fd5b815180151581146127a557600080fd5b6020808252602e908201527f4d756c746973696757616c6c65743a2063616e6e6f742063616c6c20696e746560408201526d726e616c2066756e6374696f6e7360901b606082015260800190565b600082516131dd818460208701612957565b9190910192915050565b60208082526024908201527f4d756c746973696757616c6c65743a2065787465726e616c2063616c6c2066616040820152631a5b195960e21b606082015260800190565b808202811582820484141761202357612023612d6c565b6001600160401b03818116838216029081169081811461326457613264612d6c565b5092915050565b8181038181111561202357612023612d6c565b634e487b7160e01b600052603160045260246000fdfea2646970667358221220f5393edd02b5cfb950699c3d9c82962c92d3c1a3d65cd41314b18472faaad8d664736f6c634300081c0033

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

00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000d5a4ed9d14bc273ce995b4e7e8fa0a21e59f8f3b000000000000000000000000bae2957b8c6cc7d39b7fdf5e82cf8c467b86be400000000000000000000000005a7c04218942c1c9baed35289a9b3edfed6f216f

-----Decoded View---------------
Arg [0] : _owners (address[]): 0xd5A4Ed9d14bc273ce995B4E7E8fa0a21E59F8F3b,0xBae2957B8c6CC7D39b7fDF5e82Cf8C467B86Be40,0x5a7c04218942c1c9baED35289A9b3eDfEd6F216F

-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000020
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [2] : 000000000000000000000000d5a4ed9d14bc273ce995b4e7e8fa0a21e59f8f3b
Arg [3] : 000000000000000000000000bae2957b8c6cc7d39b7fdf5e82cf8c467b86be40
Arg [4] : 0000000000000000000000005a7c04218942c1c9baed35289a9b3edfed6f216f


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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