Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0xe7d8df8F6546965A59dab007e8709965Efe1255d
Balance 0 ETH
Nonce 3426
Code Size 9143 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

9143 bytes
0x608060405234801561001057600080fd5b506004361061011b5760003560e01c80639870d7fe116100b2578063ce15861211610081578063d92d1f5611610066578063d92d1f5614610211578063e673df8a14610224578063f2fde38b146102395761011b565b8063ce158612146101f6578063d70e2000146102095761011b565b80639870d7fe146101b5578063ac8a584a146101c8578063b6830d8f146101db578063bd820688146101ee5761011b565b8063715018a6116100ee578063715018a6146101865780638117abc1146101905780638da5cb5b1461019857806390610b0e146101a05761011b565b80633644e515146101205780634c30d6c91461013e5780635b29128f146101465780636d70f7ae14610166575b600080fd5b61012861024c565b6040516101359190611ec3565b60405180910390f35b610128610270565b610159610154366004611b8a565b610294565b6040516101359190611d73565b610179610174366004611b47565b6104a8565b6040516101359190611eb8565b61018e6104dc565b005b6101596105d1565b6101596105f5565b6101a8610611565b6040516101359190611f98565b61018e6101c3366004611b47565b61064a565b61018e6101d6366004611b47565b6106dc565b6101286101e9366004611b61565b6107d0565b61012861083b565b610159610204366004611b61565b61086b565b6101a861087f565b61015961021f366004611b8a565b610942565b61022c6109f1565b6040516101359190611e5e565b61018e610247366004611b47565b610a1c565b7f21e7d5769ed93f69f85c1371d948f36256fbf72dfc5d582df976ff99d15941b881565b7f4392cdd6c9d91e0896c5def13bad6473db5d21e2b0def85ab8c2475c3e60d14c81565b600061029f336104a8565b6102de576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102d590611fe2565b60405180910390fd5b8260e0013582111561031c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102d590611fab565b600061032b6020850185611b47565b73ffffffffffffffffffffffffffffffffffffffff161415610379576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102d590612076565b61039761038c6040850160208601611b47565b846101000135610c28565b905073ffffffffffffffffffffffffffffffffffffffff811663d6bb65c26103c26020860186611b47565b6103cf60408701876120e4565b60608801356103e460a08a0160808b01611b47565b6103f460c08b0160a08c01611b47565b61040460e08c0160c08d01611b47565b8a6040518963ffffffff1660e01b8152600401610428989796959493929190611dbb565b600060405180830381600087803b15801561044257600080fd5b505af1158015610456573d6000803e3d6000fd5b507f5b03bfed1c14a02bdeceb5fa582eb1a5765fc0bc64ca0e6af4c20afc9487f081925083915061048c90506020860186611b47565b60405161049a929190611d94565b60405180910390a192915050565b60006104d47fe63c388d4543ca9e94c981423c48d71e347af88fa97254eee172e5d43f973b0583610c44565b90505b919050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461056257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a45440000000000000000000000000000000000000000604482015290519081900360640190fd5b6000805460405173ffffffffffffffffffffffffffffffffffffffff909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b7f00000000000000000000000023a19a97a2da581e3d66ef5fd1eea15024f5561181565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b6040518060400160405280600f81526020017f57414c4c45545f4352454154494f4e000000000000000000000000000000000081525081565b60005473ffffffffffffffffffffffffffffffffffffffff1633146106d057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a45440000000000000000000000000000000000000000604482015290519081900360640190fd5b6106d981610c7e565b50565b60005473ffffffffffffffffffffffffffffffffffffffff16331461076257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a45440000000000000000000000000000000000000000604482015290519081900360640190fd5b61078c7fe63c388d4543ca9e94c981423c48d71e347af88fa97254eee172e5d43f973b0582610cee565b60405173ffffffffffffffffffffffffffffffffffffffff8216907f80c0b871b97b595b16a7741c1b06fed0c6f6f558639f18ccbce50724325dc40d90600090a250565b60006040518060400160405280600f81526020017f57414c4c45545f4352454154494f4e0000000000000000000000000000000000815250838360405160200161081c93929190611cc9565b6040516020818303038152906040528051906020012090505b92915050565b60006108667fe63c388d4543ca9e94c981423c48d71e347af88fa97254eee172e5d43f973b05610f09565b905090565b6000610878838330610f1e565b9392505050565b60606040518060200161089190611afe565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082820381018352601f9091011660408190526108f2907f00000000000000000000000023a19a97a2da581e3d66ef5fd1eea15024f5561190602001611d73565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905261092e9291602001611c9a565b604051602081830303815290604052905090565b600061094d336104a8565b610983576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102d590611fe2565b8260c001358211156109c1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102d590611fab565b6109ca83610f43565b6109e46109da6020850185611b47565b8460e00135610c28565b905061083581848461113b565b60606108667fe63c388d4543ca9e94c981423c48d71e347af88fa97254eee172e5d43f973b05611249565b60005473ffffffffffffffffffffffffffffffffffffffff163314610aa257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a45440000000000000000000000000000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff8116610b2457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f5a45524f5f414444524553530000000000000000000000000000000000000000604482015290519081900360640190fd5b6000805460405173ffffffffffffffffffffffffffffffffffffffff808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6000804690507f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f836000015180519060200120846020015180519060200120838660400151604051602001610c0a959493929190611f28565b60405160208183030381529060405280519060200120915050919050565b6000610878610c3784846107d0565b610c3f61087f565b611346565b600082815260016020818152604080842073ffffffffffffffffffffffffffffffffffffffff861685529092019052902054151592915050565b610caa7fe63c388d4543ca9e94c981423c48d71e347af88fa97254eee172e5d43f973b058260016113d7565b60405173ffffffffffffffffffffffffffffffffffffffff8216907fac6fa858e9350a46cec16539926e0fde25b7629f84b5a72bffaae4df888ae86d90600090a250565b600082815260016020818152604080842073ffffffffffffffffffffffffffffffffffffffff861685529283019091529091205480610d8e57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f4e4f545f494e5f53455400000000000000000000000000000000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff831660009081526001830160205260408120556002820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019055815415610f0357600082600001836002015481548110610dfc57fe5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff908116915084168114610e9e5780836000016001840381548110610e3d57fe5b600091825260208083209190910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff948516179055918316815260018501909152604090208290555b8254839080610ea957fe5b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055019055505b50505050565b60009081526001602052604090206002015490565b6000610f3b610f2d85856107d0565b610f3561087f565b846115f2565b949350505050565b6000610f526020830183611b47565b73ffffffffffffffffffffffffffffffffffffffff161415610fa0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102d590612076565b60007f4392cdd6c9d91e0896c5def13bad6473db5d21e2b0def85ab8c2475c3e60d14c610fd06020840184611b47565b610fdd60208501856120e4565b604051602001610fee929190611c31565b60405160208183030381529060405280519060200120846040013585606001602081019061101c9190611b47565b61102c60a0880160808901611b47565b61103c60c0890160a08a01611b47565b8860c001358960e0013560405160200161105e99989796959493929190611ecc565b60405160208183030381529060405280519060200120905060006110a27f21e7d5769ed93f69f85c1371d948f36256fbf72dfc5d582df976ff99d15941b883611691565b90506111006110b46020850185611b47565b6110c2610100860186612150565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508694939250506116dd9050565b611136576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102d59061203f565b505050565b73ffffffffffffffffffffffffffffffffffffffff831663d6bb65c26111646020850185611b47565b61117160208601866120e4565b60408701356111866080890160608a01611b47565b61119660a08a0160808b01611b47565b6111a660c08b0160a08c01611b47565b896040518963ffffffff1660e01b81526004016111ca989796959493929190611dbb565b600060405180830381600087803b1580156111e457600080fd5b505af11580156111f8573d6000803e3d6000fd5b507f5b03bfed1c14a02bdeceb5fa582eb1a5765fc0bc64ca0e6af4c20afc9487f081925085915061122e90506020850185611b47565b60405161123c929190611d94565b60405180910390a1505050565b60008181526001602052604090208054600282015460609291146112ce57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e4f545f4d41494e5441494e4544000000000000000000000000000000000000604482015290519081900360640190fd5b6000838152600160209081526040918290208054835181840281018401909452808452909183018282801561133957602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff16815260019091019060200180831161130e575b5050505050915050919050565b600080838351602085016000f5905073ffffffffffffffffffffffffffffffffffffffff811661087857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f435245415445325f4641494c4544000000000000000000000000000000000000604482015290519081900360640190fd5b600083815260016020818152604080842073ffffffffffffffffffffffffffffffffffffffff87168552928301909152909120541561147757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f414c52454144595f494e5f534554000000000000000000000000000000000000604482015290519081900360640190fd5b81156115455760028101548154146114f057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f50524556494f55534c595f4e4f545f4d41494e5441494c454400000000000000604482015290519081900360640190fd5b80546001810182556000828152602090200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff85161790556115b3565b8054156115b357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f4d5553545f4d41494e5441494e00000000000000000000000000000000000000604482015290519081900360640190fd5b60028101805460019081019182905573ffffffffffffffffffffffffffffffffffffffff90941660009081529190930160205260409020919091555050565b8151602092830120604080517fff000000000000000000000000000000000000000000000000000000000000008186015260609390931b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660218401526035830194909452605580830191909152835180830390910181526075909101909252815191012073ffffffffffffffffffffffffffffffffffffffff1690565b60006040518060400160405280600281526020017f1901000000000000000000000000000000000000000000000000000000000000815250838360405160200161081c93929190611d1b565b600073ffffffffffffffffffffffffffffffffffffffff831661170257506000610878565b6117218373ffffffffffffffffffffffffffffffffffffffff16611740565b61173557611730848484611777565b610f3b565b610f3b8484846118b0565b6000813f801580159061087857507fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470141592915050565b600073ffffffffffffffffffffffffffffffffffffffff831661179c57506000610878565b8151604114806117ad575081516042145b6117e3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102d5906120ad565b60008251604214156117f757506041825260015b6118018584611a0a565b73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161491508161189d576000856040516020016118499190611d42565b60405160208183030381529060405280519060200120905061186b8185611a0a565b73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16149250505b80156118a857604283525b509392505050565b600080631626ba7e60e01b85846040516024016118ce929190611f61565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090506000808573ffffffffffffffffffffffffffffffffffffffff16836040516119559190611c7e565b600060405180830381855afa9150503d8060008114611990576040519150601f19603f3d011682016040523d82523d6000602084013e611995565b606091505b50915091508180156119a8575080516020145b80156119ff57507f1626ba7e000000000000000000000000000000000000000000000000000000006119db826000611ae2565b7fffffffff0000000000000000000000000000000000000000000000000000000016145b979650505050505050565b60008151604114611a1d57506000610835565b60208201516040830151604184015160ff167f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0821115611a635760009350505050610835565b8060ff16601b1480611a7857508060ff16601c145b15611ad65760018682858560405160008152602001604052604051611aa09493929190611f7a565b6020604051602081039080840390855afa158015611ac2573d6000803e3d6000fd5b505050602060405103519350505050610835565b60009350505050610835565b60008160040183511015611af557600080fd5b50016020015190565b6101a2806121e083390190565b803573ffffffffffffffffffffffffffffffffffffffff811681146104d757600080fd5b60006101208284031215611b41578081fd5b50919050565b600060208284031215611b58578081fd5b61087882611b0b565b60008060408385031215611b73578081fd5b611b7c83611b0b565b946020939093013593505050565b60008060408385031215611b9c578182fd5b823567ffffffffffffffff811115611bb2578283fd5b611bbe85828601611b2f565b95602094909401359450505050565b73ffffffffffffffffffffffffffffffffffffffff169052565b60008151808452611bff8160208601602086016121b3565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60008184825b85811015611c735773ffffffffffffffffffffffffffffffffffffffff611c5d83611b0b565b1683526020928301929190910190600101611c37565b509095945050505050565b60008251611c908184602087016121b3565b9190910192915050565b60008351611cac8184602088016121b3565b835190830190611cc08183602088016121b3565b01949350505050565b60008451611cdb8184602089016121b3565b60609490941b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001691909301908152601481019190915260340192915050565b60008451611d2d8184602089016121b3565b91909101928352506020820152604001919050565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c810191909152603c0190565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b73ffffffffffffffffffffffffffffffffffffffff92831681529116602082015260400190565b73ffffffffffffffffffffffffffffffffffffffff898116825260e060208084018290529083018990526000918a916101008501845b8c811015611e165783611e0386611b0b565b1682529382019390820190600101611df1565b5080945050505050866040830152611e316060830187611bcd565b611e3e6080830186611bcd565b611e4b60a0830185611bcd565b8260c08301529998505050505050505050565b6020808252825182820181905260009190848201906040850190845b81811015611eac57835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101611e7a565b50909695505050505050565b901515815260200190565b90815260200190565b98895273ffffffffffffffffffffffffffffffffffffffff97881660208a0152604089019690965260608801949094529185166080870152841660a086015290921660c084015260e08301919091526101008201526101200190565b94855260208501939093526040840191909152606083015273ffffffffffffffffffffffffffffffffffffffff16608082015260a00190565b600083825260406020830152610f3b6040830184611be7565b93845260ff9290921660208401526040830152606082015260800190565b6000602082526108786020830184611be7565b60208082526012908201527f494e56414c49445f4645455f414d4f554e540000000000000000000000000000604082015260600190565b60208082526025908201527f444953414c4c4f5745445f4f4e5f494d504c454d454e544154494f4e5f434f4e60408201527f5452414354000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526011908201527f494e56414c49445f5349474e4154555245000000000000000000000000000000604082015260600190565b6020808252600d908201527f494e56414c49445f4f574e455200000000000000000000000000000000000000604082015260600190565b60208082526018908201527f494e56414c49445f5349474e41545552455f4c454e4754480000000000000000604082015260600190565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612118578283fd5b83018035915067ffffffffffffffff821115612132578283fd5b602090810192508102360382131561214957600080fd5b9250929050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612184578283fd5b83018035915067ffffffffffffffff82111561219e578283fd5b60200191503681900382131561214957600080fd5b60005b838110156121ce5781810151838201526020016121b6565b83811115610f03575050600091015256fe608060405234801561001057600080fd5b506040516101a23803806101a28339818101604052602081101561003357600080fd5b50516001600160a01b03811661007a5760405162461bcd60e51b815260040180806020018281038252602481526020018061017e6024913960400191505060405180910390fd5b600080546001600160a01b039092166001600160a01b031990921691909117905560d5806100a96000396000f3fe608060405236603757604051339034907f8863e458255c600ae3e61be347822f3ee57088c8538b68b5dd2357e682e59e1990600090a3005b600073ffffffffffffffffffffffffffffffffffffffff8154167fa619486e0000000000000000000000000000000000000000000000000000000082351415608157808252602082f35b3682833781823684845af490503d82833e80609a573d82fd5b503d81f3fea2646970667358221220c8ef5c5147809cc480e3260788e027fa751bfcf051cf3d463bbaeeff798437f364736f6c63430007060033496e76616c6964206d617374657220636f707920616464726573732070726f7669646564a2646970667358221220d360ac2fd16db0e2272cb7800faab58e4941ce65b486740fe5c9e68f7461a3e664736f6c63430007060033

