Skip to content

Instantly share code, notes, and snippets.

@alexshchur
Created May 7, 2025 17:26
Show Gist options
  • Save alexshchur/81c48d9a8f6c7e5c929b42155d7d5a6e to your computer and use it in GitHub Desktop.
Save alexshchur/81c48d9a8f6c7e5c929b42155d7d5a6e to your computer and use it in GitHub Desktop.
# pipenv install pysha3
import sha3 # from pysha3
def keccak256(data: bytes) -> bytes:
return sha3.keccak_256(data).digest()
def encode_address(addr: str) -> bytes:
return bytes.fromhex(addr[2:].rjust(64, '0'))
def encode_uint256(value: int) -> bytes:
return value.to_bytes(32, byteorder="big")
def encode_bytes(hex_data: str) -> bytes:
assert hex_data.startswith("0x")
return keccak256(bytes.fromhex(hex_data[2:]))
def encode_string(value: str) -> bytes:
return keccak256(value.encode("utf-8"))
def encode_type_string(primary_type: str, types: dict) -> str:
fields = types[primary_type]
return f"{primary_type}(" + ",".join(f"{f['type']} {f['name']}" for f in fields) + ")"
def encode_struct_hash(primary_type: str, types: dict, data: dict) -> bytes:
type_str = encode_type_string(primary_type, types)
type_hash = keccak256(type_str.encode("utf-8"))
encoded_fields = []
for field in types[primary_type]:
name = field["name"]
field_type = field["type"]
value = data[name]
if field_type == "address":
encoded_fields.append(encode_address(value))
elif field_type == "uint256":
encoded_fields.append(encode_uint256(int(value)))
elif field_type == "bytes":
encoded_fields.append(encode_bytes(value))
elif field_type == "string":
encoded_fields.append(encode_string(value))
else:
raise ValueError(f"Unsupported field type: {field_type}")
return keccak256(type_hash + b''.join(encoded_fields))
def encode_domain_separator(domain: dict) -> bytes:
TYPE_HASH_RAW = "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
TYPE_HASH = keccak256(TYPE_HASH_RAW.encode("utf-8"))
HASHED_NAME = keccak256(domain["name"].encode("utf-8"))
HASHED_VERSION = keccak256(domain["version"].encode("utf-8"))
CHAIN_ID = encode_uint256(domain["chainId"])
VERIFYING_CONTRACT = encode_address(domain["verifyingContract"])
return keccak256(TYPE_HASH + HASHED_NAME + HASHED_VERSION + CHAIN_ID + VERIFYING_CONTRACT)
def compute_eip712_body(domain: dict, types: dict, primary_type: str, message: dict) -> bytes:
domain_separator = encode_domain_separator(domain)
print("domain_separator", domain_separator.hex())
struct_hash = encode_struct_hash(primary_type, types, message)
print("struct hash", struct_hash.hex())
return keccak256(b"\x19\x01" + domain_separator + struct_hash)
# === EIP-712 Order Type Definition ===
ORDER_EIP_712_TYPES = {
"Order": [
{"name": "owner", "type": "address"},
{"name": "beneficiary", "type": "address"},
{"name": "srcToken", "type": "address"},
{"name": "destToken", "type": "address"},
{"name": "srcAmount", "type": "uint256"},
{"name": "destAmount", "type": "uint256"},
{"name": "expectedDestAmount", "type": "uint256"},
{"name": "deadline", "type": "uint256"},
{"name": "nonce", "type": "uint256"},
{"name": "partnerAndFee", "type": "uint256"},
{"name": "permit", "type": "bytes"},
]
}
order = {
"owner": "0x12924049e2d21664e35387c69429c98e9891a820",
"beneficiary": "0x12924049e2d21664e35387c69429c98e9891a820",
"srcToken": "0x04c154b66cb340f3ae24111cc767e0184ed00cc6",
"destToken": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"srcAmount": "1202939820354578",
"destAmount": "868930905657826",
"expectedDestAmount": "873297392620931",
"deadline": "1740790593",
"nonce": "1740787014424",
"partnerAndFee": "90631063861114836560958097440945986548822432573276877133894239693005947666432",
"permit": "0x00000000000000000000000012924049e2d21664e35387c69429c98e9891a8200000000000000000000000000000000000bbf5c5fd284e657f01bd000933c96d0000000000000000000000000000000000000000000000000004461140adac120000000000000000000000000000000000000000000000000000000067c641b2000000000000000000000000000000000000000000000000000000000000001bae25978476dcaf13eb21c5140c058bc49fd4d087f0f0d23b1ccede8f9288bb33450886d34539305ede3448c44206e89074d91afcdc8e07cabbe23cf45c67dd7c"
}
domain = {
"name": "Portikus",
"version": "2.0.0",
"chainId": 1,
"verifyingContract": "0x0000000000bbf5c5fd284e657f01bd000933c96d"
}
# === Compute and Print ===
body_hash = compute_eip712_body(domain, ORDER_EIP_712_TYPES, "Order", order)
print("EIP-712 signing hash (.body):", body_hash.hex())
@alexshchur
Copy link
Author

alexshchur commented May 7, 2025

compute domain separator: https://dune.com/queries/5098950

@alexshchur
Copy link
Author

compute struct hash: https://dune.com/queries/5098965

@alexshchur
Copy link
Author

full snippet:
i.e.

keccak256("\x19\x01" || _domainSeparatorV4() || structHash(order));

https://dune.com/queries/5098978

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment