EIP712 feeder script ragger support

This commit is contained in:
Alexandre Paillier
2022-07-27 18:12:23 +02:00
parent ef7f2e128a
commit fe13260140
16 changed files with 1176 additions and 18 deletions

View File

@@ -0,0 +1,387 @@
#!/usr/bin/env python3
import json
import sys
import re
from enum import IntEnum, auto
import hashlib
from ecdsa import SigningKey
from ecdsa.util import sigencode_der
import pdb
from ethereum_client import EthereumClient, EIP712FieldType
# global variables
app_client: EthereumClient = None
parser = None
trans = None
filtering_paths = None
current_path = list()
sig_ctx = {}
class ArrayType(IntEnum):
dynamic = 0
fixed_size = auto()
# From a string typename, extract the type and all the array depth
# Input = "uint8[2][][4]" | "bool"
# Output = ('uint8', [2, None, 4]) | ('bool', [])
def get_array_levels(typename):
array_lvls = list()
regex = re.compile("(.*)\[([0-9]*)\]$")
while True:
result = regex.search(typename)
if not result:
break
typename = result.group(1)
level_size = result.group(2)
if len(level_size) == 0:
level_size = None
else:
level_size = int(level_size)
array_lvls.insert(0, level_size)
return (typename, array_lvls)
# From a string typename, extract the type and its size
# Input = "uint64" | "string"
# Output = ('uint', 64) | ('string', None)
def get_typesize(typename):
regex = re.compile("^(\w+?)(\d*)$")
result = regex.search(typename)
typename = result.group(1)
typesize = result.group(2)
if len(typesize) == 0:
typesize = None
else:
typesize = int(typesize)
return (typename, typesize)
def parse_int(typesize):
return (EIP712FieldType.INT, int(typesize / 8))
def parse_uint(typesize):
return (EIP712FieldType.UINT, int(typesize / 8))
def parse_address(typesize):
return (EIP712FieldType.ADDRESS, None)
def parse_bool(typesize):
return (EIP712FieldType.BOOL, None)
def parse_string(typesize):
return (EIP712FieldType.STRING, None)
def parse_bytes(typesize):
if typesize != None:
return (EIP712FieldType.FIX_BYTES, typesize)
return (EIP712FieldType.DYN_BYTES, None)
# set functions for each type
parsing_type_functions = {};
parsing_type_functions["int"] = parse_int
parsing_type_functions["uint"] = parse_uint
parsing_type_functions["address"] = parse_address
parsing_type_functions["bool"] = parse_bool
parsing_type_functions["string"] = parse_string
parsing_type_functions["bytes"] = parse_bytes
def send_struct_def_field(typename, keyname):
type_enum = None
(typename, array_lvls) = get_array_levels(typename)
(typename, typesize) = get_typesize(typename)
if typename in parsing_type_functions.keys():
(type_enum, typesize) = parsing_type_functions[typename](typesize)
else:
type_enum = EIP712FieldType.CUSTOM
typesize = None
app_client.eip712_send_struct_def_struct_field(type_enum,
typename,
typesize,
array_lvls,
keyname)
return (typename, type_enum, typesize, array_lvls)
def encode_integer(value, typesize):
data = bytearray()
# Some are already represented as integers in the JSON, but most as strings
if isinstance(value, str):
base = 10
if value.startswith("0x"):
base = 16
value = int(value, base)
if value == 0:
data.append(0)
else:
if value < 0: # negative number, send it as unsigned
mask = 0
for i in range(typesize): # make a mask as big as the typesize
mask = (mask << 8) | 0xff
value &= mask
while value > 0:
data.append(value & 0xff)
value >>= 8
data.reverse()
return data
def encode_int(value, typesize):
return encode_integer(value, typesize)
def encode_uint(value, typesize):
return encode_integer(value, typesize)
def encode_hex_string(value, size):
data = bytearray()
value = value[2:] # skip 0x
byte_idx = 0
while byte_idx < size:
data.append(int(value[(byte_idx * 2):(byte_idx * 2 + 2)], 16))
byte_idx += 1
return data
def encode_address(value, typesize):
return encode_hex_string(value, 20)
def encode_bool(value, typesize):
return encode_integer(value, typesize)
def encode_string(value, typesize):
data = bytearray()
for char in value:
data.append(ord(char))
return data
def encode_byte(value, typesize):
return bytearray()
def encode_bytes_fix(value, typesize):
return encode_hex_string(value, typesize)
def encode_bytes_dyn(value, typesize):
# length of the value string
# - the length of 0x (2)
# / by the length of one byte in a hex string (2)
return encode_hex_string(value, int((len(value) - 2) / 2))
# set functions for each type
encoding_functions = {}
encoding_functions[EIP712FieldType.INT] = encode_int
encoding_functions[EIP712FieldType.UINT] = encode_uint
encoding_functions[EIP712FieldType.ADDRESS] = encode_address
encoding_functions[EIP712FieldType.BOOL] = encode_bool
encoding_functions[EIP712FieldType.STRING] = encode_string
encoding_functions[EIP712FieldType.FIX_BYTES] = encode_bytes_fix
encoding_functions[EIP712FieldType.DYN_BYTES] = encode_bytes_dyn
def send_struct_impl_field(value, field):
# Something wrong happened if this triggers
if isinstance(value, list) or (field["enum"] == EIP712FieldType.CUSTOM):
breakpoint()
data = encoding_functions[field["enum"]](value, field["typesize"])
if False:#args.filtering:
path = ".".join(current_path)
if path in filtering_paths.keys():
send_filtering_field_name(filtering_paths[path])
app_client.eip712_send_struct_impl_struct_field(data)
def evaluate_field(structs, data, field, lvls_left, new_level = True):
array_lvls = field["array_lvls"]
if new_level:
current_path.append(field["name"])
if len(array_lvls) > 0 and lvls_left > 0:
app_client.eip712_send_struct_impl_array(len(data))
idx = 0
for subdata in data:
current_path.append("[]")
if not evaluate_field(structs, subdata, field, lvls_left - 1, False):
return False
current_path.pop()
idx += 1
if array_lvls[lvls_left - 1] != None:
if array_lvls[lvls_left - 1] != idx:
print("Mismatch in array size! Got %d, expected %d\n" %
(idx, array_lvls[lvls_left - 1]),
file=sys.stderr)
return False
else:
if field["enum"] == EIP712FieldType.CUSTOM:
if not send_struct_impl(structs, data, field["type"]):
return False
else:
send_struct_impl_field(data, field)
if new_level:
current_path.pop()
return True
def send_struct_impl(structs, data, structname):
# Check if it is a struct we don't known
if structname not in structs.keys():
return False
struct = structs[structname]
for f in struct:
if not evaluate_field(structs, data[f["name"]], f, len(f["array_lvls"])):
return False
return True
def send_sign():
bip32path = bytearray.fromhex("8000002c8000003c800000000000000000000000")
path_len = bytearray()
path_len.append(int(len(bip32path) / 4))
#send_apdu(INS_SIGN, 0x00, P2_VERS_NEW, path_len + bip32path)
print("send_apdu(INS_SIGN, 0x00, P2_VERS_NEW, path_len + bip32path)")
def send_filtering_activate():
#send_apdu(INS_FILTERING, P1_ACTIVATE, 0x00, bytearray())
print("send_apdu(INS_FILTERING, P1_ACTIVATE, 0x00, bytearray())")
def send_filtering_info(p1, display_name, sig):
payload = bytearray()
payload.append(len(display_name))
for char in display_name:
payload.append(ord(char))
payload.append(len(sig))
payload += sig
#send_apdu(INS_FILTERING, p1, 0x00, payload)
print("send_apdu(INS_FILTERING, p1, 0x00, payload)")
# ledgerjs doesn't actually sign anything, and instead uses already pre-computed signatures
def send_filtering_contract_name(display_name):
global sig_ctx
msg = bytearray()
msg += sig_ctx["chainid"]
msg += sig_ctx["caddr"]
msg += sig_ctx["schema_hash"]
for char in display_name:
msg.append(ord(char))
sig = sig_ctx["key"].sign_deterministic(msg, sigencode=sigencode_der)
send_filtering_info(P1_CONTRACT_NAME, display_name, sig)
# ledgerjs doesn't actually sign anything, and instead uses already pre-computed signatures
def send_filtering_field_name(display_name):
global sig_ctx
path_str = ".".join(current_path)
msg = bytearray()
msg += sig_ctx["chainid"]
msg += sig_ctx["caddr"]
msg += sig_ctx["schema_hash"]
for char in path_str:
msg.append(ord(char))
for char in display_name:
msg.append(ord(char))
sig = sig_ctx["key"].sign_deterministic(msg, sigencode=sigencode_der)
send_filtering_info(P1_FIELD_NAME, display_name, sig)
def read_filtering_file(domain, message):
data_json = None
with open("%s-filter.json" % (args.JSON_FILE)) as data:
data_json = json.load(data)
return data_json
def prepare_filtering(filtr_data, message):
global filtering_paths
if "fields" in filtr_data:
filtering_paths = filtr_data["fields"]
else:
filtering_paths = {}
def init_signature_context(types, domain):
global sig_ctx
with open(args.keypath, "r") as priv_file:
sig_ctx["key"] = SigningKey.from_pem(priv_file.read(), hashlib.sha256)
caddr = domain["verifyingContract"]
if caddr.startswith("0x"):
caddr = caddr[2:]
sig_ctx["caddr"] = bytearray.fromhex(caddr)
chainid = domain["chainId"]
sig_ctx["chainid"] = bytearray()
for i in range(8):
sig_ctx["chainid"].append(chainid & (0xff << (i * 8)))
sig_ctx["chainid"].reverse()
schema_str = json.dumps(types).replace(" ","")
schema_hash = hashlib.sha224(schema_str.encode())
sig_ctx["schema_hash"] = bytearray.fromhex(schema_hash.hexdigest())
return True
return False
def process_file(aclient: EthereumClient, input_file_path: str, filtering = False) -> bool:
global sig_ctx
global app_client
app_client = aclient
with open(input_file_path, "r") as data:
data_json = json.load(data)
domain_typename = "EIP712Domain"
message_typename = data_json["primaryType"]
types = data_json["types"]
domain = data_json["domain"]
message = data_json["message"]
if filtering:
if not init_signature_context(types, domain):
return False
filtr = read_filtering_file(domain, message)
# send types definition
for key in types.keys():
app_client.eip712_send_struct_def_struct_name(key)
for f in types[key]:
(f["type"], f["enum"], f["typesize"], f["array_lvls"]) = \
send_struct_def_field(f["type"], f["name"])
if filtering:
send_filtering_activate()
prepare_filtering(filtr, message)
# send domain implementation
app_client.eip712_send_struct_impl_root_struct(domain_typename)
if not send_struct_impl(types, domain, domain_typename):
return False
if filtering:
if filtr and "name" in filtr:
send_filtering_contract_name(filtr["name"])
else:
send_filtering_contract_name(sig_ctx["domain"]["name"])
# send message implementation
app_client.eip712_send_struct_impl_root_struct(message_typename)
if not send_struct_impl(types, message, message_typename):
return False
# sign
send_sign()
return True