Verified Source Code Full Match

Compiler: v0.7.6+commit.7338295f EVM: istanbul Optimization: Yes (100000 runs)
EIP712.sol 56 lines
// SPDX-License-Identifier: Apache-2.0
// Copyright 2017 Loopring Technology Limited.
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;


library EIP712
{
    struct Domain {
        string  name;
        string  version;
        address verifyingContract;
    }

    bytes32 constant internal EIP712_DOMAIN_TYPEHASH = keccak256(
        "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
    );

    string constant internal EIP191_HEADER = "\x19\x01";

    function hash(Domain memory domain)
        internal
        pure
        returns (bytes32)
    {
        uint _chainid;
        assembly { _chainid := chainid() }

        return keccak256(
            abi.encode(
                EIP712_DOMAIN_TYPEHASH,
                keccak256(bytes(domain.name)),
                keccak256(bytes(domain.version)),
                _chainid,
                domain.verifyingContract
            )
        );
    }

    function hashPacked(
        bytes32 domainSeparator,
        bytes32 dataHash
        )
        internal
        pure
        returns (bytes32)
    {
        return keccak256(
            abi.encodePacked(
                EIP191_HEADER,
                domainSeparator,
                dataHash
            )
        );
    }
}
ERC1271.sol 16 lines
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright 2017 Loopring Technology Limited.
pragma solidity ^0.7.0;

