Cryo Explorer Ethereum Mainnet

Address Contract Partially Verified

Address 0xFbcA8B5f5794456B59aD4177E5b212d0Db600BB6
Balance 0 ETH
Nonce 1
Code Size 4889 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

4889 bytes
0x608060405234801561000f575f80fd5b50600436106100a6575f3560e01c80635b61be2b1161006e5780635b61be2b146101535780637460837f1461017a5780639e4e73181461018d578063affed0e0146101b4578063ba9a91a5146101bd578063c49f91d3146101e4575f80fd5b806304622c2e146100aa57806311858c7a146100e45780631703a018146100f95780632a9a3cca1461010157806346f0975a1461013e575b5f80fd5b6100d17fa2743967920baf970a18574423a5e903484167f01ff6c1b931ebc9e87d7792b981565b6040519081526020015b60405180910390f35b6100f76100f2366004610fa6565b61020b565b005b6100d15f5481565b61012c61010f36600461108e565b6001600160a01b03165f9081526004602052604090205460ff1690565b60405160ff90911681526020016100db565b610146610731565b6040516100db91906110f1565b6100d17fb8dc02dde922989f2f9c331431088d8b7e24696ed816c001c5b82192a1c91a8f81565b6100f7610188366004611103565b610791565b6100d17fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc681565b6100d160015481565b6100d17f55c2a1c584c6a7013cb797a4622f427c630274bf9e8d9ec26ab9015ddaabcb3381565b6100d17fd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac5647281565b8551875114801561021d575087518751145b61027d5760405162461bcd60e51b815260206004820152602660248201527f4c656e677468206f66207369676e61747572652061727261797320646f6e742060448201526536b0ba31b41760d11b60648201526084015b60405180910390fd5b6001600160a01b03851633146102d55760405162461bcd60e51b815260206004820152601d60248201527f4578656375746f722068617320746f206265207468652073656e6465720000006044820152606401610274565b5f7f16648533e10c4f8bde2a6a78bc78b44e8745ebde881546ce1a9e5758c6c0952d7fb8dc02dde922989f2f9c331431088d8b7e24696ed816c001c5b82192a1c91a8f5f1b86858560405161032b9291906111cf565b6040805191829003822060015460208401959095526001600160a01b039384169183019190915260608201526080810192909252881660a082015260c0810186905260e001604051602081830303815290604052805190602001206040516020016103ad92919061190160f01b81526002810192909252602282015260420190565b6040516020818303038152906040528051906020012090505f805f8b5190505f5b81811015610547575f61042e868f84815181106103ed576103ed6111de565b60200260200101518f8581518110610407576104076111de565b60200260200101518f8681518110610421576104216111de565b6020026020010151610853565b9050836001600160a01b0316816001600160a01b0316116104915760405162461bcd60e51b815260206004820152601c60248201527f5369676e61747572657320617265206f7574206f66206f726465722e000000006044820152606401610274565b6001600160a01b0381165f9081526003602052604090205460ff166105125760405162461bcd60e51b815260206004820152603160248201527f41646472657373207265636f76657265642066726f6d207369676e61747572656044820152701034b9903737ba10309039b4b3b732b91760791b6064820152608401610274565b6001600160a01b0381165f90815260046020526040902054909350839061053c9060ff16866111f2565b9450506001016103ce565b505f548310156105b75760405162461bcd60e51b815260206004820152603560248201527f5369676e6174757265207765696768747320646f6e27742061646420757020746044820152746f207468652072657175697265642071756f72756d60581b6064820152608401610274565b600180546105c4916111f2565b6001556001600160a01b0388163b6106375760405162461bcd60e51b815260206004820152603060248201527f44657374696e6174696f6e20616464726573732073686f756c6420626520612060448201526f636f6e7472616374206164647265737360801b6064820152608401610274565b5f886001600160a01b03168888886040516106539291906111cf565b5f604051808303815f8787f1925050503d805f811461068d576040519150601f19603f3d011682016040523d82523d5f602084013e610692565b606091505b5050809150507f12755f149014f092798e7a1dcebf8826377f7885d03bd09cba554d56703788f78988888b6040516106cd9493929190611217565b60405180910390a1806107225760405162461bcd60e51b815260206004820181905260248201527f5375626d697373696f6e20746f2064657374696e6174696f6e206661696c65646044820152606401610274565b50505050505050505050505050565b6060600280548060200260200160405190810160405280929190818152602001828054801561078757602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311610769575b5050505050905090565b3330146108065760405162461bcd60e51b815260206004820152603f60248201527f4f6e6c79207468697320636f6e74726163742063616e20736574207369676e6560448201527f7273206166746572207369676e617475726520766572696669636174696f6e006064820152608401610274565b61081183838361087f565b7fe2c7cc05d6a250c8fb4d739ae5f31172a68a7d6c959f49711fee51c7099c801530848484604051610846949392919061125f565b60405180910390a1505050565b5f805f8061086388888888610c10565b9250925092506108738282610cd8565b50909695505050505050565b6020835111156108e75760405162461bcd60e51b815260206004820152602d60248201527f436f6e747261637420616c6c6f777320616464696e6720757020746f2033322060448201526c39b4b3b732b9399037b7363c9760991b6064820152608401610274565b5f811161092c5760405162461bcd60e51b815260206004820152601360248201527228bab7b93ab69031b0b73737ba10313290181760691b6044820152606401610274565b6002545f5b818110156109db575f60035f60028481548110610950576109506111de565b5f918252602080832091909101546001600160a01b031683528201929092526040018120805460ff1916921515929092179091556002805460049183918590811061099d5761099d6111de565b5f918252602080832091909101546001600160a01b031683528201929092526040019020805460ff191660ff92909216919091179055600101610931565b5083515f908190815b81811015610b7857826001600160a01b0316888281518110610a0857610a086111de565b60200260200101516001600160a01b031611610a665760405162461bcd60e51b815260206004820152601a60248201527f4164647265737365732073686f756c6420626520736f727465640000000000006044820152606401610274565b600160035f8a8481518110610a7d57610a7d6111de565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f205f6101000a81548160ff021916908315150217905550868181518110610acc57610acc6111de565b602002602001015160045f8a8481518110610ae957610ae96111de565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f205f6101000a81548160ff021916908360ff160217905550868181518110610b3957610b396111de565b602002602001015160ff1684610b4f91906111f2565b9350878181518110610b6357610b636111de565b602002602001015192508060010190506109e4565b5082851115610bef5760405162461bcd60e51b815260206004820152603e60248201527f51756f72756d206d757374206265206c657373207468616e206f72206571756160448201527f6c20746f2073756d206f6620616c6c207369676e6572207765696768747300006064820152608401610274565b8651610c029060029060208a0190610d94565b5050505f9290925550505050565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841115610c4957505f91506003905082610cce565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015610c9a573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b038116610cc557505f925060019150829050610cce565b92505f91508190505b9450945094915050565b5f826003811115610ceb57610ceb6112cf565b03610cf4575050565b6001826003811115610d0857610d086112cf565b03610d265760405163f645eedf60e01b815260040160405180910390fd5b6002826003811115610d3a57610d3a6112cf565b03610d5b5760405163fce698f760e01b815260048101829052602401610274565b6003826003811115610d6f57610d6f6112cf565b03610d90576040516335e2f38360e21b815260048101829052602401610274565b5050565b828054828255905f5260205f20908101928215610de7579160200282015b82811115610de757825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190610db2565b50610df3929150610df7565b5090565b5b80821115610df3575f8155600101610df8565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff81118282101715610e4857610e48610e0b565b604052919050565b5f67ffffffffffffffff821115610e6957610e69610e0b565b5060051b60200190565b5f82601f830112610e82575f80fd5b8135610e95610e9082610e50565b610e1f565b8082825260208201915060208360051b860101925085831115610eb6575f80fd5b602085015b83811015610ee157803560ff81168114610ed3575f80fd5b835260209283019201610ebb565b5095945050505050565b5f82601f830112610efa575f80fd5b8135610f08610e9082610e50565b8082825260208201915060208360051b860101925085831115610f29575f80fd5b602085015b83811015610ee1578035835260209283019201610f2e565b80356001600160a01b0381168114610f5c575f80fd5b919050565b5f8083601f840112610f71575f80fd5b50813567ffffffffffffffff811115610f88575f80fd5b602083019150836020828501011115610f9f575f80fd5b9250929050565b5f805f805f805f8060e0898b031215610fbd575f80fd5b883567ffffffffffffffff811115610fd3575f80fd5b610fdf8b828c01610e73565b985050602089013567ffffffffffffffff811115610ffb575f80fd5b6110078b828c01610eeb565b975050604089013567ffffffffffffffff811115611023575f80fd5b61102f8b828c01610eeb565b96505061103e60608a01610f46565b945061104c60808a01610f46565b935060a0890135925060c089013567ffffffffffffffff81111561106e575f80fd5b61107a8b828c01610f61565b999c989b5096995094979396929594505050565b5f6020828403121561109e575f80fd5b6110a782610f46565b9392505050565b5f8151808452602084019350602083015f5b828110156110e75781516001600160a01b03168652602095860195909101906001016110c0565b5093949350505050565b602081525f6110a760208301846110ae565b5f805f60608486031215611115575f80fd5b833567ffffffffffffffff81111561112b575f80fd5b8401601f8101861361113b575f80fd5b8035611149610e9082610e50565b8082825260208201915060208360051b85010192508883111561116a575f80fd5b6020840193505b828410156111935761118284610f46565b825260209384019390910190611171565b9550505050602084013567ffffffffffffffff8111156111b1575f80fd5b6111bd86828701610e73565b93969395505050506040919091013590565b818382375f9101908152919050565b634e487b7160e01b5f52603260045260245ffd5b8082018082111561121157634e487b7160e01b5f52601160045260245ffd5b92915050565b6001600160a01b03851681526060602082018190528101839052828460808301375f608084830101525f6080601f19601f860116830101905082604083015295945050505050565b6001600160a01b03851681526080602082018190525f90611282908301866110ae565b8281036040840152845180825260208087019201905f5b818110156112ba57835160ff16835260209384019390920191600101611299565b50506060939093019390935250949350505050565b634e487b7160e01b5f52602160045260245ffdfea26469706673582212208a2211d33b6a3e2525a613c20565b9768042c2f970e559b309fdde158d647c3964736f6c634300081a0033

