OptimistInviterHelper.sol 4.63 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
//SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";

import { OptimistInviter } from "../../universal/op-nft/OptimistInviter.sol";

/**
 * Simple helper contract that helps with testing flow and signature for OptimistInviter contract.
 * Made this a separate contract instead of including in OptimistInviter.t.sol for reusability.
 */
contract OptimistInviterHelper {
13 14 15
    /**
     * @notice EIP712 typehash for the ClaimableInvite type.
     */
16 17 18
    bytes32 public constant CLAIMABLE_INVITE_TYPEHASH =
        keccak256("ClaimableInvite(address issuer,bytes32 nonce)");

19 20 21
    /**
     * @notice EIP712 typehash for the EIP712Domain type that is included as part of the signature.
     */
22 23 24 25 26
    bytes32 public constant EIP712_DOMAIN_TYPEHASH =
        keccak256(
            "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
        );

27 28 29
    /**
     * @notice Address of OptimistInviter contract we are testing.
     */
30
    OptimistInviter public optimistInviter;
31 32 33 34

    /**
     * @notice OptimistInviter contract name. Used to construct the EIP-712 domain.
     */
35
    string public name;
36 37 38 39

    /**
     * @notice Keeps track of current nonce to generate new nonces for each invite.
     */
40 41 42 43 44 45 46 47
    uint256 public currentNonce;

    constructor(OptimistInviter _optimistInviter, string memory _name) {
        optimistInviter = _optimistInviter;
        name = _name;
    }

    /**
48 49 50 51 52
     * @notice Returns the hash of the struct ClaimableInvite.
     *
     * @param _claimableInvite ClaimableInvite struct to hash.
     *
     * @return EIP-712 typed struct hash.
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
     */
    function getClaimableInviteStructHash(OptimistInviter.ClaimableInvite memory _claimableInvite)
        public
        pure
        returns (bytes32)
    {
        return
            keccak256(
                abi.encode(
                    CLAIMABLE_INVITE_TYPEHASH,
                    _claimableInvite.issuer,
                    _claimableInvite.nonce
                )
            );
    }

    /**
     * @notice Returns a bytes32 nonce that should change everytime. In practice, people should use
     *         pseudorandom nonces.
72 73
     *
     * @return Nonce that should be used as part of ClaimableInvite.
74 75 76 77 78 79
     */
    function consumeNonce() public returns (bytes32) {
        return bytes32(keccak256(abi.encode(currentNonce++)));
    }

    /**
80 81 82 83 84
     * @notice Returns a ClaimableInvite with the issuer and current nonce.
     *
     * @param _issuer Issuer to include in the ClaimableInvite.
     *
     * @return ClaimableInvite that can be hashed & signed.
85 86 87 88 89 90 91 92 93 94
     */
    function getClaimableInviteWithNewNonce(address _issuer)
        public
        returns (OptimistInviter.ClaimableInvite memory)
    {
        return OptimistInviter.ClaimableInvite(_issuer, consumeNonce());
    }

    /**
     * @notice Computes the EIP712 digest with default correct parameters.
95 96 97 98
     *
     * @param _claimableInvite ClaimableInvite struct to hash.
     *
     * @return EIP-712 compatible digest.
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
     */
    function getDigest(OptimistInviter.ClaimableInvite calldata _claimableInvite)
        public
        view
        returns (bytes32)
    {
        return
            getDigestWithEIP712Domain(
                _claimableInvite,
                bytes(name),
                bytes(optimistInviter.EIP712_VERSION()),
                block.chainid,
                address(optimistInviter)
            );
    }

    /**
     * @notice Computes the EIP712 digest with the given domain parameters.
     *         Used for testing that different domain parameters fail.
118 119 120 121 122 123 124 125
     *
     * @param _claimableInvite   ClaimableInvite struct to hash.
     * @param _name              Contract name to use in the EIP712 domain.
     * @param _version           Contract version to use in the EIP712 domain.
     * @param _chainid           Chain ID to use in the EIP712 domain.
     * @param _verifyingContract Address to use in the EIP712 domain.
     *
     * @return EIP-712 compatible digest.
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
     */
    function getDigestWithEIP712Domain(
        OptimistInviter.ClaimableInvite calldata _claimableInvite,
        bytes memory _name,
        bytes memory _version,
        uint256 _chainid,
        address _verifyingContract
    ) public pure returns (bytes32) {
        bytes32 domainSeparator = keccak256(
            abi.encode(
                EIP712_DOMAIN_TYPEHASH,
                keccak256(_name),
                keccak256(_version),
                _chainid,
                _verifyingContract
            )
        );
        return
            ECDSA.toTypedDataHash(domainSeparator, getClaimableInviteStructHash(_claimableInvite));
    }
}