abstract contract ERC1271 {
    // bytes4(keccak256("isValidSignature(bytes32,bytes)")
    bytes4 constant internal ERC1271_MAGICVALUE = 0x1626ba7e;

    function isValidSignature(
        bytes32      _hash,
        bytes memory _signature)
        public
        view
        virtual
        returns (bytes4 magicValue);
}
Ownable.sol 56 lines
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright 2017 Loopring Technology Limited.
pragma solidity ^0.7.0;


/// @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()
    {
        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);
    }
}
MathUint.sol 45 lines
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright 2017 Loopring Technology Limited.
pragma solidity ^0.7.0;


/// @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");
    }
}
AddressSet.sol 96 lines
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright 2017 Loopring Technology Limited.
pragma solidity ^0.7.0;


/// @title AddressSet
/// @author Daniel Wang - <[email protected]>
contract AddressSet
{
    struct Set
    {
        address[] addresses;
        mapping (address => uint) positions;
        uint count;
    }
    mapping (bytes32 => Set) private sets;

    function addAddressToSet(
        bytes32 key,
        address addr,
        bool    maintainList
        ) internal
    {
        Set storage set = sets[key];
        require(set.positions[addr] == 0, "ALREADY_IN_SET");

        if (maintainList) {
            require(set.addresses.length == set.count, "PREVIOUSLY_NOT_MAINTAILED");
            set.addresses.push(addr);
        } else {
            require(set.addresses.length == 0, "MUST_MAINTAIN");
        }

        set.count += 1;
        set.positions[addr] = set.count;
    }

    function removeAddressFromSet(
        bytes32 key,
        address addr
        )
        internal
    {
        Set storage set = sets[key];
        uint pos = set.positions[addr];
        require(pos != 0, "NOT_IN_SET");

        delete set.positions[addr];
        set.count -= 1;

        if (set.addresses.length > 0) {
            address lastAddr = set.addresses[set.count];
            if (lastAddr != addr) {
                set.addresses[pos - 1] = lastAddr;
                set.positions[lastAddr] = pos;
            }
            set.addresses.pop();
        }
    }

    function removeSet(bytes32 key)
        internal
    {
        delete sets[key];
    }

    function isAddressInSet(
        bytes32 key,
        address addr
        )
        internal
        view
        returns (bool)
    {
        return sets[key].positions[addr] != 0;
    }

    function numAddressesInSet(bytes32 key)
        internal
        view
        returns (uint)
    {
        Set storage set = sets[key];
        return set.count;
    }

    function addressesInSet(bytes32 key)
        internal
        view
        returns (address[] memory)
    {
        Set storage set = sets[key];
        require(set.count == set.addresses.length, "NOT_MAINTAINED");
        return sets[key].addresses;
    }
}
AddressUtil.sol 116 lines
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright 2017 Loopring Technology Limited.
pragma solidity ^0.7.0;