View File

View File

@@ -0,0 +1,44 @@
{
"domain": {
"chainId": 5,
"name": "Ether Mail",
"verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
"version": "1"
},
"message": {
"contents": "Hello, Bob!",
"from": {
"name": "Cow",
"wallets": [
"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
"0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF"
]
},
"to": {
"name": "Bob",
"wallets": [
"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB",
"0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57",
"0xB0B0b0b0b0b0B000000000000000000000000000"
]
}
},
"primaryType": "Mail",
"types": {
"EIP712Domain": [
{ "name": "name", "type": "string" },
{ "name": "version", "type": "string" },
{ "name": "chainId", "type": "uint256" },
{ "name": "verifyingContract", "type": "address" }
],
"Mail": [
{ "name": "from", "type": "Person" },
{ "name": "to", "type": "Person" },
{ "name": "contents", "type": "string" }
],
"Person": [
{ "name": "name", "type": "string" },
{ "name": "wallets", "type": "address[]" }
]
}
}

View File

@@ -0,0 +1,31 @@
{
"domain": {
"chainId": 1337,
"name": "Ether Mail",
"verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
"version": "1"
},
"message": {
"contents": "Hello, Bob!",
"from": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
"to": [
"0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57",
"0xb1a22cc48f6784f629a994917cd6474923630c48"
],
"id": 7
},
"primaryType": "Mail",
"types": {
"EIP712Domain": [
{ "name": "name", "type": "string" },
{ "name": "version", "type": "string" },
{ "name": "chainId", "type": "uint256" },
{ "name": "verifyingContract", "type": "address" }
],
"Mail": [
{ "name": "from", "type": "address" },
{ "name": "to", "type": "address[]" },
{ "name": "contents", "type": "string" }
]
}
}

