ETH Price: $3,100.26 (+1.26%)
Gas: 5 Gwei

Contract

0xE1b59bf1dA5adE6B58fF780D8868D82FF70FD1E7
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
0x60806040102304652020-06-09 8:41:511491 days ago1591692111IN
 Create: ERC1271Module
0 ETH0.0275147537

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ERC1271Module

Compiler Version
v0.6.6+commit.6c089d02

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, None license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2020-06-09
*/

/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/
pragma solidity ^0.6.6;


/// @title Wallet
/// @dev Base contract for smart wallets.
///      Sub-contracts must NOT use non-default constructor to initialize
///      wallet states, instead, `init` shall be used. This is to enable
///      proxies to be deployed in front of the real wallet contract for
///      saving gas.
///
/// @author Daniel Wang - <[email protected]>
///
/// The design of this contract is inspired by Argent's contract codebase:
/// https://github.com/argentlabs/argent-contracts
interface Wallet
{
    function owner() external view returns (address);

    /// @dev Set a new owner.
    function setOwner(address newOwner) external;

    /// @dev Set up this wallet by assigning an original owner and a
    ///      list of initial modules. For each module, its `init` method
    ///      will be called with `address(this)` as the parameter.
    ///
    ///      Note that calling this method more than once will throw.
    ///
    /// @param _controller The Controller instance.
    /// @param _owner The owner of this wallet, must not be address(0).
    /// @param _boostrapModule The bootstrap module.
    function setup(address _controller, address _owner, address _boostrapModule) external;

    /// @dev Adds a new module. The `init` method of the module
    ///      will be called with `address(this)` as the parameter.
    ///      This method must throw if the module has already been added.
    /// @param _module The module's address.
    function addModule(address _module) external;

    /// @dev Removes an existing module. This method must throw if the module
    ///      has NOT been added or the module is the wallet's only module.
    /// @param _module The module's address.
    function removeModule(address _module) external;

    /// @dev Returns the list of modules added to this wallet in the order
    ///      they were added.
    /// @return _modules The list of modules added to this wallet.
    function modules() external view returns (address[] memory _modules);

    /// @dev Checks if a module has been added to this wallet.
    /// @param _module The module to check.
    /// @return True if the module exists; False otherwise.
    function hasModule(address _module) external view returns (bool);

    /// @dev Binds a method from the given module to this
    ///      wallet so the method can be invoked using this wallet's default
    ///      function.
    ///      Note that this method must throw when the given module has
    ///      not been added to this wallet.
    /// @param _method The method's 4-byte selector.
    /// @param _module The module's address. Use address(0) to unbind the method.
    function bindMethod(bytes4 _method, address _module) external;

    /// @dev Returns the module the given method has been bound to.
    /// @param _method The method's 4-byte selector.
    /// @return _module The address of the bound module. If no binding exists,
    ///                 returns address(0) instead.
    function boundMethodModule(bytes4 _method) external view returns (address _module);

    /// @dev Performs generic transactions. Any module that has been added to this
    ///      wallet can use this method to transact on any third-party contract with
    ///      msg.sender as this wallet itself.
    ///
    ///      This method will emit `Transacted` event if it doesn't throw.
    ///
    ///      Note: this method must ONLY allow invocations from a module that has
    ///      been added to this wallet. The wallet owner shall NOT be permitted
    ///      to call this method directly.
    ///
    /// @param mode The transaction mode, 1 for CALL, 2 for DELEGATECALL.
    /// @param to The desitination address.
    /// @param value The amount of Ether to transfer.
    /// @param data The data to send over using `to.call{value: value}(data)`
    /// @return returnData The transaction's return value.
    function transact(
        uint8    mode,
        address  to,
        uint     value,
        bytes    calldata data
        )
        external
        returns (bytes memory returnData);
}
/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/



/// @title Utility Functions for uint
/// @author Daniel Wang - <[email protected]>
library MathUint
{
    function mul(
        uint a,
        uint b
        )
        internal
        pure
        returns (uint c)
    {
        c = a * b;
        require(a == 0 || c / a == b, "MUL_OVERFLOW");
    }

    function sub(
        uint a,
        uint b
        )
        internal
        pure
        returns (uint)
    {
        require(b <= a, "SUB_UNDERFLOW");
        return a - b;
    }

    function add(
        uint a,
        uint b
        )
        internal
        pure
        returns (uint c)
    {
        c = a + b;
        require(c >= a, "ADD_OVERFLOW");
    }
}
//Mainly taken from https://github.com/GNSPS/solidity-bytes-utils/blob/master/contracts/BytesLib.sol