/// @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)
    {
        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
        // for accounts without code, i.e. `keccak256('')`
        bytes32 codehash;
        // solhint-disable-next-line no-inline-assembly
        assembly { codehash := extcodehash(addr) }
        return (codehash != 0x0 &&
                codehash != 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470);
    }

    function toPayable(
        address addr
        )
        internal
        pure
        returns (address payable)
    {
        return payable(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");
    }

    // Works like call but is slightly more efficient when data
    // needs to be copied from memory to do the call.
    function fastCall(
        address to,
        uint    gasLimit,
        uint    value,
        bytes   memory data
        )
        internal
        returns (bool success, bytes memory returnData)
    {
        if (to != address(0)) {
            assembly {
                // Do the call
                success := call(gasLimit, to, value, add(data, 32), mload(data), 0, 0)
                // Copy the return data
                let size := returndatasize()
                returnData := mload(0x40)
                mstore(returnData, size)
                returndatacopy(add(returnData, 32), 0, size)
                // Update free memory pointer
                mstore(0x40, add(returnData, add(32, size)))
            }
        }
    }

    // Like fastCall, but throws when the call is unsuccessful.
    function fastCallAndVerify(
        address to,
        uint    gasLimit,
        uint    value,
        bytes   memory data
        )
        internal
        returns (bytes memory returnData)
    {
        bool success;
        (success, returnData) = fastCall(to, gasLimit, value, data);
        if (!success) {
            assembly {
                revert(add(returnData, 32), mload(returnData))
            }
        }
    }
}
SignatureUtil.sol 167 lines
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright 2017 Loopring Technology Limited.
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;