View File

@@ -0,0 +1,55 @@
{
"domain": {
"chainId": 5,
"name": "Ether Mail",
"verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
"version": "1"
},
"message": {
"contents": "Hello, Bob!",
"from": {
"name": "Cow",
"wallets": [
"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
"0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF"
]
},
"to": [
{
"name": "Alice",
"wallets": [
"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB",
"0xB0B0b0b0b0b0B000000000000000000000000000"
]
},
{
"name": "Bob",
"wallets": [
"0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57"
]
}
]
},
"primaryType": "Mail",
"types": {
"EIP712Domain": [
{ "name": "name", "type": "string" },
{ "name": "version", "type": "string" },
{ "name": "chainId", "type": "uint256" },
{ "name": "verifyingContract", "type": "address" }
],
"Group": [
{ "name": "name", "type": "string" },
{ "name": "members", "type": "Person[]" }
],
"Mail": [
{ "name": "from", "type": "Person" },
{ "name": "to", "type": "Person[]" },
{ "name": "contents", "type": "string" }
],
"Person": [
{ "name": "name", "type": "string" },
{ "name": "wallets", "type": "address[]" }
]
}
}

View File

@@ -0,0 +1,50 @@
{
"domain": {
"chainId": 5,
"name": "Ether Mail",
"verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
"version": "1"
},
"message": {
"contents": "Hello, Bob! 012345678012345678012345678012345678012345678012345678012345678012345678012345678012345678012345678012345678012345678012345678012345678012345678012345678012345678012345678012345678012345678012345678012345678012345678012345678012345678012345678012312345678012345678012345678012345678012312345678012345678012345678012345678012312345678012345678012345678012345678012312345678012345678012345678012345678012312345678012345678012345678012345678012312345678012345678012345678012345678012312345678012345678012345678012345678012312345678012345678012345678012345678012312345678012345678012345678012345678012312345678012345678012345678012345678012312345678012345678012345678012345678012312345678012345678012345678012345678012312345678012345678012345678012345678012312345678012345678012345678012345678012312345678012345678012345678012345678012312345678012345678012345678012345678012312345678012345678012345678012345678012312345678012345678012345678012345678012312345678012345678012345678012345678012344444444444444444444123456780123456780123456780123456780123456780123456780123456789999999999999999999999999999990123456789",
"from": {
"name": "Cow",
"wallets": [
"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
"0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF"
]
},
"to": [
{
"name": "Bob",
"wallets": [
"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB",
"0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57",
"0xB0B0b0b0b0b0B000000000000000000000000000"
]
}
]
},
"primaryType": "Mail",
"types": {
"EIP712Domain": [
{ "name": "name", "type": "string" },
{ "name": "version", "type": "string" },
{ "name": "chainId", "type": "uint256" },
{ "name": "verifyingContract", "type": "address" }
],
"Group": [
{ "name": "name", "type": "string" },
{ "name": "members", "type": "Person[]" }
],
"Mail": [
{ "name": "from", "type": "Person" },
{ "name": "to", "type": "Person[]" },
{ "name": "contents", "type": "string" }
],
"Person": [
{ "name": "name", "type": "string" },
{ "name": "wallets", "type": "address[]" }
]
}
}