library BytesUtil {
    function concat(
        bytes memory _preBytes,
        bytes memory _postBytes
    )
        internal
        pure
        returns (bytes memory)
    {
        bytes memory tempBytes;

        assembly {
            // Get a location of some free memory and store it in tempBytes as
            // Solidity does for memory variables.
            tempBytes := mload(0x40)

            // Store the length of the first bytes array at the beginning of
            // the memory for tempBytes.
            let length := mload(_preBytes)
            mstore(tempBytes, length)

            // Maintain a memory counter for the current write location in the
            // temp bytes array by adding the 32 bytes for the array length to
            // the starting location.
            let mc := add(tempBytes, 0x20)
            // Stop copying when the memory counter reaches the length of the
            // first bytes array.
            let end := add(mc, length)

            for {
                // Initialize a copy counter to the start of the _preBytes data,
                // 32 bytes into its memory.
                let cc := add(_preBytes, 0x20)
            } lt(mc, end) {
                // Increase both counters by 32 bytes each iteration.
                mc := add(mc, 0x20)
                cc := add(cc, 0x20)
            } {
                // Write the _preBytes data into the tempBytes memory 32 bytes
                // at a time.
                mstore(mc, mload(cc))
            }

            // Add the length of _postBytes to the current length of tempBytes
            // and store it as the new length in the first 32 bytes of the
            // tempBytes memory.
            length := mload(_postBytes)
            mstore(tempBytes, add(length, mload(tempBytes)))

            // Move the memory counter back from a multiple of 0x20 to the
            // actual end of the _preBytes data.
            mc := end
            // Stop copying when the memory counter reaches the new combined
            // length of the arrays.
            end := add(mc, length)

            for {
                let cc := add(_postBytes, 0x20)
            } lt(mc, end) {
                mc := add(mc, 0x20)
                cc := add(cc, 0x20)
            } {
                mstore(mc, mload(cc))
            }

            // Update the free-memory pointer by padding our last write location
            // to 32 bytes: add 31 bytes to the end of tempBytes to move to the
            // next 32 byte block, then round down to the nearest multiple of
            // 32. If the sum of the length of the two arrays is zero then add
            // one before rounding down to leave a blank 32 bytes (the length block with 0).
            mstore(0x40, and(
              add(add(end, iszero(add(length, mload(_preBytes)))), 31),
              not(31) // Round down to the nearest 32 bytes.
            ))
        }

        return tempBytes;
    }

    function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal {
        assembly {
            // Read the first 32 bytes of _preBytes storage, which is the length
            // of the array. (We don't need to use the offset into the slot
            // because arrays use the entire slot.)
            let fslot := sload(_preBytes_slot)
            // Arrays of 31 bytes or less have an even value in their slot,
            // while longer arrays have an odd value. The actual length is
            // the slot divided by two for odd values, and the lowest order
            // byte divided by two for even values.
            // If the slot is even, bitwise and the slot with 255 and divide by
            // two to get the length. If the slot is odd, bitwise and the slot
            // with -1 and divide by two.
            let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
            let mlength := mload(_postBytes)
            let newlength := add(slength, mlength)
            // slength can contain both the length and contents of the array
            // if length < 32 bytes so let's prepare for that
            // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
            switch add(lt(slength, 32), lt(newlength, 32))
            case 2 {
                // Since the new array still fits in the slot, we just need to
                // update the contents of the slot.
                // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length
                sstore(
                    _preBytes_slot,
                    // all the modifications to the slot are inside this
                    // next block
                    add(
                        // we can just add to the slot contents because the
                        // bytes we want to change are the LSBs
                        fslot,
                        add(
                            mul(
                                div(
                                    // load the bytes from memory
                                    mload(add(_postBytes, 0x20)),
                                    // zero all bytes to the right
                                    exp(0x100, sub(32, mlength))
                                ),
                                // and now shift left the number of bytes to
                                // leave space for the length in the slot
                                exp(0x100, sub(32, newlength))
                            ),
                            // increase length by the double of the memory
                            // bytes length
                            mul(mlength, 2)
                        )
                    )
                )
            }
            case 1 {
                // The stored value fits in the slot, but the combined value
                // will exceed it.
                // get the keccak hash to get the contents of the array
                mstore(0x0, _preBytes_slot)
                let sc := add(keccak256(0x0, 0x20), div(slength, 32))

                // save new length
                sstore(_preBytes_slot, add(mul(newlength, 2), 1))

                // The contents of the _postBytes array start 32 bytes into
                // the structure. Our first read should obtain the `submod`
                // bytes that can fit into the unused space in the last word
                // of the stored array. To get this, we read 32 bytes starting
                // from `submod`, so the data we read overlaps with the array
                // contents by `submod` bytes. Masking the lowest-order
                // `submod` bytes allows us to add that value directly to the
                // stored value.

                let submod := sub(32, slength)
                let mc := add(_postBytes, submod)
                let end := add(_postBytes, mlength)
                let mask := sub(exp(0x100, submod), 1)

                sstore(
                    sc,
                    add(
                        and(
                            fslot,
                            0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00
                        ),
                        and(mload(mc), mask)
                    )
                )

                for {
                    mc := add(mc, 0x20)
                    sc := add(sc, 1)
                } lt(mc, end) {
                    sc := add(sc, 1)
                    mc := add(mc, 0x20)
                } {
                    sstore(sc, mload(mc))
                }

                mask := exp(0x100, sub(mc, end))

                sstore(sc, mul(div(mload(mc), mask), mask))
            }
            default {
                // get the keccak hash to get the contents of the array
                mstore(0x0, _preBytes_slot)
                // Start copying to the last used word of the stored array.
                let sc := add(keccak256(0x0, 0x20), div(slength, 32))

                // save new length
                sstore(_preBytes_slot, add(mul(newlength, 2), 1))

                // Copy over the first `submod` bytes of the new data as in
                // case 1 above.
                let slengthmod := mod(slength, 32)
                let mlengthmod := mod(mlength, 32)
                let submod := sub(32, slengthmod)
                let mc := add(_postBytes, submod)
                let end := add(_postBytes, mlength)
                let mask := sub(exp(0x100, submod), 1)

                sstore(sc, add(sload(sc), and(mload(mc), mask)))

                for {
                    sc := add(sc, 1)
                    mc := add(mc, 0x20)
                } lt(mc, end) {
                    sc := add(sc, 1)
                    mc := add(mc, 0x20)
                } {
                    sstore(sc, mload(mc))
                }

                mask := exp(0x100, sub(mc, end))

                sstore(sc, mul(div(mload(mc), mask), mask))
            }
        }
    }

    function slice(
        bytes memory _bytes,
        uint _start,
        uint _length
    )
        internal
        pure
        returns (bytes memory)
    {
        require(_bytes.length >= (_start + _length));

        bytes memory tempBytes;

        assembly {
            switch iszero(_length)
            case 0 {
                // Get a location of some free memory and store it in tempBytes as
                // Solidity does for memory variables.
                tempBytes := mload(0x40)

                // The first word of the slice result is potentially a partial
                // word read from the original array. To read it, we calculate
                // the length of that partial word and start copying that many
                // bytes into the array. The first word we copy will start with
                // data we don't care about, but the last `lengthmod` bytes will
                // land at the beginning of the contents of the new array. When
                // we're done copying, we overwrite the full first word with
                // the actual length of the slice.
                let lengthmod := and(_length, 31)

                // The multiplication in the next line is necessary
                // because when slicing multiples of 32 bytes (lengthmod == 0)
                // the following copy loop was copying the origin's length
                // and then ending prematurely not copying everything it should.
                let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
                let end := add(mc, _length)

                for {
                    // The multiplication in the next line has the same exact purpose
                    // as the one above.
                    let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
                } lt(mc, end) {
                    mc := add(mc, 0x20)
                    cc := add(cc, 0x20)
                } {
                    mstore(mc, mload(cc))
                }

                mstore(tempBytes, _length)

                //update free-memory pointer
                //allocating the array padded to 32 bytes like the compiler does now
                mstore(0x40, and(add(mc, 31), not(31)))
            }
            //if we want a zero-length slice let's just return a zero-length array
            default {
                tempBytes := mload(0x40)

                mstore(0x40, add(tempBytes, 0x20))
            }
        }

        return tempBytes;
    }

    function toAddress(bytes memory _bytes, uint _start) internal  pure returns (address) {
        require(_bytes.length >= (_start + 20));
        address tempAddress;

        assembly {
            tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
        }

        return tempAddress;
    }

    function toUint8(bytes memory _bytes, uint _start) internal  pure returns (uint8) {
        require(_bytes.length >= (_start + 1));
        uint8 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x1), _start))
        }

        return tempUint;
    }

    function toUint16(bytes memory _bytes, uint _start) internal  pure returns (uint16) {
        require(_bytes.length >= (_start + 2));
        uint16 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x2), _start))
        }

        return tempUint;
    }

    function toUint32(bytes memory _bytes, uint _start) internal  pure returns (uint32) {
        require(_bytes.length >= (_start + 4));
        uint32 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x4), _start))
        }

        return tempUint;
    }

    function toUint64(bytes memory _bytes, uint _start) internal  pure returns (uint64) {
        require(_bytes.length >= (_start + 8));
        uint64 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x8), _start))
        }

        return tempUint;
    }

    function toUint96(bytes memory _bytes, uint _start) internal  pure returns (uint96) {
        require(_bytes.length >= (_start + 12));
        uint96 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0xc), _start))
        }

        return tempUint;
    }

    function toUint128(bytes memory _bytes, uint _start) internal  pure returns (uint128) {
        require(_bytes.length >= (_start + 16));
        uint128 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x10), _start))
        }

        return tempUint;
    }

    function toUint(bytes memory _bytes, uint _start) internal  pure returns (uint256) {
        require(_bytes.length >= (_start + 32));
        uint256 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x20), _start))
        }

        return tempUint;
    }

    function toBytes4(bytes memory _bytes, uint _start) internal  pure returns (bytes4) {
        require(_bytes.length >= (_start + 4));
        bytes4 tempBytes4;

        assembly {
            tempBytes4 := mload(add(add(_bytes, 0x20), _start))
        }

        return tempBytes4;
    }

    function toBytes32(bytes memory _bytes, uint _start) internal  pure returns (bytes32) {
        require(_bytes.length >= (_start + 32));
        bytes32 tempBytes32;

        assembly {
            tempBytes32 := mload(add(add(_bytes, 0x20), _start))
        }

        return tempBytes32;
    }

    function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {
        bool success = true;

        assembly {
            let length := mload(_preBytes)

            // if lengths don't match the arrays are not equal
            switch eq(length, mload(_postBytes))
            case 1 {
                // cb is a circuit breaker in the for loop since there's
                //  no said feature for inline assembly loops
                // cb = 1 - don't breaker
                // cb = 0 - break
                let cb := 1

                let mc := add(_preBytes, 0x20)
                let end := add(mc, length)

                for {
                    let cc := add(_postBytes, 0x20)
                // the next line is the loop condition:
                // while(uint(mc < end) + cb == 2)
                } eq(add(lt(mc, end), cb), 2) {
                    mc := add(mc, 0x20)
                    cc := add(cc, 0x20)
                } {
                    // if any of these checks fails then arrays are not equal
                    if iszero(eq(mload(mc), mload(cc))) {
                        // unsuccess:
                        success := 0
                        cb := 0
                    }
                }
            }
            default {
                // unsuccess:
                success := 0
            }
        }

        return success;
    }

    function equalStorage(
        bytes storage _preBytes,
        bytes memory _postBytes
    )
        internal
        view
        returns (bool)
    {
        bool success = true;

        assembly {
            // we know _preBytes_offset is 0
            let fslot := sload(_preBytes_slot)
            // Decode the length of the stored array like in concatStorage().
            let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
            let mlength := mload(_postBytes)

            // if lengths don't match the arrays are not equal
            switch eq(slength, mlength)
            case 1 {
                // slength can contain both the length and contents of the array
                // if length < 32 bytes so let's prepare for that
                // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
                if iszero(iszero(slength)) {
                    switch lt(slength, 32)
                    case 1 {
                        // blank the last byte which is the length
                        fslot := mul(div(fslot, 0x100), 0x100)

                        if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {
                            // unsuccess:
                            success := 0
                        }
                    }
                    default {
                        // cb is a circuit breaker in the for loop since there's
                        //  no said feature for inline assembly loops
                        // cb = 1 - don't breaker
                        // cb = 0 - break
                        let cb := 1

                        // get the keccak hash to get the contents of the array
                        mstore(0x0, _preBytes_slot)
                        let sc := keccak256(0x0, 0x20)

                        let mc := add(_postBytes, 0x20)
                        let end := add(mc, mlength)

                        // the next line is the loop condition:
                        // while(uint(mc < end) + cb == 2)
                        for {} eq(add(lt(mc, end), cb), 2) {
                            sc := add(sc, 1)
                            mc := add(mc, 0x20)
                        } {
                            if iszero(eq(sload(sc), mload(mc))) {
                                // unsuccess:
                                success := 0
                                cb := 0
                            }
                        }
                    }
                }
            }
            default {
                // unsuccess:
                success := 0
            }
        }

        return success;
    }
}
// Copied from https://eips.ethereum.org/EIPS/eip-1271.



