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)
def test_signature_verification(message_encodings): account = Account.create() structured_msg = encode_structured_data(**message_encodings) signed = Account.sign_message(structured_msg, account.key) new_addr = Account.recover_message(structured_msg, signature=signed.signature) assert new_addr == account.address
def test_hashed_structured_data_with_bytes(structured_valid_data_json_string): structured_data = json.loads(structured_valid_data_json_string) # change 'contents' field to type ``bytes`` and set bytes value structured_data['types']['Mail'][3]['type'] = "bytes" structured_data['message']['contents'] = keccak(b'') structured_msg = encode_structured_data(structured_data) hashed_structured_msg = _hash_eip191_message(structured_msg) expected_hash_value_hex = "a06e87f57db20fed78428850bfe02a67d4c6c0f9bcb582b860299b21f591b1c6" assert hashed_structured_msg.hex() == expected_hash_value_hex
def test_hashed_structured_data_with_bytes32( structured_valid_data_json_string): structured_data = json.loads(structured_valid_data_json_string) # change 'contents' field to type ``bytes32`` and set bytes value structured_data['types']['Mail'][3]['type'] = "bytes32" structured_data['message']['contents'] = keccak(b'') structured_msg = encode_structured_data(structured_data) hashed_structured_msg = _hash_eip191_message(structured_msg) expected_hash_value_hex = "ff79c92bdd076a8ec12b146f82a278b30f4da5d402382e215abda4c3c186257e" assert hashed_structured_msg.hex() == expected_hash_value_hex
def test_signature_variables(message_encodings): # Check that the signature of typed message is the same as that # mentioned in the EIP. The link is as follows # https://github.com/ethereum/EIPs/blob/master/assets/eip-712/Example.js structured_msg = encode_structured_data(**message_encodings) privateKey = keccak(text="cow") acc = Account.from_key(privateKey) assert HexBytes(acc.address) == HexBytes("0xcd2a3d9f938e13cd947ec05abc7fe734df8dd826") sig = Account.sign_message(structured_msg, privateKey) assert sig.v == 27 assert hex(sig.r) == "0x58635e9afd7a2a5338cf2af3d711b50235a1955c43f8bca1657c9d0834fcdb5a" assert hex(sig.s) == "0x44a7c0169616cfdfc16815714c9bc1c94139e17a0761a17530cf3dd1746bc10b"
def test_signature_variables(message_encodings): # Check that the signature of typed message is the same as that # mentioned in the EIP. The link is as follows # https://github.com/ethereum/EIPs/blob/master/assets/eip-712/Example.js structured_msg = encode_structured_data(**message_encodings) privateKey = keccak(text="cow") acc = Account.from_key(privateKey) assert HexBytes( acc.address) == HexBytes("0xcd2a3d9f938e13cd947ec05abc7fe734df8dd826") sig = Account.sign_message(structured_msg, privateKey) assert sig.v == 28 assert hex( sig.r ) == "0x4355c47d63924e8a72e509b65029052eb6c299d53a04e167c5775fd466751c9d" assert hex( sig.s ) == "0x7299936d304c153f6443dfa05f40ff007d72911b6f72307f996231605b91562"
def generate_permit(vault, owner: Account, spender: Account, value, nonce, deadline): name = "Yearn Vault" version = vault.apiVersion() chain_id = 1 # ganache bug https://github.com/trufflesuite/ganache/issues/1643 contract = str(vault) 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": name, "version": version, "chainId": chain_id, "verifyingContract": contract, }, "primaryType": "Permit", "message": { "owner": owner.address, "spender": spender.address, "value": value, "nonce": nonce, "deadline": deadline, }, } return encode_structured_data(data)
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)
def sign_token_permit( token, owner: Account, # NOTE: Must be a eth_key account, not Brownie spender: str, allowance: int = 2**256 - 1, # Allowance to set with `permit` deadline: int = 0, # 0 means no time limit override_nonce: int = None, ): chain_id = 1 # ganache bug https://github.com/trufflesuite/ganache/issues/1643 if override_nonce: nonce = override_nonce else: nonce = token.nonces(owner.address) 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": token.name(), "version": "1", "chainId": chain_id, "verifyingContract": str(token), }, "primaryType": "Permit", "message": { "owner": owner.address, "spender": spender, "value": allowance, "nonce": nonce, "deadline": deadline, }, } permit = encode_structured_data(data) return owner.sign_message(permit)
def test_hashed_structured_data(message_encodings): structured_msg = encode_structured_data(**message_encodings) hashed_structured_msg = _hash_eip191_message(structured_msg) expected_hash_value_hex = "4e3c4173651b3054c0635dfae57a3b65ae1527ed0ba9ff76cecb6d9807687a7f" assert hashed_structured_msg.hex() == expected_hash_value_hex
def msg(self): """ This is the message hash we sign for L2 transfers """ return encode_structured_data(self.struct)
def permit(holder: Account, spender, expiry=0, allowed=True): nonce = chai.nonces(holder.address) 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": chai.name(), "version": chai.version(), "chainId": w3.eth.chainId, "verifyingContract": CHAI_ADDRESS, }, "primaryType": "Permit", "message": { "holder": holder.address, "spender": spender, "nonce": nonce, "expiry": expiry, "allowed": allowed, }, } message = encode_structured_data(data) signature = holder.sign_message(message) v, r, s = signature.v, signature.signature[:32], signature.signature[32:64] return chai_contract.functions.permit(holder.address, spender, nonce, expiry, allowed, v, r, s)
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
def sign_vault_permit( vault: Vault, owner: Account, # NOTE: Must be a eth_key account, not Brownie spender: str, allowance: int = 2**256 - 1, # Allowance to set with `permit` deadline: int = 0, # 0 means no time limit override_nonce: int = None, ): name = "Yearn Vault" version = vault.apiVersion() if override_nonce: nonce = override_nonce else: nonce = vault.nonces(owner.address) 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": name, "version": version, "chainId": chain_id(), "verifyingContract": str(vault), }, "primaryType": "Permit", "message": { "owner": owner.address, "spender": spender, "value": allowance, "nonce": nonce, "deadline": deadline, }, } permit = encode_structured_data(data) return owner.sign_message(permit).signature
def test_hashed_structured_data(message_encodings): structured_msg = encode_structured_data(**message_encodings) hashed_structured_msg = _hash_eip191_message(structured_msg) expected_hash_value_hex = "be609aee343fb3c4b28e1df9e632fca64fcfaede20f02e86244efddf30957bd2" assert hashed_structured_msg.hex() == expected_hash_value_hex