View File

@@ -0,0 +1,50 @@
{
"domain": {
"chainId": 5,
"name": "Ether Mail",
"verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
"version": "1"
},
"message": {
"contents": "0x1123456789123456789123453678912345678912345678912345678912345678912345678912345678912345678912345678912345678912345678912345678912345678912345678912345678912345678912345678991234567892345678991234567892345678991234567892345678991234567892345678991234567892345678912345678923456789",
"from": {
"name": "Cow",
"wallets": [
"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
"0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF"
]
},
"to": [
{
"name": "Bob",
"wallets": [
"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB",
"0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57",
"0xB0B0b0b0b0b0B000000000000000000000000000"
]
}
]
},
"primaryType": "Mail",
"types": {
"EIP712Domain": [
{ "name": "name", "type": "string" },
{ "name": "version", "type": "string" },
{ "name": "chainId", "type": "uint256" },
{ "name": "verifyingContract", "type": "address" }
],
"Group": [
{ "name": "name", "type": "string" },
{ "name": "members", "type": "Person[]" }
],
"Mail": [
{ "name": "from", "type": "Person" },
{ "name": "to", "type": "Person[]" },
{ "name": "contents", "type": "bytes" }
],
"Person": [
{ "name": "name", "type": "string" },
{ "name": "wallets", "type": "address[]" }
]
}
}