abstract contract ERC1271 {

    // bytes4(keccak256("isValidSignature(bytes,bytes)")
    bytes4 constant internal MAGICVALUE = 0x20c13b0b;

    /**
     * @dev Should return whether the signature provided is valid for the provided data
     * @param _data Arbitrary length data signed on the behalf of address(this)
     * @param _signature Signature byte array associated with _data
     *
     * MUST return the bytes4 magic value 0x20c13b0b when function passes.
     * MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5)
     * MUST allow external calls
     */
    function isValidSignature(
        bytes memory _data,
        bytes memory _signature)
        public
        view
        virtual
        returns (bytes4 magicValue);
}/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/





/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

pragma experimental ABIEncoderV2;




/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/



/// @title Utility Functions for addresses
/// @author Daniel Wang - <[email protected]>
/// @author Brecht Devos - <[email protected]>
library AddressUtil
{
    using AddressUtil for *;

    function isContract(
        address addr
        )
        internal
        view
        returns (bool)
    {
        uint32 size;
        assembly { size := extcodesize(addr) }
        return (size > 0);
    }

    function toPayable(
        address addr
        )
        internal
        pure
        returns (address payable)
    {
        return address(uint160(addr));
    }

    // Works like address.send but with a customizable gas limit
    // Make sure your code is safe for reentrancy when using this function!
    function sendETH(
        address to,
        uint    amount,
        uint    gasLimit
        )
        internal
        returns (bool success)
    {
        if (amount == 0) {
            return true;
        }
        address payable recipient = to.toPayable();
        /* solium-disable-next-line */
        (success, ) = recipient.call{value: amount, gas: gasLimit}("");
    }

    // Works like address.transfer but with a customizable gas limit
    // Make sure your code is safe for reentrancy when using this function!
    function sendETHAndVerify(
        address to,
        uint    amount,
        uint    gasLimit
        )
        internal
        returns (bool success)
    {
        success = to.sendETH(amount, gasLimit);
        require(success, "TRANSFER_FAILURE");
    }
}




/// @title SignatureUtil
/// @author Daniel Wang - <[email protected]>
/// @dev This method supports multihash standard. Each signature's first byte indicates
///      the signature's type, the second byte indicates the signature's length, therefore,
///      each signature will have 2 extra bytes prefix. Mulitple signatures are concatenated
///      together.
library SignatureUtil
{
    using BytesUtil     for bytes;
    using MathUint      for uint;

    enum SignatureType {
        ILLEGAL,
        INVALID,
        EIP_712,
        ETH_SIGN,
        WALLET
    }

    bytes4 constant private ERC1271_MAGICVALUE = 0x20c13b0b;

    function verifySignatures(
        bytes32   signHash,
        address[] memory signers,
        bytes[]   memory signatures
        )
        internal
        view
        returns (bool)
    {
        require(signers.length == signatures.length, "BAD_SIGNATURE_DATA");
        address lastSigner;
        for (uint i = 0; i < signers.length; i++) {
            require(signers[i] > lastSigner, "INVALID_SIGNERS_ORDER");
            lastSigner = signers[i];
            if (!verifySignature(signHash, signers[i], signatures[i])) {
                return false;
            }
        }
        return true;
    }

    function verifySignature(
        bytes32 signHash,
        address signer,
        bytes   memory signature
        )
        internal
        view
        returns (bool)
    {
        uint signatureTypeOffset = signature.length.sub(1);
        SignatureType signatureType = SignatureType(signature.toUint8(signatureTypeOffset));

        bytes memory stripped = signature.slice(0, signatureTypeOffset);

        if (signatureType == SignatureType.WALLET) {
            return verifyERC1271Signature(signHash, signer, stripped);
        } else if (signatureType == SignatureType.EIP_712) {
            return recoverECDSASigner(signHash, stripped) == signer;
        } else if (signatureType == SignatureType.ETH_SIGN) {
            bytes32 hash = keccak256(
                abi.encodePacked("\x19Ethereum Signed Message:\n32", signHash)
            );
            return recoverECDSASigner(hash, stripped) == signer;
        } else {
            return false;
        }
    }

    function verifyERC1271Signature(
        bytes32 signHash,
        address signer,
        bytes   memory signature
        )
        private
        view
        returns(bool)
    {
        bytes memory callData = abi.encodeWithSelector(
            ERC1271(0).isValidSignature.selector,
            abi.encode(signHash),
            signature
        );
        (bool success, bytes memory result) = signer.staticcall(callData);
        return (
            success &&
            result.length == 32 &&
            result.toBytes4(0) == ERC1271_MAGICVALUE
        );
    }

    function recoverECDSASigner(
        bytes32      signHash,
        bytes memory signature
        )
        internal
        pure
        returns (address)
    {
        if (signature.length != 65) {
            return address(0);
        }

        bytes32 r;
        bytes32 s;
        uint8   v;
        // we jump 32 (0x20) as the first slot of bytes contains the length
        // we jump 65 (0x41) per signature
        // for v we load 32 bytes ending with v (the first 31 come from s) then apply a mask
        assembly {
            r := mload(add(signature, 0x20))
            s := mload(add(signature, 0x40))
            v := and(mload(add(signature, 0x41)), 0xff)
        }
        // See https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/cryptography/ECDSA.sol
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return address(0);
        }
        if (v == 27 || v == 28) {
            return ecrecover(signHash, v, r, s);
        } else {
            return address(0);
        }
    }
}





