Esempio n. 1
0
def build_permit(holder, spender, dai_owned, expiry):
    data = {
        "types": {
            "EIP712Domain": [
                {"name": "name", "type": "string"},
                {"name": "version", "type": "string"},
                {"name": "chainId", "type": "uint256"},
                {"name": "verifyingContract", "type": "address"},
            ],
            "Permit": [
                {"name": "holder", "type": "address"},
                {"name": "spender", "type": "address"},
                {"name": "nonce", "type": "uint256"},
                {"name": "expiry", "type": "uint256"},
                {"name": "allowed", "type": "bool"},
            ],
        },
        "domain": {
            "name": dai_owned.name(),
            "version": dai_owned.version(),
            "chainId": 1,
            "verifyingContract": str(dai_owned),
        },
        "primaryType": "Permit",
        "message": {
            "holder": holder,
            "spender": spender,
            "nonce": dai_owned.nonces(holder),
            "expiry": 0,
            "allowed": True,
        },
    }
    assert encode_hex(hash_domain(data)) == dai_owned.DOMAIN_SEPARATOR()
    return encode_structured_data(data)
Esempio n. 2
0
def encode_structured_data(primitive: Union[bytes, int, Mapping] = None,
                           *,
                           hexstr: str = None,
                           text: str = None) -> SignableMessage:
    """
    Encode an EIP-712_ message.

    EIP-712 is the "structured data" approach (ie~ version 1 of an EIP-191 message).

    Supply the message as exactly one of the three arguments:

        - primitive, as a dict that defines the structured data
        - primitive, as bytes
        - text, as a json-encoded string
        - hexstr, as a hex-encoded (json-encoded) string

    .. WARNING:: Note that this code has not gone through an external audit, and
        the test cases are incomplete.
        Also, watch for updates to the format, as the EIP is still in DRAFT.

    :param primitive: the binary message to be signed
    :type primitive: bytes or int or Mapping (eg~ dict )
    :param hexstr: the message encoded as hex
    :param text: the message as a series of unicode characters (a normal Py3 str)
    :returns: The EIP-191 encoded message, ready for signing

    .. _EIP-712: https://eips.ethereum.org/EIPS/eip-712
    """
    if isinstance(primitive, Mapping):
        validate_structured_data(primitive)
        structured_data = primitive
    else:
        message_string = to_text(primitive, hexstr=hexstr, text=text)
        structured_data = load_and_validate_structured_message(message_string)
    return SignableMessage(
        HexBytes(b'\x01'),
        hash_domain(structured_data),
        hash_eip712_message(structured_data),
    )
Esempio n. 3
0
def signature_wrapper(message, signature_version, version_specific_data):
    if not isinstance(message, bytes):
        raise TypeError("Message is of the type {}, expected bytes".format(
            type(message)))
    if not isinstance(signature_version, bytes):
        raise TypeError(
            "Signature Version is of the type {}, expected bytes".format(
                type(signature_version)))

    if signature_version == PERSONAL_SIGN_VERSION:
        preamble = b'\x19Ethereum Signed Message:\n'
        size = str(len(message)).encode('utf-8')
        return preamble + size + message
    elif signature_version == INTENDED_VALIDATOR_SIGN_VERSION:
        wallet_address = to_bytes(hexstr=version_specific_data)
        if len(wallet_address) != 20:
            raise TypeError(
                "Invalid Wallet Address: {}".format(version_specific_data))
        wrapped_message = b'\x19' + signature_version + wallet_address + message
        return wrapped_message
    elif signature_version == STRUCTURED_DATA_SIGN_VERSION:
        message_string = to_text(primitive=message)
        structured_data = load_and_validate_structured_message(message_string)
        domainSeparator = hash_domain(structured_data)
        wrapped_message = (b'\x19' + signature_version + domainSeparator +
                           hash_message(structured_data))
        return wrapped_message
    else:
        raise NotImplementedError(
            "Currently supported signature versions are: {0}, {1}, {2}. ".
            format(
                '0x' + INTENDED_VALIDATOR_SIGN_VERSION.hex(),
                '0x' + PERSONAL_SIGN_VERSION.hex(),
                '0x' + STRUCTURED_DATA_SIGN_VERSION.hex(),
            ) + "But received signature version {}".format(
                '0x' + signature_version.hex()))
def build_permit(owner, spender, value, deadline, usdc):
    data = {
        "types": {
            "EIP712Domain": [
                {
                    "name": "name",
                    "type": "string"
                },
                {
                    "name": "version",
                    "type": "string"
                },
                {
                    "name": "chainId",
                    "type": "uint256"
                },
                {
                    "name": "verifyingContract",
                    "type": "address"
                },
            ],
            "Permit": [
                {
                    "name": "owner",
                    "type": "address"
                },
                {
                    "name": "spender",
                    "type": "address"
                },
                {
                    "name": "value",
                    "type": "uint256"
                },
                {
                    "name": "nonce",
                    "type": "uint256"
                },
                {
                    "name": "deadline",
                    "type": "uint256"
                },
            ],
        },
        "domain": {
            "name": "USD Coin",
            "version": "2",
            "chainId": 1,
            "verifyingContract": str(usdc),
        },
        "primaryType": "Permit",
        "message": {
            "owner": owner,
            "spender": spender,
            "value": value,
            "nonce": usdc.nonces(owner),
            "deadline": deadline,
        },
    }
    assert encode_hex(hash_domain(data)) == usdc.DOMAIN_SEPARATOR()
    return encode_structured_data(data)
Esempio n. 5
0
def test_hash_struct_domain(structured_valid_data_json_string):
    structured_data = json.loads(structured_valid_data_json_string)
    expected_hex_value = "f2cee375fa42b42143804025fc449deafd50cc031ca257e0b194a650a912090f"
    assert hash_domain(structured_data).hex() == expected_hex_value
Esempio n. 6
0
def test_permit(cornichon):
    owner = Account.create()
    spender = Account.create()
    nonce = cornichon.nonces(owner.address)
    expiry = chain[-1].timestamp + 3600
    amount = 10**21
    data = {
        "types": {
            "EIP712Domain": [
                {
                    "name": "name",
                    "type": "string"
                },
                {
                    "name": "version",
                    "type": "string"
                },
                {
                    "name": "chainId",
                    "type": "uint256"
                },
                {
                    "name": "verifyingContract",
                    "type": "address"
                },
            ],
            "Permit": [
                {
                    "name": "owner",
                    "type": "address"
                },
                {
                    "name": "spender",
                    "type": "address"
                },
                {
                    "name": "amount",
                    "type": "uint256"
                },
                {
                    "name": "nonce",
                    "type": "uint256"
                },
                {
                    "name": "expiry",
                    "type": "uint256"
                },
            ],
        },
        "domain": {
            "name": cornichon.name(),
            "version": cornichon.version(),
            "chainId": 1,
            "verifyingContract": str(cornichon),
        },
        "primaryType": "Permit",
        "message": {
            "owner": owner.address,
            "spender": spender.address,
            "amount": amount,
            "nonce": nonce,
            "expiry": expiry,
        },
    }
    message = encode_structured_data(data)
    signed = owner.sign_message(message)
    assert encode_hex(hash_domain(data)) == cornichon.DOMAIN_SEPARATOR()
    assert cornichon.allowance(owner.address, spender.address) == 0
    cornichon.permit(owner.address, spender.address, amount, nonce, expiry,
                     signed.signature)
    assert cornichon.allowance(owner.address, spender.address) == amount