View File

@@ -0,0 +1,45 @@
{
"domain": {
"chainId": 5,
"name": "Ether Mail",
"verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
"version": "1"
},
"message": {
"neg256" : "-256",
"pos256" : "256",
"neg128" : "-128",
"pos128" : "128",
"neg64" : "-64",
"pos64" : "64",
"neg32" : "-32",
"pos32" : "32",
"neg16" : "-16",
"pos16" : "16",
"neg8" : "-8",
"pos8" : "8"
},
"primaryType": "Test",
"types": {
"EIP712Domain": [
{ "name": "name", "type": "string" },
{ "name": "version", "type": "string" },
{ "name": "chainId", "type": "uint256" },
{ "name": "verifyingContract", "type": "address" }
],
"Test": [
{ "name": "neg256", "type": "int256" },
{ "name": "pos256", "type": "int256" },
{ "name": "neg128", "type": "int128" },
{ "name": "pos128", "type": "int128" },
{ "name": "neg64", "type": "int64" },
{ "name": "pos64", "type": "int64" },
{ "name": "neg32", "type": "int32" },
{ "name": "pos32", "type": "int32" },
{ "name": "neg16", "type": "int16" },
{ "name": "pos16", "type": "int16" },
{ "name": "neg8", "type": "int8" },
{ "name": "pos8", "type": "int8" }
]
}
}

View File

@@ -0,0 +1,25 @@
{
"domain": {
"chainId": 5,
"name": "Ether Mail",
"verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
"version": "1"
},
"message": {
"Bueno" : true,
"NoBueno": false
},
"primaryType": "Test",
"types": {
"EIP712Domain": [
{ "name": "name", "type": "string" },
{ "name": "version", "type": "string" },
{ "name": "chainId", "type": "uint256" },
{ "name": "verifyingContract", "type": "address" }
],
"Test": [
{ "name": "Bueno", "type": "bool" },
{ "name": "NoBueno", "type": "bool" }
]
}
}

View File

@@ -0,0 +1,23 @@
{
"domain": {
"chainId": 5,
"name": "Ether Mail",
"verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
"version": "1"
},
"message": {
"val" : "0x973bb640"
},
"primaryType": "Test",
"types": {
"EIP712Domain": [
{ "name": "name", "type": "string" },
{ "name": "version", "type": "string" },
{ "name": "chainId", "type": "uint256" },
{ "name": "verifyingContract", "type": "address" }
],
"Test": [
{ "name": "val", "type": "bytes4" }
]
}
}

View File