/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/


/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/



/// @title ERC20 Token Interface
/// @dev see https://github.com/ethereum/EIPs/issues/20
/// @author Daniel Wang - <[email protected]>
abstract contract ERC20
{
    function totalSupply()
        public
        view
        virtual
        returns (uint);

    function balanceOf(
        address who
        )
        public
        view
        virtual
        returns (uint);

    function allowance(
        address owner,
        address spender
        )
        public
        view
        virtual
        returns (uint);

    function transfer(
        address to,
        uint value
        )
        public
        virtual
        returns (bool);

    function transferFrom(
        address from,
        address to,
        uint    value
        )
        public
        virtual
        returns (bool);

    function approve(
        address spender,
        uint    value
        )
        public
        virtual
        returns (bool);
}

/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/



/// @title ReentrancyGuard
/// @author Brecht Devos - <[email protected]>
/// @dev Exposes a modifier that guards a function against reentrancy
///      Changing the value of the same storage value multiple times in a transaction
///      is cheap (starting from Istanbul) so there is no need to minimize
///      the number of times the value is changed
contract ReentrancyGuard
{
    //The default value must be 0 in order to work behind a proxy.
    uint private _guardValue;

    modifier nonReentrant()
    {
        require(_guardValue == 0, "REENTRANCY");
        _guardValue = 1;
        _;
        _guardValue = 0;
    }
}



/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/


/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/



/// @title Ownable
/// @author Brecht Devos - <[email protected]>
/// @dev The Ownable contract has an owner address, and provides basic
///      authorization control functions, this simplifies the implementation of
///      "user permissions".
contract Ownable
{
    address public owner;

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

    /// @dev The Ownable constructor sets the original `owner` of the contract
    ///      to the sender.
    constructor()
        public
    {
        owner = msg.sender;
    }

    /// @dev Throws if called by any account other than the owner.
    modifier onlyOwner()
    {
        require(msg.sender == owner, "UNAUTHORIZED");
        _;
    }

    /// @dev Allows the current owner to transfer control of the contract to a
    ///      new owner.
    /// @param newOwner The address to transfer ownership to.
    function transferOwnership(
        address newOwner
        )
        public
        virtual
        onlyOwner
    {
        require(newOwner != address(0), "ZERO_ADDRESS");
        emit OwnershipTransferred(owner, newOwner);
        owner = newOwner;
    }

    function renounceOwnership()
        public
        onlyOwner
    {
        emit OwnershipTransferred(owner, address(0));
        owner = address(0);
    }
}





/// @title Module
/// @dev Base contract for all smart wallet modules.
///
/// @author Daniel Wang - <[email protected]>
///
/// The design of this contract is inspired by Argent's contract codebase:
/// https://github.com/argentlabs/argent-contracts
interface Module
{
    /// @dev Activates the module for the given wallet (msg.sender) after the module is added.
    ///      Warning: this method shall ONLY be callable by a wallet.
    function activate() external;

    /// @dev Deactivates the module for the given wallet (msg.sender) before the module is removed.
    ///      Warning: this method shall ONLY be callable by a wallet.
    function deactivate() external;
}



/// @title BaseModule
/// @dev This contract implements some common functions that are likely
///      be useful for all modules.
///
/// @author Daniel Wang - <[email protected]>
///
/// The design of this contract is inspired by Argent's contract codebase:
/// https://github.com/argentlabs/argent-contracts
contract BaseModule is ReentrancyGuard, Module
{
    event Activated   (address indexed wallet);
    event Deactivated (address indexed wallet);

    modifier onlyFromWallet(address wallet) virtual
    {
        require(msg.sender == wallet, "NOT_FROM_WALLET");
        _;
    }

    modifier onlyFromMetaTx() virtual {
        require(msg.sender == address(this), "NOT_FROM_META_TX");
        _;
    }

    modifier onlyFromWalletOwner(address wallet) virtual {
        require(msg.sender == Wallet(wallet).owner(), "NOT_FROM_WALLET_OWNER");
        _;
    }

    modifier onlyFromMetaTxOrWalletOwner(address wallet) virtual {
        require(
            msg.sender == address(this) || msg.sender == Wallet(wallet).owner(),
            "NOT_FROM_METATX_OR_WALLET_OWNER");
        _;
    }

    modifier onlyFromMetaTxOrOwner(address owner) virtual {
        require(
            msg.sender == address(this) || msg.sender == owner,
            "NOT_FROM_METATX_OR_OWNER");
        _;
    }

    modifier onlyWalletOwner(address wallet, address addr) virtual {
        require(Wallet(wallet).owner() == addr, "NOT_WALLET_OWNER");
        _;
    }

    modifier notWalletOwner(address wallet, address addr) virtual {
        require(Wallet(wallet).owner() != addr, "IS_WALLET_OWNER");
        _;
    }

    function addModule(
        address wallet,
        address module
        )
        external
        nonReentrant
        onlyFromMetaTxOrWalletOwner(wallet)
    {
        Wallet(wallet).addModule(module);
    }

    /// @dev This method will cause an re-entry to the same module contract.
    function activate()
        external
        override
        virtual
    {
        address wallet = msg.sender;
        bindMethods(wallet);
        emit Activated(wallet);
    }

    /// @dev This method will cause an re-entry to the same module contract.
    function deactivate()
        external
        override
        virtual
    {
        address wallet = msg.sender;
        unbindMethods(wallet);
        emit Deactivated(wallet);
    }

    ///.@dev Gets the list of methods for binding to wallets.
    ///      Sub-contracts should override this method to provide methods for
    ///      wallet binding.
    /// @return methods A list of method selectors for binding to the wallet
    ///         when this module is activated for the wallet.
    function bindableMethods()
        public
        pure
        virtual
        returns (bytes4[] memory methods)
    {
    }

    // ===== internal & private methods =====

    /// @dev Binds all methods to the given wallet.
    function bindMethods(address wallet)
        internal
    {
        Wallet w = Wallet(wallet);
        bytes4[] memory methods = bindableMethods();
        for (uint i = 0; i < methods.length; i++) {
            w.bindMethod(methods[i], address(this));
        }
    }

    /// @dev Unbinds all methods from the given wallet.
    function unbindMethods(address wallet)
        internal
    {
        Wallet w = Wallet(wallet);
        bytes4[] memory methods = bindableMethods();
        for (uint i = 0; i < methods.length; i++) {
            w.bindMethod(methods[i], address(0));
        }
    }

    function transactCall(
        address wallet,
        address to,
        uint    value,
        bytes   memory data
        )
        internal
        returns (bytes memory)
    {
        return Wallet(wallet).transact(uint8(1), to, value, data);
    }

    // Special case for transactCall to support transfers on "bad" ERC20 tokens
    function transactTokenTransfer(
        address wallet,
        address token,
        address to,
        uint    amount
        )
        internal
        returns (bool success)
    {
        bytes memory txData = abi.encodeWithSelector(
            ERC20(0).transfer.selector,
            to,
            amount
        );
        bytes memory returnData = transactCall(wallet, token, 0, txData);
        // `transactCall` will revert if the call was unsuccessful.
        // The only extra check we have to do is verify if the return value (if there is any) is correct.
        if (returnData.length > 0) {
            success = abi.decode(returnData, (bool));
        } else {
            // If there is no return value then a failure would have resulted in a revert
            success = true;
        }
    }

    // Special case for transactCall to support approvals on "bad" ERC20 tokens
    function transactTokenApprove(
        address wallet,
        address token,
        address spender,
        uint    amount
        )
        internal
        returns (bool success)
    {
        bytes memory txData = abi.encodeWithSelector(
            ERC20(0).approve.selector,
            spender,
            amount
        );
        bytes memory returnData = transactCall(wallet, token, 0, txData);
        // `transactCall` will revert if the call was unsuccessful.
        // The only extra check we have to do is verify if the return value (if there is any) is correct.
        if (returnData.length > 0) {
            success = abi.decode(returnData, (bool));
        } else {
            // If there is no return value then a failure would have resulted in a revert
            success = true;
        }
    }

    function transactDelegateCall(
        address wallet,
        address to,
        uint    value,
        bytes   memory data
        )
        internal
        returns (bytes memory)
    {
        return Wallet(wallet).transact(uint8(2), to, value, data);
    }

    function transactStaticCall(
        address wallet,
        address to,
        bytes   memory data
        )
        internal
        returns (bytes memory)
    {
        return Wallet(wallet).transact(uint8(3), to, 0, data);
    }
}