import "../thirdparty/BytesUtil.sol";
import "./AddressUtil.sol";
import "./ERC1271.sol";
import "./MathUint.sol";


/// @title SignatureUtil
/// @author Daniel Wang - <[email protected]>
/// @dev This method supports multihash standard. Each signature's last byte indicates
///      the signature's type.
library SignatureUtil
{
    using BytesUtil     for bytes;
    using MathUint      for uint;
    using AddressUtil   for address;

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

    bytes4 constant internal ERC1271_MAGICVALUE = 0x1626ba7e;

    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)
    {
        if (signer == address(0)) {
            return false;
        }

        return signer.isContract()?
            verifyERC1271Signature(signHash, signer, signature):
            verifyEOASignature(signHash, signer, signature);
    }

    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);
        }
    }

    function verifyEOASignature(
        bytes32        signHash,
        address        signer,
        bytes   memory signature
        )
        private
        pure
        returns (bool success)
    {
        if (signer == address(0)) {
            return false;
        }

	require(signature.length == 65 || signature.length == 66, "INVALID_SIGNATURE_LENGTH");

	bool trimmed = false;
	if (signature.length == 66) {
	    // Strip off the last byte of the signature by updating the length
	    assembly {
		mstore(signature, 65)
	    }

	    trimmed = true;
	}

	success = (signer == recoverECDSASigner(signHash, signature));
	if (!success) {
            bytes32 hash = keccak256(
                abi.encodePacked("\x19Ethereum Signed Message:\n32", signHash)
            );
            success = (signer == recoverECDSASigner(hash, signature));
        }

	if (trimmed) {
	    // Restore the signature length
	    assembly {
		mstore(signature, 66)
	    }
	}
    }

    function verifyERC1271Signature(
        bytes32 signHash,
        address signer,
        bytes   memory signature
        )
        private
        view
        returns (bool)
    {
        bytes memory callData = abi.encodeWithSelector(
            ERC1271.isValidSignature.selector,
            signHash,
            signature
        );
        (bool success, bytes memory result) = signer.staticcall(callData);
        return (
            success &&
            result.length == 32 &&
            result.toBytes4(0) == ERC1271_MAGICVALUE
        );
    }
}
WalletFactory.sol 245 lines
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright 2017 Loopring Technology Limited.
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;

import "../iface/ILoopringWalletV2.sol";
import "../lib/EIP712.sol";
import "../lib/SignatureUtil.sol";
import "./WalletDeploymentLib.sol";
import "../lib/Ownable.sol";
import "../lib/AddressSet.sol";