@@ -0,0 +1,153 @@
{
"domain" : {
"chainId" : 1,
"name" : "Wyvern Exchange Contract",
"verifyingContract" : "0x7f268357a8c2552623316e2562d90e642bb538e5",
"version" : "2.3"
},
"message" : {
"basePrice" : "2000000000000000000",
"calldata" : "0x96809f90000000000000000000000000112f0732e59e7600768dfc35ba744b89f2356cd80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000495f947276749ce646f68ac8c248420045cb7b5ebdf2657ffc1fadfd73cf0a8cde95d50b62d3df8c0000000000000700000000320000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000000",
"exchange" : "0x7f268357a8c2552623316e2562d90e642bb538e5",
"expirationTime" : "1646089435",
"extra" : "0",
"feeMethod" : 1,
"feeRecipient" : "0x5b3256965e7c3cf26e11fcaf296dfc8807c01073",
"howToCall" : 1,
"listingTime" : "1645484541",
"maker" : "0x112f0732e59e7600768dfc35ba744b89f2356cd8",
"makerProtocolFee" : "0",
"makerRelayerFee" : "1250",
"nonce" : 0,
"paymentToken" : "0x0000000000000000000000000000000000000000",
"replacementPattern" : "0x000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"saleKind" : 0,
"salt" : "21014297276898013168171430966355369260039074692095359200549020767078729356431",
"side" : 1,
"staticExtradata" : "0x",
"staticTarget" : "0x0000000000000000000000000000000000000000",
"taker" : "0x0000000000000000000000000000000000000000",
"takerProtocolFee" : "0",
"takerRelayerFee" : "0",
"target" : "0xbaf2127b49fc93cbca6269fade0f7f31df4c88a7"
},
"primaryType" : "Order",
"types" : {
"EIP712Domain" : [
{
"name" : "name",
"type" : "string"
},
{
"name" : "version",
"type" : "string"
},
{
"name" : "chainId",
"type" : "uint256"
},
{
"name" : "verifyingContract",
"type" : "address"
}
],
"Order" : [
{
"name" : "exchange",
"type" : "address"
},
{
"name" : "maker",
"type" : "address"
},
{
"name" : "taker",
"type" : "address"
},
{
"name" : "makerRelayerFee",
"type" : "uint256"
},
{
"name" : "takerRelayerFee",
"type" : "uint256"
},
{
"name" : "makerProtocolFee",
"type" : "uint256"
},
{
"name" : "takerProtocolFee",
"type" : "uint256"
},
{
"name" : "feeRecipient",
"type" : "address"
},
{
"name" : "feeMethod",
"type" : "uint8"
},
{
"name" : "side",
"type" : "uint8"
},
{
"name" : "saleKind",
"type" : "uint8"
},
{
"name" : "target",
"type" : "address"
},
{
"name" : "howToCall",
"type" : "uint8"
},
{
"name" : "calldata",
"type" : "bytes"
},
{
"name" : "replacementPattern",
"type" : "bytes"
},
{
"name" : "staticTarget",
"type" : "address"
},
{
"name" : "staticExtradata",
"type" : "bytes"
},
{
"name" : "paymentToken",
"type" : "address"
},
{
"name" : "basePrice",
"type" : "uint256"
},
{
"name" : "extra",
"type" : "uint256"
},
{
"name" : "listingTime",
"type" : "uint256"
},
{
"name" : "expirationTime",
"type" : "uint256"
},
{
"name" : "salt",
"type" : "uint256"
},
{
"name" : "nonce",
"type" : "uint256"
}
]
}
}

View File

@@ -0,0 +1,110 @@
{
"domain" : {
"chainId" : 1,
"name" : "Exchange",
"verifyingContract" : "0x9757f2d2b135150bbeb65308d4a91804107cd8d6",
"version" : "2"
},
"message" : {
"data" : "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000001cf0df2a5a20cd61d68d4489eebbf85b8d39e18a00000000000000000000000000000000000000000000000000000000000000fa",
"dataType" : "0x23d235ef",
"end" : 0,
"makeAsset" : {
"assetType" : {
"assetClass" : "0x973bb640",
"data" : "0x000000000000000000000000495f947276749ce646f68ac8c248420045cb7b5ebdf2657ffc1fadfd73cf0a8cde95d50b62d3df8c000000000000070000000032"
},
"value" : "1"
},
"maker" : "0x112f0732e59e7600768dfc35ba744b89f2356cd8",
"salt" : "0xdbf0f98bc1746711579dcce549a4cc4e866fb71bf2e185bfefbb7d32f325972e",
"start" : 0,
"takeAsset" : {
"assetType" : {
"assetClass" : "0xaaaebeba",
"data" : "0x"
},
"value" : "2000000000000000000"
},
"taker" : "0x0000000000000000000000000000000000000000"
},
"primaryType" : "Order",
"types" : {
"Asset" : [
{
"name" : "assetType",
"type" : "AssetType"
},
{
"name" : "value",
"type" : "uint256"
}
],
"AssetType" : [
{
"name" : "assetClass",
"type" : "bytes4"
},
{
"name" : "data",
"type" : "bytes"
}
],
"EIP712Domain" : [
{
"name" : "name",
"type" : "string"
},
{
"name" : "version",
"type" : "string"
},
{
"name" : "chainId",
"type" : "uint256"
},
{
"name" : "verifyingContract",
"type" : "address"
}
],
"Order" : [
{
"name" : "maker",
"type" : "address"
},
{
"name" : "makeAsset",
"type" : "Asset"
},
{
"name" : "taker",
"type" : "address"
},
{
"name" : "takeAsset",
"type" : "Asset"
},
{
"name" : "salt",
"type" : "uint256"
},
{
"name" : "start",
"type" : "uint256"
},
{
"name" : "end",
"type" : "uint256"
},
{
"name" : "dataType",
"type" : "bytes4"
},
{
"name" : "data",
"type" : "bytes"
}
]
}
}