/// @title ERC1271Module
/// @dev This is the base module for supporting ERC1271.
contract ERC1271Module is ERC1271, BaseModule
{
    using SignatureUtil for bytes32;

    function bindableMethods()
        public
        pure
        override
        returns (bytes4[] memory methods)
    {
        methods = new bytes4[](1);
        methods[0] = this.isValidSignature.selector;
    }

    // Will use msg.sender to detect the wallet, so this function should be called through
    // the bounded method on the wallet itself, not directly on this module.
    function isValidSignature(
        bytes memory _data,
        bytes memory _signature)
        public
        view
        override
        returns (bytes4 magicValue)
    {
        bytes32 hash;
        if(_data.length == 32) {
            hash = BytesUtil.toBytes32(_data, 0);
        } else {
            hash = keccak256(_data);
        }
        if (hash.verifySignature(Wallet(msg.sender).owner(), _signature)) {
            return MAGICVALUE;
        } else {
            return 0;
        }
    }
}

Contract Security Audit

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"}],"name":"Activated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wallet","type":"address"}],"name":"Deactivated","type":"event"},{"inputs":[],"name":"activate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"wallet","type":"address"},{"internalType":"address","name":"module","type":"address"}],"name":"addModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"bindableMethods","outputs":[{"internalType":"bytes4[]","name":"methods","type":"bytes4[]"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"deactivate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"isValidSignature","outputs":[{"internalType":"bytes4","name":"magicValue","type":"bytes4"}],"stateMutability":"view","type":"function"}]