/// @title WalletFactory
/// @dev A factory contract to create a new wallet by deploying a proxy
///      in front of a real wallet.
/// @author Daniel Wang - <[email protected]>
contract WalletFactory is WalletDeploymentLib, Ownable, AddressSet
{

    bytes32 internal constant OPERATOR = keccak256("__OPERATOR__");
    using SignatureUtil for bytes32;

    event WalletCreated (address wallet, address owner);

    event OperatorRemoved  (address indexed operator);
    event OperatorAdded(address indexed operator);

    bytes32             public immutable DOMAIN_SEPARATOR;

    bytes32 public constant CREATE_WALLET_TYPEHASH = keccak256(
        "createWallet(address owner,address[] guardians,uint256 quota,address inheritor,address feeRecipient,address feeToken,uint256 maxFeeAmount,uint256 salt)");

    ///////////////////////////////// opeartor ///////////////////
    modifier onlyOperator
    {
        require(isOperator(msg.sender), "DISALLOWED_ON_IMPLEMENTATION_CONTRACT");
        _;
    }

    function isOperator(address addr)
        public
        view
        returns (bool)
    {
        return isAddressInSet(OPERATOR, addr);
    }

    /// @dev Gets the operators.
    /// @return The list of operators.
    function operators()
        public
        view
        returns (address[] memory)
    {
        return addressesInSet(OPERATOR);
    }

    /// @dev Gets the number of operators.
    /// @return The numer of operators.
    function numOperators()
        public
        view
        returns (uint)
    {
        return numAddressesInSet(OPERATOR);
    }

    /// @dev Adds a new operator.
    /// @param operator The new address to add.
    function addOperator(address operator)
        public
        onlyOwner
    {
        addOperatorInternal(operator);
    }

    /// @dev Removes a operator.
    /// @param operator The operator to remove.
    function removeOperator(address operator)
        public
        onlyOwner
    {
        removeAddressFromSet(OPERATOR, operator);
        emit OperatorRemoved(operator);
    }

    function addOperatorInternal(address operator)
        internal
    {
        addAddressToSet(OPERATOR, operator, true);
        emit OperatorAdded(operator);
    }

    struct WalletConfig
    {
        address   owner;
        address[] guardians;
        uint      quota;
        address   inheritor;
        address   feeRecipient;
        address   feeToken;
        uint      maxFeeAmount;
        uint      salt;
        bytes     signature;
    }

    struct WalletConfigV2
    {
        address   owner;
        address   initOwner;
        address[] guardians;
        uint      quota;
        address   inheritor;
        address   feeRecipient;
        address   feeToken;
        uint      maxFeeAmount;
        uint      salt;
    }

    constructor(
        address        _walletImplementation
        )
        WalletDeploymentLib(_walletImplementation)
    {
        DOMAIN_SEPARATOR = EIP712.hash(
            EIP712.Domain("WalletFactory", "2.0.0", address(this))
        );
    }

    /// @dev Create a new wallet by deploying a proxy.
    /// @param config The wallet's config.
    /// @param feeAmount The fee amount actually paid.
    /// @return wallet The new wallet address
    function createWallet(
        WalletConfig calldata config,
        uint                  feeAmount
        )
        onlyOperator
        external
        returns (address wallet)
    {
        require(feeAmount <= config.maxFeeAmount, "INVALID_FEE_AMOUNT");

        _validateConfig(config);
        wallet = _deploy(config.owner, config.salt);
        _initializeWallet(wallet, config, feeAmount);
    }

    /// @dev Create a new wallet by deploying a proxy.
    /// @param config The wallet's config.
    /// @param feeAmount The fee amount actually paid.
    /// @return wallet The new wallet address
    function createWalletByOperator(
        WalletConfigV2 calldata config,
        uint                  feeAmount
        )
        onlyOperator
        external
        returns (address wallet)
    {
        require(feeAmount <= config.maxFeeAmount, "INVALID_FEE_AMOUNT");

        require(config.owner != address(0), "INVALID_OWNER");
        wallet = _deploy(config.initOwner, config.salt);
        ILoopringWalletV2(wallet).initialize(
            config.owner,
            config.guardians,
            config.quota,
            config.inheritor,
            config.feeRecipient,
            config.feeToken,
            feeAmount
        );

        emit WalletCreated(wallet, config.owner);
    }

    /// @dev Computes the wallet address
    /// @param salt The initial wallet owner.
    /// @param salt A salt.
    /// @return wallet The wallet address
    function computeWalletAddress(
        address owner,
        uint    salt
        )
        public
        view
        returns (address)
    {
        return _computeWalletAddress(
            owner,
            salt,
            address(this)
        );
    }

    // --- Internal functions ---

    function _initializeWallet(
        address               wallet,
        WalletConfig calldata config,
        uint                  feeAmount
        )
        internal
    {
        ILoopringWalletV2(wallet).initialize(
            config.owner,
            config.guardians,
            config.quota,
            config.inheritor,
            config.feeRecipient,
            config.feeToken,
            feeAmount
        );

        emit WalletCreated(wallet, config.owner);
    }

    function _validateConfig(
        WalletConfig calldata config
        )
        private
        view
    {
        require(config.owner != address(0), "INVALID_OWNER");

        bytes32 dataHash = keccak256(
            abi.encode(
                CREATE_WALLET_TYPEHASH,
                config.owner,
                keccak256(abi.encodePacked(config.guardians)),
                config.quota,
                config.inheritor,
                config.feeRecipient,
                config.feeToken,
                config.maxFeeAmount,
                config.salt
            )
        );

        bytes32 signHash = EIP712.hashPacked(DOMAIN_SEPARATOR, dataHash);
        require(signHash.verifySignature(config.owner, config.signature), "INVALID_SIGNATURE");
    }
}
Create2.sol 50 lines
// SPDX-License-Identifier: UNLICENSED
// Taken from: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/970f687f04d20e01138a3e8ccf9278b1d4b3997b/contracts/utils/Create2.sol