View File

@@ -0,0 +1,92 @@
{
"types": {
"EIP712Domain": [
{
"type": "string",
"name": "name"
}
],
"LDPSigningRequest": [
{
"type": "string[3][]",
"name": "document"
},
{
"type": "string[][4]",
"name": "proof"
},
{
"type": "uint8[][][][]",
"name": "depthy"
}
]
},
"primaryType": "LDPSigningRequest",
"domain": {
"name": "Eip712Method2021"
},
"message": {
"depthy": [
[
[
[
"1",
"2"
],
[
"3"
]
]
]
],
"document": [
[
"<did:key:z6MkgFneaaMjN6zybqLNXgt4YfmVx2XZhzPdDyk4ZK81daHZ>",
"<https://www.w3.org/TR/owl-ref/#sameAs-def>",
"\"did:ethr:0xf7398bacf610bb4e3b567811279fcb3c41919f89\""
],
[
"<urn:uuid:14ab6047-bf2d-4fde-9564-51dead126ffb>",
"<https://www.w3.org/2018/credentials#credentialSubject>",
"<did:key:z6MkgFneaaMjN6zybqLNXgt4YfmVx2XZhzPdDyk4ZK81daHZ>"
],
[
"<urn:uuid:14ab6047-bf2d-4fde-9564-51dead126ffb>",
"<https://www.w3.org/2018/credentials#issuanceDate>",
"\"2021-03-04T21:08:22.615Z\"^^<http://www.w3.org/2001/XMLSchema#dateTime>"
],
[
"<urn:uuid:14ab6047-bf2d-4fde-9564-51dead126ffb>",
"<https://www.w3.org/2018/credentials#issuer>",
"<did:ethr:0xf7398bacf610bb4e3b567811279fcb3c41919f89>"
],
[
"<urn:uuid:14ab6047-bf2d-4fde-9564-51dead126ffb>",
"<http://www.w3.org/1999/02/22-rdf-syntax-ns#type>",
"<https://www.w3.org/2018/credentials#VerifiableCredential>"
]
],
"proof": [
[
"_:c14n0",
"<http://purl.org/dc/terms/created>",
"\"2021-03-04T21:08:22.616Z\"^^<http://www.w3.org/2001/XMLSchema#dateTime>"
],
[
"_:c14n0",
"<https://w3id.org/security#proofPurpose>",
"<https://w3id.org/security#assertionMethod>"
],
[
"_:c14n0",
"<https://w3id.org/security#verificationMethod>",
"<did:ethr:0xf7398bacf610bb4e3b567811279fcb3c41919f89#Eip712Method2021>"
],
[
"_:c14n0",
"<http://www.w3.org/1999/02/22-rdf-syntax-ns#type>",
"<https://w3id.org/security#Eip712Signature2021>"
]
]
}
}

View File

@@ -0,0 +1,78 @@
{
"domain": {
"chainId": 5,
"name": "Ether Mail",
"verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
"version": "1"
},
"message": {
"contents": "Hello, Bob!",
"from": {
"name": "Cow",
"wallets": [
"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
"0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF"
]
},
"to": {
"name": "test list",
"members": [
{
"name": "Bob",
"wallets": [
"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB",
"0xB0B0b0b0b0b0B000000000000000000000000000"
]
},
{
"name": "Alice",
"wallets": [
"0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57"
]
}
]
},
"attach": {
"list": [
{
"name": "first",
"size": "100"
},
{
"name": "second",
"size": "3400"
}
]
}
},
"primaryType": "Mail",
"types": {
"EIP712Domain": [
{ "name": "name", "type": "string" },
{ "name": "version", "type": "string" },
{ "name": "chainId", "type": "uint256" },
{ "name": "verifyingContract", "type": "address" }
],
"Attachment": [
{ "name": "name", "type": "string" },
{ "name": "size", "type": "uint16" }
],
"Attachments": [
{ "name": "list", "type": "Attachment[]" }
],
"MailingList": [
{ "name": "name", "type": "string" },
{ "name": "members", "type": "Person[]" }
],
"Mail": [
{ "name": "from", "type": "Person" },
{ "name": "to", "type": "MailingList" },
{ "name": "contents", "type": "string" },
{ "name": "attach", "type": "Attachments" }
],
"Person": [
{ "name": "name", "type": "string" },
{ "name": "wallets", "type": "address[]" }
]
}
}