608060405234801561001057600080fd5b50610c7e806100206000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80630f15f4c01461005c57806320c13b0b1461006657806351b42b001461008f5780635a1db8c414610097578063afa3363d146100aa575b600080fd5b6100646100bf565b005b6100796100743660046109b9565b610100565b6040516100869190610b1c565b60405180910390f35b6100646101cb565b6100646100a5366004610981565b61020c565b6100b261034d565b6040516100869190610aa7565b336100c9816103a0565b6040516001600160a01b038216907f0cc43938d137e7efade6a531f663e78c1fc75257b0d65ffda2fdaf70cb49cdf990600090a250565b60008083516020141561011f5761011884600061043e565b9050610128565b50825160208401205b6101aa336001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561016457600080fd5b505afa158015610178573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061019c9190610965565b82908563ffffffff61045a16565b156101bf57506320c13b0b60e01b90506101c5565b50600090505b92915050565b336101d581610588565b6040516001600160a01b038216907f749cb6b4c510bc468cf6b9c2086d6f0a54d6b18e25d37bf3200e68eab0880c0090600090a250565b600054156102355760405162461bcd60e51b815260040161022c90610b82565b60405180910390fd5b600160005581333014806102ca5750806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561027d57600080fd5b505afa158015610291573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102b59190610965565b6001600160a01b0316336001600160a01b0316145b6102e65760405162461bcd60e51b815260040161022c90610bcd565b604051631ed86f1960e01b81526001600160a01b03841690631ed86f1990610312908590600401610a93565b600060405180830381600087803b15801561032c57600080fd5b505af1158015610340573d6000803e3d6000fd5b5050600080555050505050565b604080516001808252818301909252606091602080830190803683370190505090506320c13b0b60e01b8160008151811061038457fe5b6001600160e01b03199092166020928302919091019091015290565b8060606103ab61034d565b905060005b815181101561043857826001600160a01b031663b149206e8383815181106103d457fe5b6020026020010151306040518363ffffffff1660e01b81526004016103fa929190610b31565b600060405180830381600087803b15801561041457600080fd5b505af1158015610428573d6000803e3d6000fd5b5050600190920191506103b09050565b50505050565b6000816020018351101561045157600080fd5b50016020015190565b6000806104726001845161062190919063ffffffff16565b90506000610486848363ffffffff61064916565b60ff16600481111561049457fe5b905060606104aa8560008563ffffffff61066516565b905060048260048111156104ba57fe5b14156104d5576104cb8787836106e5565b9350505050610581565b60028260048111156104e357fe5b141561051157856001600160a01b03166104fd88836107fc565b6001600160a01b0316149350505050610581565b600382600481111561051f57fe5b1415610579576000876040516020016105389190610a62565b604051602081830303815290604052805190602001209050866001600160a01b031661056482846107fc565b6001600160a01b031614945050505050610581565b600093505050505b9392505050565b80606061059361034d565b905060005b815181101561043857826001600160a01b031663b149206e8383815181106105bc57fe5b602002602001015160006040518363ffffffff1660e01b81526004016105e3929190610b31565b600060405180830381600087803b1580156105fd57600080fd5b505af1158015610611573d6000803e3d6000fd5b5050600190920191506105989050565b6000828211156106435760405162461bcd60e51b815260040161022c90610ba6565b50900390565b6000816001018351101561065c57600080fd5b50016001015190565b60608183018451101561067757600080fd5b606082158015610692576040519150602082016040526106dc565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156106cb5780518352602092830192016106b3565b5050858452601f01601f1916604052505b50949350505050565b600060606320c13b0b60e01b856040516020016107029190610af5565b60408051601f1981840301815290829052610721918690602401610b54565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b038381831617835250505050905060006060856001600160a01b0316836040516107729190610a46565b600060405180830381855afa9150503d80600081146107ad576040519150601f19603f3d011682016040523d82523d6000602084013e6107b2565b606091505b50915091508180156107c5575080516020145b80156107f157506320c13b0b60e01b6107e582600063ffffffff6108d416565b6001600160e01b031916145b979650505050505050565b6000815160411461080f575060006101c5565b60208201516040830151604184015160ff167f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a082111561085557600093505050506101c5565b8060ff16601b148061086a57508060ff16601c145b156108c857600186828585604051600081526020016040526040516108929493929190610afe565b6020604051602081039080840390855afa1580156108b4573d6000803e3d6000fd5b5050506020604051035193505050506101c5565b600093505050506101c5565b6000816004018351101561045157600080fd5b600082601f8301126108f7578081fd5b813567ffffffffffffffff8082111561090e578283fd5b604051601f8301601f19168101602001828111828210171561092e578485fd5b60405282815292508284830160200186101561094957600080fd5b8260208601602083013760006020848301015250505092915050565b600060208284031215610976578081fd5b815161058181610c30565b60008060408385031215610993578081fd5b823561099e81610c30565b915060208301356109ae81610c30565b809150509250929050565b600080604083850312156109cb578182fd5b823567ffffffffffffffff808211156109e2578384fd5b6109ee868387016108e7565b93506020850135915080821115610a03578283fd5b50610a10858286016108e7565b9150509250929050565b60008151808452610a32816020860160208601610c04565b601f01601f19169290920160200192915050565b60008251610a58818460208701610c04565b9190910192915050565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c810191909152603c0190565b6001600160a01b0391909116815260200190565b6020808252825182820181905260009190848201906040850190845b81811015610ae95783516001600160e01b03191683529284019291840191600101610ac3565b50909695505050505050565b90815260200190565b93845260ff9290921660208401526040830152606082015260800190565b6001600160e01b031991909116815260200190565b6001600160e01b03199290921682526001600160a01b0316602082015260400190565b600060408252610b676040830185610a1a565b8281036020840152610b798185610a1a565b95945050505050565b6020808252600a90820152695245454e5452414e435960b01b604082015260600190565b6020808252600d908201526c5355425f554e444552464c4f5760981b604082015260600190565b6020808252601f908201527f4e4f545f46524f4d5f4d45544154585f4f525f57414c4c45545f4f574e455200604082015260600190565b60005b83811015610c1f578181015183820152602001610c07565b838111156104385750506000910152565b6001600160a01b0381168114610c4557600080fd5b5056fea264697066735822122025502cbfe39ac8b0fba430691b0bf7340f40b12d68ff69c59d21f3c430b5919a64736f6c63430006060033

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100575760003560e01c80630f15f4c01461005c57806320c13b0b1461006657806351b42b001461008f5780635a1db8c414610097578063afa3363d146100aa575b600080fd5b6100646100bf565b005b6100796100743660046109b9565b610100565b6040516100869190610b1c565b60405180910390f35b6100646101cb565b6100646100a5366004610981565b61020c565b6100b261034d565b6040516100869190610aa7565b336100c9816103a0565b6040516001600160a01b038216907f0cc43938d137e7efade6a531f663e78c1fc75257b0d65ffda2fdaf70cb49cdf990600090a250565b60008083516020141561011f5761011884600061043e565b9050610128565b50825160208401205b6101aa336001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561016457600080fd5b505afa158015610178573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061019c9190610965565b82908563ffffffff61045a16565b156101bf57506320c13b0b60e01b90506101c5565b50600090505b92915050565b336101d581610588565b6040516001600160a01b038216907f749cb6b4c510bc468cf6b9c2086d6f0a54d6b18e25d37bf3200e68eab0880c0090600090a250565b600054156102355760405162461bcd60e51b815260040161022c90610b82565b60405180910390fd5b600160005581333014806102ca5750806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561027d57600080fd5b505afa158015610291573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102b59190610965565b6001600160a01b0316336001600160a01b0316145b6102e65760405162461bcd60e51b815260040161022c90610bcd565b604051631ed86f1960e01b81526001600160a01b03841690631ed86f1990610312908590600401610a93565b600060405180830381600087803b15801561032c57600080fd5b505af1158015610340573d6000803e3d6000fd5b5050600080555050505050565b604080516001808252818301909252606091602080830190803683370190505090506320c13b0b60e01b8160008151811061038457fe5b6001600160e01b03199092166020928302919091019091015290565b8060606103ab61034d565b905060005b815181101561043857826001600160a01b031663b149206e8383815181106103d457fe5b6020026020010151306040518363ffffffff1660e01b81526004016103fa929190610b31565b600060405180830381600087803b15801561041457600080fd5b505af1158015610428573d6000803e3d6000fd5b5050600190920191506103b09050565b50505050565b6000816020018351101561045157600080fd5b50016020015190565b6000806104726001845161062190919063ffffffff16565b90506000610486848363ffffffff61064916565b60ff16600481111561049457fe5b905060606104aa8560008563ffffffff61066516565b905060048260048111156104ba57fe5b14156104d5576104cb8787836106e5565b9350505050610581565b60028260048111156104e357fe5b141561051157856001600160a01b03166104fd88836107fc565b6001600160a01b0316149350505050610581565b600382600481111561051f57fe5b1415610579576000876040516020016105389190610a62565b604051602081830303815290604052805190602001209050866001600160a01b031661056482846107fc565b6001600160a01b031614945050505050610581565b600093505050505b9392505050565b80606061059361034d565b905060005b815181101561043857826001600160a01b031663b149206e8383815181106105bc57fe5b602002602001015160006040518363ffffffff1660e01b81526004016105e3929190610b31565b600060405180830381600087803b1580156105fd57600080fd5b505af1158015610611573d6000803e3d6000fd5b5050600190920191506105989050565b6000828211156106435760405162461bcd60e51b815260040161022c90610ba6565b50900390565b6000816001018351101561065c57600080fd5b50016001015190565b60608183018451101561067757600080fd5b606082158015610692576040519150602082016040526106dc565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156106cb5780518352602092830192016106b3565b5050858452601f01601f1916604052505b50949350505050565b600060606320c13b0b60e01b856040516020016107029190610af5565b60408051601f1981840301815290829052610721918690602401610b54565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b038381831617835250505050905060006060856001600160a01b0316836040516107729190610a46565b600060405180830381855afa9150503d80600081146107ad576040519150601f19603f3d011682016040523d82523d6000602084013e6107b2565b606091505b50915091508180156107c5575080516020145b80156107f157506320c13b0b60e01b6107e582600063ffffffff6108d416565b6001600160e01b031916145b979650505050505050565b6000815160411461080f575060006101c5565b60208201516040830151604184015160ff167f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a082111561085557600093505050506101c5565b8060ff16601b148061086a57508060ff16601c145b156108c857600186828585604051600081526020016040526040516108929493929190610afe565b6020604051602081039080840390855afa1580156108b4573d6000803e3d6000fd5b5050506020604051035193505050506101c5565b600093505050506101c5565b6000816004018351101561045157600080fd5b600082601f8301126108f7578081fd5b813567ffffffffffffffff8082111561090e578283fd5b604051601f8301601f19168101602001828111828210171561092e578485fd5b60405282815292508284830160200186101561094957600080fd5b8260208601602083013760006020848301015250505092915050565b600060208284031215610976578081fd5b815161058181610c30565b60008060408385031215610993578081fd5b823561099e81610c30565b915060208301356109ae81610c30565b809150509250929050565b600080604083850312156109cb578182fd5b823567ffffffffffffffff808211156109e2578384fd5b6109ee868387016108e7565b93506020850135915080821115610a03578283fd5b50610a10858286016108e7565b9150509250929050565b60008151808452610a32816020860160208601610c04565b601f01601f19169290920160200192915050565b60008251610a58818460208701610c04565b9190910192915050565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c810191909152603c0190565b6001600160a01b0391909116815260200190565b6020808252825182820181905260009190848201906040850190845b81811015610ae95783516001600160e01b03191683529284019291840191600101610ac3565b50909695505050505050565b90815260200190565b93845260ff9290921660208401526040830152606082015260800190565b6001600160e01b031991909116815260200190565b6001600160e01b03199290921682526001600160a01b0316602082015260400190565b600060408252610b676040830185610a1a565b8281036020840152610b798185610a1a565b95945050505050565b6020808252600a90820152695245454e5452414e435960b01b604082015260600190565b6020808252600d908201526c5355425f554e444552464c4f5760981b604082015260600190565b6020808252601f908201527f4e4f545f46524f4d5f4d45544154585f4f525f57414c4c45545f4f574e455200604082015260600190565b60005b83811015610c1f578181015183820152602001610c07565b838111156104385750506000910152565b6001600160a01b0381168114610c4557600080fd5b5056fea264697066735822122025502cbfe39ac8b0fba430691b0bf7340f40b12d68ff69c59d21f3c430b5919a64736f6c63430006060033