Verified Source Code Partial Match

Compiler: v0.8.26+commit.8a97fa7a EVM: shanghai Optimization: Yes (200 runs)
MultiSign.sol 192 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

import {ECDSA} from 'openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol';


/**
 * @dev This is an implementation of an on-chain multi-sign. On-chain multi-sign ensures that a quorum of signatures
 * needs to be submitted before the transaction is passed on to the ERC20 contract(in our case). To verify signatures
 * and hash data in a particular way, we use the EIP712.sol scheme: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md.
 *
 * @custom:security-contact [email protected]
 */
contract MultiSign {

    //keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract,bytes32 salt)")
    bytes32 constant public EIP712DOMAIN_TYPEHASH = 0xd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac56472;

    //keccak256("MultiSignTransaction(address destination,bytes data,uint256 nonce,address executor,uint256 gasLimit)")
    bytes32 constant public MULTISIGN_TYPEHASH = 0xb8dc02dde922989f2f9c331431088d8b7e24696ed816c001c5b82192a1c91a8f;

    //randomly generated salt
    bytes32 constant public SALT = 0x55c2a1c584c6a7013cb797a4622f427c630274bf9e8d9ec26ab9015ddaabcb33;

    //keccak256("MultiSign")
    bytes32 constant public NAME_HASH = 0xa2743967920baf970a18574423a5e903484167f01ff6c1b931ebc9e87d7792b9;

    // keccak256("1")
    bytes32 constant public VERSION_HASH = 0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6;

    bytes32 private immutable DOMAIN_SEPARATOR;

    /**
     * A state variable to store the total weight of all signatures required to successfully finish
     * execution of the `execute` method.
     */
    uint256 public quorum;
    /**
     * Every transaction submitted to this contract should have a nonce associated to it just like
     * any other EOA or Contract Account. This state variable holds that value.
     */
    uint256 public nonce;
    address[] private signersArr;
    mapping (address => bool) private isSigner;
    mapping (address => uint8) private weights;

    /**
     * @dev Event emitted when the state of the contract changes.
     *
     * @param account The contract for which the signer information was updated, which is this.
     * @param signers The new array of signer address.
     * @param weights The new array of weights of the signers.
     * @param quorum  The cumulative weight of all signatures should exceed or match this value.
     */
    event SignersChanged(address account, address[] signers, uint8[] weights, uint256 quorum);

    /**
     * @dev Event emitted when the destination contract is called with the provided calldata.
     *
     * @param destination The contract being called with the provided calldata.
     * @param data        The encoded bytes that will lead to execution of a method and change state of the destination
     *                    contract.
     * @param gasLimit    The maximum amount of gas that can be consumed by the destination contract to execute the
     *                    calldata.
     */
    event DestinationCalled(address destination, bytes data, uint256 gasLimit);

    /**
    * Default constructor to initialize the MultiSign contract.
    * Signer addresses submitted to the contract should be ordered by their string values.
    **/
    constructor (address[] memory _signers, uint8[] memory _weights, uint256 _quorum) {
        DOMAIN_SEPARATOR = keccak256(abi.encode(
            EIP712DOMAIN_TYPEHASH,
            NAME_HASH,
            VERSION_HASH,
            block.chainid,
            address(this),
            SALT
        ));

        setSigners_(_signers, _weights, _quorum);
        emit SignersChanged(address(this), _signers, _weights, _quorum);
    }

    /**
     * @dev Returns the list of signer addresses in an array.
     */
    function signers() external view returns (address[] memory) {
        return signersArr;
    }

    /**
     * @dev Given an address of a signer, return the weight of it's signature that gets counted
     * for this account.
     */
    function signerWeight(address signer) external view returns (uint8) {
        return weights[signer];
    }

    // Note that signers_ must be strictly increasing, in order to prevent duplicates
    function setSigners_(address[] memory _signers, uint8[] memory _weights, uint256 _quorum) private {
        require(_signers.length <= 32, "Contract allows adding up to 32 signers only.");
        require(_quorum > 0, "Quorum cannot be 0.");

        // remove old signers from map and set weights to 0
        uint256 existingSignerArrLength = signersArr.length;
        for (uint256 i = 0; i < existingSignerArrLength; ++i) {
            isSigner[signersArr[i]] = false;
            weights[signersArr[i]] = 0;
        }

        // add new signers to map
        uint256 signatureWeights = 0;
        address lastAdd = address(0);
        uint256 newSignerArrLength = _signers.length;
        for (uint256 i = 0; i < newSignerArrLength; ++i) {
            require(_signers[i] > lastAdd, "Addresses should be sorted");
            isSigner[_signers[i]] = true;
            weights[_signers[i]] = _weights[i];
            signatureWeights += _weights[i];
            lastAdd = _signers[i];
        }
        require(_quorum <= signatureWeights, "Quorum must be less than or equal to sum of all signer weights");

        // set signers array and quorum
        signersArr = _signers;
        quorum = _quorum;
    }

    /**
     * @dev This method facilitates changing the signer addresses, their weights and quorum. Since
     * this method changes the state of the contract, it emits the `SignersChanged` event at the
     * end of successful execution.
     * This method can be called by this contract only in order to verify that the signatures are
     * from existing signers with privilege to do so.
     */
    function setSigners(address[] memory _signers, uint8[] memory _weights, uint256 _quorum) external {
        require(msg.sender == address(this), "Only this contract can set signers after signature verification");
        setSigners_(_signers, _weights, _quorum);
        emit SignersChanged(address(this), _signers, _weights, _quorum);
    }

    /**
     * @dev This method is called by an EOA/funding account with the correct set of signatures to eventually
     * make a call to the `destination` with provided call data.
     * Example, calls to the ERC20 contract are made from this method for all MultiSign accounts.
     */
    function execute(
        uint8[] memory sigV, bytes32[] memory sigR, bytes32[] memory sigS, address executor, address destination,
        uint256 gasLimit, bytes calldata data
    ) external {

        require(sigR.length == sigS.length && sigR.length == sigV.length, "Length of signature arrays dont match.");
        require(executor == msg.sender, "Executor has to be the sender");

        bytes32 digest = keccak256(abi.encodePacked(
            "\x19\x01",
            DOMAIN_SEPARATOR,
            keccak256(abi.encode(
                MULTISIGN_TYPEHASH,
                destination,
                keccak256(data),
                nonce,
                executor,
                gasLimit
            ))
        ));

        uint256 signatureWeights = 0;
        address lastAdd = address(0); // cannot have address(0) as an owner
        uint256 signaturesLength = sigV.length;
        for (uint256 i = 0; i < signaturesLength; ++i) {
            address recovered = ECDSA.recover(digest, sigV[i], sigR[i], sigS[i]);
            require(recovered > lastAdd, "Signatures are out of order.");
            require(isSigner[recovered], "Address recovered from signature is not a signer.");
            lastAdd = recovered;
            signatureWeights += weights[recovered];
        }
        require(signatureWeights >= quorum, "Signature weights don't add up to the required quorum");

        // If we make it here all signatures are accounted for.
        nonce = nonce + 1;

        require(destination.code.length > 0, "Destination address should be a contract address");

        bool success = false;
        (success,) = destination.call{gas: gasLimit}(data);
        emit DestinationCalled(destination, data, gasLimit);
        require(success, "Submission to destination failed");
    }
}
ECDSA.sol 180 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.20;

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS
    }

    /**
     * @dev The signature derives the `address(0)`.
     */
    error ECDSAInvalidSignature();

    /**
     * @dev The signature has an invalid length.
     */
    error ECDSAInvalidSignatureLength(uint256 length);

    /**
     * @dev The signature has an S value that is in the upper half order.
     */
    error ECDSAInvalidSignatureS(bytes32 s);

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
     * return address(0) without also returning an error description. Errors are documented using an enum (error type)
     * and a bytes32 providing additional information about the error.
     *
     * If no error is returned, then the address can be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     */
    function tryRecover(
        bytes32 hash,
        bytes memory signature
    ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            assembly ("memory-safe") {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[ERC-2098 short signatures]
     */
    function tryRecover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
        unchecked {
            bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
            // We do not check for an overflow here since the shift operation results in 0 or 1.
            uint8 v = uint8((uint256(vs) >> 255) + 27);
            return tryRecover(hash, v, r, s);
        }
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     */
    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS, s);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature, bytes32(0));
        }

        return (signer, RecoverError.NoError, bytes32(0));
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
     */
    function _throwError(RecoverError error, bytes32 errorArg) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert ECDSAInvalidSignature();
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert ECDSAInvalidSignatureLength(uint256(errorArg));
        } else if (error == RecoverError.InvalidSignatureS) {
            revert ECDSAInvalidSignatureS(errorArg);
        }
    }
}

Read Contract

EIP712DOMAIN_TYPEHASH 0xc49f91d3 → bytes32
MULTISIGN_TYPEHASH 0x5b61be2b → bytes32
NAME_HASH 0x04622c2e → bytes32
SALT 0xba9a91a5 → bytes32
VERSION_HASH 0x9e4e7318 → bytes32
nonce 0xaffed0e0 → uint256
quorum 0x1703a018 → uint256
signerWeight 0x2a9a3cca → uint8
signers 0x46f0975a → address[]

Write Contract 2 functions

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

execute 0x11858c7a
uint8[] sigV
bytes32[] sigR
bytes32[] sigS
address executor
address destination
uint256 gasLimit
bytes data
setSigners 0x7460837f
address[] _signers
uint8[] _weights
uint256 _quorum

Recent Transactions

No transactions found for this address