pragma solidity ^0.7.0;

/**
 * @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer.
 * `CREATE2` can be used to compute in advance the address where a smart
 * contract will be deployed, which allows for interesting new mechanisms known
 * as 'counterfactual interactions'.
 *
 * See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more
 * information.
 */
library Create2 {
    /**
     * @dev Deploys a contract using `CREATE2`. The address where the contract
     * will be deployed can be known in advance via {computeAddress}. Note that
     * a contract cannot be deployed twice using the same salt.
     */
    function deploy(bytes32 salt, bytes memory bytecode) internal returns (address payable) {
        address payable addr;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            addr := create2(0, add(bytecode, 0x20), mload(bytecode), salt)
        }
        require(addr != address(0), "CREATE2_FAILED");
        return addr;
    }

    /**
     * @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the `bytecode`
     * or `salt` will result in a new destination address.
     */
    function computeAddress(bytes32 salt, bytes memory bytecode) internal view returns (address) {
        return computeAddress(salt, bytecode, address(this));
    }

    /**
     * @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at
     * `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}.
     */
    function computeAddress(bytes32 salt, bytes memory bytecodeHash, address deployer) internal pure returns (address) {
        bytes32 bytecodeHashHash = keccak256(bytecodeHash);
        bytes32 _data = keccak256(
            abi.encodePacked(bytes1(0xff), deployer, salt, bytecodeHashHash)
        );
        return address(bytes20(_data << 96));
    }
}
BytesUtil.sol 208 lines
// SPDX-License-Identifier: UNLICENSED
// Taken from https://github.com/GNSPS/solidity-bytes-utils/blob/master/contracts/BytesLib.sol
pragma solidity ^0.7.0;

library BytesUtil {
    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 toUint24(bytes memory _bytes, uint _start) internal  pure returns (uint24) {
        require(_bytes.length >= (_start + 3));
        uint24 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x3), _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 fastSHA256(
        bytes memory data
        )
        internal
        view
        returns (bytes32)
    {
        bytes32[] memory result = new bytes32[](1);
        bool success;
        assembly {
             let ptr := add(data, 32)
             success := staticcall(sub(gas(), 2000), 2, ptr, mload(data), add(result, 32), 32)
        }
        require(success, "SHA256_FAILED");
        return result[0];
    }
}
ILoopringWalletV2.sol 45 lines
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright 2017 Loopring Technology Limited.
pragma solidity ^0.7.0;


/// @title Loopring SmartWallet V2 interface
/// @author Brecht Devos - <[email protected]>
abstract contract ILoopringWalletV2
{
    /// @dev Initializes the smart wallet.
    /// @param owner The wallet owner address.
    /// @param guardians The initial wallet guardians.
    /// @param quota The initial wallet quota.
    /// @param inheritor The inheritor of the wallet.
    /// @param feeRecipient The address receiving the fee for creating the wallet.
    /// @param feeToken The token to use for the fee payment.
    /// @param feeAmount The amount of tokens paid to the fee recipient.
    function initialize(
        address             owner,
        address[] calldata  guardians,
        uint                quota,
        address             inheritor,
        address             feeRecipient,
        address             feeToken,
        uint                feeAmount
        )
        external
        virtual;

    /// @dev Returns the timestamp the wallet was created.
    /// @return The timestamp the wallet was created.
    function getCreationTimestamp()
        public
        view
        virtual
        returns (uint64);

    /// @dev Returns the current wallet owner.
    /// @return The current wallet owner.
    function getOwner()
        public
        view
        virtual
        returns (address);
}
WalletDeploymentLib.sol 82 lines
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright 2017 Loopring Technology Limited.
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;

import "../thirdparty/Create2.sol";
import "../thirdparty/proxies/WalletProxy.sol";


/// @title WalletDeploymentLib
/// @dev Functionality to compute wallet addresses and to deploy wallets
/// @author Brecht Devos - <[email protected]>
contract WalletDeploymentLib
{
    address public immutable walletImplementation;

    string  public constant WALLET_CREATION = "WALLET_CREATION";

    constructor(
        address _walletImplementation
        )
    {
        walletImplementation = _walletImplementation;
    }

    function getWalletCode()
        public
        view
        returns (bytes memory)
    {
        return abi.encodePacked(
            type(WalletProxy).creationCode,
            abi.encode(walletImplementation)
        );
    }

    function computeWalletSalt(
        address owner,
        uint    salt
        )
        public
        pure
        returns (bytes32)
    {
        return keccak256(
            abi.encodePacked(
                WALLET_CREATION,
                owner,
                salt
            )
        );
    }

    function _deploy(
        address owner,
        uint    salt
        )
        internal
        returns (address payable wallet)
    {
        wallet = Create2.deploy(
            computeWalletSalt(owner, salt),
            getWalletCode()
        );
    }

    function _computeWalletAddress(
        address owner,
        uint    salt,
        address deployer
        )
        internal
        view
        returns (address)
    {
        return Create2.computeAddress(
            computeWalletSalt(owner, salt),
            getWalletCode(),
            deployer
        );
    }
}
WalletProxy.sol 57 lines
// SPDX-License-Identifier: LGPL-3.0-or-later
// Taken from: https://github.com/gnosis/safe-contracts/blob/development/contracts/proxies/GnosisSafeProxy.sol
pragma solidity ^0.7.0;

/// @title IProxy - Helper interface to access masterCopy of the Proxy on-chain
/// @author Richard Meissner - <[email protected]>
interface IProxy {
    function masterCopy() external view returns (address);
}

/// @title WalletProxy - Generic proxy contract allows to execute all transactions applying the code of a master contract.
/// @author Stefan George - <[email protected]>
/// @author Richard Meissner - <[email protected]>
contract WalletProxy {

    // masterCopy always needs to be first declared variable, to ensure that it is at the same location in the contracts to which calls are delegated.
    // To reduce deployment costs this variable is internal and needs to be retrieved via `getStorageAt`
    address internal masterCopy;

    event Received(uint indexed value, address indexed sender);

    /// @dev Constructor function sets address of master copy contract.
    /// @param _masterCopy Master copy address.
    constructor(address _masterCopy)
    {
        require(_masterCopy != address(0), "Invalid master copy address provided");
        masterCopy = _masterCopy;
    }

    /// @dev Fallback function forwards all transactions and returns all received return data.
    fallback()
        payable
        external
    {
        // solium-disable-next-line security/no-inline-assembly
        assembly {
            let _masterCopy := and(sload(0), 0xffffffffffffffffffffffffffffffffffffffff)
            // 0xa619486e == keccak("masterCopy()"). The value is right padded to 32-bytes with 0s
            if eq(calldataload(0), 0xa619486e00000000000000000000000000000000000000000000000000000000) {
                mstore(0, _masterCopy)
                return(0, 0x20)
            }
            calldatacopy(0, 0, calldatasize())
            let success := delegatecall(gas(), _masterCopy, 0, calldatasize(), 0, 0)
            returndatacopy(0, 0, returndatasize())
            if eq(success, 0) { revert(0, returndatasize()) }
            return(0, returndatasize())
        }
    }

    receive()
        external
        payable
    {
        emit Received(msg.value, msg.sender);
    }
}

Read Contract

CREATE_WALLET_TYPEHASH 0x4c30d6c9 → bytes32
DOMAIN_SEPARATOR 0x3644e515 → bytes32
WALLET_CREATION 0x90610b0e → string
computeWalletAddress 0xce158612 → address
computeWalletSalt 0xb6830d8f → bytes32
getWalletCode 0xd70e2000 → bytes
isOperator 0x6d70f7ae → bool
numOperators 0xbd820688 → uint256
operators 0xe673df8a → address[]
owner 0x8da5cb5b → address
walletImplementation 0x8117abc1 → address

Write Contract 6 functions

These functions modify contract state and require a wallet transaction to execute.

addOperator 0x9870d7fe
address operator
createWallet 0x9c57ba19
tuple config
uint256 feeAmount
returns: address
createWalletByOperator 0x8f408cbc
tuple config
uint256 feeAmount
returns: address
removeOperator 0xac8a584a
address operator
renounceOwnership 0x715018a6
No parameters
transferOwnership 0xf2fde38b
address newOwner

Recent Transactions

No transactions found for this address