Deployed Bytecode Sourcemap

47211:1020:0:-:0;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;47211:1020:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12:1:-1;9;2:12;42809:187:0;;;:::i;:::-;;47704:524;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;43082:193;;;:::i;42502:221::-;;;;;;;;;:::i;47305:::-;;;:::i;:::-;;;;;;;;42809:187;42915:10;42936:19;42915:10;42936:11;:19::i;:::-;42971:17;;-1:-1:-1;;;;;42971:17:0;;;;;;;;42809:187;:::o;47704:524::-;47860:17;47895:12;47921:5;:12;47937:2;47921:18;47918:142;;;47963:29;47983:5;47990:1;47963:19;:29::i;:::-;47956:36;;47918:142;;;-1:-1:-1;48032:16:0;;;;;;47918:142;48074:60;48102:10;-1:-1:-1;;;;;48095:24:0;;:26;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;48095:26:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;48095:26:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;48095:26:0;;;;;;;;;48074:4;;48123:10;48074:60;:20;:60;:::i;:::-;48070:151;;;-1:-1:-1;;;;48158:10:0;-1:-1:-1;48151:17:0;;48070:151;-1:-1:-1;48208:1:0;;-1:-1:-1;47704:524:0;;;;;:::o;43082:193::-;43190:10;43211:21;43190:10;43211:13;:21::i;:::-;43248:19;;-1:-1:-1;;;;;43248:19:0;;;;;;;;43082:193;:::o;42502:221::-;37348:11;;:16;37340:39;;;;-1:-1:-1;;;37340:39:0;;;;;;;;;;;;;;;;;37404:1;37390:11;:15;42659:6;41831:10:::1;41853:4;41831:27;::::0;:67:::1;;;41883:6;-1:-1:-1::0;;;;;41876:20:0::1;;:22;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24::::0;17:12:::1;2:2;41876:22:0;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::1;77:16;74:1;67:27;5:2;41876:22:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;41876:22:0;;;;;;;;;-1:-1:-1::0;;;;;41862:36:0::1;:10;-1:-1:-1::0;;;;;41862:36:0::1;;41831:67;41809:138;;;;-1:-1:-1::0;;;41809:138:0::1;;;;;;;;;42683:32:::2;::::0;-1:-1:-1;;;42683:32:0;;-1:-1:-1;;;;;42683:24:0;::::2;::::0;::::2;::::0;:32:::2;::::0;42708:6;;42683:32:::2;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24::::0;17:12:::2;2:2;42683:32:0;;;;8:9:-1;5:2;;;45:16;42:1;39::::0;24:38:::2;77:16;74:1;67:27;5:2;-1:-1:::0;;37442:1:0;37428:15;;-1:-1:-1;;;;;42502:221:0:o;47305:::-;47449:15;;;47462:1;47449:15;;;;;;;;;47398:23;;47449:15;;;;;;109:14:-1;47449:15:0;88:42:-1;144:17;;-1:-1;47449:15:0;47439:25;;47488:30;;;47475:7;47483:1;47475:10;;;;;;;;-1:-1:-1;;;;;;47475:43:0;;;:10;;;;;;;;;;;:43;47305:221;:::o;43836:276::-;43925:6;43943:23;43969:17;:15;:17::i;:::-;43943:43;-1:-1:-1;44002:6:0;43997:108;44018:7;:14;44014:1;:18;43997:108;;;44054:1;-1:-1:-1;;;;;44054:12:0;;44067:7;44075:1;44067:10;;;;;;;;;;;;;;44087:4;44054:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;44054:39:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;44034:3:0;;;;;-1:-1:-1;43997:108:0;;-1:-1:-1;43997:108:0;;;43836:276;;;:::o;20932:304::-;21009:7;21055:6;21064:2;21055:11;21037:6;:13;:30;;21029:39;;12:1:-1;9;2:12;21029:39:0;-1:-1:-1;21156:30:0;21172:4;21156:30;21150:37;;20932:304::o;31165:1003::-;31338:4;31360:24;31387:23;31408:1;31387:9;:16;:20;;:23;;;;:::i;:::-;31360:50;-1:-1:-1;31421:27:0;31465:38;:9;31360:50;31465:38;:17;:38;:::i;:::-;31451:53;;;;;;;;;;31421:83;-1:-1:-1;31517:21:0;31541:39;:9;31557:1;31560:19;31541:39;:15;:39;:::i;:::-;31517:63;-1:-1:-1;31614:20:0;31597:13;:37;;;;;;;;;31593:568;;;31658:50;31681:8;31691:6;31699:8;31658:22;:50::i;:::-;31651:57;;;;;;;31593:568;31747:21;31730:13;:38;;;;;;;;;31726:435;;;31834:6;-1:-1:-1;;;;;31792:48:0;:38;31811:8;31821;31792:18;:38::i;:::-;-1:-1:-1;;;;;31792:48:0;;31785:55;;;;;;;31726:435;31879:22;31862:13;:39;;;;;;;;;31858:303;;;31918:12;32014:8;31961:62;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;31961:62:0;;;31933:105;;;;;;31918:120;;32098:6;-1:-1:-1;;;;;32060:44:0;:34;32079:4;32085:8;32060:18;:34::i;:::-;-1:-1:-1;;;;;32060:44:0;;32053:51;;;;;;;;31858:303;32144:5;32137:12;;;;;31165:1003;;;;;;:::o;44177:275::-;44268:6;44286:23;44312:17;:15;:17::i;:::-;44286:43;-1:-1:-1;44345:6:0;44340:105;44361:7;:14;44357:1;:18;44340:105;;;44397:1;-1:-1:-1;;;;;44397:12:0;;44410:7;44418:1;44410:10;;;;;;;;;;;;;;44430:1;44397:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;44397:36:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;44377:3:0;;;;;-1:-1:-1;44340:105:0;;-1:-1:-1;44340:105:0;5776:193;5884:4;5919:1;5914;:6;;5906:32;;;;-1:-1:-1;;;5906:32:0;;;;;;;;;-1:-1:-1;5956:5:0;;;5776:193::o;18536:287::-;18611:5;18655:6;18664:1;18655:10;18637:6;:13;:29;;18629:38;;12:1:-1;9;2:12;18629:38:0;-1:-1:-1;18747:29:0;18763:3;18747:29;18741:36;;18536:287::o;15583:2599::-;15730:12;15795:7;15786:6;:16;15768:6;:13;:35;;15760:44;;12:1:-1;9;2:12;15760:44:0;15817:22;15883:15;;15912:2005;;;;18061:4;18055:11;18042:24;;18114:4;18103:9;18099:20;18093:4;18086:34;15876:2259;;15912:2005;16097:4;16091:11;16078:24;;16766:2;16757:7;16753:16;17154:9;17147:17;17141:4;17137:28;17125:9;17114;17110:25;17106:60;17203:7;17199:2;17195:16;17460:6;17446:9;17439:17;17433:4;17429:28;17417:9;17409:6;17405:22;17401:57;17397:70;17231:434;17494:3;17490:2;17487:11;17231:434;;;17636:9;;17625:21;;17536:4;17528:13;;;;17569;17231:434;;;-1:-1:-1;;17685:26:0;;;17897:2;17880:11;-1:-1:-1;;17876:25:0;17870:4;17863:39;-1:-1:-1;15876:2259:0;-1:-1:-1;18165:9:0;15583:2599;-1:-1:-1;;;;15583:2599:0:o;32176:595::-;32354:4;32376:21;32437:36;;;32499:8;32488:20;;;;;;;;;;;;;-1:-1:-1;;26:21;;;22:32;6:49;;32488:20:0;;;;32400:143;;32523:9;;32400:143;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;32400:143:0;;;;-1:-1:-1;;;;;32400:143:0;;38:4:-1;29:7;25:18;67:10;61:17;-1:-1;;;;;199:8;192:4;186;182:15;179:29;167:10;160:49;0:215;;;32400:143:0;32376:167;;32555:12;32569:19;32592:6;-1:-1:-1;;;;;32592:17:0;32610:8;32592:27;;;;;;;;;;;;;;;;;;;;;;12:1:-1;19;14:27;;;;67:4;61:11;56:16;;134:4;130:9;123:4;105:16;101:27;97:43;94:1;90:51;84:4;77:65;157:16;154:1;147:27;211:16;208:1;201:4;198:1;194:12;179:49;5:228;;14:27;32:4;27:9;;5:228;;32554:65:0;;;;32652:7;:43;;;;;32676:6;:13;32693:2;32676:19;32652:43;:100;;;;-1:-1:-1;;;;32712:18:0;:6;32728:1;32712:18;:15;:18;:::i;:::-;-1:-1:-1;;;;;;32712:40:0;;32652:100;32630:133;32176:595;-1:-1:-1;;;;;;;32176:595:0:o;32779:1116::-;32933:7;32962:9;:16;32982:2;32962:22;32958:72;;-1:-1:-1;33016:1:0;33001:17;;32958:72;33367:4;33352:20;;33346:27;33413:4;33398:20;;33392:27;33463:4;33448:20;;33442:27;33471:4;33438:38;33630:66;33617:79;;33613:129;;;33728:1;33713:17;;;;;;;33613:129;33756:1;:7;;33761:2;33756:7;:18;;;;33767:1;:7;;33772:2;33767:7;33756:18;33752:136;;;33798:28;33808:8;33818:1;33821;33824;33798:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;33798:28:0;;;;;;;;33791:35;;;;;;;33752:136;33874:1;33859:17;;;;;;;20627:297;20703:6;20748;20757:1;20748:10;20730:6;:13;:29;;20722:38;;12:1:-1;9;2:12;284:440;;385:3;378:4;370:6;366:17;362:27;352:2;;-1:-1;;393:12;352:2;440:6;427:20;11012:18;;11004:6;11001:30;10998:2;;;-1:-1;;11034:12;10998:2;10668;10662:9;11107;11088:17;;-1:-1;;11084:33;10694:17;;11175:4;10694:17;10754:34;;;10790:22;;;10751:62;10748:2;;;-1:-1;;10816:12;10748:2;10668;10835:22;532:21;;;453:73;-1:-1;453:73;632:16;;;11175:4;632:16;629:25;-1:-1;626:2;;;667:1;;657:12;626:2;13580:6;11175:4;574:6;570:17;11175:4;608:5;604:16;13557:30;13636:1;11175:4;13627:6;608:5;13618:16;;13611:27;;;;345:379;;;;;732:263;;847:2;835:9;826:7;822:23;818:32;815:2;;;-1:-1;;853:12;815:2;226:6;220:13;238:33;265:5;238:33;;1002:366;;;1123:2;1111:9;1102:7;1098:23;1094:32;1091:2;;;-1:-1;;1129:12;1091:2;85:6;72:20;97:33;124:5;97:33;;;1181:63;-1:-1;1281:2;1320:22;;72:20;97:33;72:20;97:33;;;1289:63;;;;1085:283;;;;;;1375:574;;;1514:2;1502:9;1493:7;1489:23;1485:32;1482:2;;;-1:-1;;1520:12;1482:2;1578:17;1565:31;1616:18;;1608:6;1605:30;1602:2;;;-1:-1;;1638:12;1602:2;1668:62;1722:7;1713:6;1702:9;1698:22;1668:62;;;1658:72;;1795:2;1784:9;1780:18;1767:32;1753:46;;1616:18;1811:6;1808:30;1805:2;;;-1:-1;;1841:12;1805:2;;1871:62;1925:7;1916:6;1905:9;1901:22;1871:62;;;1861:72;;;1476:473;;;;;;3625:343;;3767:5;11456:12;11869:6;11864:3;11857:19;3860:52;3905:6;11906:4;11901:3;11897:14;11906:4;3886:5;3882:16;3860:52;;;11107:9;14078:14;-1:-1;;14074:28;3924:39;;;;11906:4;3924:39;;3715:253;-1:-1;;3715:253;5842:262;;4135:5;11456:12;4246:52;4291:6;4286:3;4279:4;4272:5;4268:16;4246:52;;;4310:16;;;;;5967:137;-1:-1;;5967:137;6111:511;4635:66;4615:87;;4599:2;4721:12;;3193:37;;;;6585:12;;;6319:303;6629:213;-1:-1;;;;;12965:54;;;;2354:37;;6747:2;6732:18;;6718:124;6849:357;7015:2;7029:47;;;11456:12;;7000:18;;;11857:19;;;6849:357;;7015:2;11311:14;;;;11897;;;;6849:357;2835:257;2860:6;2857:1;2854:13;2835:257;;;2921:13;;-1:-1;;;;;;12813:78;3460:36;;11713:14;;;;2106;;;;2882:1;2875:9;2835:257;;;-1:-1;7082:114;;6986:220;-1:-1;;;;;;6986:220;7213:213;3193:37;;;7331:2;7316:18;;7302:124;7433:539;3193:37;;;13102:4;13091:16;;;;7792:2;7777:18;;5795:35;7875:2;7860:18;;3193:37;7958:2;7943:18;;3193:37;7631:3;7616:19;;7602:370;7979:209;-1:-1;;;;;;12813:78;;;;3460:36;;8095:2;8080:18;;8066:122;8195:320;-1:-1;;;;;;12813:78;;;;3460:36;;-1:-1;;;;;12965:54;8501:2;8486:18;;2354:37;8339:2;8324:18;;8310:205;8865:492;;9047:2;9068:17;9061:47;9122:76;9047:2;9036:9;9032:18;9184:6;9122:76;;;9246:9;9240:4;9236:20;9231:2;9220:9;9216:18;9209:48;9271:76;9342:4;9333:6;9271:76;;;9263:84;9018:339;-1:-1;;;;;9018:339;9364:407;9555:2;9569:47;;;4972:2;9540:18;;;11857:19;-1:-1;;;11897:14;;;4988:33;5040:12;;;9526:245;9778:407;9969:2;9983:47;;;5291:2;9954:18;;;11857:19;-1:-1;;;11897:14;;;5307:36;5362:12;;;9940:245;10192:407;10383:2;10397:47;;;5613:2;10368:18;;;11857:19;5649:33;11897:14;;;5629:54;5702:12;;;10354:245;13653:268;13718:1;13725:101;13739:6;13736:1;13733:13;13725:101;;;13806:11;;;13800:18;13787:11;;;13780:39;13761:2;13754:10;13725:101;;;13841:6;13838:1;13835:13;13832:2;;;-1:-1;;13718:1;13888:16;;13881:27;13702:219;14115:117;-1:-1;;;;;12965:54;;14174:35;;14164:2;;14223:1;;14213:12;14164:2;14158:74;

Swarm Source

ipfs://25502cbfe39ac8b0fba430691b0bf7340f40b12d68ff69c59d21f3c430b5919a

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.