View File

@@ -20,14 +20,14 @@ class P2Type(IntEnum):
LEGACY_IMPLEM = 0x00
NEW_IMPLEM = 0x01,
class EIP712FieldType:
class EIP712FieldType(IntEnum):
CUSTOM = 0,
INT = auto(),
UINT = auto(),
ADDRESS = auto(),
BOOL = auto(),
STRING = auto(),
FIXED_BYTES = auto(),
INT = auto()
UINT = auto()
ADDRESS = auto()
BOOL = auto()
STRING = auto()
FIX_BYTES = auto()
DYN_BYTES = auto()
@@ -66,14 +66,14 @@ class EthereumClientCmdBuilder:
data = bytearray()
typedesc = 0
typedesc |= (len(array_levels) > 0) << 7
typedesc |= (type_size > 0) << 6
typedesc |= (type_size != None) << 6
typedesc |= field_type
data.append(typedesc)
if field_type == EIP712FieldType.CUSTOM:
data.append(len(type_name))
for char in type_name:
data.append(ord(char))
if type_size > 0:
if type_size != None:
data.append(type_size)
if len(array_levels) > 0:
data.append(len(array_levels))
@@ -107,12 +107,17 @@ class EthereumClientCmdBuilder:
data)
def eip712_send_struct_impl_struct_field(self, data: bytearray) -> Iterator[bytes]:
while len(data > 0):
# Add a 16-bit integer with the data's byte length (network byte order)
data_w_length = bytearray()
data_w_length.append((len(data) & 0xff00) >> 8)
data_w_length.append(len(data) & 0x00ff)
data_w_length += data
while len(data_w_length) > 0:
yield self._serialize(InsType.EIP712_SEND_STRUCT_IMPL,
P1Type.COMPLETE_SEND,
P2Type.STRUCT_FIELD,
data[:0xff])
data = data[0xff:]
data_w_length[:0xff])
data_w_length = data_w_length[0xff:]
def _format_bip32(self, bip32, data = bytearray()) -> bytearray:
data.append(len(bip32))
@@ -195,17 +200,14 @@ class EthereumClient:
return self._recv()
def eip712_send_struct_impl_array(self, size: int):
send._send(self._cmd_builder.eip712_send_struct_impl_array(size))
self._send(self._cmd_builder.eip712_send_struct_impl_array(size))
return self._recv()
def eip712_send_struct_impl_struct_field(self, raw_value: bytes):
ret = None
for apdu in self._cmd_builder.eip712_send_struct_impl_struct_field(
InsType.EIP712_SEND_STRUCT_IMPL,
P1Type.COMPLETE_SEND,
P2Type.STRUCT_FIELD,
data[:0xff]):
for apdu in self._cmd_builder.eip712_send_struct_impl_struct_field(raw_value):
self._send(apdu)
# TODO: Do clicks
ret = self._recv()
return ret

View File

@@ -1,6 +1,7 @@
import os
import fnmatch
from ethereum_client import EthereumClient
from eip712 import InputData
def test_eip712_legacy(app_client: EthereumClient):
bip32 = [
@@ -20,3 +21,15 @@ def test_eip712_legacy(app_client: EthereumClient):
assert v == bytes.fromhex("1c")
assert r == bytes.fromhex("ea66f747173762715751c889fea8722acac3fc35db2c226d37a2e58815398f64")
assert s == bytes.fromhex("52d8ba9153de9255da220ffd36762c0b027701a3b5110f0a765f94b16a9dfb55")
def test_eip712_new(app_client: EthereumClient):
if app_client._client.firmware.device == "nanos": # not supported
return
# Loop through JSON files
for file in os.scandir("./eip712/input_files"):
if fnmatch.fnmatch(file, "*-test.json"):
print(file.path)
InputData.process_file(app_client, file.path, False)
assert 1 == 1