diff --git a/device-protocol b/device-protocol index 70bbbbf4..80987a78 160000 --- a/device-protocol +++ b/device-protocol @@ -1 +1 @@ -Subproject commit 70bbbbf4c1174245278dd4ce1dff8dbe41ca40dd +Subproject commit 80987a7893be8a5898e17d0d7cbd04e7c80adcf6 diff --git a/keepkeylib/client.py b/keepkeylib/client.py index 72489770..f1ac6194 100644 --- a/keepkeylib/client.py +++ b/keepkeylib/client.py @@ -2068,7 +2068,9 @@ def zcash_sign_pczt(self, address_n, actions, account=None, expiry_height=None, transparent_outputs=None, transparent_inputs=None, expected_seed_fingerprint=None, - return_transparent_signatures=False): + return_transparent_signatures=False, + ironwood_actions=None, ironwood_flags=None, + ironwood_value_balance=None): """Sign a Zcash Orchard-family shielded transaction via PCZT protocol. Streams transparent outputs, then transparent inputs, then shielded @@ -2089,6 +2091,9 @@ def zcash_sign_pczt(self, address_n, actions, account=None, orchard_digest: 32-byte orchard digest shielded_pool: ZcashShieldedPool value (Orchard by default) ironwood_digest: 32-byte Ironwood digest for transaction v6 + ironwood_actions: for a ZIP 318 pool-crossing v6 transaction, the + Ironwood actions, streamed after the Orchard `actions`, with + ironwood_flags and ironwood_value_balance for their bundle orchard_flags: bundle flags byte (enables digest verification) orchard_value_balance: signed i64 value balance orchard_anchor: 32-byte anchor @@ -2096,7 +2101,9 @@ def zcash_sign_pczt(self, address_n, actions, account=None, version_group_id: transaction version group ID lock_time: transaction lock time expiry_height: transaction expiry height - transparent_outputs: output dicts matching ZcashTransparentOutput + transparent_outputs: output dicts matching ZcashTransparentOutput; + is_tex shows a P2PKH output as a ZIP 320 tex1 address, and + address_n marks the account's own one-time address transparent_inputs: input dicts matching ZcashTransparentInput; host-provided per-input sighashes are rejected by RC18 return_transparent_signatures: when true, return a tuple of @@ -2106,11 +2113,15 @@ def zcash_sign_pczt(self, address_n, actions, account=None, ZcashSignedPCZT with compact Orchard signatures and optional txid, or a tuple including transparent signatures when requested. """ - n_actions = len(actions) - if n_actions == 0: - raise ValueError("Must have at least one action") - - for idx, action in enumerate(actions): + # No action is a transparent-only transaction (ZIP 320 TEX step 2), + # which needs a transparent input to sign. + if len(actions) == 0 and not transparent_inputs: + raise ValueError("Must have at least one action or transparent input") + # Orchard actions first, then any Ironwood ones; indices count on. + stream = list(actions) + list(ironwood_actions or []) + n_actions = len(stream) + + for idx, action in enumerate(stream): if 'is_spend' not in action or not isinstance(action['is_spend'], bool): raise ValueError( "Orchard action %d must explicitly set boolean is_spend" % idx) @@ -2127,7 +2138,7 @@ def zcash_sign_pczt(self, address_n, actions, account=None, # explicitly if the caller passed it. kwargs = dict( address_n=address_n, - n_actions=n_actions, + n_actions=len(actions), total_amount=total_amount, fee=fee, branch_id=branch_id, @@ -2166,6 +2177,10 @@ def zcash_sign_pczt(self, address_n, actions, account=None, kwargs['n_transparent_inputs'] = len(transparent_inputs) if expected_seed_fingerprint is not None: kwargs['expected_seed_fingerprint'] = expected_seed_fingerprint + if ironwood_actions: + kwargs['n_ironwood_actions'] = len(ironwood_actions) + kwargs['ironwood_flags'] = ironwood_flags + kwargs['ironwood_value_balance'] = ironwood_value_balance resp = self.call(zcash_proto.ZcashSignPCZT(**kwargs)) @@ -2231,7 +2246,7 @@ def zcash_sign_pczt(self, address_n, actions, account=None, # include an index. The device controls stream order, just as it # does for transparent inputs and outputs above, so discard any # caller copy before supplying the requested index. - action = dict(actions[idx]) + action = dict(stream[idx]) action.pop('index', None) resp = self.call(zcash_proto.ZcashPCZTAction(index=idx, **action)) sent_actions.add(idx) @@ -2269,7 +2284,7 @@ def zcash_sign_pczt(self, address_n, actions, account=None, if not signature: raise Exception("Device returned an empty transparent signature") - expected_signatures = sum(1 for action in actions if action['is_spend']) + expected_signatures = sum(1 for action in stream if action['is_spend']) if len(resp.signatures) != expected_signatures: raise Exception( "Device returned %d Orchard signatures for %d real spends" diff --git a/keepkeylib/eip712_stream.py b/keepkeylib/eip712_stream.py index 9b813267..48310b6f 100644 --- a/keepkeylib/eip712_stream.py +++ b/keepkeylib/eip712_stream.py @@ -28,13 +28,24 @@ STRUCT = DataType.STRUCT # EthereumTypedDataValueAck.value max_size in messages-ethereum.options, and -# EIP712_MAX_LEAF on the device. +# EIP712_MAX_LEAF on the device: one ValueAck, and one chunk of a longer value. MAX_LEAF_BYTES = 1024 +# EIP712_MAX_VALUE: the longest `bytes` or `string` value the device takes in +# chunks. +MAX_VALUE_BYTES = 1024 * 1024 +# The Features capability (as common.capability_names() spells it) of +# firmware that takes chunked values. +CHUNKED_VALUES = 'eip712-chunked-values' MAX_IDENTIFIER_BYTES = 31 +# Struct type names (EIP712_MAX_STRUCT_NAME - 1 on the device) may also use +# ':' after the first character, as Hyperliquid's +# "HyperliquidTransaction:ApproveBuilderFee" does. +MAX_TYPE_NAME_BYTES = 47 _ARRAY_GROUP = re.compile(r'\[([0-9]*)\]') _CANONICAL_DIGITS = re.compile(r'^[1-9][0-9]*$') _IDENTIFIER = re.compile(r'^[A-Za-z_$][A-Za-z0-9_$]*$') +_TYPE_NAME = re.compile(r'^[A-Za-z_$][A-Za-z0-9_$:]*$') class Eip712Error(Exception): @@ -116,7 +127,7 @@ def parse_solidity_type(type_str): 'array_levels': levels, } - if not _IDENTIFIER.match(base) or len(base) > MAX_IDENTIFIER_BYTES: + if not _TYPE_NAME.match(base) or len(base) > MAX_TYPE_NAME_BYTES: raise Eip712Error('Unparseable EIP-712 type: %s' % type_str) return {'data_type': STRUCT, 'struct_name': base, 'array_levels': levels} @@ -146,13 +157,14 @@ def _hex_bytes(value, what): return bytes(bytearray.fromhex(h)) -def encode_value(field, value): +def encode_value(field, value, max_bytes=MAX_LEAF_BYTES): """One leaf, as the exact bytes the device will hash and display. Raw big-endian at the declared width, never a decimal string: the device does no number parsing at all, which is what removes the old path's 2**63-1 ceiling and any chance of the two sides disagreeing about what a - decimal meant. + decimal meant. A dynamic value may be up to `max_bytes` long; past + MAX_LEAF_BYTES only value_ack() can put it on the wire. """ dt = field['data_type'] @@ -197,18 +209,18 @@ def encode_value(field, value): if len(b) != size: raise Eip712Error('bytes%d must be %d bytes, got %d' % (size, size, len(b))) return b - if len(b) > MAX_LEAF_BYTES: - raise Eip712Error('bytes value is %d bytes, over the %d-byte wire limit' - % (len(b), MAX_LEAF_BYTES)) + if len(b) > max_bytes: + raise Eip712Error('bytes value is %d bytes, over the %d-byte limit' + % (len(b), max_bytes)) return b if dt == STRING: if not isinstance(value, str): raise Eip712Error('string field must be a string') b = value.encode('utf-8') - if len(b) > MAX_LEAF_BYTES: - raise Eip712Error('string value is %d bytes, over the %d-byte wire limit' - % (len(b), MAX_LEAF_BYTES)) + if len(b) > max_bytes: + raise Eip712Error('string value is %d bytes, over the %d-byte limit' + % (len(b), max_bytes)) return b raise Eip712Error('Cannot encode data type %r as a leaf' % (dt,)) @@ -227,7 +239,7 @@ def struct_members(typed_data, name): Order is part of the signature: it sets both encodeType and the order encodeData concatenates members. """ - if not isinstance(name, str) or not _IDENTIFIER.match(name) or len(name) > MAX_IDENTIFIER_BYTES: + if not isinstance(name, str) or not _TYPE_NAME.match(name) or len(name) > MAX_TYPE_NAME_BYTES: raise Eip712Error('Struct name is not a canonical EIP-712 identifier') members = typed_data['types'].get(name) if members is None: @@ -320,3 +332,47 @@ def build_struct_ack(members): for lvl in m['type']['array_levels']: entry.type.array_levels.append(lvl) return ack + + +def value_ack(typed_data, request, chunked=False): + """The EthereumTypedDataValueAck that answers a device ValueRequest. + + A value of up to MAX_LEAF_BYTES goes whole. A longer `bytes` or `string` + goes in MAX_LEAF_BYTES chunks: the first carries value_total_length, and + each later request names a value_offset that its answer echoes. The + device may read a string twice from offset 0 (it counts and checks it + before showing it), so every chunk is served by its offset alone. + + `chunked` must be True only when the firmware reports CHUNKED_VALUES. + Older firmware skips the chunk fields and would hash the first chunk + alone, so without the capability a long value is refused here. + """ + resolved = resolve_member_path(typed_data, list(request.member_path)) + ack = eth_proto.EthereumTypedDataValueAck() + if resolved[0] == 'length': + if request.HasField('value_offset'): + raise Eip712Error('Device asked for an array length in chunks') + ack.value = encode_array_length(resolved[1]) + return ack + value = encode_value(resolved[1], resolved[2], MAX_VALUE_BYTES) + if len(value) > MAX_LEAF_BYTES and request.member_path[0] == 0: + raise Eip712Error('A domain value of %d bytes cannot be signed; the ' + 'device takes at most %d' % (len(value), MAX_LEAF_BYTES)) + if request.HasField('value_offset'): + offset = request.value_offset + if len(value) <= MAX_LEAF_BYTES or offset >= len(value): + raise Eip712Error('Device asked for offset %d of a %d-byte value' + % (offset, len(value))) + ack.value = value[offset:offset + MAX_LEAF_BYTES] + ack.value_offset = offset + return ack + if len(value) <= MAX_LEAF_BYTES: + ack.value = value + return ack + if not chunked: + raise Eip712Error('A %d-byte value needs firmware that takes chunked ' + 'values (%s); this one takes at most %d bytes' + % (len(value), CHUNKED_VALUES, MAX_LEAF_BYTES)) + ack.value = value[:MAX_LEAF_BYTES] + ack.value_total_length = len(value) + return ack diff --git a/keepkeylib/eos.py b/keepkeylib/eos.py index b7c68880..8e8aa416 100644 --- a/keepkeylib/eos.py +++ b/keepkeylib/eos.py @@ -257,7 +257,7 @@ def parse_authorization(data): keys.append( proto.EosAuthorizationKey( - type=1, + type=0, # K1: the key derived from address_n address_n=address_n, weight=int(key['weight']) ) diff --git a/keepkeylib/messages_ethereum_pb2.py b/keepkeylib/messages_ethereum_pb2.py index 06c6e087..3bebe702 100644 --- a/keepkeylib/messages_ethereum_pb2.py +++ b/keepkeylib/messages_ethereum_pb2.py @@ -21,7 +21,7 @@ name='messages-ethereum.proto', package='', syntax='proto2', - serialized_pb=_b('\n\x17messages-ethereum.proto\x1a\x0btypes.proto\"=\n\x12\x45thereumGetAddress\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x14\n\x0cshow_display\x18\x02 \x01(\x08\"7\n\x0f\x45thereumAddress\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x02(\x0c\x12\x13\n\x0b\x61\x64\x64ress_str\x18\x02 \x01(\t\"\x95\x03\n\x0e\x45thereumSignTx\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\r\n\x05nonce\x18\x02 \x01(\x0c\x12\x11\n\tgas_price\x18\x03 \x01(\x0c\x12\x11\n\tgas_limit\x18\x04 \x01(\x0c\x12\n\n\x02to\x18\x05 \x01(\x0c\x12\r\n\x05value\x18\x06 \x01(\x0c\x12\x1a\n\x12\x64\x61ta_initial_chunk\x18\x07 \x01(\x0c\x12\x13\n\x0b\x64\x61ta_length\x18\x08 \x01(\r\x12\x14\n\x0cto_address_n\x18\t \x03(\r\x12(\n\x0c\x61\x64\x64ress_type\x18\n \x01(\x0e\x32\x12.OutputAddressType\x12\x10\n\x08\x63hain_id\x18\x0c \x01(\r\x12\x17\n\x0fmax_fee_per_gas\x18\r \x01(\x0c\x12 \n\x18max_priority_fee_per_gas\x18\x0e \x01(\x0c\x12\x13\n\x0btoken_value\x18\x64 \x01(\x0c\x12\x10\n\x08token_to\x18\x65 \x01(\x0c\x12\x16\n\x0etoken_shortcut\x18\x66 \x01(\t\x12\x0f\n\x07tx_type\x18g \x01(\r\x12\x0c\n\x04type\x18h \x01(\rJ\x04\x08\x0b\x10\x0c\"\x8c\x01\n\x11\x45thereumTxRequest\x12\x13\n\x0b\x64\x61ta_length\x18\x01 \x01(\r\x12\x13\n\x0bsignature_v\x18\x02 \x01(\r\x12\x13\n\x0bsignature_r\x18\x03 \x01(\x0c\x12\x13\n\x0bsignature_s\x18\x04 \x01(\x0c\x12\x0c\n\x04hash\x18\x05 \x01(\x0c\x12\x15\n\rsignature_der\x18\x06 \x01(\x0c\"#\n\rEthereumTxAck\x12\x12\n\ndata_chunk\x18\x01 \x01(\x0c\"V\n\x12\x45thereumTxMetadata\x12\x16\n\x0esigned_payload\x18\x01 \x01(\x0c\x12\x18\n\x10metadata_version\x18\x02 \x01(\r\x12\x0e\n\x06key_id\x18\x03 \x01(\r\"F\n\x13\x45thereumMetadataAck\x12\x16\n\x0e\x63lassification\x18\x01 \x02(\r\x12\x17\n\x0f\x64isplay_summary\x18\x02 \x01(\t\"\x8c\x01\n\x13LoadClearsignSigner\x12\x0e\n\x06key_id\x18\x01 \x01(\r\x12\x0e\n\x06pubkey\x18\x02 \x01(\x0c\x12\r\n\x05\x61lias\x18\x03 \x01(\t\x12\x0c\n\x04icon\x18\x04 \x01(\x0c\x12\x12\n\nicon_width\x18\x05 \x01(\r\x12\x13\n\x0bicon_height\x18\x06 \x01(\r\x12\x0f\n\x07persist\x18\x07 \x01(\x08\"9\n\x13\x45thereumSignMessage\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x0f\n\x07message\x18\x02 \x02(\x0c\"L\n\x15\x45thereumVerifyMessage\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12\x11\n\tsignature\x18\x02 \x01(\x0c\x12\x0f\n\x07message\x18\x03 \x01(\x0c\">\n\x18\x45thereumMessageSignature\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12\x11\n\tsignature\x18\x02 \x01(\x0c\"_\n\x15\x45thereumSignTypedHash\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x1d\n\x15\x64omain_separator_hash\x18\x02 \x02(\x0c\x12\x14\n\x0cmessage_hash\x18\x03 \x01(\x0c\"\x8b\x01\n\x1a\x45thereumTypedDataSignature\x12\x11\n\tsignature\x18\x01 \x02(\x0c\x12\x0f\n\x07\x61\x64\x64ress\x18\x02 \x02(\t\x12\x1d\n\x15\x64omain_separator_hash\x18\x03 \x01(\x0c\x12\x14\n\x0chas_msg_hash\x18\x04 \x02(\x08\x12\x14\n\x0cmessage_hash\x18\x05 \x01(\x0c\"\x85\x01\n\x16\x45thereum712TypesValues\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x13\n\x0b\x65ip712types\x18\x02 \x02(\t\x12\x17\n\x0f\x65ip712primetype\x18\x03 \x02(\t\x12\x12\n\neip712data\x18\x04 \x02(\t\x12\x16\n\x0e\x65ip712typevals\x18\x05 \x02(\r\"b\n\x15\x45thereumSignTypedData\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x14\n\x0cprimary_type\x18\x02 \x02(\t\x12 \n\x12metamask_v4_compat\x18\x03 \x01(\x08:\x04true\".\n\x1e\x45thereumTypedDataStructRequest\x12\x0c\n\x04name\x18\x01 \x02(\t\"\xbe\x03\n\x1a\x45thereumTypedDataStructAck\x12\x41\n\x07members\x18\x01 \x03(\x0b\x32\x30.EthereumTypedDataStructAck.EthereumStructMember\x1a\x61\n\x14\x45thereumStructMember\x12;\n\x04type\x18\x01 \x02(\x0b\x32-.EthereumTypedDataStructAck.EthereumFieldType\x12\x0c\n\x04name\x18\x02 \x02(\t\x1a\x8d\x01\n\x11\x45thereumFieldType\x12?\n\tdata_type\x18\x01 \x02(\x0e\x32,.EthereumTypedDataStructAck.EthereumDataType\x12\x0c\n\x04size\x18\x02 \x01(\r\x12\x13\n\x0bstruct_name\x18\x03 \x01(\t\x12\x14\n\x0c\x61rray_levels\x18\x04 \x03(\r\"j\n\x10\x45thereumDataType\x12\x08\n\x04UINT\x10\x01\x12\x07\n\x03INT\x10\x02\x12\t\n\x05\x42YTES\x10\x03\x12\n\n\x06STRING\x10\x04\x12\x08\n\x04\x42OOL\x10\x05\x12\x0b\n\x07\x41\x44\x44RESS\x10\x06\x12\t\n\x05\x41RRAY\x10\x07\x12\n\n\x06STRUCT\x10\x08\"4\n\x1d\x45thereumTypedDataValueRequest\x12\x13\n\x0bmember_path\x18\x01 \x03(\r\"*\n\x19\x45thereumTypedDataValueAck\x12\r\n\x05value\x18\x01 \x02(\x0c\"h\n\x1b\x45thereumClearSignDefinition\x12\x15\n\rdefinition_id\x18\x01 \x02(\x0c\x12\x0e\n\x06offset\x18\x02 \x02(\r\x12\x14\n\x0ctotal_length\x18\x03 \x02(\r\x12\x0c\n\x04\x64\x61ta\x18\x04 \x02(\x0c\"^\n\x1e\x45thereumClearSignDefinitionAck\x12\x15\n\rdefinition_id\x18\x01 \x02(\x0c\x12\x13\n\x0bnext_offset\x18\x02 \x02(\r\x12\x10\n\x08\x63omplete\x18\x03 \x02(\x08\"\xef\x01\n\"EthereumClearSignDefinitionRequest\x12.\n\x04kind\x18\x01 \x02(\x0e\x32 .EthereumClearSignDefinitionKind\x12\x10\n\x08\x63hain_id\x18\x02 \x02(\x04\x12\x18\n\x10\x63ontract_address\x18\x03 \x01(\x0c\x12\x1d\n\x15selector_or_type_hash\x18\x04 \x01(\x0c\x12\x15\n\rdefinition_id\x18\x05 \x01(\x0c\x12\x0e\n\x06offset\x18\x06 \x02(\r\x12\x0e\n\x06length\x18\x07 \x02(\r\x12\x17\n\x0frecursion_depth\x18\x08 \x01(\r\"m\n EthereumClearSignDefinitionChunk\x12\x15\n\rdefinition_id\x18\x01 \x02(\x0c\x12\x0e\n\x06offset\x18\x02 \x02(\r\x12\x14\n\x0ctotal_length\x18\x03 \x02(\r\x12\x0c\n\x04\x64\x61ta\x18\x04 \x02(\x0c*s\n\x1f\x45thereumClearSignDefinitionKind\x12\x14\n\x10\x45RC7730_CALLDATA\x10\x01\x12\x12\n\x0e\x45RC7730_EIP712\x10\x02\x12\x11\n\rERC7730_TOKEN\x10\x03\x12\x13\n\x0f\x45RC7730_NETWORK\x10\x04\x42\x34\n\x1a\x63om.keepkey.deviceprotocolB\x16KeepKeyMessageEthereum') + serialized_pb=_b('\n\x17messages-ethereum.proto\x1a\x0btypes.proto\"=\n\x12\x45thereumGetAddress\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x14\n\x0cshow_display\x18\x02 \x01(\x08\"7\n\x0f\x45thereumAddress\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x02(\x0c\x12\x13\n\x0b\x61\x64\x64ress_str\x18\x02 \x01(\t\"\x95\x03\n\x0e\x45thereumSignTx\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\r\n\x05nonce\x18\x02 \x01(\x0c\x12\x11\n\tgas_price\x18\x03 \x01(\x0c\x12\x11\n\tgas_limit\x18\x04 \x01(\x0c\x12\n\n\x02to\x18\x05 \x01(\x0c\x12\r\n\x05value\x18\x06 \x01(\x0c\x12\x1a\n\x12\x64\x61ta_initial_chunk\x18\x07 \x01(\x0c\x12\x13\n\x0b\x64\x61ta_length\x18\x08 \x01(\r\x12\x14\n\x0cto_address_n\x18\t \x03(\r\x12(\n\x0c\x61\x64\x64ress_type\x18\n \x01(\x0e\x32\x12.OutputAddressType\x12\x10\n\x08\x63hain_id\x18\x0c \x01(\r\x12\x17\n\x0fmax_fee_per_gas\x18\r \x01(\x0c\x12 \n\x18max_priority_fee_per_gas\x18\x0e \x01(\x0c\x12\x13\n\x0btoken_value\x18\x64 \x01(\x0c\x12\x10\n\x08token_to\x18\x65 \x01(\x0c\x12\x16\n\x0etoken_shortcut\x18\x66 \x01(\t\x12\x0f\n\x07tx_type\x18g \x01(\r\x12\x0c\n\x04type\x18h \x01(\rJ\x04\x08\x0b\x10\x0c\"\x8c\x01\n\x11\x45thereumTxRequest\x12\x13\n\x0b\x64\x61ta_length\x18\x01 \x01(\r\x12\x13\n\x0bsignature_v\x18\x02 \x01(\r\x12\x13\n\x0bsignature_r\x18\x03 \x01(\x0c\x12\x13\n\x0bsignature_s\x18\x04 \x01(\x0c\x12\x0c\n\x04hash\x18\x05 \x01(\x0c\x12\x15\n\rsignature_der\x18\x06 \x01(\x0c\"#\n\rEthereumTxAck\x12\x12\n\ndata_chunk\x18\x01 \x01(\x0c\"V\n\x12\x45thereumTxMetadata\x12\x16\n\x0esigned_payload\x18\x01 \x01(\x0c\x12\x18\n\x10metadata_version\x18\x02 \x01(\r\x12\x0e\n\x06key_id\x18\x03 \x01(\r\"F\n\x13\x45thereumMetadataAck\x12\x16\n\x0e\x63lassification\x18\x01 \x02(\r\x12\x17\n\x0f\x64isplay_summary\x18\x02 \x01(\t\"\x8c\x01\n\x13LoadClearsignSigner\x12\x0e\n\x06key_id\x18\x01 \x01(\r\x12\x0e\n\x06pubkey\x18\x02 \x01(\x0c\x12\r\n\x05\x61lias\x18\x03 \x01(\t\x12\x0c\n\x04icon\x18\x04 \x01(\x0c\x12\x12\n\nicon_width\x18\x05 \x01(\r\x12\x13\n\x0bicon_height\x18\x06 \x01(\r\x12\x0f\n\x07persist\x18\x07 \x01(\x08\"9\n\x13\x45thereumSignMessage\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x0f\n\x07message\x18\x02 \x02(\x0c\"L\n\x15\x45thereumVerifyMessage\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12\x11\n\tsignature\x18\x02 \x01(\x0c\x12\x0f\n\x07message\x18\x03 \x01(\x0c\">\n\x18\x45thereumMessageSignature\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12\x11\n\tsignature\x18\x02 \x01(\x0c\"_\n\x15\x45thereumSignTypedHash\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x1d\n\x15\x64omain_separator_hash\x18\x02 \x02(\x0c\x12\x14\n\x0cmessage_hash\x18\x03 \x01(\x0c\"\x8b\x01\n\x1a\x45thereumTypedDataSignature\x12\x11\n\tsignature\x18\x01 \x02(\x0c\x12\x0f\n\x07\x61\x64\x64ress\x18\x02 \x02(\t\x12\x1d\n\x15\x64omain_separator_hash\x18\x03 \x01(\x0c\x12\x14\n\x0chas_msg_hash\x18\x04 \x02(\x08\x12\x14\n\x0cmessage_hash\x18\x05 \x01(\x0c\"\x85\x01\n\x16\x45thereum712TypesValues\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x13\n\x0b\x65ip712types\x18\x02 \x02(\t\x12\x17\n\x0f\x65ip712primetype\x18\x03 \x02(\t\x12\x12\n\neip712data\x18\x04 \x02(\t\x12\x16\n\x0e\x65ip712typevals\x18\x05 \x02(\r\"b\n\x15\x45thereumSignTypedData\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x14\n\x0cprimary_type\x18\x02 \x02(\t\x12 \n\x12metamask_v4_compat\x18\x03 \x01(\x08:\x04true\".\n\x1e\x45thereumTypedDataStructRequest\x12\x0c\n\x04name\x18\x01 \x02(\t\"\xbe\x03\n\x1a\x45thereumTypedDataStructAck\x12\x41\n\x07members\x18\x01 \x03(\x0b\x32\x30.EthereumTypedDataStructAck.EthereumStructMember\x1a\x61\n\x14\x45thereumStructMember\x12;\n\x04type\x18\x01 \x02(\x0b\x32-.EthereumTypedDataStructAck.EthereumFieldType\x12\x0c\n\x04name\x18\x02 \x02(\t\x1a\x8d\x01\n\x11\x45thereumFieldType\x12?\n\tdata_type\x18\x01 \x02(\x0e\x32,.EthereumTypedDataStructAck.EthereumDataType\x12\x0c\n\x04size\x18\x02 \x01(\r\x12\x13\n\x0bstruct_name\x18\x03 \x01(\t\x12\x14\n\x0c\x61rray_levels\x18\x04 \x03(\r\"j\n\x10\x45thereumDataType\x12\x08\n\x04UINT\x10\x01\x12\x07\n\x03INT\x10\x02\x12\t\n\x05\x42YTES\x10\x03\x12\n\n\x06STRING\x10\x04\x12\x08\n\x04\x42OOL\x10\x05\x12\x0b\n\x07\x41\x44\x44RESS\x10\x06\x12\t\n\x05\x41RRAY\x10\x07\x12\n\n\x06STRUCT\x10\x08\"J\n\x1d\x45thereumTypedDataValueRequest\x12\x13\n\x0bmember_path\x18\x01 \x03(\r\x12\x14\n\x0cvalue_offset\x18\x02 \x01(\r\"\\\n\x19\x45thereumTypedDataValueAck\x12\r\n\x05value\x18\x01 \x02(\x0c\x12\x1a\n\x12value_total_length\x18\x02 \x01(\r\x12\x14\n\x0cvalue_offset\x18\x03 \x01(\r\"h\n\x1b\x45thereumClearSignDefinition\x12\x15\n\rdefinition_id\x18\x01 \x02(\x0c\x12\x0e\n\x06offset\x18\x02 \x02(\r\x12\x14\n\x0ctotal_length\x18\x03 \x02(\r\x12\x0c\n\x04\x64\x61ta\x18\x04 \x02(\x0c\"^\n\x1e\x45thereumClearSignDefinitionAck\x12\x15\n\rdefinition_id\x18\x01 \x02(\x0c\x12\x13\n\x0bnext_offset\x18\x02 \x02(\r\x12\x10\n\x08\x63omplete\x18\x03 \x02(\x08\"\xef\x01\n\"EthereumClearSignDefinitionRequest\x12.\n\x04kind\x18\x01 \x02(\x0e\x32 .EthereumClearSignDefinitionKind\x12\x10\n\x08\x63hain_id\x18\x02 \x02(\x04\x12\x18\n\x10\x63ontract_address\x18\x03 \x01(\x0c\x12\x1d\n\x15selector_or_type_hash\x18\x04 \x01(\x0c\x12\x15\n\rdefinition_id\x18\x05 \x01(\x0c\x12\x0e\n\x06offset\x18\x06 \x02(\r\x12\x0e\n\x06length\x18\x07 \x02(\r\x12\x17\n\x0frecursion_depth\x18\x08 \x01(\r\"m\n EthereumClearSignDefinitionChunk\x12\x15\n\rdefinition_id\x18\x01 \x02(\x0c\x12\x0e\n\x06offset\x18\x02 \x02(\r\x12\x14\n\x0ctotal_length\x18\x03 \x02(\r\x12\x0c\n\x04\x64\x61ta\x18\x04 \x02(\x0c*s\n\x1f\x45thereumClearSignDefinitionKind\x12\x14\n\x10\x45RC7730_CALLDATA\x10\x01\x12\x12\n\x0e\x45RC7730_EIP712\x10\x02\x12\x11\n\rERC7730_TOKEN\x10\x03\x12\x13\n\x0f\x45RC7730_NETWORK\x10\x04\x42\x34\n\x1a\x63om.keepkey.deviceprotocolB\x16KeepKeyMessageEthereum') , dependencies=[types__pb2.DESCRIPTOR,]) @@ -50,8 +50,8 @@ ], containing_type=None, options=None, - serialized_start=2877, - serialized_end=2992, + serialized_start=2949, + serialized_end=3064, ) _sym_db.RegisterEnumDescriptor(_ETHEREUMCLEARSIGNDEFINITIONKIND) @@ -1082,6 +1082,13 @@ message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='value_offset', full_name='EthereumTypedDataValueRequest.value_offset', index=1, + number=2, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), ], extensions=[ ], @@ -1095,7 +1102,7 @@ oneofs=[ ], serialized_start=2224, - serialized_end=2276, + serialized_end=2298, ) @@ -1113,6 +1120,20 @@ message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='value_total_length', full_name='EthereumTypedDataValueAck.value_total_length', index=1, + number=2, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='value_offset', full_name='EthereumTypedDataValueAck.value_offset', index=2, + number=3, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), ], extensions=[ ], @@ -1125,8 +1146,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2278, - serialized_end=2320, + serialized_start=2300, + serialized_end=2392, ) @@ -1177,8 +1198,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2322, - serialized_end=2426, + serialized_start=2394, + serialized_end=2498, ) @@ -1222,8 +1243,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2428, - serialized_end=2522, + serialized_start=2500, + serialized_end=2594, ) @@ -1302,8 +1323,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2525, - serialized_end=2764, + serialized_start=2597, + serialized_end=2836, ) @@ -1354,8 +1375,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2766, - serialized_end=2875, + serialized_start=2838, + serialized_end=2947, ) _ETHEREUMSIGNTX.fields_by_name['address_type'].enum_type = types__pb2._OUTPUTADDRESSTYPE diff --git a/keepkeylib/messages_pb2.py b/keepkeylib/messages_pb2.py index 30aaf84b..d07232a2 100644 --- a/keepkeylib/messages_pb2.py +++ b/keepkeylib/messages_pb2.py @@ -21,7 +21,7 @@ name='messages.proto', package='', syntax='proto2', - serialized_pb=_b('\n\x0emessages.proto\x1a\x0btypes.proto\"\x0c\n\nInitialize\"\r\n\x0bGetFeatures\"\xf1\x0c\n\x08\x46\x65\x61tures\x12\x0e\n\x06vendor\x18\x01 \x01(\t\x12\x15\n\rmajor_version\x18\x02 \x01(\r\x12\x15\n\rminor_version\x18\x03 \x01(\r\x12\x15\n\rpatch_version\x18\x04 \x01(\r\x12\x17\n\x0f\x62ootloader_mode\x18\x05 \x01(\x08\x12\x11\n\tdevice_id\x18\x06 \x01(\t\x12\x16\n\x0epin_protection\x18\x07 \x01(\x08\x12\x1d\n\x15passphrase_protection\x18\x08 \x01(\x08\x12\x10\n\x08language\x18\t \x01(\t\x12\r\n\x05label\x18\n \x01(\t\x12\x18\n\x05\x63oins\x18\x0b \x03(\x0b\x32\t.CoinType\x12\x13\n\x0binitialized\x18\x0c \x01(\x08\x12\x10\n\x08revision\x18\r \x01(\x0c\x12\x17\n\x0f\x62ootloader_hash\x18\x0e \x01(\x0c\x12\x10\n\x08imported\x18\x0f \x01(\x08\x12\x12\n\npin_cached\x18\x10 \x01(\x08\x12\x19\n\x11passphrase_cached\x18\x11 \x01(\x08\x12\x1d\n\x08policies\x18\x12 \x03(\x0b\x32\x0b.PolicyType\x12\r\n\x05model\x18\x15 \x01(\t\x12\x18\n\x10\x66irmware_variant\x18\x16 \x01(\t\x12\x15\n\rfirmware_hash\x18\x17 \x01(\x0c\x12\x11\n\tno_backup\x18\x18 \x01(\x08\x12\x1c\n\x14wipe_code_protection\x18\x19 \x01(\x08\x12\x1a\n\x12\x61uto_lock_delay_ms\x18\x1a \x01(\r\x12\x18\n\x10supports_taproot\x18\x1b \x01(\x08\x12\x1b\n\x13supports_dice_modes\x18\x1c \x01(\x08\x12\'\n\x1fsupports_solana_lut_attestation\x18\x1d \x01(\x08\x12.\n\x0c\x63\x61pabilities\x18\x1e \x03(\x0e\x32\x14.Features.CapabilityB\x02\x10\x01\"\xb4\x07\n\nCapability\x12\x1a\n\x16\x43\x41PABILITY_UNSPECIFIED\x10\x00\x12#\n\x1f\x43\x41PABILITY_ENTROPY_AUDIT_BUDGET\x10\x01\x12-\n)CAPABILITY_ERC20_UNLIMITED_APPROVE_REVIEW\x10\x02\x12,\n(CAPABILITY_ERC20_UNLIMITED_PERMIT_REVIEW\x10\x03\x12%\n!CAPABILITY_ERC7730_RUNTIME_REVIEW\x10\x04\x12#\n\x1f\x43\x41PABILITY_EVM_CERTIFIED_INTENT\x10\x05\x12$\n CAPABILITY_EVM_MAX_AMOUNT_REVIEW\x10\x06\x12\x1e\n\x1a\x43\x41PABILITY_EVM_TX_METADATA\x10\x07\x12\'\n#CAPABILITY_EVM_UNKNOWN_TOKEN_REVIEW\x10\x08\x12\"\n\x1e\x43\x41PABILITY_HIVE_RELEASE_REVIEW\x10\t\x12(\n$CAPABILITY_LEGACY_EVM_ROUTER_SIGNING\x10\n\x12\"\n\x1e\x43\x41PABILITY_MAYA_SINGLE_MESSAGE\x10\x0b\x12\"\n\x1e\x43\x41PABILITY_OSMOSIS_WIRE_GUARDS\x10\x0c\x12\x1d\n\x19\x43\x41PABILITY_PERMIT2_REVIEW\x10\r\x12%\n!CAPABILITY_PROMPT_WORKFLOW_UNWIND\x10\x0e\x12&\n\"CAPABILITY_PROTECTED_PING_PRESENCE\x10\x0f\x12!\n\x1d\x43\x41PABILITY_RIPPLE_MEMO_POLICY\x10\x10\x12%\n!CAPABILITY_SESSION_TRUST_LIFETIME\x10\x11\x12&\n\"CAPABILITY_SOLANA_CERTIFIED_REVIEW\x10\x12\x12%\n!CAPABILITY_SOLANA_LUT_ATTESTATION\x10\x13\x12$\n CAPABILITY_SOLANA_RUNTIME_REVIEW\x10\x14\x12\x1e\n\x1a\x43\x41PABILITY_STORAGE_V19_KDF\x10\x15\x12\"\n\x1e\x43\x41PABILITY_TENDERMINT_PROGRESS\x10\x16\x12\"\n\x1e\x43\x41PABILITY_SAFE_RESET_CEREMONY\x10\x17\x12\"\n\x1e\x43\x41PABILITY_THOR_DEPOSIT_REVIEW\x10\x18\"*\n\x0cGetCoinTable\x12\r\n\x05start\x18\x01 \x01(\r\x12\x0b\n\x03\x65nd\x18\x02 \x01(\r\"L\n\tCoinTable\x12\x18\n\x05table\x18\x01 \x03(\x0b\x32\t.CoinType\x12\x11\n\tnum_coins\x18\x02 \x01(\r\x12\x12\n\nchunk_size\x18\x03 \x01(\r\"\x0e\n\x0c\x43learSession\"y\n\rApplySettings\x12\x10\n\x08language\x18\x01 \x01(\t\x12\r\n\x05label\x18\x02 \x01(\t\x12\x16\n\x0euse_passphrase\x18\x03 \x01(\x08\x12\x1a\n\x12\x61uto_lock_delay_ms\x18\x04 \x01(\r\x12\x13\n\x0bu2f_counter\x18\x05 \x01(\r\"\x1b\n\tChangePin\x12\x0e\n\x06remove\x18\x01 \x01(\x08\"\x87\x01\n\x04Ping\x12\x0f\n\x07message\x18\x01 \x01(\t\x12\x19\n\x11\x62utton_protection\x18\x02 \x01(\x08\x12\x16\n\x0epin_protection\x18\x03 \x01(\x08\x12\x1d\n\x15passphrase_protection\x18\x04 \x01(\x08\x12\x1c\n\x14wipe_code_protection\x18\x05 \x01(\x08\"\x1a\n\x07Success\x12\x0f\n\x07message\x18\x01 \x01(\t\"6\n\x07\x46\x61ilure\x12\x1a\n\x04\x63ode\x18\x01 \x01(\x0e\x32\x0c.FailureType\x12\x0f\n\x07message\x18\x02 \x01(\t\"?\n\rButtonRequest\x12 \n\x04\x63ode\x18\x01 \x01(\x0e\x32\x12.ButtonRequestType\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\t\"\x0b\n\tButtonAck\"7\n\x10PinMatrixRequest\x12#\n\x04type\x18\x01 \x01(\x0e\x32\x15.PinMatrixRequestType\"\x1b\n\x0cPinMatrixAck\x12\x0b\n\x03pin\x18\x01 \x02(\t\"\x08\n\x06\x43\x61ncel\"\x13\n\x11PassphraseRequest\"#\n\rPassphraseAck\x12\x12\n\npassphrase\x18\x01 \x02(\t\"\x1a\n\nGetEntropy\x12\x0c\n\x04size\x18\x01 \x02(\r\"\x1a\n\x07\x45ntropy\x12\x0f\n\x07\x65ntropy\x18\x01 \x02(\x0c\"\xa2\x01\n\x0cGetPublicKey\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x18\n\x10\x65\x63\x64sa_curve_name\x18\x02 \x01(\t\x12\x14\n\x0cshow_display\x18\x03 \x01(\x08\x12\x1a\n\tcoin_name\x18\x04 \x01(\t:\x07\x42itcoin\x12\x33\n\x0bscript_type\x18\x05 \x01(\x0e\x32\x10.InputScriptType:\x0cSPENDADDRESS\"4\n\tPublicKey\x12\x19\n\x04node\x18\x01 \x02(\x0b\x32\x0b.HDNodeType\x12\x0c\n\x04xpub\x18\x02 \x01(\t\"\xb3\x01\n\nGetAddress\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x1a\n\tcoin_name\x18\x02 \x01(\t:\x07\x42itcoin\x12\x14\n\x0cshow_display\x18\x03 \x01(\x08\x12+\n\x08multisig\x18\x04 \x01(\x0b\x32\x19.MultisigRedeemScriptType\x12\x33\n\x0bscript_type\x18\x05 \x01(\x0e\x32\x10.InputScriptType:\x0cSPENDADDRESS\"\x1a\n\x07\x41\x64\x64ress\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x02(\t\"\x0c\n\nWipeDevice\"\xbb\x01\n\nLoadDevice\x12\x10\n\x08mnemonic\x18\x01 \x01(\t\x12\x19\n\x04node\x18\x02 \x01(\x0b\x32\x0b.HDNodeType\x12\x0b\n\x03pin\x18\x03 \x01(\t\x12\x1d\n\x15passphrase_protection\x18\x04 \x01(\x08\x12\x19\n\x08language\x18\x05 \x01(\t:\x07\x65nglish\x12\r\n\x05label\x18\x06 \x01(\t\x12\x15\n\rskip_checksum\x18\x07 \x01(\x08\x12\x13\n\x0bu2f_counter\x18\x08 \x01(\r\"\x8a\x02\n\x0bResetDevice\x12\x16\n\x0e\x64isplay_random\x18\x01 \x01(\x08\x12\x15\n\x08strength\x18\x02 \x01(\r:\x03\x32\x35\x36\x12\x1d\n\x15passphrase_protection\x18\x03 \x01(\x08\x12\x16\n\x0epin_protection\x18\x04 \x01(\x08\x12\x19\n\x08language\x18\x05 \x01(\t:\x07\x65nglish\x12\r\n\x05label\x18\x06 \x01(\t\x12\x11\n\tno_backup\x18\x07 \x01(\x08\x12\x1a\n\x12\x61uto_lock_delay_ms\x18\x08 \x01(\r\x12\x13\n\x0bu2f_counter\x18\t \x01(\r\x12\x14\n\x0c\x64ice_entropy\x18\n \x01(\x08\x12\x11\n\tdice_only\x18\x0b \x01(\x08\"\x10\n\x0e\x45ntropyRequest\"\x1d\n\nEntropyAck\x12\x0f\n\x07\x65ntropy\x18\x01 \x01(\x0c\"\xff\x01\n\x0eRecoveryDevice\x12\x12\n\nword_count\x18\x01 \x01(\r\x12\x1d\n\x15passphrase_protection\x18\x02 \x01(\x08\x12\x16\n\x0epin_protection\x18\x03 \x01(\x08\x12\x19\n\x08language\x18\x04 \x01(\t:\x07\x65nglish\x12\r\n\x05label\x18\x05 \x01(\t\x12\x18\n\x10\x65nforce_wordlist\x18\x06 \x01(\x08\x12\x1c\n\x14use_character_cipher\x18\x07 \x01(\x08\x12\x1a\n\x12\x61uto_lock_delay_ms\x18\x08 \x01(\r\x12\x13\n\x0bu2f_counter\x18\t \x01(\r\x12\x0f\n\x07\x64ry_run\x18\n \x01(\x08\"\r\n\x0bWordRequest\"\x17\n\x07WordAck\x12\x0c\n\x04word\x18\x01 \x02(\t\";\n\x10\x43haracterRequest\x12\x10\n\x08word_pos\x18\x01 \x02(\r\x12\x15\n\rcharacter_pos\x18\x02 \x02(\r\"?\n\x0c\x43haracterAck\x12\x11\n\tcharacter\x18\x01 \x01(\t\x12\x0e\n\x06\x64\x65lete\x18\x02 \x01(\x08\x12\x0c\n\x04\x64one\x18\x03 \x01(\x08\"\x82\x01\n\x0bSignMessage\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x0f\n\x07message\x18\x02 \x02(\x0c\x12\x1a\n\tcoin_name\x18\x03 \x01(\t:\x07\x42itcoin\x12\x33\n\x0bscript_type\x18\x04 \x01(\x0e\x32\x10.InputScriptType:\x0cSPENDADDRESS\"`\n\rVerifyMessage\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\t\x12\x11\n\tsignature\x18\x02 \x01(\x0c\x12\x0f\n\x07message\x18\x03 \x01(\x0c\x12\x1a\n\tcoin_name\x18\x04 \x01(\t:\x07\x42itcoin\"6\n\x10MessageSignature\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\t\x12\x11\n\tsignature\x18\x02 \x01(\x0c\"v\n\x0e\x45ncryptMessage\x12\x0e\n\x06pubkey\x18\x01 \x01(\x0c\x12\x0f\n\x07message\x18\x02 \x01(\x0c\x12\x14\n\x0c\x64isplay_only\x18\x03 \x01(\x08\x12\x11\n\taddress_n\x18\x04 \x03(\r\x12\x1a\n\tcoin_name\x18\x05 \x01(\t:\x07\x42itcoin\"@\n\x10\x45ncryptedMessage\x12\r\n\x05nonce\x18\x01 \x01(\x0c\x12\x0f\n\x07message\x18\x02 \x01(\x0c\x12\x0c\n\x04hmac\x18\x03 \x01(\x0c\"Q\n\x0e\x44\x65\x63ryptMessage\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\r\n\x05nonce\x18\x02 \x01(\x0c\x12\x0f\n\x07message\x18\x03 \x01(\x0c\x12\x0c\n\x04hmac\x18\x04 \x01(\x0c\"4\n\x10\x44\x65\x63ryptedMessage\x12\x0f\n\x07message\x18\x01 \x01(\x0c\x12\x0f\n\x07\x61\x64\x64ress\x18\x02 \x01(\t\"\x8c\x01\n\x0e\x43ipherKeyValue\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x0b\n\x03key\x18\x02 \x01(\t\x12\r\n\x05value\x18\x03 \x01(\x0c\x12\x0f\n\x07\x65ncrypt\x18\x04 \x01(\x08\x12\x16\n\x0e\x61sk_on_encrypt\x18\x05 \x01(\x08\x12\x16\n\x0e\x61sk_on_decrypt\x18\x06 \x01(\x08\x12\n\n\x02iv\x18\x07 \x01(\x0c\"!\n\x10\x43ipheredKeyValue\x12\r\n\x05value\x18\x01 \x01(\x0c\"5\n\x10GetBip85Mnemonic\x12\x12\n\nword_count\x18\x01 \x02(\r\x12\r\n\x05index\x18\x02 \x02(\r\"!\n\rBip85Mnemonic\x12\x10\n\x08mnemonic\x18\x01 \x02(\t\"\xce\x01\n\x06SignTx\x12\x15\n\routputs_count\x18\x01 \x02(\r\x12\x14\n\x0cinputs_count\x18\x02 \x02(\r\x12\x1a\n\tcoin_name\x18\x03 \x01(\t:\x07\x42itcoin\x12\x12\n\x07version\x18\x04 \x01(\r:\x01\x31\x12\x14\n\tlock_time\x18\x05 \x01(\r:\x01\x30\x12\x0e\n\x06\x65xpiry\x18\x06 \x01(\r\x12\x14\n\x0coverwintered\x18\x07 \x01(\x08\x12\x18\n\x10version_group_id\x18\x08 \x01(\r\x12\x11\n\tbranch_id\x18\n \x01(\r\"\x85\x01\n\tTxRequest\x12\"\n\x0crequest_type\x18\x01 \x01(\x0e\x32\x0c.RequestType\x12&\n\x07\x64\x65tails\x18\x02 \x01(\x0b\x32\x15.TxRequestDetailsType\x12,\n\nserialized\x18\x03 \x01(\x0b\x32\x18.TxRequestSerializedType\"%\n\x05TxAck\x12\x1c\n\x02tx\x18\x01 \x01(\x0b\x32\x10.TransactionType\"+\n\x08RawTxAck\x12\x1f\n\x02tx\x18\x01 \x01(\x0b\x32\x13.RawTransactionType\"}\n\x0cSignIdentity\x12\x1f\n\x08identity\x18\x01 \x01(\x0b\x32\r.IdentityType\x12\x18\n\x10\x63hallenge_hidden\x18\x02 \x01(\x0c\x12\x18\n\x10\x63hallenge_visual\x18\x03 \x01(\t\x12\x18\n\x10\x65\x63\x64sa_curve_name\x18\x04 \x01(\t\"H\n\x0eSignedIdentity\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\t\x12\x12\n\npublic_key\x18\x02 \x01(\x0c\x12\x11\n\tsignature\x18\x03 \x01(\x0c\",\n\rApplyPolicies\x12\x1b\n\x06policy\x18\x01 \x03(\x0b\x32\x0b.PolicyType\"?\n\tFlashHash\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\r\x12\x0e\n\x06length\x18\x02 \x01(\r\x12\x11\n\tchallenge\x18\x03 \x01(\x0c\":\n\nFlashWrite\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\r\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\r\n\x05\x65rase\x18\x03 \x01(\x08\"!\n\x11\x46lashHashResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"5\n\x12\x44\x65\x62ugLinkFlashDump\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\r\x12\x0e\n\x06length\x18\x02 \x01(\r\"*\n\x1a\x44\x65\x62ugLinkFlashDumpResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"\x0b\n\tSoftReset\"\x0f\n\rFirmwareErase\"7\n\x0e\x46irmwareUpload\x12\x14\n\x0cpayload_hash\x18\x01 \x02(\x0c\x12\x0f\n\x07payload\x18\x02 \x02(\x0c\"2\n\x11\x44\x65\x62ugLinkDecision\x12\x0e\n\x06yes_no\x18\x01 \x02(\x08\x12\r\n\x05input\x18\x02 \x01(\t\"\x13\n\x11\x44\x65\x62ugLinkGetState\"\x99\x03\n\x0e\x44\x65\x62ugLinkState\x12\x0e\n\x06layout\x18\x01 \x01(\x0c\x12\x0b\n\x03pin\x18\x02 \x01(\t\x12\x0e\n\x06matrix\x18\x03 \x01(\t\x12\x10\n\x08mnemonic\x18\x04 \x01(\t\x12\x19\n\x04node\x18\x05 \x01(\x0b\x32\x0b.HDNodeType\x12\x1d\n\x15passphrase_protection\x18\x06 \x01(\x08\x12\x12\n\nreset_word\x18\x07 \x01(\t\x12\x15\n\rreset_entropy\x18\x08 \x01(\x0c\x12\x1a\n\x12recovery_fake_word\x18\t \x01(\t\x12\x19\n\x11recovery_word_pos\x18\n \x01(\r\x12\x17\n\x0frecovery_cipher\x18\x0b \x01(\t\x12$\n\x1crecovery_auto_completed_word\x18\x0c \x01(\t\x12\x15\n\rfirmware_hash\x18\r \x01(\x0c\x12\x14\n\x0cstorage_hash\x18\x0e \x01(\x0c\x12\x13\n\x0b\x64ice_digest\x18\x0f \x01(\x0c\x12\x15\n\rconfirm_title\x18\x10 \x01(\t\x12\x14\n\x0c\x63onfirm_body\x18\x11 \x01(\t\"\x0f\n\rDebugLinkStop\";\n\x0c\x44\x65\x62ugLinkLog\x12\r\n\x05level\x18\x01 \x01(\r\x12\x0e\n\x06\x62ucket\x18\x02 \x01(\t\x12\x0c\n\x04text\x18\x03 \x01(\t\"\x15\n\x13\x44\x65\x62ugLinkFillConfig\" \n\x0e\x43hangeWipeCode\x12\x0e\n\x06remove\x18\x01 \x01(\x08\"\x1f\n\x1d\x43learsignAttestorGetPublicKey\"0\n\x1a\x43learsignAttestorPublicKey\x12\x12\n\npublic_key\x18\x01 \x01(\x0c\"(\n\x15\x43learsignAttestorSign\x12\x0f\n\x07payload\x18\x01 \x01(\x0c\"C\n\x1a\x43learsignAttestorSignature\x12\x11\n\tsignature\x18\x01 \x01(\x0c\x12\x12\n\npublic_key\x18\x02 \x01(\x0c*\xc3\x46\n\x0bMessageType\x12 \n\x16MessageType_Initialize\x10\x00\x1a\x04\x90\xb5\x18\x01\x12\x1a\n\x10MessageType_Ping\x10\x01\x1a\x04\x90\xb5\x18\x01\x12\x1d\n\x13MessageType_Success\x10\x02\x1a\x04\x98\xb5\x18\x01\x12\x1d\n\x13MessageType_Failure\x10\x03\x1a\x04\x98\xb5\x18\x01\x12\x1f\n\x15MessageType_ChangePin\x10\x04\x1a\x04\x90\xb5\x18\x01\x12 \n\x16MessageType_WipeDevice\x10\x05\x1a\x04\x90\xb5\x18\x01\x12#\n\x19MessageType_FirmwareErase\x10\x06\x1a\x04\x90\xb5\x18\x01\x12$\n\x1aMessageType_FirmwareUpload\x10\x07\x1a\x04\x90\xb5\x18\x01\x12 \n\x16MessageType_GetEntropy\x10\t\x1a\x04\x90\xb5\x18\x01\x12\x1d\n\x13MessageType_Entropy\x10\n\x1a\x04\x98\xb5\x18\x01\x12\"\n\x18MessageType_GetPublicKey\x10\x0b\x1a\x04\x90\xb5\x18\x01\x12\x1f\n\x15MessageType_PublicKey\x10\x0c\x1a\x04\x98\xb5\x18\x01\x12 \n\x16MessageType_LoadDevice\x10\r\x1a\x04\x90\xb5\x18\x01\x12!\n\x17MessageType_ResetDevice\x10\x0e\x1a\x04\x90\xb5\x18\x01\x12\x1c\n\x12MessageType_SignTx\x10\x0f\x1a\x04\x90\xb5\x18\x01\x12\x1e\n\x14MessageType_Features\x10\x11\x1a\x04\x98\xb5\x18\x01\x12&\n\x1cMessageType_PinMatrixRequest\x10\x12\x1a\x04\x98\xb5\x18\x01\x12\"\n\x18MessageType_PinMatrixAck\x10\x13\x1a\x04\x90\xb5\x18\x01\x12\x1c\n\x12MessageType_Cancel\x10\x14\x1a\x04\x90\xb5\x18\x01\x12\x1f\n\x15MessageType_TxRequest\x10\x15\x1a\x04\x98\xb5\x18\x01\x12\x1b\n\x11MessageType_TxAck\x10\x16\x1a\x04\x90\xb5\x18\x01\x12$\n\x1aMessageType_CipherKeyValue\x10\x17\x1a\x04\x90\xb5\x18\x01\x12\"\n\x18MessageType_ClearSession\x10\x18\x1a\x04\x90\xb5\x18\x01\x12#\n\x19MessageType_ApplySettings\x10\x19\x1a\x04\x90\xb5\x18\x01\x12#\n\x19MessageType_ButtonRequest\x10\x1a\x1a\x04\x98\xb5\x18\x01\x12\x1f\n\x15MessageType_ButtonAck\x10\x1b\x1a\x04\x90\xb5\x18\x01\x12 \n\x16MessageType_GetAddress\x10\x1d\x1a\x04\x90\xb5\x18\x01\x12\x1d\n\x13MessageType_Address\x10\x1e\x1a\x04\x98\xb5\x18\x01\x12$\n\x1aMessageType_EntropyRequest\x10#\x1a\x04\x98\xb5\x18\x01\x12 \n\x16MessageType_EntropyAck\x10$\x1a\x04\x90\xb5\x18\x01\x12!\n\x17MessageType_SignMessage\x10&\x1a\x04\x90\xb5\x18\x01\x12#\n\x19MessageType_VerifyMessage\x10\'\x1a\x04\x90\xb5\x18\x01\x12&\n\x1cMessageType_MessageSignature\x10(\x1a\x04\x98\xb5\x18\x01\x12\'\n\x1dMessageType_PassphraseRequest\x10)\x1a\x04\x98\xb5\x18\x01\x12#\n\x19MessageType_PassphraseAck\x10*\x1a\x04\x90\xb5\x18\x01\x12$\n\x1aMessageType_RecoveryDevice\x10-\x1a\x04\x90\xb5\x18\x01\x12!\n\x17MessageType_WordRequest\x10.\x1a\x04\x98\xb5\x18\x01\x12\x1d\n\x13MessageType_WordAck\x10/\x1a\x04\x90\xb5\x18\x01\x12&\n\x1cMessageType_CipheredKeyValue\x10\x30\x1a\x04\x98\xb5\x18\x01\x12$\n\x1aMessageType_EncryptMessage\x10\x31\x1a\x04\x90\xb5\x18\x01\x12&\n\x1cMessageType_EncryptedMessage\x10\x32\x1a\x04\x98\xb5\x18\x01\x12$\n\x1aMessageType_DecryptMessage\x10\x33\x1a\x04\x90\xb5\x18\x01\x12&\n\x1cMessageType_DecryptedMessage\x10\x34\x1a\x04\x98\xb5\x18\x01\x12\"\n\x18MessageType_SignIdentity\x10\x35\x1a\x04\x90\xb5\x18\x01\x12$\n\x1aMessageType_SignedIdentity\x10\x36\x1a\x04\x98\xb5\x18\x01\x12!\n\x17MessageType_GetFeatures\x10\x37\x1a\x04\x90\xb5\x18\x01\x12(\n\x1eMessageType_EthereumGetAddress\x10\x38\x1a\x04\x90\xb5\x18\x01\x12%\n\x1bMessageType_EthereumAddress\x10\x39\x1a\x04\x98\xb5\x18\x01\x12$\n\x1aMessageType_EthereumSignTx\x10:\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1dMessageType_EthereumTxRequest\x10;\x1a\x04\x98\xb5\x18\x01\x12#\n\x19MessageType_EthereumTxAck\x10<\x1a\x04\x90\xb5\x18\x01\x12&\n\x1cMessageType_CharacterRequest\x10P\x1a\x04\x98\xb5\x18\x01\x12\"\n\x18MessageType_CharacterAck\x10Q\x1a\x04\x90\xb5\x18\x01\x12\x1e\n\x14MessageType_RawTxAck\x10R\x1a\x04\x90\xb5\x18\x01\x12#\n\x19MessageType_ApplyPolicies\x10S\x1a\x04\x90\xb5\x18\x01\x12\x1f\n\x15MessageType_FlashHash\x10T\x1a\x04\x90\xb5\x18\x01\x12 \n\x16MessageType_FlashWrite\x10U\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1dMessageType_FlashHashResponse\x10V\x1a\x04\x98\xb5\x18\x01\x12(\n\x1eMessageType_DebugLinkFlashDump\x10W\x1a\x04\xa0\xb5\x18\x01\x12\x30\n&MessageType_DebugLinkFlashDumpResponse\x10X\x1a\x04\xa8\xb5\x18\x01\x12\x1f\n\x15MessageType_SoftReset\x10Y\x1a\x04\xa0\xb5\x18\x01\x12\'\n\x1dMessageType_DebugLinkDecision\x10\x64\x1a\x04\xa0\xb5\x18\x01\x12\'\n\x1dMessageType_DebugLinkGetState\x10\x65\x1a\x04\xa0\xb5\x18\x01\x12$\n\x1aMessageType_DebugLinkState\x10\x66\x1a\x04\xa8\xb5\x18\x01\x12#\n\x19MessageType_DebugLinkStop\x10g\x1a\x04\xa0\xb5\x18\x01\x12\"\n\x18MessageType_DebugLinkLog\x10h\x1a\x04\xa8\xb5\x18\x01\x12)\n\x1fMessageType_DebugLinkFillConfig\x10i\x1a\x04\xa8\xb5\x18\x01\x12\"\n\x18MessageType_GetCoinTable\x10j\x1a\x04\x90\xb5\x18\x01\x12\x1f\n\x15MessageType_CoinTable\x10k\x1a\x04\x98\xb5\x18\x01\x12)\n\x1fMessageType_EthereumSignMessage\x10l\x1a\x04\x90\xb5\x18\x01\x12+\n!MessageType_EthereumVerifyMessage\x10m\x1a\x04\x90\xb5\x18\x01\x12.\n$MessageType_EthereumMessageSignature\x10n\x1a\x04\x98\xb5\x18\x01\x12$\n\x1aMessageType_ChangeWipeCode\x10o\x1a\x04\x90\xb5\x18\x01\x12+\n!MessageType_EthereumSignTypedHash\x10p\x1a\x04\x90\xb5\x18\x01\x12\x30\n&MessageType_EthereumTypedDataSignature\x10q\x1a\x04\x98\xb5\x18\x01\x12,\n\"MessageType_Ethereum712TypesValues\x10r\x1a\x04\x90\xb5\x18\x01\x12(\n\x1eMessageType_EthereumTxMetadata\x10s\x1a\x04\x90\xb5\x18\x01\x12)\n\x1fMessageType_EthereumMetadataAck\x10t\x1a\x04\x98\xb5\x18\x01\x12)\n\x1fMessageType_LoadClearsignSigner\x10u\x1a\x04\x90\xb5\x18\x01\x12,\n!MessageType_EthereumSignTypedData\x10\xa8\r\x1a\x04\x90\xb5\x18\x01\x12\x35\n*MessageType_EthereumTypedDataStructRequest\x10\xa9\r\x1a\x04\x98\xb5\x18\x01\x12\x31\n&MessageType_EthereumTypedDataStructAck\x10\xaa\r\x1a\x04\x90\xb5\x18\x01\x12\x34\n)MessageType_EthereumTypedDataValueRequest\x10\xab\r\x1a\x04\x98\xb5\x18\x01\x12\x30\n%MessageType_EthereumTypedDataValueAck\x10\xac\r\x1a\x04\x90\xb5\x18\x01\x12\x32\n\'MessageType_EthereumClearSignDefinition\x10\xad\r\x1a\x04\x90\xb5\x18\x01\x12\x35\n*MessageType_EthereumClearSignDefinitionAck\x10\xae\r\x1a\x04\x98\xb5\x18\x01\x12\x39\n.MessageType_EthereumClearSignDefinitionRequest\x10\xaf\r\x1a\x04\x98\xb5\x18\x01\x12\x37\n,MessageType_EthereumClearSignDefinitionChunk\x10\xb0\r\x1a\x04\x90\xb5\x18\x01\x12&\n\x1cMessageType_GetBip85Mnemonic\x10x\x1a\x04\x90\xb5\x18\x01\x12#\n\x19MessageType_Bip85Mnemonic\x10y\x1a\x04\x98\xb5\x18\x01\x12\'\n\x1cMessageType_RippleGetAddress\x10\x90\x03\x1a\x04\x90\xb5\x18\x01\x12$\n\x19MessageType_RippleAddress\x10\x91\x03\x1a\x04\x98\xb5\x18\x01\x12#\n\x18MessageType_RippleSignTx\x10\x92\x03\x1a\x04\x90\xb5\x18\x01\x12%\n\x1aMessageType_RippleSignedTx\x10\x93\x03\x1a\x04\x90\xb5\x18\x01\x12*\n\x1fMessageType_ThorchainGetAddress\x10\xf4\x03\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1cMessageType_ThorchainAddress\x10\xf5\x03\x1a\x04\x98\xb5\x18\x01\x12&\n\x1bMessageType_ThorchainSignTx\x10\xf6\x03\x1a\x04\x90\xb5\x18\x01\x12*\n\x1fMessageType_ThorchainMsgRequest\x10\xf7\x03\x1a\x04\x98\xb5\x18\x01\x12&\n\x1bMessageType_ThorchainMsgAck\x10\xf8\x03\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_ThorchainSignedTx\x10\xf9\x03\x1a\x04\x98\xb5\x18\x01\x12&\n\x1bMessageType_EosGetPublicKey\x10\xd8\x04\x1a\x04\x90\xb5\x18\x01\x12#\n\x18MessageType_EosPublicKey\x10\xd9\x04\x1a\x04\x98\xb5\x18\x01\x12 \n\x15MessageType_EosSignTx\x10\xda\x04\x1a\x04\x90\xb5\x18\x01\x12)\n\x1eMessageType_EosTxActionRequest\x10\xdb\x04\x1a\x04\x98\xb5\x18\x01\x12%\n\x1aMessageType_EosTxActionAck\x10\xdc\x04\x1a\x04\x90\xb5\x18\x01\x12\"\n\x17MessageType_EosSignedTx\x10\xdd\x04\x1a\x04\x98\xb5\x18\x01\x12%\n\x1aMessageType_NanoGetAddress\x10\xbc\x05\x1a\x04\x90\xb5\x18\x01\x12\"\n\x17MessageType_NanoAddress\x10\xbd\x05\x1a\x04\x98\xb5\x18\x01\x12!\n\x16MessageType_NanoSignTx\x10\xbe\x05\x1a\x04\x90\xb5\x18\x01\x12#\n\x18MessageType_NanoSignedTx\x10\xbf\x05\x1a\x04\x98\xb5\x18\x01\x12\'\n\x1cMessageType_SolanaGetAddress\x10\xee\x05\x1a\x04\x90\xb5\x18\x01\x12$\n\x19MessageType_SolanaAddress\x10\xef\x05\x1a\x04\x98\xb5\x18\x01\x12#\n\x18MessageType_SolanaSignTx\x10\xf0\x05\x1a\x04\x90\xb5\x18\x01\x12%\n\x1aMessageType_SolanaSignedTx\x10\xf1\x05\x1a\x04\x98\xb5\x18\x01\x12(\n\x1dMessageType_SolanaSignMessage\x10\xf2\x05\x1a\x04\x90\xb5\x18\x01\x12-\n\"MessageType_SolanaMessageSignature\x10\xf3\x05\x1a\x04\x98\xb5\x18\x01\x12\x30\n%MessageType_SolanaSignOffchainMessage\x10\xf4\x05\x1a\x04\x90\xb5\x18\x01\x12\x35\n*MessageType_SolanaOffchainMessageSignature\x10\xf5\x05\x1a\x04\x98\xb5\x18\x01\x12(\n\x1dMessageType_BinanceGetAddress\x10\xa0\x06\x1a\x04\x90\xb5\x18\x01\x12%\n\x1aMessageType_BinanceAddress\x10\xa1\x06\x1a\x04\x98\xb5\x18\x01\x12*\n\x1fMessageType_BinanceGetPublicKey\x10\xa2\x06\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1cMessageType_BinancePublicKey\x10\xa3\x06\x1a\x04\x98\xb5\x18\x01\x12$\n\x19MessageType_BinanceSignTx\x10\xa4\x06\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1cMessageType_BinanceTxRequest\x10\xa5\x06\x1a\x04\x98\xb5\x18\x01\x12)\n\x1eMessageType_BinanceTransferMsg\x10\xa6\x06\x1a\x04\x90\xb5\x18\x01\x12&\n\x1bMessageType_BinanceOrderMsg\x10\xa7\x06\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1cMessageType_BinanceCancelMsg\x10\xa8\x06\x1a\x04\x90\xb5\x18\x01\x12&\n\x1bMessageType_BinanceSignedTx\x10\xa9\x06\x1a\x04\x98\xb5\x18\x01\x12\'\n\x1cMessageType_CosmosGetAddress\x10\x84\x07\x1a\x04\x90\xb5\x18\x01\x12$\n\x19MessageType_CosmosAddress\x10\x85\x07\x1a\x04\x98\xb5\x18\x01\x12#\n\x18MessageType_CosmosSignTx\x10\x86\x07\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1cMessageType_CosmosMsgRequest\x10\x87\x07\x1a\x04\x98\xb5\x18\x01\x12#\n\x18MessageType_CosmosMsgAck\x10\x88\x07\x1a\x04\x90\xb5\x18\x01\x12%\n\x1aMessageType_CosmosSignedTx\x10\x89\x07\x1a\x04\x98\xb5\x18\x01\x12(\n\x1dMessageType_CosmosMsgDelegate\x10\x8a\x07\x1a\x04\x98\xb5\x18\x01\x12*\n\x1fMessageType_CosmosMsgUndelegate\x10\x8b\x07\x1a\x04\x98\xb5\x18\x01\x12*\n\x1fMessageType_CosmosMsgRedelegate\x10\x8c\x07\x1a\x04\x98\xb5\x18\x01\x12\'\n\x1cMessageType_CosmosMsgRewards\x10\x8d\x07\x1a\x04\x98\xb5\x18\x01\x12+\n MessageType_CosmosMsgIBCTransfer\x10\x8e\x07\x1a\x04\x98\xb5\x18\x01\x12+\n MessageType_TendermintGetAddress\x10\xe8\x07\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_TendermintAddress\x10\xe9\x07\x1a\x04\x98\xb5\x18\x01\x12\'\n\x1cMessageType_TendermintSignTx\x10\xea\x07\x1a\x04\x90\xb5\x18\x01\x12+\n MessageType_TendermintMsgRequest\x10\xeb\x07\x1a\x04\x98\xb5\x18\x01\x12\'\n\x1cMessageType_TendermintMsgAck\x10\xec\x07\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_TendermintMsgSend\x10\xed\x07\x1a\x04\x90\xb5\x18\x01\x12)\n\x1eMessageType_TendermintSignedTx\x10\xee\x07\x1a\x04\x98\xb5\x18\x01\x12,\n!MessageType_TendermintMsgDelegate\x10\xef\x07\x1a\x04\x98\xb5\x18\x01\x12.\n#MessageType_TendermintMsgUndelegate\x10\xf0\x07\x1a\x04\x98\xb5\x18\x01\x12.\n#MessageType_TendermintMsgRedelegate\x10\xf1\x07\x1a\x04\x98\xb5\x18\x01\x12+\n MessageType_TendermintMsgRewards\x10\xf2\x07\x1a\x04\x98\xb5\x18\x01\x12/\n$MessageType_TendermintMsgIBCTransfer\x10\xf3\x07\x1a\x04\x98\xb5\x18\x01\x12(\n\x1dMessageType_OsmosisGetAddress\x10\xcc\x08\x1a\x04\x90\xb5\x18\x01\x12%\n\x1aMessageType_OsmosisAddress\x10\xcd\x08\x1a\x04\x98\xb5\x18\x01\x12$\n\x19MessageType_OsmosisSignTx\x10\xce\x08\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_OsmosisMsgRequest\x10\xcf\x08\x1a\x04\x98\xb5\x18\x01\x12$\n\x19MessageType_OsmosisMsgAck\x10\xd0\x08\x1a\x04\x90\xb5\x18\x01\x12%\n\x1aMessageType_OsmosisMsgSend\x10\xd1\x08\x1a\x04\x90\xb5\x18\x01\x12)\n\x1eMessageType_OsmosisMsgDelegate\x10\xd2\x08\x1a\x04\x90\xb5\x18\x01\x12+\n MessageType_OsmosisMsgUndelegate\x10\xd3\x08\x1a\x04\x90\xb5\x18\x01\x12+\n MessageType_OsmosisMsgRedelegate\x10\xd4\x08\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_OsmosisMsgRewards\x10\xd5\x08\x1a\x04\x90\xb5\x18\x01\x12&\n\x1bMessageType_OsmosisMsgLPAdd\x10\xd6\x08\x1a\x04\x90\xb5\x18\x01\x12)\n\x1eMessageType_OsmosisMsgLPRemove\x10\xd7\x08\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_OsmosisMsgLPStake\x10\xd8\x08\x1a\x04\x90\xb5\x18\x01\x12*\n\x1fMessageType_OsmosisMsgLPUnstake\x10\xd9\x08\x1a\x04\x90\xb5\x18\x01\x12,\n!MessageType_OsmosisMsgIBCTransfer\x10\xda\x08\x1a\x04\x90\xb5\x18\x01\x12%\n\x1aMessageType_OsmosisMsgSwap\x10\xdb\x08\x1a\x04\x90\xb5\x18\x01\x12&\n\x1bMessageType_OsmosisSignedTx\x10\xdc\x08\x1a\x04\x98\xb5\x18\x01\x12*\n\x1fMessageType_MayachainGetAddress\x10\xb0\t\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1cMessageType_MayachainAddress\x10\xb1\t\x1a\x04\x98\xb5\x18\x01\x12&\n\x1bMessageType_MayachainSignTx\x10\xb2\t\x1a\x04\x90\xb5\x18\x01\x12*\n\x1fMessageType_MayachainMsgRequest\x10\xb3\t\x1a\x04\x98\xb5\x18\x01\x12&\n\x1bMessageType_MayachainMsgAck\x10\xb4\t\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_MayachainSignedTx\x10\xb5\t\x1a\x04\x98\xb5\x18\x01\x12$\n\x19MessageType_ZcashSignPCZT\x10\x94\n\x1a\x04\x90\xb5\x18\x01\x12&\n\x1bMessageType_ZcashPCZTAction\x10\x95\n\x1a\x04\x90\xb5\x18\x01\x12)\n\x1eMessageType_ZcashPCZTActionAck\x10\x96\n\x1a\x04\x98\xb5\x18\x01\x12&\n\x1bMessageType_ZcashSignedPCZT\x10\x97\n\x1a\x04\x98\xb5\x18\x01\x12)\n\x1eMessageType_ZcashGetOrchardFVK\x10\x98\n\x1a\x04\x90\xb5\x18\x01\x12&\n\x1bMessageType_ZcashOrchardFVK\x10\x99\n\x1a\x04\x98\xb5\x18\x01\x12,\n!MessageType_ZcashTransparentInput\x10\x9a\n\x1a\x04\x90\xb5\x18\x01\x12-\n\"MessageType_ZcashTransparentSigned\x10\x9b\n\x1a\x04\x98\xb5\x18\x01\x12*\n\x1fMessageType_ZcashDisplayAddress\x10\x9c\n\x1a\x04\x90\xb5\x18\x01\x12#\n\x18MessageType_ZcashAddress\x10\x9d\n\x1a\x04\x98\xb5\x18\x01\x12-\n\"MessageType_ZcashTransparentOutput\x10\x9e\n\x1a\x04\x90\xb5\x18\x01\x12*\n\x1fMessageType_ZcashTransparentAck\x10\x9f\n\x1a\x04\x98\xb5\x18\x01\x12%\n\x1aMessageType_TronGetAddress\x10\xf8\n\x1a\x04\x90\xb5\x18\x01\x12\"\n\x17MessageType_TronAddress\x10\xf9\n\x1a\x04\x98\xb5\x18\x01\x12!\n\x16MessageType_TronSignTx\x10\xfa\n\x1a\x04\x90\xb5\x18\x01\x12#\n\x18MessageType_TronSignedTx\x10\xfb\n\x1a\x04\x98\xb5\x18\x01\x12&\n\x1bMessageType_TronSignMessage\x10\xfc\n\x1a\x04\x90\xb5\x18\x01\x12+\n MessageType_TronMessageSignature\x10\xfd\n\x1a\x04\x98\xb5\x18\x01\x12(\n\x1dMessageType_TronVerifyMessage\x10\xfe\n\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_TronSignTypedHash\x10\xff\n\x1a\x04\x90\xb5\x18\x01\x12-\n\"MessageType_TronTypedDataSignature\x10\x80\x0b\x1a\x04\x98\xb5\x18\x01\x12$\n\x19MessageType_TonGetAddress\x10\xdc\x0b\x1a\x04\x90\xb5\x18\x01\x12!\n\x16MessageType_TonAddress\x10\xdd\x0b\x1a\x04\x98\xb5\x18\x01\x12 \n\x15MessageType_TonSignTx\x10\xde\x0b\x1a\x04\x90\xb5\x18\x01\x12\"\n\x17MessageType_TonSignedTx\x10\xdf\x0b\x1a\x04\x98\xb5\x18\x01\x12%\n\x1aMessageType_TonSignMessage\x10\xe0\x0b\x1a\x04\x90\xb5\x18\x01\x12*\n\x1fMessageType_TonMessageSignature\x10\xe1\x0b\x1a\x04\x98\xb5\x18\x01\x12\'\n\x1cMessageType_HiveGetPublicKey\x10\xc0\x0c\x1a\x04\x90\xb5\x18\x01\x12$\n\x19MessageType_HivePublicKey\x10\xc1\x0c\x1a\x04\x98\xb5\x18\x01\x12!\n\x16MessageType_HiveSignTx\x10\xc2\x0c\x1a\x04\x90\xb5\x18\x01\x12#\n\x18MessageType_HiveSignedTx\x10\xc3\x0c\x1a\x04\x98\xb5\x18\x01\x12(\n\x1dMessageType_HiveGetPublicKeys\x10\xc4\x0c\x1a\x04\x90\xb5\x18\x01\x12%\n\x1aMessageType_HivePublicKeys\x10\xc5\x0c\x1a\x04\x98\xb5\x18\x01\x12,\n!MessageType_HiveSignAccountCreate\x10\xc6\x0c\x1a\x04\x90\xb5\x18\x01\x12.\n#MessageType_HiveSignedAccountCreate\x10\xc7\x0c\x1a\x04\x98\xb5\x18\x01\x12,\n!MessageType_HiveSignAccountUpdate\x10\xc8\x0c\x1a\x04\x90\xb5\x18\x01\x12.\n#MessageType_HiveSignedAccountUpdate\x10\xc9\x0c\x1a\x04\x98\xb5\x18\x01\x12%\n\x1aMessageType_NearGetAddress\x10\xca\x0c\x1a\x04\x90\xb5\x18\x01\x12\"\n\x17MessageType_NearAddress\x10\xcb\x0c\x1a\x04\x98\xb5\x18\x01\x12!\n\x16MessageType_NearSignTx\x10\xcc\x0c\x1a\x04\x90\xb5\x18\x01\x12#\n\x18MessageType_NearSignedTx\x10\xcd\x0c\x1a\x04\x98\xb5\x18\x01\x12&\n\x1bMessageType_HiveSignMessage\x10\xce\x0c\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_HiveSignedMessage\x10\xcf\x0c\x1a\x04\x98\xb5\x18\x01\x12)\n\x1eMessageType_HiveSignOperations\x10\xd0\x0c\x1a\x04\x90\xb5\x18\x01\x12+\n MessageType_HiveSignedOperations\x10\xd1\x0c\x1a\x04\x98\xb5\x18\x01\x12\x34\n)MessageType_ClearsignAttestorGetPublicKey\x10\xa4\r\x1a\x04\x90\xb5\x18\x01\x12\x31\n&MessageType_ClearsignAttestorPublicKey\x10\xa5\r\x1a\x04\x98\xb5\x18\x01\x12,\n!MessageType_ClearsignAttestorSign\x10\xa6\r\x1a\x04\x90\xb5\x18\x01\x12\x31\n&MessageType_ClearsignAttestorSignature\x10\xa7\r\x1a\x04\x98\xb5\x18\x01\x42,\n\x1a\x63om.keepkey.deviceprotocolB\x0eKeepKeyMessage') + serialized_pb=_b('\n\x0emessages.proto\x1a\x0btypes.proto\"\x0c\n\nInitialize\"\r\n\x0bGetFeatures\"\xb9\r\n\x08\x46\x65\x61tures\x12\x0e\n\x06vendor\x18\x01 \x01(\t\x12\x15\n\rmajor_version\x18\x02 \x01(\r\x12\x15\n\rminor_version\x18\x03 \x01(\r\x12\x15\n\rpatch_version\x18\x04 \x01(\r\x12\x17\n\x0f\x62ootloader_mode\x18\x05 \x01(\x08\x12\x11\n\tdevice_id\x18\x06 \x01(\t\x12\x16\n\x0epin_protection\x18\x07 \x01(\x08\x12\x1d\n\x15passphrase_protection\x18\x08 \x01(\x08\x12\x10\n\x08language\x18\t \x01(\t\x12\r\n\x05label\x18\n \x01(\t\x12\x18\n\x05\x63oins\x18\x0b \x03(\x0b\x32\t.CoinType\x12\x13\n\x0binitialized\x18\x0c \x01(\x08\x12\x10\n\x08revision\x18\r \x01(\x0c\x12\x17\n\x0f\x62ootloader_hash\x18\x0e \x01(\x0c\x12\x10\n\x08imported\x18\x0f \x01(\x08\x12\x12\n\npin_cached\x18\x10 \x01(\x08\x12\x19\n\x11passphrase_cached\x18\x11 \x01(\x08\x12\x1d\n\x08policies\x18\x12 \x03(\x0b\x32\x0b.PolicyType\x12\r\n\x05model\x18\x15 \x01(\t\x12\x18\n\x10\x66irmware_variant\x18\x16 \x01(\t\x12\x15\n\rfirmware_hash\x18\x17 \x01(\x0c\x12\x11\n\tno_backup\x18\x18 \x01(\x08\x12\x1c\n\x14wipe_code_protection\x18\x19 \x01(\x08\x12\x1a\n\x12\x61uto_lock_delay_ms\x18\x1a \x01(\r\x12\x18\n\x10supports_taproot\x18\x1b \x01(\x08\x12\x1b\n\x13supports_dice_modes\x18\x1c \x01(\x08\x12\'\n\x1fsupports_solana_lut_attestation\x18\x1d \x01(\x08\x12.\n\x0c\x63\x61pabilities\x18\x1e \x03(\x0e\x32\x14.Features.CapabilityB\x02\x10\x01\"\xfc\x07\n\nCapability\x12\x1a\n\x16\x43\x41PABILITY_UNSPECIFIED\x10\x00\x12#\n\x1f\x43\x41PABILITY_ENTROPY_AUDIT_BUDGET\x10\x01\x12-\n)CAPABILITY_ERC20_UNLIMITED_APPROVE_REVIEW\x10\x02\x12,\n(CAPABILITY_ERC20_UNLIMITED_PERMIT_REVIEW\x10\x03\x12%\n!CAPABILITY_ERC7730_RUNTIME_REVIEW\x10\x04\x12#\n\x1f\x43\x41PABILITY_EVM_CERTIFIED_INTENT\x10\x05\x12$\n CAPABILITY_EVM_MAX_AMOUNT_REVIEW\x10\x06\x12\x1e\n\x1a\x43\x41PABILITY_EVM_TX_METADATA\x10\x07\x12\'\n#CAPABILITY_EVM_UNKNOWN_TOKEN_REVIEW\x10\x08\x12\"\n\x1e\x43\x41PABILITY_HIVE_RELEASE_REVIEW\x10\t\x12(\n$CAPABILITY_LEGACY_EVM_ROUTER_SIGNING\x10\n\x12\"\n\x1e\x43\x41PABILITY_MAYA_SINGLE_MESSAGE\x10\x0b\x12\"\n\x1e\x43\x41PABILITY_OSMOSIS_WIRE_GUARDS\x10\x0c\x12\x1d\n\x19\x43\x41PABILITY_PERMIT2_REVIEW\x10\r\x12%\n!CAPABILITY_PROMPT_WORKFLOW_UNWIND\x10\x0e\x12&\n\"CAPABILITY_PROTECTED_PING_PRESENCE\x10\x0f\x12!\n\x1d\x43\x41PABILITY_RIPPLE_MEMO_POLICY\x10\x10\x12%\n!CAPABILITY_SESSION_TRUST_LIFETIME\x10\x11\x12&\n\"CAPABILITY_SOLANA_CERTIFIED_REVIEW\x10\x12\x12%\n!CAPABILITY_SOLANA_LUT_ATTESTATION\x10\x13\x12$\n CAPABILITY_SOLANA_RUNTIME_REVIEW\x10\x14\x12\x1e\n\x1a\x43\x41PABILITY_STORAGE_V19_KDF\x10\x15\x12\"\n\x1e\x43\x41PABILITY_TENDERMINT_PROGRESS\x10\x16\x12\"\n\x1e\x43\x41PABILITY_SAFE_RESET_CEREMONY\x10\x17\x12\"\n\x1e\x43\x41PABILITY_THOR_DEPOSIT_REVIEW\x10\x18\x12 \n\x1c\x43\x41PABILITY_TRON_TRC20_REVIEW\x10\x19\x12$\n CAPABILITY_EIP712_CHUNKED_VALUES\x10\x1a\"*\n\x0cGetCoinTable\x12\r\n\x05start\x18\x01 \x01(\r\x12\x0b\n\x03\x65nd\x18\x02 \x01(\r\"L\n\tCoinTable\x12\x18\n\x05table\x18\x01 \x03(\x0b\x32\t.CoinType\x12\x11\n\tnum_coins\x18\x02 \x01(\r\x12\x12\n\nchunk_size\x18\x03 \x01(\r\"\x0e\n\x0c\x43learSession\"y\n\rApplySettings\x12\x10\n\x08language\x18\x01 \x01(\t\x12\r\n\x05label\x18\x02 \x01(\t\x12\x16\n\x0euse_passphrase\x18\x03 \x01(\x08\x12\x1a\n\x12\x61uto_lock_delay_ms\x18\x04 \x01(\r\x12\x13\n\x0bu2f_counter\x18\x05 \x01(\r\"\x1b\n\tChangePin\x12\x0e\n\x06remove\x18\x01 \x01(\x08\"\x87\x01\n\x04Ping\x12\x0f\n\x07message\x18\x01 \x01(\t\x12\x19\n\x11\x62utton_protection\x18\x02 \x01(\x08\x12\x16\n\x0epin_protection\x18\x03 \x01(\x08\x12\x1d\n\x15passphrase_protection\x18\x04 \x01(\x08\x12\x1c\n\x14wipe_code_protection\x18\x05 \x01(\x08\"\x1a\n\x07Success\x12\x0f\n\x07message\x18\x01 \x01(\t\"6\n\x07\x46\x61ilure\x12\x1a\n\x04\x63ode\x18\x01 \x01(\x0e\x32\x0c.FailureType\x12\x0f\n\x07message\x18\x02 \x01(\t\"?\n\rButtonRequest\x12 \n\x04\x63ode\x18\x01 \x01(\x0e\x32\x12.ButtonRequestType\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\t\"\x0b\n\tButtonAck\"7\n\x10PinMatrixRequest\x12#\n\x04type\x18\x01 \x01(\x0e\x32\x15.PinMatrixRequestType\"\x1b\n\x0cPinMatrixAck\x12\x0b\n\x03pin\x18\x01 \x02(\t\"\x08\n\x06\x43\x61ncel\"\x13\n\x11PassphraseRequest\"#\n\rPassphraseAck\x12\x12\n\npassphrase\x18\x01 \x02(\t\"\x1a\n\nGetEntropy\x12\x0c\n\x04size\x18\x01 \x02(\r\"\x1a\n\x07\x45ntropy\x12\x0f\n\x07\x65ntropy\x18\x01 \x02(\x0c\"\xa2\x01\n\x0cGetPublicKey\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x18\n\x10\x65\x63\x64sa_curve_name\x18\x02 \x01(\t\x12\x14\n\x0cshow_display\x18\x03 \x01(\x08\x12\x1a\n\tcoin_name\x18\x04 \x01(\t:\x07\x42itcoin\x12\x33\n\x0bscript_type\x18\x05 \x01(\x0e\x32\x10.InputScriptType:\x0cSPENDADDRESS\"4\n\tPublicKey\x12\x19\n\x04node\x18\x01 \x02(\x0b\x32\x0b.HDNodeType\x12\x0c\n\x04xpub\x18\x02 \x01(\t\"\xb3\x01\n\nGetAddress\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x1a\n\tcoin_name\x18\x02 \x01(\t:\x07\x42itcoin\x12\x14\n\x0cshow_display\x18\x03 \x01(\x08\x12+\n\x08multisig\x18\x04 \x01(\x0b\x32\x19.MultisigRedeemScriptType\x12\x33\n\x0bscript_type\x18\x05 \x01(\x0e\x32\x10.InputScriptType:\x0cSPENDADDRESS\"\x1a\n\x07\x41\x64\x64ress\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x02(\t\"\x0c\n\nWipeDevice\"\xbb\x01\n\nLoadDevice\x12\x10\n\x08mnemonic\x18\x01 \x01(\t\x12\x19\n\x04node\x18\x02 \x01(\x0b\x32\x0b.HDNodeType\x12\x0b\n\x03pin\x18\x03 \x01(\t\x12\x1d\n\x15passphrase_protection\x18\x04 \x01(\x08\x12\x19\n\x08language\x18\x05 \x01(\t:\x07\x65nglish\x12\r\n\x05label\x18\x06 \x01(\t\x12\x15\n\rskip_checksum\x18\x07 \x01(\x08\x12\x13\n\x0bu2f_counter\x18\x08 \x01(\r\"\x8a\x02\n\x0bResetDevice\x12\x16\n\x0e\x64isplay_random\x18\x01 \x01(\x08\x12\x15\n\x08strength\x18\x02 \x01(\r:\x03\x32\x35\x36\x12\x1d\n\x15passphrase_protection\x18\x03 \x01(\x08\x12\x16\n\x0epin_protection\x18\x04 \x01(\x08\x12\x19\n\x08language\x18\x05 \x01(\t:\x07\x65nglish\x12\r\n\x05label\x18\x06 \x01(\t\x12\x11\n\tno_backup\x18\x07 \x01(\x08\x12\x1a\n\x12\x61uto_lock_delay_ms\x18\x08 \x01(\r\x12\x13\n\x0bu2f_counter\x18\t \x01(\r\x12\x14\n\x0c\x64ice_entropy\x18\n \x01(\x08\x12\x11\n\tdice_only\x18\x0b \x01(\x08\"\x10\n\x0e\x45ntropyRequest\"\x1d\n\nEntropyAck\x12\x0f\n\x07\x65ntropy\x18\x01 \x01(\x0c\"\xff\x01\n\x0eRecoveryDevice\x12\x12\n\nword_count\x18\x01 \x01(\r\x12\x1d\n\x15passphrase_protection\x18\x02 \x01(\x08\x12\x16\n\x0epin_protection\x18\x03 \x01(\x08\x12\x19\n\x08language\x18\x04 \x01(\t:\x07\x65nglish\x12\r\n\x05label\x18\x05 \x01(\t\x12\x18\n\x10\x65nforce_wordlist\x18\x06 \x01(\x08\x12\x1c\n\x14use_character_cipher\x18\x07 \x01(\x08\x12\x1a\n\x12\x61uto_lock_delay_ms\x18\x08 \x01(\r\x12\x13\n\x0bu2f_counter\x18\t \x01(\r\x12\x0f\n\x07\x64ry_run\x18\n \x01(\x08\"\r\n\x0bWordRequest\"\x17\n\x07WordAck\x12\x0c\n\x04word\x18\x01 \x02(\t\";\n\x10\x43haracterRequest\x12\x10\n\x08word_pos\x18\x01 \x02(\r\x12\x15\n\rcharacter_pos\x18\x02 \x02(\r\"?\n\x0c\x43haracterAck\x12\x11\n\tcharacter\x18\x01 \x01(\t\x12\x0e\n\x06\x64\x65lete\x18\x02 \x01(\x08\x12\x0c\n\x04\x64one\x18\x03 \x01(\x08\"\x82\x01\n\x0bSignMessage\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x0f\n\x07message\x18\x02 \x02(\x0c\x12\x1a\n\tcoin_name\x18\x03 \x01(\t:\x07\x42itcoin\x12\x33\n\x0bscript_type\x18\x04 \x01(\x0e\x32\x10.InputScriptType:\x0cSPENDADDRESS\"`\n\rVerifyMessage\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\t\x12\x11\n\tsignature\x18\x02 \x01(\x0c\x12\x0f\n\x07message\x18\x03 \x01(\x0c\x12\x1a\n\tcoin_name\x18\x04 \x01(\t:\x07\x42itcoin\"6\n\x10MessageSignature\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\t\x12\x11\n\tsignature\x18\x02 \x01(\x0c\"v\n\x0e\x45ncryptMessage\x12\x0e\n\x06pubkey\x18\x01 \x01(\x0c\x12\x0f\n\x07message\x18\x02 \x01(\x0c\x12\x14\n\x0c\x64isplay_only\x18\x03 \x01(\x08\x12\x11\n\taddress_n\x18\x04 \x03(\r\x12\x1a\n\tcoin_name\x18\x05 \x01(\t:\x07\x42itcoin\"@\n\x10\x45ncryptedMessage\x12\r\n\x05nonce\x18\x01 \x01(\x0c\x12\x0f\n\x07message\x18\x02 \x01(\x0c\x12\x0c\n\x04hmac\x18\x03 \x01(\x0c\"Q\n\x0e\x44\x65\x63ryptMessage\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\r\n\x05nonce\x18\x02 \x01(\x0c\x12\x0f\n\x07message\x18\x03 \x01(\x0c\x12\x0c\n\x04hmac\x18\x04 \x01(\x0c\"4\n\x10\x44\x65\x63ryptedMessage\x12\x0f\n\x07message\x18\x01 \x01(\x0c\x12\x0f\n\x07\x61\x64\x64ress\x18\x02 \x01(\t\"\x8c\x01\n\x0e\x43ipherKeyValue\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x0b\n\x03key\x18\x02 \x01(\t\x12\r\n\x05value\x18\x03 \x01(\x0c\x12\x0f\n\x07\x65ncrypt\x18\x04 \x01(\x08\x12\x16\n\x0e\x61sk_on_encrypt\x18\x05 \x01(\x08\x12\x16\n\x0e\x61sk_on_decrypt\x18\x06 \x01(\x08\x12\n\n\x02iv\x18\x07 \x01(\x0c\"!\n\x10\x43ipheredKeyValue\x12\r\n\x05value\x18\x01 \x01(\x0c\"5\n\x10GetBip85Mnemonic\x12\x12\n\nword_count\x18\x01 \x02(\r\x12\r\n\x05index\x18\x02 \x02(\r\"!\n\rBip85Mnemonic\x12\x10\n\x08mnemonic\x18\x01 \x02(\t\"\xce\x01\n\x06SignTx\x12\x15\n\routputs_count\x18\x01 \x02(\r\x12\x14\n\x0cinputs_count\x18\x02 \x02(\r\x12\x1a\n\tcoin_name\x18\x03 \x01(\t:\x07\x42itcoin\x12\x12\n\x07version\x18\x04 \x01(\r:\x01\x31\x12\x14\n\tlock_time\x18\x05 \x01(\r:\x01\x30\x12\x0e\n\x06\x65xpiry\x18\x06 \x01(\r\x12\x14\n\x0coverwintered\x18\x07 \x01(\x08\x12\x18\n\x10version_group_id\x18\x08 \x01(\r\x12\x11\n\tbranch_id\x18\n \x01(\r\"\x85\x01\n\tTxRequest\x12\"\n\x0crequest_type\x18\x01 \x01(\x0e\x32\x0c.RequestType\x12&\n\x07\x64\x65tails\x18\x02 \x01(\x0b\x32\x15.TxRequestDetailsType\x12,\n\nserialized\x18\x03 \x01(\x0b\x32\x18.TxRequestSerializedType\"%\n\x05TxAck\x12\x1c\n\x02tx\x18\x01 \x01(\x0b\x32\x10.TransactionType\"+\n\x08RawTxAck\x12\x1f\n\x02tx\x18\x01 \x01(\x0b\x32\x13.RawTransactionType\"}\n\x0cSignIdentity\x12\x1f\n\x08identity\x18\x01 \x01(\x0b\x32\r.IdentityType\x12\x18\n\x10\x63hallenge_hidden\x18\x02 \x01(\x0c\x12\x18\n\x10\x63hallenge_visual\x18\x03 \x01(\t\x12\x18\n\x10\x65\x63\x64sa_curve_name\x18\x04 \x01(\t\"H\n\x0eSignedIdentity\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\t\x12\x12\n\npublic_key\x18\x02 \x01(\x0c\x12\x11\n\tsignature\x18\x03 \x01(\x0c\",\n\rApplyPolicies\x12\x1b\n\x06policy\x18\x01 \x03(\x0b\x32\x0b.PolicyType\"?\n\tFlashHash\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\r\x12\x0e\n\x06length\x18\x02 \x01(\r\x12\x11\n\tchallenge\x18\x03 \x01(\x0c\":\n\nFlashWrite\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\r\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\r\n\x05\x65rase\x18\x03 \x01(\x08\"!\n\x11\x46lashHashResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"5\n\x12\x44\x65\x62ugLinkFlashDump\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\r\x12\x0e\n\x06length\x18\x02 \x01(\r\"*\n\x1a\x44\x65\x62ugLinkFlashDumpResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"\x0b\n\tSoftReset\"\x0f\n\rFirmwareErase\"7\n\x0e\x46irmwareUpload\x12\x14\n\x0cpayload_hash\x18\x01 \x02(\x0c\x12\x0f\n\x07payload\x18\x02 \x02(\x0c\"2\n\x11\x44\x65\x62ugLinkDecision\x12\x0e\n\x06yes_no\x18\x01 \x02(\x08\x12\r\n\x05input\x18\x02 \x01(\t\"\x13\n\x11\x44\x65\x62ugLinkGetState\"\x99\x03\n\x0e\x44\x65\x62ugLinkState\x12\x0e\n\x06layout\x18\x01 \x01(\x0c\x12\x0b\n\x03pin\x18\x02 \x01(\t\x12\x0e\n\x06matrix\x18\x03 \x01(\t\x12\x10\n\x08mnemonic\x18\x04 \x01(\t\x12\x19\n\x04node\x18\x05 \x01(\x0b\x32\x0b.HDNodeType\x12\x1d\n\x15passphrase_protection\x18\x06 \x01(\x08\x12\x12\n\nreset_word\x18\x07 \x01(\t\x12\x15\n\rreset_entropy\x18\x08 \x01(\x0c\x12\x1a\n\x12recovery_fake_word\x18\t \x01(\t\x12\x19\n\x11recovery_word_pos\x18\n \x01(\r\x12\x17\n\x0frecovery_cipher\x18\x0b \x01(\t\x12$\n\x1crecovery_auto_completed_word\x18\x0c \x01(\t\x12\x15\n\rfirmware_hash\x18\r \x01(\x0c\x12\x14\n\x0cstorage_hash\x18\x0e \x01(\x0c\x12\x13\n\x0b\x64ice_digest\x18\x0f \x01(\x0c\x12\x15\n\rconfirm_title\x18\x10 \x01(\t\x12\x14\n\x0c\x63onfirm_body\x18\x11 \x01(\t\"\x0f\n\rDebugLinkStop\";\n\x0c\x44\x65\x62ugLinkLog\x12\r\n\x05level\x18\x01 \x01(\r\x12\x0e\n\x06\x62ucket\x18\x02 \x01(\t\x12\x0c\n\x04text\x18\x03 \x01(\t\"\x15\n\x13\x44\x65\x62ugLinkFillConfig\" \n\x0e\x43hangeWipeCode\x12\x0e\n\x06remove\x18\x01 \x01(\x08\"\x1f\n\x1d\x43learsignAttestorGetPublicKey\"0\n\x1a\x43learsignAttestorPublicKey\x12\x12\n\npublic_key\x18\x01 \x01(\x0c\"(\n\x15\x43learsignAttestorSign\x12\x0f\n\x07payload\x18\x01 \x01(\x0c\"C\n\x1a\x43learsignAttestorSignature\x12\x11\n\tsignature\x18\x01 \x01(\x0c\x12\x12\n\npublic_key\x18\x02 \x01(\x0c*\xc3\x46\n\x0bMessageType\x12 \n\x16MessageType_Initialize\x10\x00\x1a\x04\x90\xb5\x18\x01\x12\x1a\n\x10MessageType_Ping\x10\x01\x1a\x04\x90\xb5\x18\x01\x12\x1d\n\x13MessageType_Success\x10\x02\x1a\x04\x98\xb5\x18\x01\x12\x1d\n\x13MessageType_Failure\x10\x03\x1a\x04\x98\xb5\x18\x01\x12\x1f\n\x15MessageType_ChangePin\x10\x04\x1a\x04\x90\xb5\x18\x01\x12 \n\x16MessageType_WipeDevice\x10\x05\x1a\x04\x90\xb5\x18\x01\x12#\n\x19MessageType_FirmwareErase\x10\x06\x1a\x04\x90\xb5\x18\x01\x12$\n\x1aMessageType_FirmwareUpload\x10\x07\x1a\x04\x90\xb5\x18\x01\x12 \n\x16MessageType_GetEntropy\x10\t\x1a\x04\x90\xb5\x18\x01\x12\x1d\n\x13MessageType_Entropy\x10\n\x1a\x04\x98\xb5\x18\x01\x12\"\n\x18MessageType_GetPublicKey\x10\x0b\x1a\x04\x90\xb5\x18\x01\x12\x1f\n\x15MessageType_PublicKey\x10\x0c\x1a\x04\x98\xb5\x18\x01\x12 \n\x16MessageType_LoadDevice\x10\r\x1a\x04\x90\xb5\x18\x01\x12!\n\x17MessageType_ResetDevice\x10\x0e\x1a\x04\x90\xb5\x18\x01\x12\x1c\n\x12MessageType_SignTx\x10\x0f\x1a\x04\x90\xb5\x18\x01\x12\x1e\n\x14MessageType_Features\x10\x11\x1a\x04\x98\xb5\x18\x01\x12&\n\x1cMessageType_PinMatrixRequest\x10\x12\x1a\x04\x98\xb5\x18\x01\x12\"\n\x18MessageType_PinMatrixAck\x10\x13\x1a\x04\x90\xb5\x18\x01\x12\x1c\n\x12MessageType_Cancel\x10\x14\x1a\x04\x90\xb5\x18\x01\x12\x1f\n\x15MessageType_TxRequest\x10\x15\x1a\x04\x98\xb5\x18\x01\x12\x1b\n\x11MessageType_TxAck\x10\x16\x1a\x04\x90\xb5\x18\x01\x12$\n\x1aMessageType_CipherKeyValue\x10\x17\x1a\x04\x90\xb5\x18\x01\x12\"\n\x18MessageType_ClearSession\x10\x18\x1a\x04\x90\xb5\x18\x01\x12#\n\x19MessageType_ApplySettings\x10\x19\x1a\x04\x90\xb5\x18\x01\x12#\n\x19MessageType_ButtonRequest\x10\x1a\x1a\x04\x98\xb5\x18\x01\x12\x1f\n\x15MessageType_ButtonAck\x10\x1b\x1a\x04\x90\xb5\x18\x01\x12 \n\x16MessageType_GetAddress\x10\x1d\x1a\x04\x90\xb5\x18\x01\x12\x1d\n\x13MessageType_Address\x10\x1e\x1a\x04\x98\xb5\x18\x01\x12$\n\x1aMessageType_EntropyRequest\x10#\x1a\x04\x98\xb5\x18\x01\x12 \n\x16MessageType_EntropyAck\x10$\x1a\x04\x90\xb5\x18\x01\x12!\n\x17MessageType_SignMessage\x10&\x1a\x04\x90\xb5\x18\x01\x12#\n\x19MessageType_VerifyMessage\x10\'\x1a\x04\x90\xb5\x18\x01\x12&\n\x1cMessageType_MessageSignature\x10(\x1a\x04\x98\xb5\x18\x01\x12\'\n\x1dMessageType_PassphraseRequest\x10)\x1a\x04\x98\xb5\x18\x01\x12#\n\x19MessageType_PassphraseAck\x10*\x1a\x04\x90\xb5\x18\x01\x12$\n\x1aMessageType_RecoveryDevice\x10-\x1a\x04\x90\xb5\x18\x01\x12!\n\x17MessageType_WordRequest\x10.\x1a\x04\x98\xb5\x18\x01\x12\x1d\n\x13MessageType_WordAck\x10/\x1a\x04\x90\xb5\x18\x01\x12&\n\x1cMessageType_CipheredKeyValue\x10\x30\x1a\x04\x98\xb5\x18\x01\x12$\n\x1aMessageType_EncryptMessage\x10\x31\x1a\x04\x90\xb5\x18\x01\x12&\n\x1cMessageType_EncryptedMessage\x10\x32\x1a\x04\x98\xb5\x18\x01\x12$\n\x1aMessageType_DecryptMessage\x10\x33\x1a\x04\x90\xb5\x18\x01\x12&\n\x1cMessageType_DecryptedMessage\x10\x34\x1a\x04\x98\xb5\x18\x01\x12\"\n\x18MessageType_SignIdentity\x10\x35\x1a\x04\x90\xb5\x18\x01\x12$\n\x1aMessageType_SignedIdentity\x10\x36\x1a\x04\x98\xb5\x18\x01\x12!\n\x17MessageType_GetFeatures\x10\x37\x1a\x04\x90\xb5\x18\x01\x12(\n\x1eMessageType_EthereumGetAddress\x10\x38\x1a\x04\x90\xb5\x18\x01\x12%\n\x1bMessageType_EthereumAddress\x10\x39\x1a\x04\x98\xb5\x18\x01\x12$\n\x1aMessageType_EthereumSignTx\x10:\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1dMessageType_EthereumTxRequest\x10;\x1a\x04\x98\xb5\x18\x01\x12#\n\x19MessageType_EthereumTxAck\x10<\x1a\x04\x90\xb5\x18\x01\x12&\n\x1cMessageType_CharacterRequest\x10P\x1a\x04\x98\xb5\x18\x01\x12\"\n\x18MessageType_CharacterAck\x10Q\x1a\x04\x90\xb5\x18\x01\x12\x1e\n\x14MessageType_RawTxAck\x10R\x1a\x04\x90\xb5\x18\x01\x12#\n\x19MessageType_ApplyPolicies\x10S\x1a\x04\x90\xb5\x18\x01\x12\x1f\n\x15MessageType_FlashHash\x10T\x1a\x04\x90\xb5\x18\x01\x12 \n\x16MessageType_FlashWrite\x10U\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1dMessageType_FlashHashResponse\x10V\x1a\x04\x98\xb5\x18\x01\x12(\n\x1eMessageType_DebugLinkFlashDump\x10W\x1a\x04\xa0\xb5\x18\x01\x12\x30\n&MessageType_DebugLinkFlashDumpResponse\x10X\x1a\x04\xa8\xb5\x18\x01\x12\x1f\n\x15MessageType_SoftReset\x10Y\x1a\x04\xa0\xb5\x18\x01\x12\'\n\x1dMessageType_DebugLinkDecision\x10\x64\x1a\x04\xa0\xb5\x18\x01\x12\'\n\x1dMessageType_DebugLinkGetState\x10\x65\x1a\x04\xa0\xb5\x18\x01\x12$\n\x1aMessageType_DebugLinkState\x10\x66\x1a\x04\xa8\xb5\x18\x01\x12#\n\x19MessageType_DebugLinkStop\x10g\x1a\x04\xa0\xb5\x18\x01\x12\"\n\x18MessageType_DebugLinkLog\x10h\x1a\x04\xa8\xb5\x18\x01\x12)\n\x1fMessageType_DebugLinkFillConfig\x10i\x1a\x04\xa8\xb5\x18\x01\x12\"\n\x18MessageType_GetCoinTable\x10j\x1a\x04\x90\xb5\x18\x01\x12\x1f\n\x15MessageType_CoinTable\x10k\x1a\x04\x98\xb5\x18\x01\x12)\n\x1fMessageType_EthereumSignMessage\x10l\x1a\x04\x90\xb5\x18\x01\x12+\n!MessageType_EthereumVerifyMessage\x10m\x1a\x04\x90\xb5\x18\x01\x12.\n$MessageType_EthereumMessageSignature\x10n\x1a\x04\x98\xb5\x18\x01\x12$\n\x1aMessageType_ChangeWipeCode\x10o\x1a\x04\x90\xb5\x18\x01\x12+\n!MessageType_EthereumSignTypedHash\x10p\x1a\x04\x90\xb5\x18\x01\x12\x30\n&MessageType_EthereumTypedDataSignature\x10q\x1a\x04\x98\xb5\x18\x01\x12,\n\"MessageType_Ethereum712TypesValues\x10r\x1a\x04\x90\xb5\x18\x01\x12(\n\x1eMessageType_EthereumTxMetadata\x10s\x1a\x04\x90\xb5\x18\x01\x12)\n\x1fMessageType_EthereumMetadataAck\x10t\x1a\x04\x98\xb5\x18\x01\x12)\n\x1fMessageType_LoadClearsignSigner\x10u\x1a\x04\x90\xb5\x18\x01\x12,\n!MessageType_EthereumSignTypedData\x10\xa8\r\x1a\x04\x90\xb5\x18\x01\x12\x35\n*MessageType_EthereumTypedDataStructRequest\x10\xa9\r\x1a\x04\x98\xb5\x18\x01\x12\x31\n&MessageType_EthereumTypedDataStructAck\x10\xaa\r\x1a\x04\x90\xb5\x18\x01\x12\x34\n)MessageType_EthereumTypedDataValueRequest\x10\xab\r\x1a\x04\x98\xb5\x18\x01\x12\x30\n%MessageType_EthereumTypedDataValueAck\x10\xac\r\x1a\x04\x90\xb5\x18\x01\x12\x32\n\'MessageType_EthereumClearSignDefinition\x10\xad\r\x1a\x04\x90\xb5\x18\x01\x12\x35\n*MessageType_EthereumClearSignDefinitionAck\x10\xae\r\x1a\x04\x98\xb5\x18\x01\x12\x39\n.MessageType_EthereumClearSignDefinitionRequest\x10\xaf\r\x1a\x04\x98\xb5\x18\x01\x12\x37\n,MessageType_EthereumClearSignDefinitionChunk\x10\xb0\r\x1a\x04\x90\xb5\x18\x01\x12&\n\x1cMessageType_GetBip85Mnemonic\x10x\x1a\x04\x90\xb5\x18\x01\x12#\n\x19MessageType_Bip85Mnemonic\x10y\x1a\x04\x98\xb5\x18\x01\x12\'\n\x1cMessageType_RippleGetAddress\x10\x90\x03\x1a\x04\x90\xb5\x18\x01\x12$\n\x19MessageType_RippleAddress\x10\x91\x03\x1a\x04\x98\xb5\x18\x01\x12#\n\x18MessageType_RippleSignTx\x10\x92\x03\x1a\x04\x90\xb5\x18\x01\x12%\n\x1aMessageType_RippleSignedTx\x10\x93\x03\x1a\x04\x90\xb5\x18\x01\x12*\n\x1fMessageType_ThorchainGetAddress\x10\xf4\x03\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1cMessageType_ThorchainAddress\x10\xf5\x03\x1a\x04\x98\xb5\x18\x01\x12&\n\x1bMessageType_ThorchainSignTx\x10\xf6\x03\x1a\x04\x90\xb5\x18\x01\x12*\n\x1fMessageType_ThorchainMsgRequest\x10\xf7\x03\x1a\x04\x98\xb5\x18\x01\x12&\n\x1bMessageType_ThorchainMsgAck\x10\xf8\x03\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_ThorchainSignedTx\x10\xf9\x03\x1a\x04\x98\xb5\x18\x01\x12&\n\x1bMessageType_EosGetPublicKey\x10\xd8\x04\x1a\x04\x90\xb5\x18\x01\x12#\n\x18MessageType_EosPublicKey\x10\xd9\x04\x1a\x04\x98\xb5\x18\x01\x12 \n\x15MessageType_EosSignTx\x10\xda\x04\x1a\x04\x90\xb5\x18\x01\x12)\n\x1eMessageType_EosTxActionRequest\x10\xdb\x04\x1a\x04\x98\xb5\x18\x01\x12%\n\x1aMessageType_EosTxActionAck\x10\xdc\x04\x1a\x04\x90\xb5\x18\x01\x12\"\n\x17MessageType_EosSignedTx\x10\xdd\x04\x1a\x04\x98\xb5\x18\x01\x12%\n\x1aMessageType_NanoGetAddress\x10\xbc\x05\x1a\x04\x90\xb5\x18\x01\x12\"\n\x17MessageType_NanoAddress\x10\xbd\x05\x1a\x04\x98\xb5\x18\x01\x12!\n\x16MessageType_NanoSignTx\x10\xbe\x05\x1a\x04\x90\xb5\x18\x01\x12#\n\x18MessageType_NanoSignedTx\x10\xbf\x05\x1a\x04\x98\xb5\x18\x01\x12\'\n\x1cMessageType_SolanaGetAddress\x10\xee\x05\x1a\x04\x90\xb5\x18\x01\x12$\n\x19MessageType_SolanaAddress\x10\xef\x05\x1a\x04\x98\xb5\x18\x01\x12#\n\x18MessageType_SolanaSignTx\x10\xf0\x05\x1a\x04\x90\xb5\x18\x01\x12%\n\x1aMessageType_SolanaSignedTx\x10\xf1\x05\x1a\x04\x98\xb5\x18\x01\x12(\n\x1dMessageType_SolanaSignMessage\x10\xf2\x05\x1a\x04\x90\xb5\x18\x01\x12-\n\"MessageType_SolanaMessageSignature\x10\xf3\x05\x1a\x04\x98\xb5\x18\x01\x12\x30\n%MessageType_SolanaSignOffchainMessage\x10\xf4\x05\x1a\x04\x90\xb5\x18\x01\x12\x35\n*MessageType_SolanaOffchainMessageSignature\x10\xf5\x05\x1a\x04\x98\xb5\x18\x01\x12(\n\x1dMessageType_BinanceGetAddress\x10\xa0\x06\x1a\x04\x90\xb5\x18\x01\x12%\n\x1aMessageType_BinanceAddress\x10\xa1\x06\x1a\x04\x98\xb5\x18\x01\x12*\n\x1fMessageType_BinanceGetPublicKey\x10\xa2\x06\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1cMessageType_BinancePublicKey\x10\xa3\x06\x1a\x04\x98\xb5\x18\x01\x12$\n\x19MessageType_BinanceSignTx\x10\xa4\x06\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1cMessageType_BinanceTxRequest\x10\xa5\x06\x1a\x04\x98\xb5\x18\x01\x12)\n\x1eMessageType_BinanceTransferMsg\x10\xa6\x06\x1a\x04\x90\xb5\x18\x01\x12&\n\x1bMessageType_BinanceOrderMsg\x10\xa7\x06\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1cMessageType_BinanceCancelMsg\x10\xa8\x06\x1a\x04\x90\xb5\x18\x01\x12&\n\x1bMessageType_BinanceSignedTx\x10\xa9\x06\x1a\x04\x98\xb5\x18\x01\x12\'\n\x1cMessageType_CosmosGetAddress\x10\x84\x07\x1a\x04\x90\xb5\x18\x01\x12$\n\x19MessageType_CosmosAddress\x10\x85\x07\x1a\x04\x98\xb5\x18\x01\x12#\n\x18MessageType_CosmosSignTx\x10\x86\x07\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1cMessageType_CosmosMsgRequest\x10\x87\x07\x1a\x04\x98\xb5\x18\x01\x12#\n\x18MessageType_CosmosMsgAck\x10\x88\x07\x1a\x04\x90\xb5\x18\x01\x12%\n\x1aMessageType_CosmosSignedTx\x10\x89\x07\x1a\x04\x98\xb5\x18\x01\x12(\n\x1dMessageType_CosmosMsgDelegate\x10\x8a\x07\x1a\x04\x98\xb5\x18\x01\x12*\n\x1fMessageType_CosmosMsgUndelegate\x10\x8b\x07\x1a\x04\x98\xb5\x18\x01\x12*\n\x1fMessageType_CosmosMsgRedelegate\x10\x8c\x07\x1a\x04\x98\xb5\x18\x01\x12\'\n\x1cMessageType_CosmosMsgRewards\x10\x8d\x07\x1a\x04\x98\xb5\x18\x01\x12+\n MessageType_CosmosMsgIBCTransfer\x10\x8e\x07\x1a\x04\x98\xb5\x18\x01\x12+\n MessageType_TendermintGetAddress\x10\xe8\x07\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_TendermintAddress\x10\xe9\x07\x1a\x04\x98\xb5\x18\x01\x12\'\n\x1cMessageType_TendermintSignTx\x10\xea\x07\x1a\x04\x90\xb5\x18\x01\x12+\n MessageType_TendermintMsgRequest\x10\xeb\x07\x1a\x04\x98\xb5\x18\x01\x12\'\n\x1cMessageType_TendermintMsgAck\x10\xec\x07\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_TendermintMsgSend\x10\xed\x07\x1a\x04\x90\xb5\x18\x01\x12)\n\x1eMessageType_TendermintSignedTx\x10\xee\x07\x1a\x04\x98\xb5\x18\x01\x12,\n!MessageType_TendermintMsgDelegate\x10\xef\x07\x1a\x04\x98\xb5\x18\x01\x12.\n#MessageType_TendermintMsgUndelegate\x10\xf0\x07\x1a\x04\x98\xb5\x18\x01\x12.\n#MessageType_TendermintMsgRedelegate\x10\xf1\x07\x1a\x04\x98\xb5\x18\x01\x12+\n MessageType_TendermintMsgRewards\x10\xf2\x07\x1a\x04\x98\xb5\x18\x01\x12/\n$MessageType_TendermintMsgIBCTransfer\x10\xf3\x07\x1a\x04\x98\xb5\x18\x01\x12(\n\x1dMessageType_OsmosisGetAddress\x10\xcc\x08\x1a\x04\x90\xb5\x18\x01\x12%\n\x1aMessageType_OsmosisAddress\x10\xcd\x08\x1a\x04\x98\xb5\x18\x01\x12$\n\x19MessageType_OsmosisSignTx\x10\xce\x08\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_OsmosisMsgRequest\x10\xcf\x08\x1a\x04\x98\xb5\x18\x01\x12$\n\x19MessageType_OsmosisMsgAck\x10\xd0\x08\x1a\x04\x90\xb5\x18\x01\x12%\n\x1aMessageType_OsmosisMsgSend\x10\xd1\x08\x1a\x04\x90\xb5\x18\x01\x12)\n\x1eMessageType_OsmosisMsgDelegate\x10\xd2\x08\x1a\x04\x90\xb5\x18\x01\x12+\n MessageType_OsmosisMsgUndelegate\x10\xd3\x08\x1a\x04\x90\xb5\x18\x01\x12+\n MessageType_OsmosisMsgRedelegate\x10\xd4\x08\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_OsmosisMsgRewards\x10\xd5\x08\x1a\x04\x90\xb5\x18\x01\x12&\n\x1bMessageType_OsmosisMsgLPAdd\x10\xd6\x08\x1a\x04\x90\xb5\x18\x01\x12)\n\x1eMessageType_OsmosisMsgLPRemove\x10\xd7\x08\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_OsmosisMsgLPStake\x10\xd8\x08\x1a\x04\x90\xb5\x18\x01\x12*\n\x1fMessageType_OsmosisMsgLPUnstake\x10\xd9\x08\x1a\x04\x90\xb5\x18\x01\x12,\n!MessageType_OsmosisMsgIBCTransfer\x10\xda\x08\x1a\x04\x90\xb5\x18\x01\x12%\n\x1aMessageType_OsmosisMsgSwap\x10\xdb\x08\x1a\x04\x90\xb5\x18\x01\x12&\n\x1bMessageType_OsmosisSignedTx\x10\xdc\x08\x1a\x04\x98\xb5\x18\x01\x12*\n\x1fMessageType_MayachainGetAddress\x10\xb0\t\x1a\x04\x90\xb5\x18\x01\x12\'\n\x1cMessageType_MayachainAddress\x10\xb1\t\x1a\x04\x98\xb5\x18\x01\x12&\n\x1bMessageType_MayachainSignTx\x10\xb2\t\x1a\x04\x90\xb5\x18\x01\x12*\n\x1fMessageType_MayachainMsgRequest\x10\xb3\t\x1a\x04\x98\xb5\x18\x01\x12&\n\x1bMessageType_MayachainMsgAck\x10\xb4\t\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_MayachainSignedTx\x10\xb5\t\x1a\x04\x98\xb5\x18\x01\x12$\n\x19MessageType_ZcashSignPCZT\x10\x94\n\x1a\x04\x90\xb5\x18\x01\x12&\n\x1bMessageType_ZcashPCZTAction\x10\x95\n\x1a\x04\x90\xb5\x18\x01\x12)\n\x1eMessageType_ZcashPCZTActionAck\x10\x96\n\x1a\x04\x98\xb5\x18\x01\x12&\n\x1bMessageType_ZcashSignedPCZT\x10\x97\n\x1a\x04\x98\xb5\x18\x01\x12)\n\x1eMessageType_ZcashGetOrchardFVK\x10\x98\n\x1a\x04\x90\xb5\x18\x01\x12&\n\x1bMessageType_ZcashOrchardFVK\x10\x99\n\x1a\x04\x98\xb5\x18\x01\x12,\n!MessageType_ZcashTransparentInput\x10\x9a\n\x1a\x04\x90\xb5\x18\x01\x12-\n\"MessageType_ZcashTransparentSigned\x10\x9b\n\x1a\x04\x98\xb5\x18\x01\x12*\n\x1fMessageType_ZcashDisplayAddress\x10\x9c\n\x1a\x04\x90\xb5\x18\x01\x12#\n\x18MessageType_ZcashAddress\x10\x9d\n\x1a\x04\x98\xb5\x18\x01\x12-\n\"MessageType_ZcashTransparentOutput\x10\x9e\n\x1a\x04\x90\xb5\x18\x01\x12*\n\x1fMessageType_ZcashTransparentAck\x10\x9f\n\x1a\x04\x98\xb5\x18\x01\x12%\n\x1aMessageType_TronGetAddress\x10\xf8\n\x1a\x04\x90\xb5\x18\x01\x12\"\n\x17MessageType_TronAddress\x10\xf9\n\x1a\x04\x98\xb5\x18\x01\x12!\n\x16MessageType_TronSignTx\x10\xfa\n\x1a\x04\x90\xb5\x18\x01\x12#\n\x18MessageType_TronSignedTx\x10\xfb\n\x1a\x04\x98\xb5\x18\x01\x12&\n\x1bMessageType_TronSignMessage\x10\xfc\n\x1a\x04\x90\xb5\x18\x01\x12+\n MessageType_TronMessageSignature\x10\xfd\n\x1a\x04\x98\xb5\x18\x01\x12(\n\x1dMessageType_TronVerifyMessage\x10\xfe\n\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_TronSignTypedHash\x10\xff\n\x1a\x04\x90\xb5\x18\x01\x12-\n\"MessageType_TronTypedDataSignature\x10\x80\x0b\x1a\x04\x98\xb5\x18\x01\x12$\n\x19MessageType_TonGetAddress\x10\xdc\x0b\x1a\x04\x90\xb5\x18\x01\x12!\n\x16MessageType_TonAddress\x10\xdd\x0b\x1a\x04\x98\xb5\x18\x01\x12 \n\x15MessageType_TonSignTx\x10\xde\x0b\x1a\x04\x90\xb5\x18\x01\x12\"\n\x17MessageType_TonSignedTx\x10\xdf\x0b\x1a\x04\x98\xb5\x18\x01\x12%\n\x1aMessageType_TonSignMessage\x10\xe0\x0b\x1a\x04\x90\xb5\x18\x01\x12*\n\x1fMessageType_TonMessageSignature\x10\xe1\x0b\x1a\x04\x98\xb5\x18\x01\x12\'\n\x1cMessageType_HiveGetPublicKey\x10\xc0\x0c\x1a\x04\x90\xb5\x18\x01\x12$\n\x19MessageType_HivePublicKey\x10\xc1\x0c\x1a\x04\x98\xb5\x18\x01\x12!\n\x16MessageType_HiveSignTx\x10\xc2\x0c\x1a\x04\x90\xb5\x18\x01\x12#\n\x18MessageType_HiveSignedTx\x10\xc3\x0c\x1a\x04\x98\xb5\x18\x01\x12(\n\x1dMessageType_HiveGetPublicKeys\x10\xc4\x0c\x1a\x04\x90\xb5\x18\x01\x12%\n\x1aMessageType_HivePublicKeys\x10\xc5\x0c\x1a\x04\x98\xb5\x18\x01\x12,\n!MessageType_HiveSignAccountCreate\x10\xc6\x0c\x1a\x04\x90\xb5\x18\x01\x12.\n#MessageType_HiveSignedAccountCreate\x10\xc7\x0c\x1a\x04\x98\xb5\x18\x01\x12,\n!MessageType_HiveSignAccountUpdate\x10\xc8\x0c\x1a\x04\x90\xb5\x18\x01\x12.\n#MessageType_HiveSignedAccountUpdate\x10\xc9\x0c\x1a\x04\x98\xb5\x18\x01\x12%\n\x1aMessageType_NearGetAddress\x10\xca\x0c\x1a\x04\x90\xb5\x18\x01\x12\"\n\x17MessageType_NearAddress\x10\xcb\x0c\x1a\x04\x98\xb5\x18\x01\x12!\n\x16MessageType_NearSignTx\x10\xcc\x0c\x1a\x04\x90\xb5\x18\x01\x12#\n\x18MessageType_NearSignedTx\x10\xcd\x0c\x1a\x04\x98\xb5\x18\x01\x12&\n\x1bMessageType_HiveSignMessage\x10\xce\x0c\x1a\x04\x90\xb5\x18\x01\x12(\n\x1dMessageType_HiveSignedMessage\x10\xcf\x0c\x1a\x04\x98\xb5\x18\x01\x12)\n\x1eMessageType_HiveSignOperations\x10\xd0\x0c\x1a\x04\x90\xb5\x18\x01\x12+\n MessageType_HiveSignedOperations\x10\xd1\x0c\x1a\x04\x98\xb5\x18\x01\x12\x34\n)MessageType_ClearsignAttestorGetPublicKey\x10\xa4\r\x1a\x04\x90\xb5\x18\x01\x12\x31\n&MessageType_ClearsignAttestorPublicKey\x10\xa5\r\x1a\x04\x98\xb5\x18\x01\x12,\n!MessageType_ClearsignAttestorSign\x10\xa6\r\x1a\x04\x90\xb5\x18\x01\x12\x31\n&MessageType_ClearsignAttestorSignature\x10\xa7\r\x1a\x04\x98\xb5\x18\x01\x42,\n\x1a\x63om.keepkey.deviceprotocolB\x0eKeepKeyMessage') , dependencies=[types__pb2.DESCRIPTOR,]) @@ -926,8 +926,8 @@ ], containing_type=None, options=None, - serialized_start=6602, - serialized_end=15629, + serialized_start=6674, + serialized_end=15701, ) _sym_db.RegisterEnumDescriptor(_MESSAGETYPE) @@ -1263,11 +1263,19 @@ name='CAPABILITY_THOR_DEPOSIT_REVIEW', index=24, number=24, options=None, type=None), + _descriptor.EnumValueDescriptor( + name='CAPABILITY_TRON_TRC20_REVIEW', index=25, number=25, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='CAPABILITY_EIP712_CHUNKED_VALUES', index=26, number=26, + options=None, + type=None), ], containing_type=None, options=None, serialized_start=762, - serialized_end=1710, + serialized_end=1782, ) _sym_db.RegisterEnumDescriptor(_FEATURES_CAPABILITY) @@ -1537,7 +1545,7 @@ oneofs=[ ], serialized_start=61, - serialized_end=1710, + serialized_end=1782, ) @@ -1574,8 +1582,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1712, - serialized_end=1754, + serialized_start=1784, + serialized_end=1826, ) @@ -1619,8 +1627,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1756, - serialized_end=1832, + serialized_start=1828, + serialized_end=1904, ) @@ -1643,8 +1651,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1834, - serialized_end=1848, + serialized_start=1906, + serialized_end=1920, ) @@ -1702,8 +1710,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1850, - serialized_end=1971, + serialized_start=1922, + serialized_end=2043, ) @@ -1733,8 +1741,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1973, - serialized_end=2000, + serialized_start=2045, + serialized_end=2072, ) @@ -1792,8 +1800,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2003, - serialized_end=2138, + serialized_start=2075, + serialized_end=2210, ) @@ -1823,8 +1831,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2140, - serialized_end=2166, + serialized_start=2212, + serialized_end=2238, ) @@ -1861,8 +1869,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2168, - serialized_end=2222, + serialized_start=2240, + serialized_end=2294, ) @@ -1899,8 +1907,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2224, - serialized_end=2287, + serialized_start=2296, + serialized_end=2359, ) @@ -1923,8 +1931,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2289, - serialized_end=2300, + serialized_start=2361, + serialized_end=2372, ) @@ -1954,8 +1962,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2302, - serialized_end=2357, + serialized_start=2374, + serialized_end=2429, ) @@ -1985,8 +1993,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2359, - serialized_end=2386, + serialized_start=2431, + serialized_end=2458, ) @@ -2009,8 +2017,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2388, - serialized_end=2396, + serialized_start=2460, + serialized_end=2468, ) @@ -2033,8 +2041,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2398, - serialized_end=2417, + serialized_start=2470, + serialized_end=2489, ) @@ -2064,8 +2072,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2419, - serialized_end=2454, + serialized_start=2491, + serialized_end=2526, ) @@ -2095,8 +2103,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2456, - serialized_end=2482, + serialized_start=2528, + serialized_end=2554, ) @@ -2126,8 +2134,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2484, - serialized_end=2510, + serialized_start=2556, + serialized_end=2582, ) @@ -2185,8 +2193,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2513, - serialized_end=2675, + serialized_start=2585, + serialized_end=2747, ) @@ -2223,8 +2231,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2677, - serialized_end=2729, + serialized_start=2749, + serialized_end=2801, ) @@ -2282,8 +2290,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2732, - serialized_end=2911, + serialized_start=2804, + serialized_end=2983, ) @@ -2313,8 +2321,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2913, - serialized_end=2939, + serialized_start=2985, + serialized_end=3011, ) @@ -2337,8 +2345,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2941, - serialized_end=2953, + serialized_start=3013, + serialized_end=3025, ) @@ -2417,8 +2425,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2956, - serialized_end=3143, + serialized_start=3028, + serialized_end=3215, ) @@ -2518,8 +2526,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3146, - serialized_end=3412, + serialized_start=3218, + serialized_end=3484, ) @@ -2542,8 +2550,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3414, - serialized_end=3430, + serialized_start=3486, + serialized_end=3502, ) @@ -2573,8 +2581,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3432, - serialized_end=3461, + serialized_start=3504, + serialized_end=3533, ) @@ -2667,8 +2675,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3464, - serialized_end=3719, + serialized_start=3536, + serialized_end=3791, ) @@ -2691,8 +2699,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3721, - serialized_end=3734, + serialized_start=3793, + serialized_end=3806, ) @@ -2722,8 +2730,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3736, - serialized_end=3759, + serialized_start=3808, + serialized_end=3831, ) @@ -2760,8 +2768,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3761, - serialized_end=3820, + serialized_start=3833, + serialized_end=3892, ) @@ -2805,8 +2813,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3822, - serialized_end=3885, + serialized_start=3894, + serialized_end=3957, ) @@ -2857,8 +2865,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3888, - serialized_end=4018, + serialized_start=3960, + serialized_end=4090, ) @@ -2909,8 +2917,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4020, - serialized_end=4116, + serialized_start=4092, + serialized_end=4188, ) @@ -2947,8 +2955,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4118, - serialized_end=4172, + serialized_start=4190, + serialized_end=4244, ) @@ -3006,8 +3014,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4174, - serialized_end=4292, + serialized_start=4246, + serialized_end=4364, ) @@ -3051,8 +3059,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4294, - serialized_end=4358, + serialized_start=4366, + serialized_end=4430, ) @@ -3103,8 +3111,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4360, - serialized_end=4441, + serialized_start=4432, + serialized_end=4513, ) @@ -3141,8 +3149,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4443, - serialized_end=4495, + serialized_start=4515, + serialized_end=4567, ) @@ -3214,8 +3222,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4498, - serialized_end=4638, + serialized_start=4570, + serialized_end=4710, ) @@ -3245,8 +3253,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4640, - serialized_end=4673, + serialized_start=4712, + serialized_end=4745, ) @@ -3283,8 +3291,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4675, - serialized_end=4728, + serialized_start=4747, + serialized_end=4800, ) @@ -3314,8 +3322,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4730, - serialized_end=4763, + serialized_start=4802, + serialized_end=4835, ) @@ -3401,8 +3409,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4766, - serialized_end=4972, + serialized_start=4838, + serialized_end=5044, ) @@ -3446,8 +3454,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4975, - serialized_end=5108, + serialized_start=5047, + serialized_end=5180, ) @@ -3477,8 +3485,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5110, - serialized_end=5147, + serialized_start=5182, + serialized_end=5219, ) @@ -3508,8 +3516,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5149, - serialized_end=5192, + serialized_start=5221, + serialized_end=5264, ) @@ -3560,8 +3568,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5194, - serialized_end=5319, + serialized_start=5266, + serialized_end=5391, ) @@ -3605,8 +3613,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5321, - serialized_end=5393, + serialized_start=5393, + serialized_end=5465, ) @@ -3636,8 +3644,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5395, - serialized_end=5439, + serialized_start=5467, + serialized_end=5511, ) @@ -3681,8 +3689,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5441, - serialized_end=5504, + serialized_start=5513, + serialized_end=5576, ) @@ -3726,8 +3734,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5506, - serialized_end=5564, + serialized_start=5578, + serialized_end=5636, ) @@ -3757,8 +3765,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5566, - serialized_end=5599, + serialized_start=5638, + serialized_end=5671, ) @@ -3795,8 +3803,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5601, - serialized_end=5654, + serialized_start=5673, + serialized_end=5726, ) @@ -3826,8 +3834,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5656, - serialized_end=5698, + serialized_start=5728, + serialized_end=5770, ) @@ -3850,8 +3858,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5700, - serialized_end=5711, + serialized_start=5772, + serialized_end=5783, ) @@ -3874,8 +3882,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5713, - serialized_end=5728, + serialized_start=5785, + serialized_end=5800, ) @@ -3912,8 +3920,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5730, - serialized_end=5785, + serialized_start=5802, + serialized_end=5857, ) @@ -3950,8 +3958,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5787, - serialized_end=5837, + serialized_start=5859, + serialized_end=5909, ) @@ -3974,8 +3982,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5839, - serialized_end=5858, + serialized_start=5911, + serialized_end=5930, ) @@ -4117,8 +4125,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5861, - serialized_end=6270, + serialized_start=5933, + serialized_end=6342, ) @@ -4141,8 +4149,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=6272, - serialized_end=6287, + serialized_start=6344, + serialized_end=6359, ) @@ -4186,8 +4194,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=6289, - serialized_end=6348, + serialized_start=6361, + serialized_end=6420, ) @@ -4210,8 +4218,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=6350, - serialized_end=6371, + serialized_start=6422, + serialized_end=6443, ) @@ -4241,8 +4249,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=6373, - serialized_end=6405, + serialized_start=6445, + serialized_end=6477, ) @@ -4265,8 +4273,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=6407, - serialized_end=6438, + serialized_start=6479, + serialized_end=6510, ) @@ -4296,8 +4304,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=6440, - serialized_end=6488, + serialized_start=6512, + serialized_end=6560, ) @@ -4327,8 +4335,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=6490, - serialized_end=6530, + serialized_start=6562, + serialized_end=6602, ) @@ -4365,8 +4373,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=6532, - serialized_end=6599, + serialized_start=6604, + serialized_end=6671, ) _FEATURES.fields_by_name['coins'].message_type = types__pb2._COINTYPE diff --git a/keepkeylib/messages_zcash_pb2.py b/keepkeylib/messages_zcash_pb2.py index 953b2849..026e3128 100644 --- a/keepkeylib/messages_zcash_pb2.py +++ b/keepkeylib/messages_zcash_pb2.py @@ -20,7 +20,7 @@ name='messages-zcash.proto', package='', syntax='proto2', - serialized_pb=_b('\n\x14messages-zcash.proto\"\xd9\x04\n\rZcashSignPCZT\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x0f\n\x07\x61\x63\x63ount\x18\x02 \x01(\r\x12\x11\n\tpczt_data\x18\x03 \x01(\x0c\x12\x11\n\tn_actions\x18\x04 \x01(\r\x12\x14\n\x0ctotal_amount\x18\x05 \x01(\x04\x12\x0b\n\x03\x66\x65\x65\x18\x06 \x01(\x04\x12\x11\n\tbranch_id\x18\x07 \x01(\r\x12\x15\n\rheader_digest\x18\x08 \x01(\x0c\x12\x1a\n\x12transparent_digest\x18\t \x01(\x0c\x12\x16\n\x0esapling_digest\x18\n \x01(\x0c\x12\x16\n\x0eorchard_digest\x18\x0b \x01(\x0c\x12\x15\n\rorchard_flags\x18\x0c \x01(\r\x12\x1d\n\x15orchard_value_balance\x18\r \x01(\x03\x12\x16\n\x0eorchard_anchor\x18\x0e \x01(\x0c\x12\x12\n\ntx_version\x18\x0f \x01(\r\x12\x18\n\x10version_group_id\x18\x10 \x01(\r\x12\x11\n\tlock_time\x18\x11 \x01(\r\x12\x15\n\rexpiry_height\x18\x12 \x01(\r\x12\x46\n\rshielded_pool\x18\x13 \x01(\x0e\x32\x12.ZcashShieldedPool:\x1bZCASH_SHIELDED_POOL_ORCHARD\x12\x17\n\x0fironwood_digest\x18\x14 \x01(\x0c\x12\x1d\n\x15n_transparent_outputs\x18\x1d \x01(\r\x12\x1c\n\x14n_transparent_inputs\x18\x1e \x01(\r\x12!\n\x19\x65xpected_seed_fingerprint\x18\x1f \x01(\x0c\"\xa3\x02\n\x0fZcashPCZTAction\x12\r\n\x05index\x18\x01 \x01(\r\x12\r\n\x05\x61lpha\x18\x02 \x01(\x0c\x12\x0f\n\x07sighash\x18\x03 \x01(\x0c\x12\x0e\n\x06\x63v_net\x18\x04 \x01(\x0c\x12\r\n\x05value\x18\x05 \x01(\x04\x12\x10\n\x08is_spend\x18\x06 \x01(\x08\x12\x11\n\tnullifier\x18\x07 \x01(\x0c\x12\x0b\n\x03\x63mx\x18\x08 \x01(\x0c\x12\x0b\n\x03\x65pk\x18\t \x01(\x0c\x12\x13\n\x0b\x65nc_compact\x18\n \x01(\x0c\x12\x10\n\x08\x65nc_memo\x18\x0b \x01(\x0c\x12\x16\n\x0e\x65nc_noncompact\x18\x0c \x01(\x0c\x12\n\n\x02rk\x18\r \x01(\x0c\x12\x16\n\x0eout_ciphertext\x18\x0e \x01(\x0c\x12\x11\n\trecipient\x18\x0f \x01(\x0c\x12\r\n\x05rseed\x18\x10 \x01(\x0c\"(\n\x12ZcashPCZTActionAck\x12\x12\n\nnext_index\x18\x01 \x01(\r\"3\n\x0fZcashSignedPCZT\x12\x12\n\nsignatures\x18\x01 \x03(\x0c\x12\x0c\n\x04txid\x18\x02 \x01(\x0c\"N\n\x12ZcashGetOrchardFVK\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x0f\n\x07\x61\x63\x63ount\x18\x02 \x01(\r\x12\x14\n\x0cshow_display\x18\x03 \x01(\x08\"Q\n\x0fZcashOrchardFVK\x12\n\n\x02\x61k\x18\x01 \x01(\x0c\x12\n\n\x02nk\x18\x02 \x01(\x0c\x12\x0c\n\x04rivk\x18\x03 \x01(\x0c\x12\x18\n\x10seed_fingerprint\x18\x04 \x01(\x0c\"N\n\x16ZcashTransparentOutput\x12\r\n\x05index\x18\x01 \x02(\r\x12\x0e\n\x06\x61mount\x18\x02 \x01(\x04\x12\x15\n\rscript_pubkey\x18\x03 \x01(\x0c\"\xb0\x01\n\x15ZcashTransparentInput\x12\r\n\x05index\x18\x01 \x02(\r\x12\x0f\n\x07sighash\x18\x02 \x01(\x0c\x12\x11\n\taddress_n\x18\x03 \x03(\r\x12\x0e\n\x06\x61mount\x18\x04 \x01(\x04\x12\x14\n\x0cprevout_txid\x18\x05 \x01(\x0c\x12\x15\n\rprevout_index\x18\x06 \x01(\r\x12\x10\n\x08sequence\x18\x07 \x01(\r\x12\x15\n\rscript_pubkey\x18\x08 \x01(\x0c\"J\n\x13ZcashTransparentAck\x12\x19\n\x11next_output_index\x18\x01 \x01(\r\x12\x18\n\x10next_input_index\x18\x02 \x01(\r\",\n\x16ZcashTransparentSigned\x12\x12\n\nsignatures\x18\x01 \x03(\x0c\"\x8b\x01\n\x13ZcashDisplayAddress\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x0f\n\x07\x61\x63\x63ount\x18\x02 \x01(\r\x12!\n\x19\x65xpected_seed_fingerprint\x18\x07 \x01(\x0cJ\x04\x08\x03\x10\x04J\x04\x08\x04\x10\x05J\x04\x08\x05\x10\x06J\x04\x08\x06\x10\x07R\x07\x61\x64\x64ressR\x02\x61kR\x02nkR\x04rivk\"9\n\x0cZcashAddress\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\t\x12\x18\n\x10seed_fingerprint\x18\x02 \x01(\x0c*V\n\x11ZcashShieldedPool\x12\x1f\n\x1bZCASH_SHIELDED_POOL_ORCHARD\x10\x00\x12 \n\x1cZCASH_SHIELDED_POOL_IRONWOOD\x10\x01\x42\x31\n\x1a\x63om.keepkey.deviceprotocolB\x13KeepKeyMessageZcash') + serialized_pb=_b('\n\x14messages-zcash.proto\"\xad\x05\n\rZcashSignPCZT\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x0f\n\x07\x61\x63\x63ount\x18\x02 \x01(\r\x12\x11\n\tpczt_data\x18\x03 \x01(\x0c\x12\x11\n\tn_actions\x18\x04 \x01(\r\x12\x14\n\x0ctotal_amount\x18\x05 \x01(\x04\x12\x0b\n\x03\x66\x65\x65\x18\x06 \x01(\x04\x12\x11\n\tbranch_id\x18\x07 \x01(\r\x12\x15\n\rheader_digest\x18\x08 \x01(\x0c\x12\x1a\n\x12transparent_digest\x18\t \x01(\x0c\x12\x16\n\x0esapling_digest\x18\n \x01(\x0c\x12\x16\n\x0eorchard_digest\x18\x0b \x01(\x0c\x12\x15\n\rorchard_flags\x18\x0c \x01(\r\x12\x1d\n\x15orchard_value_balance\x18\r \x01(\x03\x12\x16\n\x0eorchard_anchor\x18\x0e \x01(\x0c\x12\x12\n\ntx_version\x18\x0f \x01(\r\x12\x18\n\x10version_group_id\x18\x10 \x01(\r\x12\x11\n\tlock_time\x18\x11 \x01(\r\x12\x15\n\rexpiry_height\x18\x12 \x01(\r\x12\x46\n\rshielded_pool\x18\x13 \x01(\x0e\x32\x12.ZcashShieldedPool:\x1bZCASH_SHIELDED_POOL_ORCHARD\x12\x17\n\x0fironwood_digest\x18\x14 \x01(\x0c\x12\x1a\n\x12n_ironwood_actions\x18\x15 \x01(\r\x12\x16\n\x0eironwood_flags\x18\x16 \x01(\r\x12\x1e\n\x16ironwood_value_balance\x18\x17 \x01(\x03\x12\x1d\n\x15n_transparent_outputs\x18\x1d \x01(\r\x12\x1c\n\x14n_transparent_inputs\x18\x1e \x01(\r\x12!\n\x19\x65xpected_seed_fingerprint\x18\x1f \x01(\x0c\"\xb9\x02\n\x0fZcashPCZTAction\x12\r\n\x05index\x18\x01 \x01(\r\x12\r\n\x05\x61lpha\x18\x02 \x01(\x0c\x12\x0f\n\x07sighash\x18\x03 \x01(\x0c\x12\x0e\n\x06\x63v_net\x18\x04 \x01(\x0c\x12\r\n\x05value\x18\x05 \x01(\x04\x12\x10\n\x08is_spend\x18\x06 \x01(\x08\x12\x11\n\tnullifier\x18\x07 \x01(\x0c\x12\x0b\n\x03\x63mx\x18\x08 \x01(\x0c\x12\x0b\n\x03\x65pk\x18\t \x01(\x0c\x12\x13\n\x0b\x65nc_compact\x18\n \x01(\x0c\x12\x10\n\x08\x65nc_memo\x18\x0b \x01(\x0c\x12\x16\n\x0e\x65nc_noncompact\x18\x0c \x01(\x0c\x12\n\n\x02rk\x18\r \x01(\x0c\x12\x16\n\x0eout_ciphertext\x18\x0e \x01(\x0c\x12\x11\n\trecipient\x18\x0f \x01(\x0c\x12\r\n\x05rseed\x18\x10 \x01(\x0c\x12\x14\n\x0cuser_address\x18\x11 \x01(\t\"(\n\x12ZcashPCZTActionAck\x12\x12\n\nnext_index\x18\x01 \x01(\r\"3\n\x0fZcashSignedPCZT\x12\x12\n\nsignatures\x18\x01 \x03(\x0c\x12\x0c\n\x04txid\x18\x02 \x01(\x0c\"N\n\x12ZcashGetOrchardFVK\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x0f\n\x07\x61\x63\x63ount\x18\x02 \x01(\r\x12\x14\n\x0cshow_display\x18\x03 \x01(\x08\"Q\n\x0fZcashOrchardFVK\x12\n\n\x02\x61k\x18\x01 \x01(\x0c\x12\n\n\x02nk\x18\x02 \x01(\x0c\x12\x0c\n\x04rivk\x18\x03 \x01(\x0c\x12\x18\n\x10seed_fingerprint\x18\x04 \x01(\x0c\"q\n\x16ZcashTransparentOutput\x12\r\n\x05index\x18\x01 \x02(\r\x12\x0e\n\x06\x61mount\x18\x02 \x01(\x04\x12\x15\n\rscript_pubkey\x18\x03 \x01(\x0c\x12\x0e\n\x06is_tex\x18\x04 \x01(\x08\x12\x11\n\taddress_n\x18\x05 \x03(\r\"\xb0\x01\n\x15ZcashTransparentInput\x12\r\n\x05index\x18\x01 \x02(\r\x12\x0f\n\x07sighash\x18\x02 \x01(\x0c\x12\x11\n\taddress_n\x18\x03 \x03(\r\x12\x0e\n\x06\x61mount\x18\x04 \x01(\x04\x12\x14\n\x0cprevout_txid\x18\x05 \x01(\x0c\x12\x15\n\rprevout_index\x18\x06 \x01(\r\x12\x10\n\x08sequence\x18\x07 \x01(\r\x12\x15\n\rscript_pubkey\x18\x08 \x01(\x0c\"J\n\x13ZcashTransparentAck\x12\x19\n\x11next_output_index\x18\x01 \x01(\r\x12\x18\n\x10next_input_index\x18\x02 \x01(\r\",\n\x16ZcashTransparentSigned\x12\x12\n\nsignatures\x18\x01 \x03(\x0c\"\x8b\x01\n\x13ZcashDisplayAddress\x12\x11\n\taddress_n\x18\x01 \x03(\r\x12\x0f\n\x07\x61\x63\x63ount\x18\x02 \x01(\r\x12!\n\x19\x65xpected_seed_fingerprint\x18\x07 \x01(\x0cJ\x04\x08\x03\x10\x04J\x04\x08\x04\x10\x05J\x04\x08\x05\x10\x06J\x04\x08\x06\x10\x07R\x07\x61\x64\x64ressR\x02\x61kR\x02nkR\x04rivk\"9\n\x0cZcashAddress\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\t\x12\x18\n\x10seed_fingerprint\x18\x02 \x01(\x0c*V\n\x11ZcashShieldedPool\x12\x1f\n\x1bZCASH_SHIELDED_POOL_ORCHARD\x10\x00\x12 \n\x1cZCASH_SHIELDED_POOL_IRONWOOD\x10\x01\x42\x31\n\x1a\x63om.keepkey.deviceprotocolB\x13KeepKeyMessageZcash') ) _ZCASHSHIELDEDPOOL = _descriptor.EnumDescriptor( @@ -40,8 +40,8 @@ ], containing_type=None, options=None, - serialized_start=1762, - serialized_end=1848, + serialized_start=1903, + serialized_end=1989, ) _sym_db.RegisterEnumDescriptor(_ZCASHSHIELDEDPOOL) @@ -199,21 +199,42 @@ is_extension=False, extension_scope=None, options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( - name='n_transparent_outputs', full_name='ZcashSignPCZT.n_transparent_outputs', index=20, + name='n_ironwood_actions', full_name='ZcashSignPCZT.n_ironwood_actions', index=20, + number=21, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='ironwood_flags', full_name='ZcashSignPCZT.ironwood_flags', index=21, + number=22, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='ironwood_value_balance', full_name='ZcashSignPCZT.ironwood_value_balance', index=22, + number=23, type=3, cpp_type=2, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='n_transparent_outputs', full_name='ZcashSignPCZT.n_transparent_outputs', index=23, number=29, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( - name='n_transparent_inputs', full_name='ZcashSignPCZT.n_transparent_inputs', index=21, + name='n_transparent_inputs', full_name='ZcashSignPCZT.n_transparent_inputs', index=24, number=30, type=13, cpp_type=3, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( - name='expected_seed_fingerprint', full_name='ZcashSignPCZT.expected_seed_fingerprint', index=22, + name='expected_seed_fingerprint', full_name='ZcashSignPCZT.expected_seed_fingerprint', index=25, number=31, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, @@ -232,7 +253,7 @@ oneofs=[ ], serialized_start=25, - serialized_end=626, + serialized_end=710, ) @@ -355,6 +376,13 @@ message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='user_address', full_name='ZcashPCZTAction.user_address', index=16, + number=17, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), ], extensions=[ ], @@ -367,8 +395,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=629, - serialized_end=920, + serialized_start=713, + serialized_end=1026, ) @@ -398,8 +426,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=922, - serialized_end=962, + serialized_start=1028, + serialized_end=1068, ) @@ -436,8 +464,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=964, - serialized_end=1015, + serialized_start=1070, + serialized_end=1121, ) @@ -481,8 +509,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1017, - serialized_end=1095, + serialized_start=1123, + serialized_end=1201, ) @@ -533,8 +561,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1097, - serialized_end=1178, + serialized_start=1203, + serialized_end=1284, ) @@ -566,6 +594,20 @@ message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='is_tex', full_name='ZcashTransparentOutput.is_tex', index=3, + number=4, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='address_n', full_name='ZcashTransparentOutput.address_n', index=4, + number=5, type=13, cpp_type=3, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), ], extensions=[ ], @@ -578,8 +620,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1180, - serialized_end=1258, + serialized_start=1286, + serialized_end=1399, ) @@ -658,8 +700,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1261, - serialized_end=1437, + serialized_start=1402, + serialized_end=1578, ) @@ -696,8 +738,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1439, - serialized_end=1513, + serialized_start=1580, + serialized_end=1654, ) @@ -727,8 +769,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1515, - serialized_end=1559, + serialized_start=1656, + serialized_end=1700, ) @@ -772,8 +814,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1562, - serialized_end=1701, + serialized_start=1703, + serialized_end=1842, ) @@ -810,8 +852,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1703, - serialized_end=1760, + serialized_start=1844, + serialized_end=1901, ) _ZCASHSIGNPCZT.fields_by_name['shielded_pool'].enum_type = _ZCASHSHIELDEDPOOL diff --git a/scripts/generate-test-report.py b/scripts/generate-test-report.py index cd4ae9f7..bf934cbb 100644 --- a/scripts/generate-test-report.py +++ b/scripts/generate-test-report.py @@ -202,6 +202,23 @@ def gap(self, h=4): def finish(self): self._flush() +def parse_report_junit(path): + """parse_junit, plus section L from the bitcoin-only JUnit CI writes + beside it: those tests only run on the bitcoin-only image and skip on + the full one, so the full JUnit alone shows them as withheld.""" + results = parse_junit(path) + btc = os.path.join(os.path.dirname(path), 'junit-merged-bitcoin-only.xml') + if os.path.abspath(btc) != os.path.abspath(path) and os.path.isfile(btc): + # The census and missing capabilities describe the full run only. + census, missing = dict(JUNIT_CENSUS), set(JUNIT_MISSING_CAPABILITIES) + btc_results = parse_junit(btc) + JUNIT_CENSUS.clear(); JUNIT_CENSUS.update(census) + JUNIT_MISSING_CAPABILITIES.clear(); JUNIT_MISSING_CAPABILITIES.update(missing) + for key, status in btc_results.items(): + if key.startswith('test_msg_bitcoin_only_variant::'): + results[key] = status + return results + def _lookup(results, mod, meth): """Look up a test result by module::method. Every SECTIONS module is a test_msg_* module, so parse_junit always emits a 'mod::meth' key -- there is @@ -220,8 +237,11 @@ def ver_ge(a, b): return ver_t(a) >= ver_t(b) # Tests whose newer fail-closed behavior deliberately returns before drawing a # confirmation screen. Keep their historical catalog text, but do not schedule # or audit an OLED capture once the refusal behavior is active. +# (floor, ceiling): no capture from floor up to, not including, ceiling. _NO_SCREEN_FROM = { - ('test_msg_signtx_ethereum_erc20', 'test_approve_all'): '7.14.2', + # 7.14.x refuses an unlimited approve before drawing; from 7.15 it signs + # after an UNLIMITED APPROVAL warning, which is the evidence to capture. + ('test_msg_signtx_ethereum_erc20', 'test_approve_all'): ('7.14.2', '7.15.0'), } @@ -246,8 +266,8 @@ def _screens_for(fw_version, mod, meth, screens): 'test_reset_device_dice_mixed_is_verifiable', 'test_reset_device_dice_only_is_verifiable')): return [] - floor = _NO_SCREEN_FROM.get((mod, meth)) - if floor and ver_ge(fw_version, floor): + window = _NO_SCREEN_FROM.get((mod, meth)) + if window and ver_ge(fw_version, window[0]) and not ver_ge(fw_version, window[1]): return [] return screens @@ -490,9 +510,8 @@ def _v_catalog_tests(start_id=17): silently go stale (as happened when the old hand-written V17-V23 test names drifted from the dynamically-generated ones). - Signing entries get screenshot hints. The unlimited-approval refusal is - deliberately screenless: its wire assertion requires immediate Failure, - so setup or home frames must never be used as approval evidence. + Signing entries get screenshot hints, the unlimited approval included: + from 7.15 it signs after a warning screen. """ if not CLEARSIGN_FLOWS: return [] @@ -505,12 +524,12 @@ def _v_catalog_tests(start_id=17): if f['key'] == 'erc20-approve-unlimited': out.append(( 'V%d' % i, 'test_msg_ethereum_clear_signing', method, - 'Unlimited ERC-20 approval refused before confirmation', - 'Even with AdvancedMode and valid runtime metadata, unlimited ' - 'approval returns Failure before any ButtonRequest or signature. ' - 'The wire test requires that immediate refusal; no OLED approval ' - 'screen is expected.', - [], + 'Unlimited ERC-20 approval signs after a warning', + 'From 7.15 an unlimited approval is signed after an UNLIMITED ' + 'APPROVAL warning naming the spender and token; the signature is ' + 'checked against the device address. 7.14.x refused it before ' + 'any ButtonRequest.', + ['Unlimited approval warning'], )) i += 1 continue @@ -920,7 +939,8 @@ def _arg_shown(a): ('K1c', 'test_msg_resetdevice', 'test_reset_device_dice_rejects_biased_rolls', 'Loaded die is refused', 'Fifty ones -- one face on 100% of the rolls. Refused with SyntaxError before any digest ' - 'is drawn, per Coldcard\'s 30%-per-face rule, so a biased die never becomes a wallet.', + 'is drawn: this exceeds the one-in-a-million fair-die frequency threshold. ' + 'The frequency check detects severe bias; it is not an entropy guarantee.', []), ('K1d', 'test_msg_resetdevice', 'test_reset_device_dice_only_requires_dice_entropy', 'dice_only without dice_entropy is refused', @@ -982,10 +1002,11 @@ def _arg_shown(a): 'Bytes past the declared roll count must not affect the result, so uninitialized tail ' 'bytes of the roll buffer can never leak into seed material.', []), - ('K7b', 'Dice', 'BiasGateIsThirtyPercentPerFace', + ('K7b', 'Dice', 'BiasGateRefusesOnlyAtOneInAMillion', 'Loaded-die gate threshold', - 'Coldcard\'s rule: any face over 30% of the rolls is refused. 30/99 fails, 29/99 passes; ' - '16/50 fails, 15/50 (exactly 30%) passes.', + 'For every face, 25/50, 32/75, and 39/99 rolls are refused; one fewer passes. ' + 'Each threshold bounds the fair-die probability of any face reaching that count ' + 'below one in a million. This avoids rejecting ordinary fair-die sequences.', []), ('K7c', 'Dice', 'BiasGateRejectsNonDiceBytes', 'Non-d6 bytes are refused', @@ -1246,8 +1267,8 @@ def _arg_shown(a): ['Approval screen']), ('E11', 'test_msg_signtx_ethereum_erc20', 'test_approve_all', 'ERC-20 approve unlimited', - 'MAX_UINT256 approval. Older firmware showed an "UNLIMITED" warning; 7.14.2 and later ' - 'refuse it before drawing a confirmation screen.', + 'MAX_UINT256 approval. 7.14.2 through 7.14.x refuse it before drawing anything. From ' + '7.15 it signs after an UNLIMITED APPROVAL warning that names the spender and token.', ['Unlimited approval warning']), ('E12', 'test_msg_ethereum_makerdao', 'test_generate', 'MakerDAO generate DAI', 'Complex DeFi contract interaction (MakerDAO CDP).', []), @@ -1258,35 +1279,28 @@ def _arg_shown(a): ('E15', 'test_msg_ethereum_cfunc', 'test_sign_execTx', 'Contract function call', 'Generic contract call signing.', []), ('E16', 'test_sign_typed_data', 'test_ethereum_sign_typed_data_hash', - 'EIP-712 typed data is BLIND-signed, behind AdvancedMode', - 'The only working EIP-712 path. The host computes both 32-byte hashes and the device ' - 'signs them, so it cannot show a recipient, an amount or a chain -- it shows the two ' - 'digests and asks whether to trust the host. The test proves both halves of the gate: ' - 'with AdvancedMode ON the signature is produced, and with it OFF the device refuses ' - 'with "Enable AdvancedMode to blind-sign typed hashes". Every EIP-712 signature a ' - 'KeepKey produces today, Permit2 approvals included, takes this path.', + 'Precomputed EIP-712 hashes are BLIND-signed, behind AdvancedMode', + 'For a host that sends only the two 32-byte hashes. The device cannot show a recipient, ' + 'an amount or a chain from them -- it shows the digests and asks whether to trust the ' + 'host. The test proves both halves of the gate: with AdvancedMode ON the signature is ' + 'produced, and with it OFF the device refuses with "Enable AdvancedMode to blind-sign ' + 'typed hashes". From 7.15 a host that sends the document itself gets the streamed path ' + 'in section TD, where the device reads and shows every field it signs.', []), ('E16b', 'test_sign_typed_data', 'test_ethereum_sign_x402_eip3009', - 'Structured EIP-712 is DISABLED, and x402 EIP-3009 is refused', - 'This entry asserted the opposite until 2026-08-21, and the report shipped it green: it ' - 'claimed the device "computes the EIP-712 hashes itself and displays every ' - 'TransferWithAuthorization field", and declared two screens for fields that are never ' - 'drawn. The test underneath had already been rewritten to assert the REFUSAL. A reader ' - 'would have concluded x402 EVM payments clear-sign. They do not.\n' - 'What the test actually proves: Ethereum712TypesValues is answered with ' - '"Structured EIP-712 disabled pending canonical display hardening". The JSON parser ' - 'could not guarantee the displayed value was the value hashed, so 7.14.2 withdrew the ' - 'path rather than ship it. The EIP-712 V4 reference hashes stay in the fixture, unused, ' - 'as the vector to re-assert when the streaming implementation lands (SRS-7.16 R-4.1, ' - 'R-4.2).\n' - 'The screen list is EMPTY because a refusal draws nothing -- the evidence is the ' - 'Failure on the wire.', + 'The legacy one-shot JSON EIP-712 endpoint stays refused', + 'Ethereum712TypesValues is answered with "Structured EIP-712 disabled". Its JSON parser ' + 'could not guarantee that the value displayed was the value hashed, so 7.14.2 withdrew it ' + 'and 7.15 keeps it closed: structured EIP-712 goes through the streamed protocol in ' + 'section TD instead. The vector is an x402 EIP-3009 TransferWithAuthorization; its EIP-712 ' + 'V4 reference hashes stay in the fixture as an independent oracle. The screen list is ' + 'empty because a refusal draws nothing -- the evidence is the Failure on the wire.', []), ('E17', 'test_msg_ethereum_erc20_uniswap_liquidity', 'test_sign_uni_approve_liquidity_ETH_refused', - 'Uniswap V2 unlimited LP-token approval refused', + 'Uniswap V2 unlimited LP-token approval refused (7.14.x)', 'Enables AdvancedMode, then attempts an unlimited FOX/WETH LP-token approval. ' - 'The device refuses it with Failure_ActionCancelled and the explicit disabled-approval ' - 'reason before any signing consent. The refusal itself is checked on the wire.', + '7.14.x refuses it with Failure_ActionCancelled before any signing consent, checked on ' + 'the wire. From 7.15 unlimited approvals sign after a warning, so this skips there.', ['Enable Policy: AdvancedMode']), ('E18', 'test_msg_ethereum_erc20_uniswap_liquidity', 'test_sign_uni_add_liquidity_ETH', 'Uniswap V2 add liquidity ETH+token', @@ -2817,17 +2831,11 @@ def _arg_shown(a): []), ('L3', 'test_msg_bitcoin_only_variant', 'test_firmware_variant_names_the_bitcoin_only_product', 'features.firmware_variant must name the product', - 'FAILED ON THE BITCOIN-ONLY IMAGE AS MEASURED, and the failure is the finding. ' - 'firmware_variant is the only wire-visible product identifier and the whole pyk suite ' - 'gates on it: common.requires_fullFeature() skips a test when it reads "KeepKeyBTC" or ' - '"EmulatorBTC". The bitcoin-only emulator reported plain "Emulator", so ' - 'requires_fullFeature() is dead code and every altcoin test in the directory runs ' - 'against a bitcoin-only image and fails instead of skipping. Section X of this report ' - 'states the KeepKeyBTC contract as fact. variant_getName() has two arms and only the ' - 'EMULATOR one returns a literal; the hardware arm takes the model variant name from ' - 'variant_getInfo() and has no BITCOIN_ONLY case at all, so bitcoin-only HARDWARE reports ' - 'exactly what a multi-chain device of the same model reports. The assertion is by ' - 'suffix, not against a fixed string, so it stays honest for both arms.', + 'The bitcoin-only emulator once reported plain "Emulator", so ' + 'common.requires_fullFeature(), which skips on "KeepKeyBTC" or "EmulatorBTC", was dead ' + 'code and altcoin tests failed against the bitcoin-only image instead of skipping. The ' + 'variant now names the product on both the emulator and hardware arms. The assertion is ' + 'by suffix, not a fixed string, so it holds for both.', []), ('L4', 'test_msg_bitcoin_only_variant', 'test_altcoin_message_handlers_are_absent', 'Every stripped chain refuses without drawing', @@ -2903,24 +2911,14 @@ def _arg_shown(a): []), ('L11', 'test_msg_bitcoin_only_variant', 'test_op_return_does_not_poison_the_duplicate_detector', 'An OP_RETURN output must not poison the duplicate detector', - 'FAILS ON BOTH PRODUCTS, and the failure is the finding. Sign a transaction whose last ' - 'output is OP_RETURN, then sign the transaction L10 just proved is allowed, and the ' - 'device answers "WARNING: DUPLICATE TRANSACTION! Already signed a tx with the same ' - 'outputs. To try again, unplug/replug KeepKey." and aborts. signing.c calls ' - 'txin_dgst_final() once per output, but txin_dgst_save_and_reset() -- the only thing that ' - 're-initialises the SHA-256 context -- is reached only on the pay-to-address path; an ' - 'OP_RETURN output returns before it. So a transaction ending in OP_RETURN leaves the ' - 'context finalised and never re-initialised, the next transaction\'s inputs are hashed ' - 'into a finalised context, and its digest no longer matches while amount and address ' - 'still do -- precisely the (same outputs, different inputs) pattern the check exists to ' - 'flag. Fail-safe, in that it refuses rather than signs, but it refuses a legitimate ' - 'transaction and demands a replug, and every OP_RETURN-terminated transaction arms it: ' - 'that is every THORChain and Maya swap the wallet builds. Nothing had caught it because ' - 'common.KeepKeyTest wipes the device in setUp, so no existing test signs two transactions ' - 'in one session.', + 'Sign a transaction whose last output is OP_RETURN, then sign the transaction L10 proved ' + 'is allowed: it must sign. It once failed on both products with "WARNING: DUPLICATE ' + 'TRANSACTION!", because an OP_RETURN output returned before txin_dgst_save_and_reset() ' + 're-initialised the digest context, so the next transaction hashed its inputs into a ' + 'finalised context. Every THORChain and Maya swap ends in OP_RETURN and armed it. The ' + 'common setUp wipes the device, so no other test signs two transactions in one session.', ['Send 0.0038 BTC to 1MJ2tj2ThBE62zXbBYA5ZaN3fdve5CPAz1 (first transaction)', - 'CONFIRM OP_RETURN: the memo that arms the detector', - 'WARNING: DUPLICATE TRANSACTION! Already signed a tx with the same outputs']), + 'CONFIRM OP_RETURN: the memo that used to arm the detector']), ]), ('U', 'Storage Upgrade Preservation', '7.15.0', 'A signed UPGRADE must never wipe. An older firmware must never parse a newer storage ' @@ -4148,7 +4146,7 @@ def main(): if not args.junit: print('ERROR: --validate-junit requires --junit=', file=sys.stderr) sys.exit(2) - results = parse_junit(args.junit) + results = parse_report_junit(args.junit) ok, failures = validate_junit(fw, results, args.variant) if ok: print(f'SECTIONS validation passed: all tests for fw {fw} are pass or skip') @@ -4170,7 +4168,13 @@ def main(): if supplied: os.environ['KK_BUILD_LABEL'] = ' | '.join(supplied) - results = parse_junit(args.junit) if args.junit else {} + results = parse_report_junit(args.junit) if args.junit else {} + # A staged control has no row of its own in a tree whose firmware reports + # its capability missing; show it withheld rather than pending. Rendering + # only: validate_junit applies the same exemption itself. + for (mod, meth), cap in _TEST_CAPABILITY.items(): + if cap in JUNIT_MISSING_CAPABILITIES: + results.setdefault('%s::%s' % (mod, meth), 'skip') render(args.output, fw, results, args.screenshots) if __name__ == '__main__': diff --git a/tests/common.py b/tests/common.py index 37b1d36a..de156f25 100644 --- a/tests/common.py +++ b/tests/common.py @@ -27,6 +27,8 @@ import os import semver +import oled_text + from google.protobuf.message import EncodeError from keepkeylib.client import KeepKeyClient, KeepKeyDebuglinkClient, KeepKeyDebuglinkClientVerbose from keepkeylib.transport_udp import EmulatorNotResponding @@ -182,6 +184,46 @@ def setup_mnemonic_pin_passphrase(self): def tearDown(self): self.client.close() + def assert_shows_address(self, call, expected): + """Run `call`, a show_display request, and assert one of the screens + it confirms shows ALL of `expected` -- a known vector or the + show_display=False response, never the value under test. Returns + what `call` returns. Only where neither exists may `expected` be a + function of that result. + + Before 7.14.3 DebugLinkState was built in the shared response arena + (fixed in 7.14.3 and 7.15), so reading the screen during the confirm + wiped a response already built. There `call` runs unwatched and + nothing is asserted.""" + # Cached Features, not firmware_at_least(): its Initialize would break + # a caller's set_expected_responses(). + features = self.client.features + if (features.major_version, features.minor_version, + features.patch_version) < (7, 14, 3): + return call() + screens = [] + press = self.client.callback_ButtonRequest + nested = 'callback_ButtonRequest' in vars(self.client) + + def capture(msg): + screens.append(self.client._read_oled_after_settle()) + return press(msg) + + self.client.callback_ButtonRequest = capture + try: + result = call() + finally: + if nested: # an enclosing check is capturing too + self.client.callback_ButtonRequest = press + else: + del self.client.callback_ButtonRequest + if callable(expected): + expected = expected(result) + self.assertTrue( + any(oled_text.shows_address(s, expected) for s in screens), + "none of %d screens shows all of %r" % (len(screens), expected)) + return result + def assertEqual(self, lhs, rhs): if type(lhs) == type(b'') and type(rhs) == type(''): super(KeepKeyTest, self).assertEqual(lhs, rhs.encode('utf-8')) @@ -236,6 +278,15 @@ def requires_release_capability(self, capability): "Staged release tree does not yet provide capability: " + capability) + def requires_capability_absent(self, capability): + """Skip when the firmware reports `capability`: for a refusal that + the capability's behaviour replaces within the same version.""" + enum = messages_pb2.Features.Capability + enum.Value("CAPABILITY_" + capability.upper().replace("-", "_")) + reported = self.firmware_capabilities() + if reported is not None and capability in reported: + self.skipTest("Firmware provides capability: " + capability) + def requires_taproot(self): """Skip unless the firmware reports taproot support. diff --git a/tests/eip712_corpus.json b/tests/eip712_corpus.json new file mode 100644 index 00000000..6e498a6c --- /dev/null +++ b/tests/eip712_corpus.json @@ -0,0 +1,6968 @@ +[ + { + "id": "permit2-PermitSingle", + "source": [ + "https://github.com/Uniswap/permit2/blob/cc56ad0f3439c502c246fc5cfcc3db92bb8b7219/src/libraries/PermitHash.sol" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "PermitSingle": [ + { + "name": "details", + "type": "PermitDetails" + }, + { + "name": "spender", + "type": "address" + }, + { + "name": "sigDeadline", + "type": "uint256" + } + ], + "PermitDetails": [ + { + "name": "token", + "type": "address" + }, + { + "name": "amount", + "type": "uint160" + }, + { + "name": "expiration", + "type": "uint48" + }, + { + "name": "nonce", + "type": "uint48" + } + ] + }, + "primaryType": "PermitSingle", + "domain": { + "name": "Permit2", + "chainId": 1, + "verifyingContract": "0x000000000022D473030F116dDEE9F6B43aC78BA3" + }, + "message": { + "details": { + "token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "amount": "1000000", + "expiration": "1893456000", + "nonce": "0" + }, + "spender": "0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD", + "sigDeadline": "1775803746" + } + }, + "expected": { + "domain_separator": "866a5aba21966af95d6c7ab78eb2b2fc913915c28be3b9aa07cc04ff903e3f28", + "message_hash": "434404194ecf97fbcbf7e55f4bdd2ff1f78f0689ea793bda4b85c7e73060a815", + "digest": "8b4985b6263546864eb8921379708c29bf922304edf4fc0abe5e077f853a60b2" + } + }, + { + "id": "permit2-PermitSingle-unlimited", + "source": [ + "https://github.com/Uniswap/permit2/blob/cc56ad0f3439c502c246fc5cfcc3db92bb8b7219/src/libraries/PermitHash.sol", + "https://github.com/Uniswap/sdks/blob/main/sdks/permit2-sdk/src/constants.ts" + ], + "requires_capability": "erc20-unlimited-permit-review", + "unlimited_screen": "details.amount\nuint160: UNLIMITED", + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "PermitSingle": [ + { + "name": "details", + "type": "PermitDetails" + }, + { + "name": "spender", + "type": "address" + }, + { + "name": "sigDeadline", + "type": "uint256" + } + ], + "PermitDetails": [ + { + "name": "token", + "type": "address" + }, + { + "name": "amount", + "type": "uint160" + }, + { + "name": "expiration", + "type": "uint48" + }, + { + "name": "nonce", + "type": "uint48" + } + ] + }, + "primaryType": "PermitSingle", + "domain": { + "name": "Permit2", + "chainId": 1, + "verifyingContract": "0x000000000022D473030F116dDEE9F6B43aC78BA3" + }, + "message": { + "details": { + "token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "amount": "1461501637330902918203684832716283019655932542975", + "expiration": "1778393946", + "nonce": "0" + }, + "spender": "0x66a9893cC07D91D95644AEDD05D03f95e1dBA8Af", + "sigDeadline": "1775803746" + } + }, + "expected": { + "domain_separator": "866a5aba21966af95d6c7ab78eb2b2fc913915c28be3b9aa07cc04ff903e3f28", + "message_hash": "8cadbd22e396ba77b30a62c8219759ec221ed18cde6fe1c31204fb3d53c1ecf8", + "digest": "eb4da5f3381371818ca113f3f4697da6c5ee1bbb098effde0f8f399b208f7bd7" + } + }, + { + "id": "permit2-PermitBatch", + "source": [ + "https://github.com/Uniswap/permit2/blob/cc56ad0f3439c502c246fc5cfcc3db92bb8b7219/src/libraries/PermitHash.sol" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "PermitBatch": [ + { + "name": "details", + "type": "PermitDetails[]" + }, + { + "name": "spender", + "type": "address" + }, + { + "name": "sigDeadline", + "type": "uint256" + } + ], + "PermitDetails": [ + { + "name": "token", + "type": "address" + }, + { + "name": "amount", + "type": "uint160" + }, + { + "name": "expiration", + "type": "uint48" + }, + { + "name": "nonce", + "type": "uint48" + } + ] + }, + "primaryType": "PermitBatch", + "domain": { + "name": "Permit2", + "chainId": 1, + "verifyingContract": "0x000000000022D473030F116dDEE9F6B43aC78BA3" + }, + "message": { + "details": [ + { + "token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "amount": "1000000", + "expiration": "1893456000", + "nonce": "0" + }, + { + "token": "0x6B175474E89094C44Da98b954EedeAC495271d0F", + "amount": "2000000", + "expiration": "1893456000", + "nonce": "1" + }, + { + "token": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "amount": "3000000", + "expiration": "1893456000", + "nonce": "2" + }, + { + "token": "0xdAC17F958D2ee523a2206206994597C13D831ec7", + "amount": "4000000", + "expiration": "1893456000", + "nonce": "3" + }, + { + "token": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", + "amount": "5000000", + "expiration": "1893456000", + "nonce": "4" + } + ], + "spender": "0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD", + "sigDeadline": "1775803746" + } + }, + "expected": { + "domain_separator": "866a5aba21966af95d6c7ab78eb2b2fc913915c28be3b9aa07cc04ff903e3f28", + "message_hash": "988853f08bc1888f09fc0fac97c129a5f79f8700da45e7135511753138073bb2", + "digest": "21b393815af1f64e893e0681d486fd4baf58532c1b079aa5d52a3d212fba7d31" + } + }, + { + "id": "permit2-PermitBatch-20", + "source": [ + "https://github.com/Uniswap/permit2/blob/cc56ad0f3439c502c246fc5cfcc3db92bb8b7219/src/libraries/PermitHash.sol" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "PermitBatch": [ + { + "name": "details", + "type": "PermitDetails[]" + }, + { + "name": "spender", + "type": "address" + }, + { + "name": "sigDeadline", + "type": "uint256" + } + ], + "PermitDetails": [ + { + "name": "token", + "type": "address" + }, + { + "name": "amount", + "type": "uint160" + }, + { + "name": "expiration", + "type": "uint48" + }, + { + "name": "nonce", + "type": "uint48" + } + ] + }, + "primaryType": "PermitBatch", + "domain": { + "name": "Permit2", + "chainId": 1, + "verifyingContract": "0x000000000022D473030F116dDEE9F6B43aC78BA3" + }, + "message": { + "details": [ + { + "token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "amount": "1000000", + "expiration": "1893456000", + "nonce": "0" + }, + { + "token": "0x6B175474E89094C44Da98b954EedeAC495271d0F", + "amount": "2000000", + "expiration": "1893456000", + "nonce": "1" + }, + { + "token": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "amount": "3000000", + "expiration": "1893456000", + "nonce": "2" + }, + { + "token": "0xdAC17F958D2ee523a2206206994597C13D831ec7", + "amount": "4000000", + "expiration": "1893456000", + "nonce": "3" + }, + { + "token": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", + "amount": "5000000", + "expiration": "1893456000", + "nonce": "4" + }, + { + "token": "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984", + "amount": "6000000", + "expiration": "1893456000", + "nonce": "5" + }, + { + "token": "0x514910771AF9Ca656af840dff83E8264EcF986CA", + "amount": "7000000", + "expiration": "1893456000", + "nonce": "6" + }, + { + "token": "0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9", + "amount": "8000000", + "expiration": "1893456000", + "nonce": "7" + }, + { + "token": "0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2", + "amount": "9000000", + "expiration": "1893456000", + "nonce": "8" + }, + { + "token": "0xc00e94Cb662C3520282E6f5717214004A7f26888", + "amount": "10000000", + "expiration": "1893456000", + "nonce": "9" + }, + { + "token": "0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F", + "amount": "11000000", + "expiration": "1893456000", + "nonce": "10" + }, + { + "token": "0xD533a949740bb3306d119CC777fa900bA034cd52", + "amount": "12000000", + "expiration": "1893456000", + "nonce": "11" + }, + { + "token": "0x5A98FcBEA516Cf06857215779Fd812CA3beF1B32", + "amount": "13000000", + "expiration": "1893456000", + "nonce": "12" + }, + { + "token": "0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0", + "amount": "14000000", + "expiration": "1893456000", + "nonce": "13" + }, + { + "token": "0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE", + "amount": "15000000", + "expiration": "1893456000", + "nonce": "14" + }, + { + "token": "0x4d224452801ACEd8B2F0aebE155379bb5D594381", + "amount": "16000000", + "expiration": "1893456000", + "nonce": "15" + }, + { + "token": "0xC18360217D8F7Ab5e7c516566761Ea12Ce7F9D72", + "amount": "17000000", + "expiration": "1893456000", + "nonce": "16" + }, + { + "token": "0x111111111117dC0aa78b770fA6A738034120C302", + "amount": "18000000", + "expiration": "1893456000", + "nonce": "17" + }, + { + "token": "0x6B3595068778DD592e39A122f4f5a5cF09C90fE2", + "amount": "19000000", + "expiration": "1893456000", + "nonce": "18" + }, + { + "token": "0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e", + "amount": "20000000", + "expiration": "1893456000", + "nonce": "19" + } + ], + "spender": "0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD", + "sigDeadline": "1775803746" + } + }, + "expected": { + "domain_separator": "866a5aba21966af95d6c7ab78eb2b2fc913915c28be3b9aa07cc04ff903e3f28", + "message_hash": "9be08a04cc2b5ee94ecba4347a8469ee3d3192f50b2613d59887f090f195142f", + "digest": "384af6a2fc07a1e70fa27fec8120723fb7ac8c922c53cfe2d8aaed6e6a401e33" + } + }, + { + "id": "permit2-PermitBatch-32", + "source": [ + "https://github.com/Uniswap/permit2/blob/cc56ad0f3439c502c246fc5cfcc3db92bb8b7219/src/libraries/PermitHash.sol" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "PermitBatch": [ + { + "name": "details", + "type": "PermitDetails[]" + }, + { + "name": "spender", + "type": "address" + }, + { + "name": "sigDeadline", + "type": "uint256" + } + ], + "PermitDetails": [ + { + "name": "token", + "type": "address" + }, + { + "name": "amount", + "type": "uint160" + }, + { + "name": "expiration", + "type": "uint48" + }, + { + "name": "nonce", + "type": "uint48" + } + ] + }, + "primaryType": "PermitBatch", + "domain": { + "name": "Permit2", + "chainId": 1, + "verifyingContract": "0x000000000022D473030F116dDEE9F6B43aC78BA3" + }, + "message": { + "details": [ + { + "token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "amount": "1000000", + "expiration": "1893456000", + "nonce": "0" + }, + { + "token": "0x6B175474E89094C44Da98b954EedeAC495271d0F", + "amount": "2000000", + "expiration": "1893456000", + "nonce": "1" + }, + { + "token": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "amount": "3000000", + "expiration": "1893456000", + "nonce": "2" + }, + { + "token": "0xdAC17F958D2ee523a2206206994597C13D831ec7", + "amount": "4000000", + "expiration": "1893456000", + "nonce": "3" + }, + { + "token": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", + "amount": "5000000", + "expiration": "1893456000", + "nonce": "4" + }, + { + "token": "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984", + "amount": "6000000", + "expiration": "1893456000", + "nonce": "5" + }, + { + "token": "0x514910771AF9Ca656af840dff83E8264EcF986CA", + "amount": "7000000", + "expiration": "1893456000", + "nonce": "6" + }, + { + "token": "0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9", + "amount": "8000000", + "expiration": "1893456000", + "nonce": "7" + }, + { + "token": "0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2", + "amount": "9000000", + "expiration": "1893456000", + "nonce": "8" + }, + { + "token": "0xc00e94Cb662C3520282E6f5717214004A7f26888", + "amount": "10000000", + "expiration": "1893456000", + "nonce": "9" + }, + { + "token": "0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F", + "amount": "11000000", + "expiration": "1893456000", + "nonce": "10" + }, + { + "token": "0xD533a949740bb3306d119CC777fa900bA034cd52", + "amount": "12000000", + "expiration": "1893456000", + "nonce": "11" + }, + { + "token": "0x5A98FcBEA516Cf06857215779Fd812CA3beF1B32", + "amount": "13000000", + "expiration": "1893456000", + "nonce": "12" + }, + { + "token": "0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0", + "amount": "14000000", + "expiration": "1893456000", + "nonce": "13" + }, + { + "token": "0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE", + "amount": "15000000", + "expiration": "1893456000", + "nonce": "14" + }, + { + "token": "0x4d224452801ACEd8B2F0aebE155379bb5D594381", + "amount": "16000000", + "expiration": "1893456000", + "nonce": "15" + }, + { + "token": "0xC18360217D8F7Ab5e7c516566761Ea12Ce7F9D72", + "amount": "17000000", + "expiration": "1893456000", + "nonce": "16" + }, + { + "token": "0x111111111117dC0aa78b770fA6A738034120C302", + "amount": "18000000", + "expiration": "1893456000", + "nonce": "17" + }, + { + "token": "0x6B3595068778DD592e39A122f4f5a5cF09C90fE2", + "amount": "19000000", + "expiration": "1893456000", + "nonce": "18" + }, + { + "token": "0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e", + "amount": "20000000", + "expiration": "1893456000", + "nonce": "19" + }, + { + "token": "0xba100000625a3754423978a60c9317c58a424e3D", + "amount": "21000000", + "expiration": "1893456000", + "nonce": "20" + }, + { + "token": "0xc944E90C64B2c07662A292be6244BDf05Cda44a7", + "amount": "22000000", + "expiration": "1893456000", + "nonce": "21" + }, + { + "token": "0xD33526068D116cE69F19A9ee46F0bd304F21A51f", + "amount": "23000000", + "expiration": "1893456000", + "nonce": "22" + }, + { + "token": "0x853d955aCEf822Db058eb8505911ED77F175b99e", + "amount": "24000000", + "expiration": "1893456000", + "nonce": "23" + }, + { + "token": "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84", + "amount": "25000000", + "expiration": "1893456000", + "nonce": "24" + }, + { + "token": "0xae78736Cd615f374D3085123A210448E74Fc6393", + "amount": "26000000", + "expiration": "1893456000", + "nonce": "25" + }, + { + "token": "0xBe9895146f7AF43049ca1c1AE358B0541Ea49704", + "amount": "27000000", + "expiration": "1893456000", + "nonce": "26" + }, + { + "token": "0x6982508145454Ce325dDbE47a25d4ec3d2311933", + "amount": "28000000", + "expiration": "1893456000", + "nonce": "27" + }, + { + "token": "0xB50721BCf8d664c30412Cfbc6cf7a15145234ad1", + "amount": "29000000", + "expiration": "1893456000", + "nonce": "28" + }, + { + "token": "0x5283D291DBCF85356A21bA090E6db59121208b44", + "amount": "30000000", + "expiration": "1893456000", + "nonce": "29" + }, + { + "token": "0x92D6C1e31e14520e676a687F0a93788B716BEff5", + "amount": "31000000", + "expiration": "1893456000", + "nonce": "30" + }, + { + "token": "0x3432B6A60D23Ca0dFCa7761B7ab56459D9C964D0", + "amount": "32000000", + "expiration": "1893456000", + "nonce": "31" + } + ], + "spender": "0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD", + "sigDeadline": "1775803746" + } + }, + "expected": { + "domain_separator": "866a5aba21966af95d6c7ab78eb2b2fc913915c28be3b9aa07cc04ff903e3f28", + "message_hash": "26ac74547827726b6c9b707bd325892b633aaef21046c2f12937a075a47fe852", + "digest": "a85ffbece1abfb51170f9d17e6e63ed14b6a5e8ee6b6b39054fe5b8153a9f76a" + } + }, + { + "id": "permit2-PermitTransferFrom", + "source": [ + "https://github.com/Uniswap/permit2/blob/cc56ad0f3439c502c246fc5cfcc3db92bb8b7219/src/libraries/PermitHash.sol" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "PermitTransferFrom": [ + { + "name": "permitted", + "type": "TokenPermissions" + }, + { + "name": "spender", + "type": "address" + }, + { + "name": "nonce", + "type": "uint256" + }, + { + "name": "deadline", + "type": "uint256" + } + ], + "TokenPermissions": [ + { + "name": "token", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ] + }, + "primaryType": "PermitTransferFrom", + "domain": { + "name": "Permit2", + "chainId": 1, + "verifyingContract": "0x000000000022D473030F116dDEE9F6B43aC78BA3" + }, + "message": { + "permitted": { + "token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "amount": "250000000" + }, + "spender": "0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD", + "nonce": "1997", + "deadline": "1775803746" + } + }, + "expected": { + "domain_separator": "866a5aba21966af95d6c7ab78eb2b2fc913915c28be3b9aa07cc04ff903e3f28", + "message_hash": "a72b11929a9c4bff37f00eb63b3615519e00a8aa297140855c44cfff4da27146", + "digest": "ece4ce2c0d6c3f27171599e51e0b42287645bb3029f07ef9671ddca458007d5e" + } + }, + { + "id": "permit2-PermitBatchTransferFrom", + "source": [ + "https://github.com/Uniswap/permit2/blob/cc56ad0f3439c502c246fc5cfcc3db92bb8b7219/src/libraries/PermitHash.sol" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "PermitBatchTransferFrom": [ + { + "name": "permitted", + "type": "TokenPermissions[]" + }, + { + "name": "spender", + "type": "address" + }, + { + "name": "nonce", + "type": "uint256" + }, + { + "name": "deadline", + "type": "uint256" + } + ], + "TokenPermissions": [ + { + "name": "token", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ] + }, + "primaryType": "PermitBatchTransferFrom", + "domain": { + "name": "Permit2", + "chainId": 1, + "verifyingContract": "0x000000000022D473030F116dDEE9F6B43aC78BA3" + }, + "message": { + "permitted": [ + { + "token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "amount": "1000000" + }, + { + "token": "0x6B175474E89094C44Da98b954EedeAC495271d0F", + "amount": "10000000" + }, + { + "token": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "amount": "100000000" + }, + { + "token": "0xdAC17F958D2ee523a2206206994597C13D831ec7", + "amount": "1000000000" + }, + { + "token": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", + "amount": "10000000000" + } + ], + "spender": "0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD", + "nonce": "1998", + "deadline": "1775803746" + } + }, + "expected": { + "domain_separator": "866a5aba21966af95d6c7ab78eb2b2fc913915c28be3b9aa07cc04ff903e3f28", + "message_hash": "b0347a078a3a77dee64d7c255ba56e39221a3d6c5b2375d2e89d09b28533b5ab", + "digest": "31227578aa0209aad26446c56711f4f4ad009a6befab3034ce466ad45e295090" + } + }, + { + "id": "uniswapx-ExclusiveDutchOrder", + "source": [ + "https://github.com/Uniswap/permit2/blob/cc56ad0f3439c502c246fc5cfcc3db92bb8b7219/src/libraries/PermitHash.sol", + "https://github.com/Uniswap/UniswapX/blob/eb7ce077036258b9510b42ad37aa920cf3aaf308/src/lib/ExclusiveDutchOrderLib.sol", + "https://github.com/Uniswap/UniswapX/blob/eb7ce077036258b9510b42ad37aa920cf3aaf308/src/lib/OrderInfoLib.sol", + "https://github.com/Uniswap/UniswapX/blob/eb7ce077036258b9510b42ad37aa920cf3aaf308/src/lib/DutchOrderLib.sol" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "PermitWitnessTransferFrom": [ + { + "name": "permitted", + "type": "TokenPermissions" + }, + { + "name": "spender", + "type": "address" + }, + { + "name": "nonce", + "type": "uint256" + }, + { + "name": "deadline", + "type": "uint256" + }, + { + "name": "witness", + "type": "ExclusiveDutchOrder" + } + ], + "DutchOutput": [ + { + "name": "token", + "type": "address" + }, + { + "name": "startAmount", + "type": "uint256" + }, + { + "name": "endAmount", + "type": "uint256" + }, + { + "name": "recipient", + "type": "address" + } + ], + "ExclusiveDutchOrder": [ + { + "name": "info", + "type": "OrderInfo" + }, + { + "name": "decayStartTime", + "type": "uint256" + }, + { + "name": "decayEndTime", + "type": "uint256" + }, + { + "name": "exclusiveFiller", + "type": "address" + }, + { + "name": "exclusivityOverrideBps", + "type": "uint256" + }, + { + "name": "inputToken", + "type": "address" + }, + { + "name": "inputStartAmount", + "type": "uint256" + }, + { + "name": "inputEndAmount", + "type": "uint256" + }, + { + "name": "outputs", + "type": "DutchOutput[]" + } + ], + "OrderInfo": [ + { + "name": "reactor", + "type": "address" + }, + { + "name": "swapper", + "type": "address" + }, + { + "name": "nonce", + "type": "uint256" + }, + { + "name": "deadline", + "type": "uint256" + }, + { + "name": "additionalValidationContract", + "type": "address" + }, + { + "name": "additionalValidationData", + "type": "bytes" + } + ], + "TokenPermissions": [ + { + "name": "token", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ] + }, + "primaryType": "PermitWitnessTransferFrom", + "domain": { + "name": "Permit2", + "chainId": 1, + "verifyingContract": "0x000000000022D473030F116dDEE9F6B43aC78BA3" + }, + "message": { + "permitted": { + "token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "amount": "3500000000" + }, + "spender": "0x6000da47483062A0D734Ba3dc7576Ce6A0B645C4", + "nonce": "1993353164669688581970088190602701610056397261180510327052393484288", + "deadline": "1775803746", + "witness": { + "info": { + "reactor": "0x6000da47483062A0D734Ba3dc7576Ce6A0B645C4", + "swapper": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", + "nonce": "1993353164669688581970088190602701610056397261180510327052393484288", + "deadline": "1775803746", + "additionalValidationContract": "0x0000000000000000000000000000000000000000", + "additionalValidationData": "0x" + }, + "decayStartTime": "1775803680", + "decayEndTime": "1775803740", + "exclusiveFiller": "0xff8ba4d1fc3762f6154cc942ccf30049a2a0cec6", + "exclusivityOverrideBps": "100", + "inputToken": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "inputStartAmount": "3500000000", + "inputEndAmount": "3500000000", + "outputs": [ + { + "token": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "startAmount": "1000000000000000000", + "endAmount": "990000000000000000", + "recipient": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94" + }, + { + "token": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "startAmount": "1500000000000000", + "endAmount": "1485000000000000", + "recipient": "0x27213E28D7fDA5c57Fe9e5dD923818DBCcf71c47" + } + ] + } + } + }, + "expected": { + "domain_separator": "866a5aba21966af95d6c7ab78eb2b2fc913915c28be3b9aa07cc04ff903e3f28", + "message_hash": "9d5278e60026d517ef5795ddfa37fdbb3c45bb9aa1428e1100420191c4d582bf", + "digest": "5def1fbddaf0631deb17c013e1778be8a134da1e4f4ce1ed070479f12e4cdc67" + } + }, + { + "id": "uniswapx-V2DutchOrder", + "source": [ + "https://github.com/Uniswap/permit2/blob/cc56ad0f3439c502c246fc5cfcc3db92bb8b7219/src/libraries/PermitHash.sol", + "https://github.com/Uniswap/UniswapX/blob/eb7ce077036258b9510b42ad37aa920cf3aaf308/src/lib/V2DutchOrderLib.sol", + "https://github.com/Uniswap/UniswapX/blob/eb7ce077036258b9510b42ad37aa920cf3aaf308/src/lib/OrderInfoLib.sol" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "PermitWitnessTransferFrom": [ + { + "name": "permitted", + "type": "TokenPermissions" + }, + { + "name": "spender", + "type": "address" + }, + { + "name": "nonce", + "type": "uint256" + }, + { + "name": "deadline", + "type": "uint256" + }, + { + "name": "witness", + "type": "V2DutchOrder" + } + ], + "DutchOutput": [ + { + "name": "token", + "type": "address" + }, + { + "name": "startAmount", + "type": "uint256" + }, + { + "name": "endAmount", + "type": "uint256" + }, + { + "name": "recipient", + "type": "address" + } + ], + "OrderInfo": [ + { + "name": "reactor", + "type": "address" + }, + { + "name": "swapper", + "type": "address" + }, + { + "name": "nonce", + "type": "uint256" + }, + { + "name": "deadline", + "type": "uint256" + }, + { + "name": "additionalValidationContract", + "type": "address" + }, + { + "name": "additionalValidationData", + "type": "bytes" + } + ], + "TokenPermissions": [ + { + "name": "token", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "V2DutchOrder": [ + { + "name": "info", + "type": "OrderInfo" + }, + { + "name": "cosigner", + "type": "address" + }, + { + "name": "baseInputToken", + "type": "address" + }, + { + "name": "baseInputStartAmount", + "type": "uint256" + }, + { + "name": "baseInputEndAmount", + "type": "uint256" + }, + { + "name": "baseOutputs", + "type": "DutchOutput[]" + } + ] + }, + "primaryType": "PermitWitnessTransferFrom", + "domain": { + "name": "Permit2", + "chainId": 1, + "verifyingContract": "0x000000000022D473030F116dDEE9F6B43aC78BA3" + }, + "message": { + "permitted": { + "token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "amount": "3500000000" + }, + "spender": "0x00000011F84B9aa48e5f8aA8B9897600006289Be", + "nonce": "1993353164669688581970088190602701610056397261180510327052393484289", + "deadline": "1775803746", + "witness": { + "info": { + "reactor": "0x00000011F84B9aa48e5f8aA8B9897600006289Be", + "swapper": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", + "nonce": "1993353164669688581970088190602701610056397261180510327052393484288", + "deadline": "1775803746", + "additionalValidationContract": "0x0000000000000000000000000000000000000000", + "additionalValidationData": "0x" + }, + "cosigner": "0x4449cd34d1eb1fedcf02a1be3834ffde8e6a6180", + "baseInputToken": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "baseInputStartAmount": "3500000000", + "baseInputEndAmount": "3500000000", + "baseOutputs": [ + { + "token": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "startAmount": "1000000000000000000", + "endAmount": "990000000000000000", + "recipient": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94" + }, + { + "token": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "startAmount": "1500000000000000", + "endAmount": "1485000000000000", + "recipient": "0x27213E28D7fDA5c57Fe9e5dD923818DBCcf71c47" + } + ] + } + } + }, + "expected": { + "domain_separator": "866a5aba21966af95d6c7ab78eb2b2fc913915c28be3b9aa07cc04ff903e3f28", + "message_hash": "1d895c005457e7cdee8450d706c53a359a4176c12dd4d48f9e38339160809b83", + "digest": "7cc7576f193542ecfbed9254ff7785c3aa296d2382d317858aa13d87dd24d652" + } + }, + { + "id": "uniswapx-PriorityOrder", + "source": [ + "https://github.com/Uniswap/permit2/blob/cc56ad0f3439c502c246fc5cfcc3db92bb8b7219/src/libraries/PermitHash.sol", + "https://github.com/Uniswap/UniswapX/blob/eb7ce077036258b9510b42ad37aa920cf3aaf308/src/lib/PriorityOrderLib.sol", + "https://github.com/Uniswap/UniswapX/blob/eb7ce077036258b9510b42ad37aa920cf3aaf308/src/lib/OrderInfoLib.sol" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "PermitWitnessTransferFrom": [ + { + "name": "permitted", + "type": "TokenPermissions" + }, + { + "name": "spender", + "type": "address" + }, + { + "name": "nonce", + "type": "uint256" + }, + { + "name": "deadline", + "type": "uint256" + }, + { + "name": "witness", + "type": "PriorityOrder" + } + ], + "OrderInfo": [ + { + "name": "reactor", + "type": "address" + }, + { + "name": "swapper", + "type": "address" + }, + { + "name": "nonce", + "type": "uint256" + }, + { + "name": "deadline", + "type": "uint256" + }, + { + "name": "additionalValidationContract", + "type": "address" + }, + { + "name": "additionalValidationData", + "type": "bytes" + } + ], + "PriorityInput": [ + { + "name": "token", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + }, + { + "name": "mpsPerPriorityFeeWei", + "type": "uint256" + } + ], + "PriorityOrder": [ + { + "name": "info", + "type": "OrderInfo" + }, + { + "name": "cosigner", + "type": "address" + }, + { + "name": "auctionStartBlock", + "type": "uint256" + }, + { + "name": "baselinePriorityFeeWei", + "type": "uint256" + }, + { + "name": "input", + "type": "PriorityInput" + }, + { + "name": "outputs", + "type": "PriorityOutput[]" + } + ], + "PriorityOutput": [ + { + "name": "token", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + }, + { + "name": "mpsPerPriorityFeeWei", + "type": "uint256" + }, + { + "name": "recipient", + "type": "address" + } + ], + "TokenPermissions": [ + { + "name": "token", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ] + }, + "primaryType": "PermitWitnessTransferFrom", + "domain": { + "name": "Permit2", + "chainId": 8453, + "verifyingContract": "0x000000000022D473030F116dDEE9F6B43aC78BA3" + }, + "message": { + "permitted": { + "token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + "amount": "100000000" + }, + "spender": "0x0000000000fbd5e2a41b6d0f3b0fe9ed9b2d0cc9", + "nonce": "1993353164669688581970088190602701610056397261180510327052393484290", + "deadline": "1775803746", + "witness": { + "info": { + "reactor": "0x0000000000fbd5e2a41b6d0f3b0fe9ed9b2d0cc9", + "swapper": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", + "nonce": "1993353164669688581970088190602701610056397261180510327052393484288", + "deadline": "1775803746", + "additionalValidationContract": "0x0000000000000000000000000000000000000000", + "additionalValidationData": "0x" + }, + "cosigner": "0x0000000000000000000000000000000000000000", + "auctionStartBlock": "24000000", + "baselinePriorityFeeWei": "0", + "input": { + "token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + "amount": "100000000", + "mpsPerPriorityFeeWei": "0" + }, + "outputs": [ + { + "token": "0x4200000000000000000000000000000000000006", + "amount": "28000000000000000", + "mpsPerPriorityFeeWei": "1", + "recipient": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94" + }, + { + "token": "0x4200000000000000000000000000000000000006", + "amount": "42000000000000", + "mpsPerPriorityFeeWei": "0", + "recipient": "0x7FFC3DBF3B2b50Ff3A1D5523bc24Bb5043837B14" + } + ] + } + } + }, + "expected": { + "domain_separator": "3b6f35e4fce979ef8eac3bcdc8c3fc38fe7911bb0c69c8fe72bf1fd1a17e6f07", + "message_hash": "a641126490de075257de4fc0b0ade25f8fa4bfc12858d49bb388cdcf34fd0c78", + "digest": "c7b4e513709348a52a6b13dea66c18975713be646ec021d9d62fb632874c7eb5" + } + }, + { + "id": "seaport-OrderComponents", + "source": [ + "https://github.com/ProjectOpenSea/seaport-core/blob/523097f9cee66c15d308c900c50f336b291cda08/src/lib/ConsiderationBase.sol" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "OrderComponents": [ + { + "name": "offerer", + "type": "address" + }, + { + "name": "zone", + "type": "address" + }, + { + "name": "offer", + "type": "OfferItem[]" + }, + { + "name": "consideration", + "type": "ConsiderationItem[]" + }, + { + "name": "orderType", + "type": "uint8" + }, + { + "name": "startTime", + "type": "uint256" + }, + { + "name": "endTime", + "type": "uint256" + }, + { + "name": "zoneHash", + "type": "bytes32" + }, + { + "name": "salt", + "type": "uint256" + }, + { + "name": "conduitKey", + "type": "bytes32" + }, + { + "name": "counter", + "type": "uint256" + } + ], + "ConsiderationItem": [ + { + "name": "itemType", + "type": "uint8" + }, + { + "name": "token", + "type": "address" + }, + { + "name": "identifierOrCriteria", + "type": "uint256" + }, + { + "name": "startAmount", + "type": "uint256" + }, + { + "name": "endAmount", + "type": "uint256" + }, + { + "name": "recipient", + "type": "address" + } + ], + "OfferItem": [ + { + "name": "itemType", + "type": "uint8" + }, + { + "name": "token", + "type": "address" + }, + { + "name": "identifierOrCriteria", + "type": "uint256" + }, + { + "name": "startAmount", + "type": "uint256" + }, + { + "name": "endAmount", + "type": "uint256" + } + ] + }, + "primaryType": "OrderComponents", + "domain": { + "name": "Seaport", + "version": "1.6", + "chainId": 1, + "verifyingContract": "0x0000000000000068F116a894984e2DB1123eB395" + }, + "message": { + "offerer": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", + "zone": "0x0000000000000000000000000000000000000000", + "offer": [ + { + "itemType": 2, + "token": "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D", + "identifierOrCriteria": "8520", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D", + "identifierOrCriteria": "8521", + "startAmount": "1", + "endAmount": "1" + } + ], + "consideration": [ + { + "itemType": 0, + "token": "0x0000000000000000000000000000000000000000", + "identifierOrCriteria": "0", + "startAmount": "19500000000000000000", + "endAmount": "19500000000000000000", + "recipient": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94" + }, + { + "itemType": 0, + "token": "0x0000000000000000000000000000000000000000", + "identifierOrCriteria": "0", + "startAmount": "500000000000000000", + "endAmount": "500000000000000000", + "recipient": "0x0000a26b00c1F0DF003000390027140000fAa719" + }, + { + "itemType": 0, + "token": "0x0000000000000000000000000000000000000000", + "identifierOrCriteria": "0", + "startAmount": "1000000000000000000", + "endAmount": "1000000000000000000", + "recipient": "0xA858DDc0445d8131daC4d1DE01f834ffcbA52Ef1" + } + ], + "orderType": 0, + "startTime": "1775700000", + "endTime": "1778300000", + "zoneHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "salt": "24446860302761739304752683030156737591518664810215442929818227897836383814680", + "conduitKey": "0x0000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f0000", + "counter": "0" + } + }, + "expected": { + "domain_separator": "fce34bc6e1752c1117e5063116d25cad2fa2bdcf15ff2d2e275eece7dc31ba64", + "message_hash": "5bdedde642e259a1841ef18afaf47285be8da69b311260a27436eba16517c016", + "digest": "b6f6cd11f7cd0e8f8ed8964727b57e23d38680ad2d818d3a87b551e4762a1f69" + } + }, + { + "id": "seaport-OrderComponents-bundle-10x6", + "source": [ + "https://github.com/ProjectOpenSea/seaport-core/blob/523097f9cee66c15d308c900c50f336b291cda08/src/lib/ConsiderationBase.sol" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "OrderComponents": [ + { + "name": "offerer", + "type": "address" + }, + { + "name": "zone", + "type": "address" + }, + { + "name": "offer", + "type": "OfferItem[]" + }, + { + "name": "consideration", + "type": "ConsiderationItem[]" + }, + { + "name": "orderType", + "type": "uint8" + }, + { + "name": "startTime", + "type": "uint256" + }, + { + "name": "endTime", + "type": "uint256" + }, + { + "name": "zoneHash", + "type": "bytes32" + }, + { + "name": "salt", + "type": "uint256" + }, + { + "name": "conduitKey", + "type": "bytes32" + }, + { + "name": "counter", + "type": "uint256" + } + ], + "ConsiderationItem": [ + { + "name": "itemType", + "type": "uint8" + }, + { + "name": "token", + "type": "address" + }, + { + "name": "identifierOrCriteria", + "type": "uint256" + }, + { + "name": "startAmount", + "type": "uint256" + }, + { + "name": "endAmount", + "type": "uint256" + }, + { + "name": "recipient", + "type": "address" + } + ], + "OfferItem": [ + { + "name": "itemType", + "type": "uint8" + }, + { + "name": "token", + "type": "address" + }, + { + "name": "identifierOrCriteria", + "type": "uint256" + }, + { + "name": "startAmount", + "type": "uint256" + }, + { + "name": "endAmount", + "type": "uint256" + } + ] + }, + "primaryType": "OrderComponents", + "domain": { + "name": "Seaport", + "version": "1.6", + "chainId": 1, + "verifyingContract": "0x0000000000000068F116a894984e2DB1123eB395" + }, + "message": { + "offerer": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", + "zone": "0x0000000000000000000000000000000000000000", + "offer": [ + { + "itemType": 2, + "token": "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D", + "identifierOrCriteria": "8520", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D", + "identifierOrCriteria": "8521", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D", + "identifierOrCriteria": "8522", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xED5AF388653567Af2F388E6224dC7C4b3241C544", + "identifierOrCriteria": "4100", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xED5AF388653567Af2F388E6224dC7C4b3241C544", + "identifierOrCriteria": "4101", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xED5AF388653567Af2F388E6224dC7C4b3241C544", + "identifierOrCriteria": "4102", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0x8a90CAb2b38dba80c64b7734e58Ee1dB38B8992e", + "identifierOrCriteria": "700", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0x8a90CAb2b38dba80c64b7734e58Ee1dB38B8992e", + "identifierOrCriteria": "701", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "3300", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "3301", + "startAmount": "1", + "endAmount": "1" + } + ], + "consideration": [ + { + "itemType": 0, + "token": "0x0000000000000000000000000000000000000000", + "identifierOrCriteria": "0", + "startAmount": "118500000000000000000", + "endAmount": "118500000000000000000", + "recipient": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94" + }, + { + "itemType": 0, + "token": "0x0000000000000000000000000000000000000000", + "identifierOrCriteria": "0", + "startAmount": "625000000000000000", + "endAmount": "625000000000000000", + "recipient": "0x0000a26b00c1F0DF003000390027140000fAa719" + }, + { + "itemType": 0, + "token": "0x0000000000000000000000000000000000000000", + "identifierOrCriteria": "0", + "startAmount": "2400000000000000000", + "endAmount": "2400000000000000000", + "recipient": "0x00000000000000000000000000000000a11cE000" + }, + { + "itemType": 0, + "token": "0x0000000000000000000000000000000000000000", + "identifierOrCriteria": "0", + "startAmount": "1800000000000000000", + "endAmount": "1800000000000000000", + "recipient": "0x00000000000000000000000000000000A11ce001" + }, + { + "itemType": 0, + "token": "0x0000000000000000000000000000000000000000", + "identifierOrCriteria": "0", + "startAmount": "1500000000000000000", + "endAmount": "1500000000000000000", + "recipient": "0x00000000000000000000000000000000a11CE002" + }, + { + "itemType": 0, + "token": "0x0000000000000000000000000000000000000000", + "identifierOrCriteria": "0", + "startAmount": "1175000000000000000", + "endAmount": "1175000000000000000", + "recipient": "0x00000000000000000000000000000000A11ce003" + } + ], + "orderType": 0, + "startTime": "1775700000", + "endTime": "1778300000", + "zoneHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "salt": "24446860302761739304752683030156737591518664810215442929818227897836383814680", + "conduitKey": "0x0000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f0000", + "counter": "0" + } + }, + "expected": { + "domain_separator": "fce34bc6e1752c1117e5063116d25cad2fa2bdcf15ff2d2e275eece7dc31ba64", + "message_hash": "777e35ac429840a63b28d70ae83c7d0917f2c287fc0cf8fe659d2527510b93b1", + "digest": "af42126e4b5bfe74494b27766b259c698ba314a928d06ac1633b5ca1cf3e5e30" + } + }, + { + "id": "seaport-OrderComponents-consideration-12", + "source": [ + "https://github.com/ProjectOpenSea/seaport-core/blob/523097f9cee66c15d308c900c50f336b291cda08/src/lib/ConsiderationBase.sol" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "OrderComponents": [ + { + "name": "offerer", + "type": "address" + }, + { + "name": "zone", + "type": "address" + }, + { + "name": "offer", + "type": "OfferItem[]" + }, + { + "name": "consideration", + "type": "ConsiderationItem[]" + }, + { + "name": "orderType", + "type": "uint8" + }, + { + "name": "startTime", + "type": "uint256" + }, + { + "name": "endTime", + "type": "uint256" + }, + { + "name": "zoneHash", + "type": "bytes32" + }, + { + "name": "salt", + "type": "uint256" + }, + { + "name": "conduitKey", + "type": "bytes32" + }, + { + "name": "counter", + "type": "uint256" + } + ], + "ConsiderationItem": [ + { + "name": "itemType", + "type": "uint8" + }, + { + "name": "token", + "type": "address" + }, + { + "name": "identifierOrCriteria", + "type": "uint256" + }, + { + "name": "startAmount", + "type": "uint256" + }, + { + "name": "endAmount", + "type": "uint256" + }, + { + "name": "recipient", + "type": "address" + } + ], + "OfferItem": [ + { + "name": "itemType", + "type": "uint8" + }, + { + "name": "token", + "type": "address" + }, + { + "name": "identifierOrCriteria", + "type": "uint256" + }, + { + "name": "startAmount", + "type": "uint256" + }, + { + "name": "endAmount", + "type": "uint256" + } + ] + }, + "primaryType": "OrderComponents", + "domain": { + "name": "Seaport", + "version": "1.6", + "chainId": 1, + "verifyingContract": "0x0000000000000068F116a894984e2DB1123eB395" + }, + "message": { + "offerer": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", + "zone": "0x0000000000000000000000000000000000000000", + "offer": [ + { + "itemType": 2, + "token": "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D", + "identifierOrCriteria": "9001", + "startAmount": "1", + "endAmount": "1" + } + ], + "consideration": [ + { + "itemType": 0, + "token": "0x0000000000000000000000000000000000000000", + "identifierOrCriteria": "0", + "startAmount": "15000000000000000000", + "endAmount": "15000000000000000000", + "recipient": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94" + }, + { + "itemType": 0, + "token": "0x0000000000000000000000000000000000000000", + "identifierOrCriteria": "0", + "startAmount": "100000000000000000", + "endAmount": "100000000000000000", + "recipient": "0x0000a26b00c1F0DF003000390027140000fAa719" + }, + { + "itemType": 0, + "token": "0x0000000000000000000000000000000000000000", + "identifierOrCriteria": "0", + "startAmount": "50000000000000000", + "endAmount": "50000000000000000", + "recipient": "0x0000000000000000000000000000000005B11700" + }, + { + "itemType": 0, + "token": "0x0000000000000000000000000000000000000000", + "identifierOrCriteria": "0", + "startAmount": "100000000000000000", + "endAmount": "100000000000000000", + "recipient": "0x0000000000000000000000000000000005B11701" + }, + { + "itemType": 0, + "token": "0x0000000000000000000000000000000000000000", + "identifierOrCriteria": "0", + "startAmount": "150000000000000000", + "endAmount": "150000000000000000", + "recipient": "0x0000000000000000000000000000000005b11702" + }, + { + "itemType": 0, + "token": "0x0000000000000000000000000000000000000000", + "identifierOrCriteria": "0", + "startAmount": "200000000000000000", + "endAmount": "200000000000000000", + "recipient": "0x0000000000000000000000000000000005B11703" + }, + { + "itemType": 0, + "token": "0x0000000000000000000000000000000000000000", + "identifierOrCriteria": "0", + "startAmount": "250000000000000000", + "endAmount": "250000000000000000", + "recipient": "0x0000000000000000000000000000000005b11704" + }, + { + "itemType": 0, + "token": "0x0000000000000000000000000000000000000000", + "identifierOrCriteria": "0", + "startAmount": "300000000000000000", + "endAmount": "300000000000000000", + "recipient": "0x0000000000000000000000000000000005b11705" + }, + { + "itemType": 0, + "token": "0x0000000000000000000000000000000000000000", + "identifierOrCriteria": "0", + "startAmount": "350000000000000000", + "endAmount": "350000000000000000", + "recipient": "0x0000000000000000000000000000000005B11706" + }, + { + "itemType": 0, + "token": "0x0000000000000000000000000000000000000000", + "identifierOrCriteria": "0", + "startAmount": "400000000000000000", + "endAmount": "400000000000000000", + "recipient": "0x0000000000000000000000000000000005b11707" + }, + { + "itemType": 0, + "token": "0x0000000000000000000000000000000000000000", + "identifierOrCriteria": "0", + "startAmount": "450000000000000000", + "endAmount": "450000000000000000", + "recipient": "0x0000000000000000000000000000000005b11708" + }, + { + "itemType": 0, + "token": "0x0000000000000000000000000000000000000000", + "identifierOrCriteria": "0", + "startAmount": "500000000000000000", + "endAmount": "500000000000000000", + "recipient": "0x0000000000000000000000000000000005b11709" + } + ], + "orderType": 0, + "startTime": "1775700000", + "endTime": "1778300000", + "zoneHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "salt": "24446860302761739304752683030156737591518664810215442929818227897836383814680", + "conduitKey": "0x0000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f0000", + "counter": "0" + } + }, + "expected": { + "domain_separator": "fce34bc6e1752c1117e5063116d25cad2fa2bdcf15ff2d2e275eece7dc31ba64", + "message_hash": "66e666071d1faf7d9f74130449bf619b95c9f52fd04eb7a435903319e8afaa20", + "digest": "bfb6130599bda35f4a32de5ec2c1f65d5024bae151657ad3445fd0042fb0f844" + } + }, + { + "id": "seaport-OrderComponents-bundle-32", + "source": [ + "https://github.com/ProjectOpenSea/seaport-core/blob/523097f9cee66c15d308c900c50f336b291cda08/src/lib/ConsiderationBase.sol" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "OrderComponents": [ + { + "name": "offerer", + "type": "address" + }, + { + "name": "zone", + "type": "address" + }, + { + "name": "offer", + "type": "OfferItem[]" + }, + { + "name": "consideration", + "type": "ConsiderationItem[]" + }, + { + "name": "orderType", + "type": "uint8" + }, + { + "name": "startTime", + "type": "uint256" + }, + { + "name": "endTime", + "type": "uint256" + }, + { + "name": "zoneHash", + "type": "bytes32" + }, + { + "name": "salt", + "type": "uint256" + }, + { + "name": "conduitKey", + "type": "bytes32" + }, + { + "name": "counter", + "type": "uint256" + } + ], + "ConsiderationItem": [ + { + "name": "itemType", + "type": "uint8" + }, + { + "name": "token", + "type": "address" + }, + { + "name": "identifierOrCriteria", + "type": "uint256" + }, + { + "name": "startAmount", + "type": "uint256" + }, + { + "name": "endAmount", + "type": "uint256" + }, + { + "name": "recipient", + "type": "address" + } + ], + "OfferItem": [ + { + "name": "itemType", + "type": "uint8" + }, + { + "name": "token", + "type": "address" + }, + { + "name": "identifierOrCriteria", + "type": "uint256" + }, + { + "name": "startAmount", + "type": "uint256" + }, + { + "name": "endAmount", + "type": "uint256" + } + ] + }, + "primaryType": "OrderComponents", + "domain": { + "name": "Seaport", + "version": "1.6", + "chainId": 1, + "verifyingContract": "0x0000000000000068F116a894984e2DB1123eB395" + }, + "message": { + "offerer": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", + "zone": "0x0000000000000000000000000000000000000000", + "offer": [ + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "5000", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "5001", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "5002", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "5003", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "5004", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "5005", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "5006", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "5007", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "5008", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "5009", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "5010", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "5011", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "5012", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "5013", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "5014", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "5015", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "5016", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "5017", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "5018", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "5019", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "5020", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "5021", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "5022", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "5023", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "5024", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "5025", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "5026", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "5027", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "5028", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "5029", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "5030", + "startAmount": "1", + "endAmount": "1" + }, + { + "itemType": 2, + "token": "0xBd3531dA5CF5857e7CfAA92426877b022e612cf8", + "identifierOrCriteria": "5031", + "startAmount": "1", + "endAmount": "1" + } + ], + "consideration": [ + { + "itemType": 0, + "token": "0x0000000000000000000000000000000000000000", + "identifierOrCriteria": "0", + "startAmount": "320000000000000000000", + "endAmount": "320000000000000000000", + "recipient": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94" + }, + { + "itemType": 0, + "token": "0x0000000000000000000000000000000000000000", + "identifierOrCriteria": "0", + "startAmount": "1600000000000000000", + "endAmount": "1600000000000000000", + "recipient": "0x0000a26b00c1F0DF003000390027140000fAa719" + } + ], + "orderType": 0, + "startTime": "1775700000", + "endTime": "1778300000", + "zoneHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "salt": "24446860302761739304752683030156737591518664810215442929818227897836383814680", + "conduitKey": "0x0000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f0000", + "counter": "0" + } + }, + "expected": { + "domain_separator": "fce34bc6e1752c1117e5063116d25cad2fa2bdcf15ff2d2e275eece7dc31ba64", + "message_hash": "b3b1ba0d3e233fb87c9d866c87b2ef5b77e85b80d64f1ba9b2e3d9dc98a14402", + "digest": "8f9f180ebb10f7799149df0dbdcf11edc50f7f3cce4e5b2c742a142f286c5ee0" + } + }, + { + "id": "looksrare-Maker", + "source": [ + "https://github.com/LooksRare/contracts-exchange-v2/blob/7fca5650da653a2a0680e18e60164e639c18f830/contracts/libraries/OrderStructs.sol" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Maker": [ + { + "name": "quoteType", + "type": "uint8" + }, + { + "name": "globalNonce", + "type": "uint256" + }, + { + "name": "subsetNonce", + "type": "uint256" + }, + { + "name": "orderNonce", + "type": "uint256" + }, + { + "name": "strategyId", + "type": "uint256" + }, + { + "name": "collectionType", + "type": "uint8" + }, + { + "name": "collection", + "type": "address" + }, + { + "name": "currency", + "type": "address" + }, + { + "name": "signer", + "type": "address" + }, + { + "name": "startTime", + "type": "uint256" + }, + { + "name": "endTime", + "type": "uint256" + }, + { + "name": "price", + "type": "uint256" + }, + { + "name": "itemIds", + "type": "uint256[]" + }, + { + "name": "amounts", + "type": "uint256[]" + }, + { + "name": "additionalParameters", + "type": "bytes" + } + ] + }, + "primaryType": "Maker", + "domain": { + "name": "LooksRareProtocol", + "version": "2", + "chainId": 1, + "verifyingContract": "0x0000000000E655fAe4d56241588680F86E3b2377" + }, + "message": { + "quoteType": 1, + "globalNonce": "0", + "subsetNonce": "0", + "orderNonce": "7", + "strategyId": "0", + "collectionType": 0, + "collection": "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D", + "currency": "0x0000000000000000000000000000000000000000", + "signer": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", + "startTime": "1775700000", + "endTime": "1778300000", + "price": "21000000000000000000", + "itemIds": [ + "8520", + "8521" + ], + "amounts": [ + "1", + "1" + ], + "additionalParameters": "0x" + } + }, + "expected": { + "domain_separator": "13be80cb8c4239588caab638256c555b825f3fbead883414b042fd375781040c", + "message_hash": "f66521e3a0d0416b42e738575d0e63db76241755e1d097629aa2e5f17927513c", + "digest": "c63794a61c6b972160381131e7d63b7d3a695f512248b9e061327c85d10e9004" + } + }, + { + "id": "blur-Order", + "source": [ + "https://github.com/code-423n4/2022-10-blur/blob/main/contracts/lib/EIP712.sol" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Order": [ + { + "name": "trader", + "type": "address" + }, + { + "name": "side", + "type": "uint8" + }, + { + "name": "matchingPolicy", + "type": "address" + }, + { + "name": "collection", + "type": "address" + }, + { + "name": "tokenId", + "type": "uint256" + }, + { + "name": "amount", + "type": "uint256" + }, + { + "name": "paymentToken", + "type": "address" + }, + { + "name": "price", + "type": "uint256" + }, + { + "name": "listingTime", + "type": "uint256" + }, + { + "name": "expirationTime", + "type": "uint256" + }, + { + "name": "fees", + "type": "Fee[]" + }, + { + "name": "salt", + "type": "uint256" + }, + { + "name": "extraParams", + "type": "bytes" + }, + { + "name": "nonce", + "type": "uint256" + } + ], + "Fee": [ + { + "name": "rate", + "type": "uint16" + }, + { + "name": "recipient", + "type": "address" + } + ] + }, + "primaryType": "Order", + "domain": { + "name": "Blur Exchange", + "version": "1.0", + "chainId": 1, + "verifyingContract": "0x000000000000Ad05Ccc4F10045630fb830B95127" + }, + "message": { + "trader": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", + "side": 1, + "matchingPolicy": "0x00000000006411739DA1c40B106F8511de5D1FAC", + "collection": "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D", + "tokenId": "8520", + "amount": "1", + "paymentToken": "0x0000000000000000000000000000000000000000", + "price": "20000000000000000000", + "listingTime": "1775700000", + "expirationTime": "1778300000", + "fees": [ + { + "rate": 50, + "recipient": "0xaab1d2c1fc1c5b4e8a1de8b3fe2f5fc6e2fb86d3" + }, + { + "rate": 250, + "recipient": "0xA858DDc0445d8131daC4d1DE01f834ffcbA52Ef1" + } + ], + "salt": "265875887785256855606558013756560384533", + "extraParams": "0x01", + "nonce": "0" + } + }, + "expected": { + "domain_separator": "68e25ba9bdf16f19b7227e3ee7fff0b93558367587fc73fd50c5d978a0cd227f", + "message_hash": "c8858619b0e96f15b33b91c260c45570945ec84d5310016888785cec1252ec40", + "digest": "89424a5eaf944e4bda74c080e649e8f6bd3443a6e6b86a48e4100fc43c01a380" + } + }, + { + "id": "blur-Root", + "source": [ + "https://github.com/code-423n4/2022-10-blur/blob/main/contracts/lib/EIP712.sol" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Root": [ + { + "name": "root", + "type": "bytes32" + } + ] + }, + "primaryType": "Root", + "domain": { + "name": "Blur Exchange", + "version": "1.0", + "chainId": 1, + "verifyingContract": "0x000000000000Ad05Ccc4F10045630fb830B95127" + }, + "message": { + "root": "0x6f1c86e1ea4b8b1d9f7f0c5c2e1d6a3b4c5d6e7f8091a2b3c4d5e6f708192a3b" + } + }, + "expected": { + "domain_separator": "68e25ba9bdf16f19b7227e3ee7fff0b93558367587fc73fd50c5d978a0cd227f", + "message_hash": "aeadf10ef9755aa81ad8a3219731271fe417be9c783dc542a42d5edfb3b77317", + "digest": "6d3bc4aec615720499edd705ee6673b5f1b40a1a3afa1a8d85ac273ebc427253" + } + }, + { + "id": "1inch-Order", + "source": [ + "https://github.com/1inch/limit-order-protocol/blob/50bd1300315606a3d32e9021898374c9d0dc2335/contracts/OrderLib.sol", + "https://sourcify.dev/#/lookup/0x111111125421cA6dc452d289314280a0f8842A65" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Order": [ + { + "name": "salt", + "type": "uint256" + }, + { + "name": "maker", + "type": "address" + }, + { + "name": "receiver", + "type": "address" + }, + { + "name": "makerAsset", + "type": "address" + }, + { + "name": "takerAsset", + "type": "address" + }, + { + "name": "makingAmount", + "type": "uint256" + }, + { + "name": "takingAmount", + "type": "uint256" + }, + { + "name": "makerTraits", + "type": "uint256" + } + ] + }, + "primaryType": "Order", + "domain": { + "name": "1inch Aggregation Router", + "version": "6", + "chainId": 1, + "verifyingContract": "0x111111125421cA6dc452d289314280a0f8842A65" + }, + "message": { + "salt": "102412815611287462193218283713587453612380483585130722463424346577", + "maker": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", + "receiver": "0x0000000000000000000000000000000000000000", + "makerAsset": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "takerAsset": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "makingAmount": "1000000000000000000", + "takingAmount": "3500000000", + "makerTraits": "62419173104490761595518734106557662061518414611782227068396304425790442831872" + } + }, + "expected": { + "domain_separator": "d999e213f11c7bfa3e796c3409e316f25e02aa3e25e5c207a92e381c7d22b6de", + "message_hash": "0dfdbba222c62bc366f22ca6339e12520ce10684376c80d61176781ac00c3f4b", + "digest": "cddd12ad70f117d173e3e40ae060696c549fdc0ec98bc913083f20f6ba3163d9" + } + }, + { + "id": "cow-Order", + "source": [ + "https://github.com/cowprotocol/contracts/blob/c07a93e3596194c5e3cf331c755a3f9f0e4a17d8/src/contracts/libraries/GPv2Order.sol" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Order": [ + { + "name": "sellToken", + "type": "address" + }, + { + "name": "buyToken", + "type": "address" + }, + { + "name": "receiver", + "type": "address" + }, + { + "name": "sellAmount", + "type": "uint256" + }, + { + "name": "buyAmount", + "type": "uint256" + }, + { + "name": "validTo", + "type": "uint32" + }, + { + "name": "appData", + "type": "bytes32" + }, + { + "name": "feeAmount", + "type": "uint256" + }, + { + "name": "kind", + "type": "string" + }, + { + "name": "partiallyFillable", + "type": "bool" + }, + { + "name": "sellTokenBalance", + "type": "string" + }, + { + "name": "buyTokenBalance", + "type": "string" + } + ] + }, + "primaryType": "Order", + "domain": { + "name": "Gnosis Protocol", + "version": "v2", + "chainId": 1, + "verifyingContract": "0x9008D19f58AAbD9eD0D60971565AA8510560ab41" + }, + "message": { + "sellToken": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "buyToken": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "receiver": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", + "sellAmount": "1000000000000000000", + "buyAmount": "3480000000", + "validTo": 1775803746, + "appData": "0xf785fae7a7c5abc49f3cd6a61f6df1ff26433392b066ee9ff2240ff1eb7ab6e4", + "feeAmount": "0", + "kind": "sell", + "partiallyFillable": false, + "sellTokenBalance": "erc20", + "buyTokenBalance": "erc20" + } + }, + "expected": { + "domain_separator": "c078f884a2676e1345748b1feace7b0abee5d00ecadb6e574dcdd109a63e8943", + "message_hash": "cdc3f27a64d63d4d714edd7ac17d8ba1891d43b9743d7776cd58ad5fc4cec3a7", + "digest": "576a9e87719762457271789254f3ab5a2fa6a6bc7d20972883ac69ca076ffad8" + } + }, + { + "id": "cow-OrderCancellations", + "source": [ + "https://github.com/cowprotocol/cow-sdk/blob/8ac240cbea721a546618d3667a24c8054664d934/packages/contracts-ts/src/order.ts" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "OrderCancellations": [ + { + "name": "orderUids", + "type": "bytes[]" + } + ] + }, + "primaryType": "OrderCancellations", + "domain": { + "name": "Gnosis Protocol", + "version": "v2", + "chainId": 1, + "verifyingContract": "0x9008D19f58AAbD9eD0D60971565AA8510560ab41" + }, + "message": { + "orderUids": [ + "0xabababababababababababababababababababababababababababababababab9858effd232b4033e47d90003d41ec34ecaeda9469d89d62", + "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd9858effd232b4033e47d90003d41ec34ecaeda9469d89d63" + ] + } + }, + "expected": { + "domain_separator": "c078f884a2676e1345748b1feace7b0abee5d00ecadb6e574dcdd109a63e8943", + "message_hash": "c2db95270ee0d0e6ae186f42a5acbd1d0809010e2f83398fca5ad7fa7e7dd803", + "digest": "5898792dcf9f9d984e4d0ce6b0dc8a10ebd652e8722e944b38bad099f1a968a4" + } + }, + { + "id": "0x-LimitOrder", + "source": [ + "https://github.com/0xProject/protocol/blob/2c8e51e36ccbafa39f7c9003f4087710665acb02/contracts/zero-ex/contracts/src/features/libs/LibNativeOrder.sol" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "LimitOrder": [ + { + "name": "makerToken", + "type": "address" + }, + { + "name": "takerToken", + "type": "address" + }, + { + "name": "makerAmount", + "type": "uint128" + }, + { + "name": "takerAmount", + "type": "uint128" + }, + { + "name": "takerTokenFeeAmount", + "type": "uint128" + }, + { + "name": "maker", + "type": "address" + }, + { + "name": "taker", + "type": "address" + }, + { + "name": "sender", + "type": "address" + }, + { + "name": "feeRecipient", + "type": "address" + }, + { + "name": "pool", + "type": "bytes32" + }, + { + "name": "expiry", + "type": "uint64" + }, + { + "name": "salt", + "type": "uint256" + } + ] + }, + "primaryType": "LimitOrder", + "domain": { + "name": "ZeroEx", + "version": "1.0.0", + "chainId": 1, + "verifyingContract": "0xDef1C0ded9bec7F1a1670819833240f027b25EfF" + }, + "message": { + "makerToken": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "takerToken": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "makerAmount": "1000000000000000000", + "takerAmount": "3500000000", + "takerTokenFeeAmount": "0", + "maker": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", + "taker": "0x0000000000000000000000000000000000000000", + "sender": "0x0000000000000000000000000000000000000000", + "feeRecipient": "0x0000000000000000000000000000000000000000", + "pool": "0x0000000000000000000000000000000000000000000000000000000000000000", + "expiry": "1775803746", + "salt": "54308148374513278436071736734563213846290466613155327734536137082462373451223" + } + }, + "expected": { + "domain_separator": "fe3a8808ff7909b8c36164e6e9a076597c21c3fc2ec6f2c8ac04529c41ce507e", + "message_hash": "52eeeafb7e1db5a5dd3c0604bac947a340ea48a297fb5b4eabe88509e4bd8688", + "digest": "474fd3e0afa906ca55fd290375e08ccde65bf824e8bf85fff0c656849e713e88" + } + }, + { + "id": "0x-RfqOrder", + "source": [ + "https://github.com/0xProject/protocol/blob/2c8e51e36ccbafa39f7c9003f4087710665acb02/contracts/zero-ex/contracts/src/features/libs/LibNativeOrder.sol" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "RfqOrder": [ + { + "name": "makerToken", + "type": "address" + }, + { + "name": "takerToken", + "type": "address" + }, + { + "name": "makerAmount", + "type": "uint128" + }, + { + "name": "takerAmount", + "type": "uint128" + }, + { + "name": "maker", + "type": "address" + }, + { + "name": "taker", + "type": "address" + }, + { + "name": "txOrigin", + "type": "address" + }, + { + "name": "pool", + "type": "bytes32" + }, + { + "name": "expiry", + "type": "uint64" + }, + { + "name": "salt", + "type": "uint256" + } + ] + }, + "primaryType": "RfqOrder", + "domain": { + "name": "ZeroEx", + "version": "1.0.0", + "chainId": 1, + "verifyingContract": "0xDef1C0ded9bec7F1a1670819833240f027b25EfF" + }, + "message": { + "makerToken": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "takerToken": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "makerAmount": "3500000000", + "takerAmount": "1000000000000000000", + "maker": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", + "taker": "0x0000000000000000000000000000000000000000", + "txOrigin": "0x27213E28D7fDA5c57Fe9e5dD923818DBCcf71c47", + "pool": "0x0000000000000000000000000000000000000000000000000000000000000000", + "expiry": "1775803746", + "salt": "1775803000" + } + }, + "expected": { + "domain_separator": "fe3a8808ff7909b8c36164e6e9a076597c21c3fc2ec6f2c8ac04529c41ce507e", + "message_hash": "4fe4aaaecb08c6b07ebd5c06ba57304d9e8bf650668e51afd87c81f243578043", + "digest": "24dd6dea5cd2de49c1701d67eaf8487efdc213828d2c00a97408379a0e1fcd98" + } + }, + { + "id": "0x-OtcOrder", + "source": [ + "https://github.com/0xProject/protocol/blob/2c8e51e36ccbafa39f7c9003f4087710665acb02/contracts/zero-ex/contracts/src/features/libs/LibNativeOrder.sol" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "OtcOrder": [ + { + "name": "makerToken", + "type": "address" + }, + { + "name": "takerToken", + "type": "address" + }, + { + "name": "makerAmount", + "type": "uint128" + }, + { + "name": "takerAmount", + "type": "uint128" + }, + { + "name": "maker", + "type": "address" + }, + { + "name": "taker", + "type": "address" + }, + { + "name": "txOrigin", + "type": "address" + }, + { + "name": "expiryAndNonce", + "type": "uint256" + } + ] + }, + "primaryType": "OtcOrder", + "domain": { + "name": "ZeroEx", + "version": "1.0.0", + "chainId": 1, + "verifyingContract": "0xDef1C0ded9bec7F1a1670819833240f027b25EfF" + }, + "message": { + "makerToken": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "takerToken": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "makerAmount": "3500000000", + "takerAmount": "1000000000000000000", + "maker": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", + "taker": "0x0000000000000000000000000000000000000000", + "txOrigin": "0x27213E28D7fDA5c57Fe9e5dD923818DBCcf71c47", + "expiryAndNonce": "2724834893716958296099287542290232898829043766902734489108736" + } + }, + "expected": { + "domain_separator": "fe3a8808ff7909b8c36164e6e9a076597c21c3fc2ec6f2c8ac04529c41ce507e", + "message_hash": "c3d531dfd43da6373e92accb783b6c56e7eaa7148a88b36a0bdd4b156c73133d", + "digest": "a575e5d5eab33f2c528564d24febb5c74ad8919c25581ac9c7012f338b0590d1" + } + }, + { + "id": "safe-SafeTx", + "source": [ + "https://github.com/safe-global/safe-smart-account/blob/v1.4.1/contracts/Safe.sol", + "https://github.com/safe-global/safe-smart-account/blob/v1.3.0/contracts/GnosisSafe.sol" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "SafeTx": [ + { + "name": "to", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + }, + { + "name": "data", + "type": "bytes" + }, + { + "name": "operation", + "type": "uint8" + }, + { + "name": "safeTxGas", + "type": "uint256" + }, + { + "name": "baseGas", + "type": "uint256" + }, + { + "name": "gasPrice", + "type": "uint256" + }, + { + "name": "gasToken", + "type": "address" + }, + { + "name": "refundReceiver", + "type": "address" + }, + { + "name": "nonce", + "type": "uint256" + } + ] + }, + "primaryType": "SafeTx", + "domain": { + "chainId": 1, + "verifyingContract": "0x4F2083f5fBede34C2714aFfb3105539775f7FE64" + }, + "message": { + "to": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "value": "0", + "data": "0xa9059cbb00000000000000000000000027213e28d7fda5c57fe9e5dd923818dbccf71c470000000000000000000000000000000000000000000000000000000059682f00", + "operation": 0, + "safeTxGas": "0", + "baseGas": "0", + "gasPrice": "0", + "gasToken": "0x0000000000000000000000000000000000000000", + "refundReceiver": "0x0000000000000000000000000000000000000000", + "nonce": "42" + } + }, + "expected": { + "domain_separator": "facf7a68664ed3dabebe8e263b4cf03d3e1ba8bbda764c9697c80c7e38b41c62", + "message_hash": "f1e5adf415ba2dc900ccdd63831d31c79f9a30e40a2d41a8a0683c8d8f535f1d", + "digest": "c6d5a71fd45369207a574d910998c708553d0a8960cbc8ea4515f04891f78878" + } + }, + { + "id": "safe-SafeTx-approve-unlimited", + "source": [ + "https://github.com/safe-global/safe-smart-account/blob/v1.4.1/contracts/Safe.sol", + "https://github.com/safe-global/safe-smart-account/blob/v1.3.0/contracts/GnosisSafe.sol" + ], + "requires_capability": "erc20-unlimited-approve-review", + "unlimited_screen": "Allow 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45 to spend ALL your USDC", + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "SafeTx": [ + { + "name": "to", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + }, + { + "name": "data", + "type": "bytes" + }, + { + "name": "operation", + "type": "uint8" + }, + { + "name": "safeTxGas", + "type": "uint256" + }, + { + "name": "baseGas", + "type": "uint256" + }, + { + "name": "gasPrice", + "type": "uint256" + }, + { + "name": "gasToken", + "type": "address" + }, + { + "name": "refundReceiver", + "type": "address" + }, + { + "name": "nonce", + "type": "uint256" + } + ] + }, + "primaryType": "SafeTx", + "domain": { + "chainId": 1, + "verifyingContract": "0x4F2083f5fBede34C2714aFfb3105539775f7FE64" + }, + "message": { + "to": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "value": "0", + "data": "0x095ea7b300000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc45ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "operation": 0, + "safeTxGas": "0", + "baseGas": "0", + "gasPrice": "0", + "gasToken": "0x0000000000000000000000000000000000000000", + "refundReceiver": "0x0000000000000000000000000000000000000000", + "nonce": "43" + } + }, + "expected": { + "domain_separator": "facf7a68664ed3dabebe8e263b4cf03d3e1ba8bbda764c9697c80c7e38b41c62", + "message_hash": "52f96cddec6b14f4496fe53708bb359ef7fcc6f1ccedf63177fd6237b5054b4b", + "digest": "efbe9929ce3de6463119639b299b403e582c1113a2d2a9434b4ba914a1dcffb3" + } + }, + { + "id": "safe-SafeMessage", + "source": [ + "https://github.com/safe-global/safe-smart-account/blob/v1.4.1/contracts/handler/CompatibilityFallbackHandler.sol" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "SafeMessage": [ + { + "name": "message", + "type": "bytes" + } + ] + }, + "primaryType": "SafeMessage", + "domain": { + "chainId": 1, + "verifyingContract": "0x4F2083f5fBede34C2714aFfb3105539775f7FE64" + }, + "message": { + "message": "0x5369676e20696e20746f206170702e6578616d706c652e6f7267207769746820796f75722053616665" + } + }, + "expected": { + "domain_separator": "facf7a68664ed3dabebe8e263b4cf03d3e1ba8bbda764c9697c80c7e38b41c62", + "message_hash": "50c1323949a0f56f1d841a54dcf0b029edeeb52ad42daa386d59ce7d8f5d9e26", + "digest": "10d37e6ca3e5d88f02051f712267a3763f108f8cc1bf478290254f3f6770cc79" + } + }, + { + "id": "eip2612-Permit", + "source": [ + "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/c98b7188338e3c5fce903747894561af78863bbb/contracts/token/ERC20/extensions/ERC20Permit.sol" + ], + "doc": { + "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" + } + ] + }, + "primaryType": "Permit", + "domain": { + "name": "USD Coin", + "version": "2", + "chainId": 1, + "verifyingContract": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" + }, + "message": { + "owner": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", + "spender": "0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD", + "value": "250000000", + "nonce": "0", + "deadline": "1775803746" + } + }, + "expected": { + "domain_separator": "06c37168a7db5138defc7866392bb87a741f9b3d104deb5094588ce041cae335", + "message_hash": "10de0bd7514d5a137be30ca8b8d727c944556d219ac5338577ea5b44bbecc21a", + "digest": "9dfbe3c2bc66846b4e4d05cf917567d5448bac92b4b575285df4b198f459ed94" + } + }, + { + "id": "eip2612-Permit-unlimited", + "source": [ + "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/c98b7188338e3c5fce903747894561af78863bbb/contracts/token/ERC20/extensions/ERC20Permit.sol" + ], + "requires_capability": "erc20-unlimited-permit-review", + "unlimited_screen": "value\nuint256: UNLIMITED", + "doc": { + "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" + } + ] + }, + "primaryType": "Permit", + "domain": { + "name": "USD Coin", + "version": "2", + "chainId": 1, + "verifyingContract": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" + }, + "message": { + "owner": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", + "spender": "0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD", + "value": "115792089237316195423570985008687907853269984665640564039457584007913129639935", + "nonce": "0", + "deadline": "1775803746" + } + }, + "expected": { + "domain_separator": "06c37168a7db5138defc7866392bb87a741f9b3d104deb5094588ce041cae335", + "message_hash": "33ffd631195880f28f81f273a3be51c770ca95311a3f90cf2caa81f3b338a26c", + "digest": "e8f07ca0d9556242ed695a7367e5ffe5d5e8b3913a82a763a83cf1be5d03ad1f" + } + }, + { + "id": "dai-Permit", + "source": [ + "https://github.com/makerdao/dss/blob/fa4f6630afb0624d04a003e920b0d71a00331d98/src/dai.sol" + ], + "doc": { + "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" + } + ] + }, + "primaryType": "Permit", + "domain": { + "name": "Dai Stablecoin", + "version": "1", + "chainId": 1, + "verifyingContract": "0x6B175474E89094C44Da98b954EedeAC495271d0F" + }, + "message": { + "holder": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", + "spender": "0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD", + "nonce": "3", + "expiry": "1775803746", + "allowed": false + } + }, + "expected": { + "domain_separator": "dbb8cf42e1ecb028be3f3dbc922e1d878b963f411dc388ced501601c60f7c6f7", + "message_hash": "ab11f761da4f18c351b557993fff3af1b5276e0ca318a34eb7ff374040587863", + "digest": "ea585737a895795b5b84df7ff9082e15098bda1e22cc312b27ce64c6b656bde6" + } + }, + { + "id": "dai-Permit-allowed", + "source": [ + "https://github.com/makerdao/dss/blob/fa4f6630afb0624d04a003e920b0d71a00331d98/src/dai.sol" + ], + "requires_capability": "erc20-unlimited-permit-review", + "unlimited_screen": "allowed\nbool: UNLIMITED (allowed)", + "doc": { + "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" + } + ] + }, + "primaryType": "Permit", + "domain": { + "name": "Dai Stablecoin", + "version": "1", + "chainId": 1, + "verifyingContract": "0x6B175474E89094C44Da98b954EedeAC495271d0F" + }, + "message": { + "holder": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", + "spender": "0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD", + "nonce": "3", + "expiry": "1775803746", + "allowed": true + } + }, + "expected": { + "domain_separator": "dbb8cf42e1ecb028be3f3dbc922e1d878b963f411dc388ced501601c60f7c6f7", + "message_hash": "d087cc737aa821393dd824ea87dcb51376c51b9815d52c6f5102c6e843b128c0", + "digest": "c2b81aa8b44a91816e41ff0810a9ccb9bf0226cbdfd901493205a18fc5eb94a4" + } + }, + { + "id": "hyperliquid-Agent", + "source": [ + "https://github.com/hyperliquid-dex/hyperliquid-python-sdk/blob/2fdb18f9517675ea03695a0962bd19eece9c83f0/hyperliquid/utils/signing.py" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Agent": [ + { + "name": "source", + "type": "string" + }, + { + "name": "connectionId", + "type": "bytes32" + } + ] + }, + "primaryType": "Agent", + "domain": { + "name": "Exchange", + "version": "1", + "chainId": 1337, + "verifyingContract": "0x0000000000000000000000000000000000000000" + }, + "message": { + "source": "a", + "connectionId": "0x5a9c4e1b6f3d2a8c7e0b1d4f6a8c2e4b6d8f0a1c3e5b7d9f1a3c5e7b9d1f3a5c" + } + }, + "expected": { + "domain_separator": "d79297fcdf2ffcd4ae223d01edaa2ba214ff8f401d7c9300d995d17c82aa4040", + "message_hash": "f4ece6c5a5f1499c017ee17624f5a4ac0a476f42a270b0300b96840c4fb407ad", + "digest": "6bce8eb48553ebe6181a9cdba358196071b0ac1f204f124cc3c6d9fcfe0d87e0" + } + }, + { + "id": "hyperliquid-UsdSend", + "source": [ + "https://github.com/hyperliquid-dex/hyperliquid-python-sdk/blob/2fdb18f9517675ea03695a0962bd19eece9c83f0/hyperliquid/utils/signing.py" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "HyperliquidTransaction:UsdSend": [ + { + "name": "hyperliquidChain", + "type": "string" + }, + { + "name": "destination", + "type": "string" + }, + { + "name": "amount", + "type": "string" + }, + { + "name": "time", + "type": "uint64" + } + ] + }, + "primaryType": "HyperliquidTransaction:UsdSend", + "domain": { + "name": "HyperliquidSignTransaction", + "version": "1", + "chainId": 421614, + "verifyingContract": "0x0000000000000000000000000000000000000000" + }, + "message": { + "hyperliquidChain": "Mainnet", + "destination": "0x27213e28d7fda5c57fe9e5dd923818dbccf71c47", + "amount": "125.5", + "time": 1775803746123 + } + }, + "expected": { + "domain_separator": "feb1393ca4412a4ca577bd51d04f0a77033514c602f4d0a11490fb95f7428df6", + "message_hash": "518cb9e1a640cb3f4f1284c76dfd63a9a71962c694c22dc3f6dff33ba6f6ab92", + "digest": "ccaa5b3b61614b569661dc3b3898d09db03661064d3300c6dfc50a48c5257621" + } + }, + { + "id": "hyperliquid-Withdraw", + "source": [ + "https://github.com/hyperliquid-dex/hyperliquid-python-sdk/blob/2fdb18f9517675ea03695a0962bd19eece9c83f0/hyperliquid/utils/signing.py" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "HyperliquidTransaction:Withdraw": [ + { + "name": "hyperliquidChain", + "type": "string" + }, + { + "name": "destination", + "type": "string" + }, + { + "name": "amount", + "type": "string" + }, + { + "name": "time", + "type": "uint64" + } + ] + }, + "primaryType": "HyperliquidTransaction:Withdraw", + "domain": { + "name": "HyperliquidSignTransaction", + "version": "1", + "chainId": 421614, + "verifyingContract": "0x0000000000000000000000000000000000000000" + }, + "message": { + "hyperliquidChain": "Mainnet", + "destination": "0x9858effd232b4033e47d90003d41ec34ecaeda94", + "amount": "1000", + "time": 1775803746124 + } + }, + "expected": { + "domain_separator": "feb1393ca4412a4ca577bd51d04f0a77033514c602f4d0a11490fb95f7428df6", + "message_hash": "dd5d1b845532de3345180aaeaf23bbb2b7bbcd4ff128c3278dae59485cb62609", + "digest": "7da96947dfdab71f98adc8b1dd35f14ca9d89a3748a47948fcbce63459a00153" + } + }, + { + "id": "hyperliquid-SpotSend", + "source": [ + "https://github.com/hyperliquid-dex/hyperliquid-python-sdk/blob/2fdb18f9517675ea03695a0962bd19eece9c83f0/hyperliquid/utils/signing.py" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "HyperliquidTransaction:SpotSend": [ + { + "name": "hyperliquidChain", + "type": "string" + }, + { + "name": "destination", + "type": "string" + }, + { + "name": "token", + "type": "string" + }, + { + "name": "amount", + "type": "string" + }, + { + "name": "time", + "type": "uint64" + } + ] + }, + "primaryType": "HyperliquidTransaction:SpotSend", + "domain": { + "name": "HyperliquidSignTransaction", + "version": "1", + "chainId": 421614, + "verifyingContract": "0x0000000000000000000000000000000000000000" + }, + "message": { + "hyperliquidChain": "Mainnet", + "destination": "0x27213e28d7fda5c57fe9e5dd923818dbccf71c47", + "token": "PURR:0xc4bf3f870c0e9465323c0b6ed28096c2", + "amount": "42", + "time": 1775803746125 + } + }, + "expected": { + "domain_separator": "feb1393ca4412a4ca577bd51d04f0a77033514c602f4d0a11490fb95f7428df6", + "message_hash": "9873b52950b87cda36625decbdeedcfbc0821cc1c49c413ec361f50286ed624a", + "digest": "024b66a25a2fd6473d749d58a5ab9811278d3ac66f0fa014d7a2c7ae3ef22086" + } + }, + { + "id": "hyperliquid-ApproveAgent", + "source": [ + "https://github.com/hyperliquid-dex/hyperliquid-python-sdk/blob/2fdb18f9517675ea03695a0962bd19eece9c83f0/hyperliquid/utils/signing.py" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "HyperliquidTransaction:ApproveAgent": [ + { + "name": "hyperliquidChain", + "type": "string" + }, + { + "name": "agentAddress", + "type": "address" + }, + { + "name": "agentName", + "type": "string" + }, + { + "name": "nonce", + "type": "uint64" + } + ] + }, + "primaryType": "HyperliquidTransaction:ApproveAgent", + "domain": { + "name": "HyperliquidSignTransaction", + "version": "1", + "chainId": 421614, + "verifyingContract": "0x0000000000000000000000000000000000000000" + }, + "message": { + "hyperliquidChain": "Mainnet", + "agentAddress": "0x7FFC3DBF3B2b50Ff3A1D5523bc24Bb5043837B14", + "agentName": "keepkey", + "nonce": 1775803746126 + } + }, + "expected": { + "domain_separator": "feb1393ca4412a4ca577bd51d04f0a77033514c602f4d0a11490fb95f7428df6", + "message_hash": "0edbc16bac693bf270904285960c7a2aad984948616503c31b188cc314001f50", + "digest": "727fae5d7d7ffa519fb0f06bff340d863a9d366d3650feda6c25bc834d616b7e" + } + }, + { + "id": "hyperliquid-ApproveBuilderFee", + "source": [ + "https://github.com/hyperliquid-dex/hyperliquid-python-sdk/blob/2fdb18f9517675ea03695a0962bd19eece9c83f0/hyperliquid/utils/signing.py" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "HyperliquidTransaction:ApproveBuilderFee": [ + { + "name": "hyperliquidChain", + "type": "string" + }, + { + "name": "maxFeeRate", + "type": "string" + }, + { + "name": "builder", + "type": "address" + }, + { + "name": "nonce", + "type": "uint64" + } + ] + }, + "primaryType": "HyperliquidTransaction:ApproveBuilderFee", + "domain": { + "name": "HyperliquidSignTransaction", + "version": "1", + "chainId": 421614, + "verifyingContract": "0x0000000000000000000000000000000000000000" + }, + "message": { + "hyperliquidChain": "Mainnet", + "maxFeeRate": "0.1%", + "builder": "0xaab1d2c1fc1c5b4e8a1de8b3fe2f5fc6e2fb86d3", + "nonce": 1775803746127 + } + }, + "expected": { + "domain_separator": "feb1393ca4412a4ca577bd51d04f0a77033514c602f4d0a11490fb95f7428df6", + "message_hash": "40faac2eae76730154845cadb657e0eb6189a2e62d8996a3507384d37df30dd8", + "digest": "a157aa4e572a9371cd72316b9e56d5c6b870932d480b9c1c213ce754e27f0b7d" + } + }, + { + "id": "polymarket-Order", + "source": [ + "https://github.com/Polymarket/ctf-exchange/blob/ed5c7708b7be3aa98bf5f0c6602b57cc498e2ef4/src/exchange/libraries/OrderStructs.sol" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Order": [ + { + "name": "salt", + "type": "uint256" + }, + { + "name": "maker", + "type": "address" + }, + { + "name": "signer", + "type": "address" + }, + { + "name": "taker", + "type": "address" + }, + { + "name": "tokenId", + "type": "uint256" + }, + { + "name": "makerAmount", + "type": "uint256" + }, + { + "name": "takerAmount", + "type": "uint256" + }, + { + "name": "expiration", + "type": "uint256" + }, + { + "name": "nonce", + "type": "uint256" + }, + { + "name": "feeRateBps", + "type": "uint256" + }, + { + "name": "side", + "type": "uint8" + }, + { + "name": "signatureType", + "type": "uint8" + } + ] + }, + "primaryType": "Order", + "domain": { + "name": "Polymarket CTF Exchange", + "version": "1", + "chainId": 137, + "verifyingContract": "0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E" + }, + "message": { + "salt": "479249096354", + "maker": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", + "signer": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", + "taker": "0x0000000000000000000000000000000000000000", + "tokenId": "71321045679252212594626385532706912750332728571942532289631379312455583992563", + "makerAmount": "50000000", + "takerAmount": "100000000", + "expiration": "0", + "nonce": "0", + "feeRateBps": "0", + "side": 0, + "signatureType": 0 + } + }, + "expected": { + "domain_separator": "1a573e3617c78403b5b4b892827992f027b03d4eaf570048b8ee8cdd84d151be", + "message_hash": "02d6222deeec96f60bb0fd5b2fa76da7f7a416223bbb77a5126bdd95c6ed4c27", + "digest": "4adaa897f6212a9a351ea8f1e30129c3746eccf4a02e2128961a152e7c10ce0d" + } + }, + { + "id": "polymarket-ClobAuth", + "source": [ + "https://github.com/Polymarket/clob-client/blob/7df8257dc95f99edb257b53a7873e273a9b4a9b3/src/signing/eip712.ts" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + } + ], + "ClobAuth": [ + { + "name": "address", + "type": "address" + }, + { + "name": "timestamp", + "type": "string" + }, + { + "name": "nonce", + "type": "uint256" + }, + { + "name": "message", + "type": "string" + } + ] + }, + "primaryType": "ClobAuth", + "domain": { + "name": "ClobAuthDomain", + "version": "1", + "chainId": 137 + }, + "message": { + "address": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", + "timestamp": "1775803746", + "nonce": "0", + "message": "This message attests that I control the given wallet" + } + }, + "expected": { + "domain_separator": "cfc66be2a3b30464cb3b588324101f660c9a205fa76e8e5f83ee16a528e1c4cb", + "message_hash": "6998fb300c3c08c2bafe9e47d73aab51025acdf054307f4f4583d94404c97fcf", + "digest": "26632c686b33505c3e6f3001b3a7581f30dce9f94720ad249a2286fea252adff" + } + }, + { + "id": "compound-Ballot", + "source": [ + "https://github.com/compound-finance/compound-protocol/blob/a3214f67b73310d547e00fc578e8355911c9d376/contracts/Governance/GovernorBravoDelegate.sol" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Ballot": [ + { + "name": "proposalId", + "type": "uint256" + }, + { + "name": "support", + "type": "uint8" + } + ] + }, + "primaryType": "Ballot", + "domain": { + "name": "Compound Governor Bravo", + "chainId": 1, + "verifyingContract": "0xc0Da02939E1441F497fd74F78cE7Decb17B66529" + }, + "message": { + "proposalId": "289", + "support": 1 + } + }, + "expected": { + "domain_separator": "d34731531481fb0dd71602b43ef32fd12c76bc12d76869812352236afaa4b346", + "message_hash": "91d8e3e95c41471dd654460e8b12395e1b0ee5682bfc1598134898b7a964a582", + "digest": "5e70ede1f42b52b245a35a58e2f2da91eef453a540c808247f785ed62dc7c9e2" + } + }, + { + "id": "oz-governor-v5-ExtendedBallot", + "source": [ + "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.4.0/contracts/governance/Governor.sol" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "ExtendedBallot": [ + { + "name": "proposalId", + "type": "uint256" + }, + { + "name": "support", + "type": "uint8" + }, + { + "name": "voter", + "type": "address" + }, + { + "name": "nonce", + "type": "uint256" + }, + { + "name": "reason", + "type": "string" + }, + { + "name": "params", + "type": "bytes" + } + ] + }, + "primaryType": "ExtendedBallot", + "domain": { + "name": "Compound Governor", + "version": "1", + "chainId": 1, + "verifyingContract": "0x309a862bbC1A00e45506cB8A802D1ff10004c8C0" + }, + "message": { + "proposalId": "10770658185911291573227826359627312367262036453227096346419573049937349025001", + "support": 1, + "voter": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", + "nonce": "0", + "reason": "Supports the risk parameter update.", + "params": "0x" + } + }, + "expected": { + "domain_separator": "3abcb92fd8e6968fd834a2cc50bb05abdd78c74cd0fac3f017c47fcc8b743e87", + "message_hash": "05ce3e96fc27ffd71d0e36c688ecab14c00a49fac2c65bdfbd64af3ca49191f5", + "digest": "2f8c569b46c093b83c7ae290f31893ef6956910121ddcb1ca55f1326a6819845" + } + }, + { + "id": "oz-governor-v4-ExtendedBallot", + "source": [ + "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.6/contracts/governance/Governor.sol" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "ExtendedBallot": [ + { + "name": "proposalId", + "type": "uint256" + }, + { + "name": "support", + "type": "uint8" + }, + { + "name": "reason", + "type": "string" + }, + { + "name": "params", + "type": "bytes" + } + ] + }, + "primaryType": "ExtendedBallot", + "domain": { + "name": "ENS Governor", + "version": "1", + "chainId": 1, + "verifyingContract": "0x323A76393544d5ecca80cd6ef2A560C6a395b7E3" + }, + "message": { + "proposalId": "42", + "support": 0, + "reason": "Against: needs an audit first.", + "params": "0x" + } + }, + "expected": { + "domain_separator": "7569da846e8a3624f3e70461387f0c2bae53ef7edc30b5d3a5fbe2b74fa7c741", + "message_hash": "d0e00d45e7cd483b28090a1512888e0bd907dce94815a2750c5064941e7bf76b", + "digest": "1d95b248abb2fc734628421684b93ce1980641738dca34190a3ee4916c20f6d8" + } + }, + { + "id": "compound-Delegation", + "source": [ + "https://github.com/compound-finance/compound-protocol/blob/a3214f67b73310d547e00fc578e8355911c9d376/contracts/Governance/Comp.sol" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "Delegation": [ + { + "name": "delegatee", + "type": "address" + }, + { + "name": "nonce", + "type": "uint256" + }, + { + "name": "expiry", + "type": "uint256" + } + ] + }, + "primaryType": "Delegation", + "domain": { + "name": "Compound", + "chainId": 1, + "verifyingContract": "0xc00e94Cb662C3520282E6f5717214004A7f26888" + }, + "message": { + "delegatee": "0x7FFC3DBF3B2b50Ff3A1D5523bc24Bb5043837B14", + "nonce": "0", + "expiry": "1775803746" + } + }, + "expected": { + "domain_separator": "97529df852bab657e1ffa498f205743fdd7e2b2dcbcc1173bacf2cd17133d278", + "message_hash": "ca7258eec1792ca72c50d4c4e2aca40d71485e77c86b39b9d04695ab7098500d", + "digest": "014c88c699f48e4680fdf86ab4a638876ff93812b0dd20106f3797caa8adb4ca" + } + }, + { + "id": "aave-SubmitVote", + "source": [ + "https://github.com/bgd-labs/aave-governance-v3/blob/497226efad1ca3723074034c8341fb90931fc2b2/src/contracts/voting/VotingMachineWithProofs.sol" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "SubmitVote": [ + { + "name": "proposalId", + "type": "uint256" + }, + { + "name": "voter", + "type": "address" + }, + { + "name": "support", + "type": "bool" + }, + { + "name": "votingAssetsWithSlot", + "type": "VotingAssetWithSlot[]" + } + ], + "VotingAssetWithSlot": [ + { + "name": "underlyingAsset", + "type": "address" + }, + { + "name": "slot", + "type": "uint128" + } + ] + }, + "primaryType": "SubmitVote", + "domain": { + "name": "Aave Voting Machine", + "version": "V1", + "chainId": 137, + "verifyingContract": "0xc8a2ADC4261c6b669CdFf69E717E77C9cFeB420d" + }, + "message": { + "proposalId": "312", + "voter": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", + "support": true, + "votingAssetsWithSlot": [ + { + "underlyingAsset": "0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9", + "slot": "0" + }, + { + "underlyingAsset": "0x4da27a545c0c5B758a6BA100e3a049001de870f5", + "slot": "0" + }, + { + "underlyingAsset": "0xA700b4eB416Be35b2911fd5Dee80678ff64fF6C9", + "slot": "52" + } + ] + } + }, + "expected": { + "domain_separator": "ae1a4d19b2c550c11439cbcb934c88b16b8585f876d64fe1a6a6ae8e9e863c46", + "message_hash": "0fbe44b065abb8e818ecd154ba83b7a7f6f4824400446e44e97c426eb4989019", + "digest": "ad46f18dee90c1e41f3505c75706e0780e5b47ceb64e6406e85863ad17278f2c" + } + }, + { + "id": "dydx-DelegateByType", + "source": [ + "https://github.com/dydxfoundation/governance-contracts/blob/804a6e41f96f8b67daeff1d681b4c1c66ceb2547/contracts/governance/token/GovernancePowerDelegationERC20Mixin.sol" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "DelegateByType": [ + { + "name": "delegatee", + "type": "address" + }, + { + "name": "type", + "type": "uint256" + }, + { + "name": "nonce", + "type": "uint256" + }, + { + "name": "expiry", + "type": "uint256" + } + ] + }, + "primaryType": "DelegateByType", + "domain": { + "name": "dYdX", + "version": "1", + "chainId": 1, + "verifyingContract": "0x92D6C1e31e14520e676a687F0a93788B716BEff5" + }, + "message": { + "delegatee": "0x7FFC3DBF3B2b50Ff3A1D5523bc24Bb5043837B14", + "type": "1", + "nonce": "0", + "expiry": "1775803746" + } + }, + "expected": { + "domain_separator": "17e76dd75f3dfe3e50d31322433cc1405e898404a5724da2d4804cab81e0a88a", + "message_hash": "6dfed76dfede64f4af0c2768ac6d52b71f00d84ae5d32686448b7b5beb4c33a2", + "digest": "820d885ba6d39bf57def942b8c33ee3508d4fff87a09e50fb2f6ecaa486f8dd9" + } + }, + { + "id": "across-GaslessCrossChainOrder", + "source": [ + "https://github.com/across-protocol/contracts/blob/master/contracts/erc7683/ERC7683Permit2Lib.sol", + "https://github.com/Uniswap/permit2/blob/cc56ad0f3439c502c246fc5cfcc3db92bb8b7219/src/libraries/PermitHash.sol" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "PermitWitnessTransferFrom": [ + { + "name": "permitted", + "type": "TokenPermissions" + }, + { + "name": "spender", + "type": "address" + }, + { + "name": "nonce", + "type": "uint256" + }, + { + "name": "deadline", + "type": "uint256" + }, + { + "name": "witness", + "type": "GaslessCrossChainOrder" + } + ], + "AcrossOrderData": [ + { + "name": "inputToken", + "type": "address" + }, + { + "name": "inputAmount", + "type": "uint256" + }, + { + "name": "outputToken", + "type": "address" + }, + { + "name": "outputAmount", + "type": "uint256" + }, + { + "name": "destinationChainId", + "type": "uint256" + }, + { + "name": "recipient", + "type": "bytes32" + }, + { + "name": "exclusiveRelayer", + "type": "address" + }, + { + "name": "exclusivityPeriod", + "type": "uint32" + }, + { + "name": "message", + "type": "bytes" + } + ], + "GaslessCrossChainOrder": [ + { + "name": "originSettler", + "type": "address" + }, + { + "name": "user", + "type": "address" + }, + { + "name": "nonce", + "type": "uint256" + }, + { + "name": "originChainId", + "type": "uint256" + }, + { + "name": "openDeadline", + "type": "uint32" + }, + { + "name": "fillDeadline", + "type": "uint32" + }, + { + "name": "orderDataType", + "type": "bytes32" + }, + { + "name": "orderData", + "type": "AcrossOrderData" + } + ], + "TokenPermissions": [ + { + "name": "token", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ] + }, + "primaryType": "PermitWitnessTransferFrom", + "domain": { + "name": "Permit2", + "chainId": 42161, + "verifyingContract": "0x000000000022D473030F116dDEE9F6B43aC78BA3" + }, + "message": { + "permitted": { + "token": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", + "amount": "500000000" + }, + "spender": "0xB0B07055F214Ce59ccB968663d3435B9f3294998", + "nonce": "77", + "deadline": "1775803746", + "witness": { + "originSettler": "0xB0B07055F214Ce59ccB968663d3435B9f3294998", + "user": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", + "nonce": "77", + "originChainId": "42161", + "openDeadline": 1775803746, + "fillDeadline": 1775814546, + "orderDataType": "0x9df4b782e7bbc178b3b93bfe8aafb909e84e39484d7f3c59f400f1b4691f85e2", + "orderData": { + "inputToken": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", + "inputAmount": "500000000", + "outputToken": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "outputAmount": "499650000", + "destinationChainId": "1", + "recipient": "0x0000000000000000000000009858effd232b4033e47d90003d41ec34ecaeda94", + "exclusiveRelayer": "0x0000000000000000000000000000000000000000", + "exclusivityPeriod": 0, + "message": "0x" + } + } + } + }, + "expected": { + "domain_separator": "8a6e6e19bdfb3db3409910416b47c2f8fc28b49488d6555c7fceaa4479135bc3", + "message_hash": "a0e1fae1fef174757d2b9652c3d1721a9262a393e50904e7f51ba49c2e5e18a6", + "digest": "89121d721fbf3935ca58a646da33ae08eef33bdc61fb9584826bc68eb5b867d9" + } + }, + { + "id": "snapshot-Vote-uint32", + "source": [ + "https://github.com/snapshot-labs/snapshot.js/blob/ae2a8209e03ca1fa133a9105949a9386f3b539ed/src/sign/types.ts" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + } + ], + "Vote": [ + { + "name": "from", + "type": "string" + }, + { + "name": "space", + "type": "string" + }, + { + "name": "timestamp", + "type": "uint64" + }, + { + "name": "proposal", + "type": "string" + }, + { + "name": "choice", + "type": "uint32" + }, + { + "name": "reason", + "type": "string" + }, + { + "name": "app", + "type": "string" + }, + { + "name": "metadata", + "type": "string" + } + ] + }, + "primaryType": "Vote", + "domain": { + "name": "snapshot", + "version": "0.1.4" + }, + "message": { + "from": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", + "space": "aavedao.eth", + "timestamp": 1775803746, + "proposal": "0x9e0b3d8a0b6b31c5c1b8c0b4e2c6b0bfa4f3dd1b0ec0e4b2d8a6b5c2e1f3a4d5", + "choice": 1, + "reason": "", + "app": "snapshot-v2", + "metadata": "{}" + } + }, + "expected": { + "domain_separator": "484fce18f892e8535a4b6700e197a8026f4213f809d23ae117da03b497e18670", + "message_hash": "7fabb0616963ab661ad570fdac5cd6dfc1896f62e75891bde5fdcd8e8fda9c30", + "digest": "2ebf83b128be8aa355a81a15424a3fc8966f27c7c2bceadf191be84304a16760" + } + }, + { + "id": "snapshot-Vote-reason-multiline", + "source": [ + "https://github.com/snapshot-labs/snapshot.js/blob/ae2a8209e03ca1fa133a9105949a9386f3b539ed/src/sign/types.ts" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + } + ], + "Vote": [ + { + "name": "from", + "type": "string" + }, + { + "name": "space", + "type": "string" + }, + { + "name": "timestamp", + "type": "uint64" + }, + { + "name": "proposal", + "type": "string" + }, + { + "name": "choice", + "type": "uint32" + }, + { + "name": "reason", + "type": "string" + }, + { + "name": "app", + "type": "string" + }, + { + "name": "metadata", + "type": "string" + } + ] + }, + "primaryType": "Vote", + "domain": { + "name": "snapshot", + "version": "0.1.4" + }, + "message": { + "from": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", + "space": "aavedao.eth", + "timestamp": 1775803746, + "proposal": "0x9e0b3d8a0b6b31c5c1b8c0b4e2c6b0bfa4f3dd1b0ec0e4b2d8a6b5c2e1f3a4d5", + "choice": 1, + "reason": "Supporting this.\n\n\tThe treasury numbers check out;\r\nsee the forum thread.", + "app": "snapshot-v2", + "metadata": "{}" + } + }, + "expected": { + "domain_separator": "484fce18f892e8535a4b6700e197a8026f4213f809d23ae117da03b497e18670", + "message_hash": "8b3db279e4027f639c6e9e69aeaa2760e4cbd76172e0508eb9d55504b0203dd5", + "digest": "fb036054282ff5c208db428da469c2aad81334ee2ea75713a848adefd932f8ae" + } + }, + { + "id": "snapshot-Vote-uint32[]", + "source": [ + "https://github.com/snapshot-labs/snapshot.js/blob/ae2a8209e03ca1fa133a9105949a9386f3b539ed/src/sign/types.ts" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + } + ], + "Vote": [ + { + "name": "from", + "type": "string" + }, + { + "name": "space", + "type": "string" + }, + { + "name": "timestamp", + "type": "uint64" + }, + { + "name": "proposal", + "type": "string" + }, + { + "name": "choice", + "type": "uint32[]" + }, + { + "name": "reason", + "type": "string" + }, + { + "name": "app", + "type": "string" + }, + { + "name": "metadata", + "type": "string" + } + ] + }, + "primaryType": "Vote", + "domain": { + "name": "snapshot", + "version": "0.1.4" + }, + "message": { + "from": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", + "space": "aavedao.eth", + "timestamp": 1775803746, + "proposal": "0x9e0b3d8a0b6b31c5c1b8c0b4e2c6b0bfa4f3dd1b0ec0e4b2d8a6b5c2e1f3a4d5", + "choice": [ + 1, + 3 + ], + "reason": "", + "app": "snapshot-v2", + "metadata": "{}" + } + }, + "expected": { + "domain_separator": "484fce18f892e8535a4b6700e197a8026f4213f809d23ae117da03b497e18670", + "message_hash": "445458b701f220e28b2f7851e2fb67d2d30f86ee9cfec5e947a86915c5b374fa", + "digest": "8942a9b491d57715c6becc2325fbe330fcb3c1fb1d4027267b64ca0bfadaa60a" + } + }, + { + "id": "snapshot-Vote-string", + "source": [ + "https://github.com/snapshot-labs/snapshot.js/blob/ae2a8209e03ca1fa133a9105949a9386f3b539ed/src/sign/types.ts" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + } + ], + "Vote": [ + { + "name": "from", + "type": "string" + }, + { + "name": "space", + "type": "string" + }, + { + "name": "timestamp", + "type": "uint64" + }, + { + "name": "proposal", + "type": "string" + }, + { + "name": "choice", + "type": "string" + }, + { + "name": "reason", + "type": "string" + }, + { + "name": "app", + "type": "string" + }, + { + "name": "metadata", + "type": "string" + } + ] + }, + "primaryType": "Vote", + "domain": { + "name": "snapshot", + "version": "0.1.4" + }, + "message": { + "from": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", + "space": "aavedao.eth", + "timestamp": 1775803746, + "proposal": "0x9e0b3d8a0b6b31c5c1b8c0b4e2c6b0bfa4f3dd1b0ec0e4b2d8a6b5c2e1f3a4d5", + "choice": "{\"1\":60,\"2\":40}", + "reason": "", + "app": "snapshot-v2", + "metadata": "{}" + } + }, + "expected": { + "domain_separator": "484fce18f892e8535a4b6700e197a8026f4213f809d23ae117da03b497e18670", + "message_hash": "c5740e9f7b1eb3cc1c58a4c2e7ece755e59f657c58e707ecfb699847e787954e", + "digest": "13505558c6022d086c119463c0c57887a4de806e74d298e3b26b95b31bd763c8" + } + }, + { + "id": "snapshot-Vote-legacy-bytes32", + "source": [ + "https://github.com/snapshot-labs/snapshot.js/blob/2a13d16e/src/sign/types.ts" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + } + ], + "Vote": [ + { + "name": "from", + "type": "address" + }, + { + "name": "space", + "type": "string" + }, + { + "name": "timestamp", + "type": "uint64" + }, + { + "name": "proposal", + "type": "bytes32" + }, + { + "name": "choice", + "type": "uint32" + }, + { + "name": "reason", + "type": "string" + }, + { + "name": "app", + "type": "string" + }, + { + "name": "metadata", + "type": "string" + } + ] + }, + "primaryType": "Vote", + "domain": { + "name": "snapshot", + "version": "0.1.4" + }, + "message": { + "from": "0x9858EfFD232B4033E47d90003D41EC34EcaEda94", + "space": "ens.eth", + "timestamp": 1775803746, + "proposal": "0x9e0b3d8a0b6b31c5c1b8c0b4e2c6b0bfa4f3dd1b0ec0e4b2d8a6b5c2e1f3a4d5", + "choice": 2, + "reason": "", + "app": "snapshot", + "metadata": "{}" + } + }, + "expected": { + "domain_separator": "484fce18f892e8535a4b6700e197a8026f4213f809d23ae117da03b497e18670", + "message_hash": "39aed682da209db5214780de752b4319204bb3e8d48faa0bc1698c2bb0147637", + "digest": "6672ce6256f657e4e9af0ac1eb6f7ca3e256cbdc9c8052f743da4bf899e211d0" + } + }, + { + "id": "metamask-Mail-v4", + "source": [ + "https://github.com/MetaMask/test-dapp/blob/v7.0.0/src/index.js" + ], + "doc": { + "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[]" + } + ], + "Group": [ + { + "name": "name", + "type": "string" + }, + { + "name": "members", + "type": "Person[]" + } + ] + }, + "primaryType": "Mail", + "domain": { + "name": "Ether Mail", + "version": "1", + "chainId": 1, + "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "from": { + "name": "Cow", + "wallets": [ + "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", + "0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF" + ] + }, + "to": [ + { + "name": "Bob", + "wallets": [ + "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB", + "0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57", + "0xB0B0b0b0b0b0B000000000000000000000000000" + ] + } + ], + "contents": "Hello, Bob!" + } + }, + "expected": { + "domain_separator": "f2cee375fa42b42143804025fc449deafd50cc031ca257e0b194a650a912090f", + "message_hash": "eb4221181ff3f1a83ea7313993ca9218496e424604ba9492bb4052c03d5c3df8", + "digest": "a85c2e2b118698e88db68a8105b794a8cc7cec074e89ef991cb4f5f533819cc2" + } + }, + { + "id": "eip712-spec-Mail", + "source": [ + "https://github.com/ethereum/EIPs/blob/master/assets/eip-712/Example.js" + ], + "doc": { + "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": "wallet", + "type": "address" + } + ] + }, + "primaryType": "Mail", + "domain": { + "name": "Ether Mail", + "version": "1", + "chainId": 1, + "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC" + }, + "message": { + "from": { + "name": "Cow", + "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" + }, + "to": { + "name": "Bob", + "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" + }, + "contents": "Hello, Bob!" + } + }, + "expected": { + "domain_separator": "f2cee375fa42b42143804025fc449deafd50cc031ca257e0b194a650a912090f", + "message_hash": "c52c0ee5d84264471806290a3f2c4cecfc5490626bf912d01f240d7a274b371e", + "digest": "be609aee343fb3c4b28e1df9e632fca64fcfaede20f02e86244efddf30957bd2" + } + }, + { + "id": "uniswapx-V3DutchOrder-arbitrum", + "source": [ + "https://github.com/Uniswap/permit2/blob/cc56ad0f3439c502c246fc5cfcc3db92bb8b7219/src/libraries/PermitHash.sol", + "https://github.com/Uniswap/UniswapX/blob/eb7ce077036258b9510b42ad37aa920cf3aaf308/src/lib/V3DutchOrderLib.sol", + "https://github.com/Uniswap/UniswapX/blob/eb7ce077036258b9510b42ad37aa920cf3aaf308/src/lib/OrderInfoLib.sol", + "https://github.com/Uniswap/UniswapX/blob/eb7ce077036258b9510b42ad37aa920cf3aaf308/src/lib/DutchOrderLib.sol", + "https://arbiscan.io/tx/0x1f2f270bf65d2b7f02b2a141f71e23bfcc3a84b37c9a0921577516c58031678d" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "PermitWitnessTransferFrom": [ + { + "name": "permitted", + "type": "TokenPermissions" + }, + { + "name": "spender", + "type": "address" + }, + { + "name": "nonce", + "type": "uint256" + }, + { + "name": "deadline", + "type": "uint256" + }, + { + "name": "witness", + "type": "V3DutchOrder" + } + ], + "NonlinearDutchDecay": [ + { + "name": "relativeBlocks", + "type": "uint256" + }, + { + "name": "relativeAmounts", + "type": "int256[]" + } + ], + "OrderInfo": [ + { + "name": "reactor", + "type": "address" + }, + { + "name": "swapper", + "type": "address" + }, + { + "name": "nonce", + "type": "uint256" + }, + { + "name": "deadline", + "type": "uint256" + }, + { + "name": "additionalValidationContract", + "type": "address" + }, + { + "name": "additionalValidationData", + "type": "bytes" + } + ], + "TokenPermissions": [ + { + "name": "token", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "V3DutchInput": [ + { + "name": "token", + "type": "address" + }, + { + "name": "startAmount", + "type": "uint256" + }, + { + "name": "curve", + "type": "NonlinearDutchDecay" + }, + { + "name": "maxAmount", + "type": "uint256" + }, + { + "name": "adjustmentPerGweiBaseFee", + "type": "uint256" + } + ], + "V3DutchOrder": [ + { + "name": "info", + "type": "OrderInfo" + }, + { + "name": "cosigner", + "type": "address" + }, + { + "name": "startingBaseFee", + "type": "uint256" + }, + { + "name": "baseInput", + "type": "V3DutchInput" + }, + { + "name": "baseOutputs", + "type": "V3DutchOutput[]" + } + ], + "V3DutchOutput": [ + { + "name": "token", + "type": "address" + }, + { + "name": "startAmount", + "type": "uint256" + }, + { + "name": "curve", + "type": "NonlinearDutchDecay" + }, + { + "name": "recipient", + "type": "address" + }, + { + "name": "minAmount", + "type": "uint256" + }, + { + "name": "adjustmentPerGweiBaseFee", + "type": "uint256" + } + ] + }, + "primaryType": "PermitWitnessTransferFrom", + "domain": { + "name": "Permit2", + "chainId": 42161, + "verifyingContract": "0x000000000022D473030F116dDEE9F6B43aC78BA3" + }, + "message": { + "permitted": { + "token": "0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f", + "amount": "12514477" + }, + "spender": "0xB274d5F4b833b61B340b654d600A864fB604a87c", + "nonce": "1993355410060173619975858542007397613024848003638926934372819132074995782145", + "deadline": "1791402675", + "witness": { + "info": { + "reactor": "0xB274d5F4b833b61B340b654d600A864fB604a87c", + "swapper": "0x7f05C94cE299Eea9FCdAE798Be34E226a0cb1e77", + "nonce": "1993355410060173619975858542007397613024848003638926934372819132074995782145", + "deadline": "1791402675", + "additionalValidationContract": "0x0000000000000000000000000000000000000000", + "additionalValidationData": "0x" + }, + "cosigner": "0x4449Cd34d1eb1FEDCF02A1Be3834FfDe8E6A6180", + "startingBaseFee": "0", + "baseInput": { + "token": "0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f", + "startAmount": "12514477", + "curve": { + "relativeBlocks": "32", + "relativeAmounts": [ + "0" + ] + }, + "maxAmount": "12514477", + "adjustmentPerGweiBaseFee": "0" + }, + "baseOutputs": [ + { + "token": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", + "startAmount": "10407262726", + "curve": { + "relativeBlocks": "32", + "relativeAmounts": [ + "260181569" + ] + }, + "recipient": "0x7f05C94cE299Eea9FCdAE798Be34E226a0cb1e77", + "minAmount": "10147081157", + "adjustmentPerGweiBaseFee": "0" + } + ] + } + } + }, + "expected": { + "domain_separator": "8a6e6e19bdfb3db3409910416b47c2f8fc28b49488d6555c7fceaa4479135bc3", + "message_hash": "d9f38d5095c80dc8118342f144211cb537cc6b9b98027c20cefed85ffaf1cf5c", + "digest": "2a1fba9e8c26066eadd659350dc6e6cc17a9a63c8c4fbdbd771049adb754c33a" + } + }, + { + "id": "uniswapx-V3DutchOrder-arbitrum-curve16", + "source": [ + "https://github.com/Uniswap/permit2/blob/cc56ad0f3439c502c246fc5cfcc3db92bb8b7219/src/libraries/PermitHash.sol", + "https://github.com/Uniswap/UniswapX/blob/eb7ce077036258b9510b42ad37aa920cf3aaf308/src/lib/V3DutchOrderLib.sol", + "https://github.com/Uniswap/UniswapX/blob/eb7ce077036258b9510b42ad37aa920cf3aaf308/src/lib/OrderInfoLib.sol", + "https://github.com/Uniswap/UniswapX/blob/eb7ce077036258b9510b42ad37aa920cf3aaf308/src/lib/DutchOrderLib.sol", + "https://arbiscan.io/tx/0x1f2f270bf65d2b7f02b2a141f71e23bfcc3a84b37c9a0921577516c58031678d", + "https://github.com/Uniswap/UniswapX/blob/eb7ce077036258b9510b42ad37aa920cf3aaf308/src/lib/NonlinearDutchDecayLib.sol", + "https://github.com/Uniswap/UniswapX/blob/eb7ce077036258b9510b42ad37aa920cf3aaf308/src/types/Uint16Array.sol" + ], + "requires_capability": "eip712-chunked-values", + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "PermitWitnessTransferFrom": [ + { + "name": "permitted", + "type": "TokenPermissions" + }, + { + "name": "spender", + "type": "address" + }, + { + "name": "nonce", + "type": "uint256" + }, + { + "name": "deadline", + "type": "uint256" + }, + { + "name": "witness", + "type": "V3DutchOrder" + } + ], + "NonlinearDutchDecay": [ + { + "name": "relativeBlocks", + "type": "uint256" + }, + { + "name": "relativeAmounts", + "type": "int256[]" + } + ], + "OrderInfo": [ + { + "name": "reactor", + "type": "address" + }, + { + "name": "swapper", + "type": "address" + }, + { + "name": "nonce", + "type": "uint256" + }, + { + "name": "deadline", + "type": "uint256" + }, + { + "name": "additionalValidationContract", + "type": "address" + }, + { + "name": "additionalValidationData", + "type": "bytes" + } + ], + "TokenPermissions": [ + { + "name": "token", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "V3DutchInput": [ + { + "name": "token", + "type": "address" + }, + { + "name": "startAmount", + "type": "uint256" + }, + { + "name": "curve", + "type": "NonlinearDutchDecay" + }, + { + "name": "maxAmount", + "type": "uint256" + }, + { + "name": "adjustmentPerGweiBaseFee", + "type": "uint256" + } + ], + "V3DutchOrder": [ + { + "name": "info", + "type": "OrderInfo" + }, + { + "name": "cosigner", + "type": "address" + }, + { + "name": "startingBaseFee", + "type": "uint256" + }, + { + "name": "baseInput", + "type": "V3DutchInput" + }, + { + "name": "baseOutputs", + "type": "V3DutchOutput[]" + } + ], + "V3DutchOutput": [ + { + "name": "token", + "type": "address" + }, + { + "name": "startAmount", + "type": "uint256" + }, + { + "name": "curve", + "type": "NonlinearDutchDecay" + }, + { + "name": "recipient", + "type": "address" + }, + { + "name": "minAmount", + "type": "uint256" + }, + { + "name": "adjustmentPerGweiBaseFee", + "type": "uint256" + } + ] + }, + "primaryType": "PermitWitnessTransferFrom", + "domain": { + "name": "Permit2", + "chainId": 42161, + "verifyingContract": "0x000000000022D473030F116dDEE9F6B43aC78BA3" + }, + "message": { + "permitted": { + "token": "0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f", + "amount": "12514477" + }, + "spender": "0xB274d5F4b833b61B340b654d600A864fB604a87c", + "nonce": "1993355410060173619975858542007397613024848003638926934372819132074995782145", + "deadline": "1791402675", + "witness": { + "info": { + "reactor": "0xB274d5F4b833b61B340b654d600A864fB604a87c", + "swapper": "0x7f05C94cE299Eea9FCdAE798Be34E226a0cb1e77", + "nonce": "1993355410060173619975858542007397613024848003638926934372819132074995782145", + "deadline": "1791402675", + "additionalValidationContract": "0x0000000000000000000000000000000000000000", + "additionalValidationData": "0x" + }, + "cosigner": "0x4449Cd34d1eb1FEDCF02A1Be3834FfDe8E6A6180", + "startingBaseFee": "0", + "baseInput": { + "token": "0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f", + "startAmount": "12514477", + "curve": { + "relativeBlocks": "56539914882827008174051697847791522700364166669018632573655171137406238722", + "relativeAmounts": [ + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0", + "0" + ] + }, + "maxAmount": "12514477", + "adjustmentPerGweiBaseFee": "0" + }, + "baseOutputs": [ + { + "token": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", + "startAmount": "10407262726", + "curve": { + "relativeBlocks": "56539914882827008174051697847791522700364166669018632573655171137406238722", + "relativeAmounts": [ + "16261348", + "32522696", + "48784044", + "65045392", + "81306740", + "97568088", + "113829436", + "130090784", + "146352132", + "162613480", + "178874828", + "195136176", + "211397524", + "227658872", + "243920220", + "260181568" + ] + }, + "recipient": "0x7f05C94cE299Eea9FCdAE798Be34E226a0cb1e77", + "minAmount": "10147081157", + "adjustmentPerGweiBaseFee": "0" + } + ] + } + } + }, + "expected": { + "domain_separator": "8a6e6e19bdfb3db3409910416b47c2f8fc28b49488d6555c7fceaa4479135bc3", + "message_hash": "1b7a77c239ffc05a83f3ac787234661b980a447d8791a54a785d9bb8950f3255", + "digest": "95fbdb5178abf6c7d90c1f5d463cc767e7b08ae701238bde83b16d002e2d5a5a" + } + }, + { + "id": "uniswapx-V3DutchOrder-arbitrum-fee-output", + "source": [ + "https://github.com/Uniswap/permit2/blob/cc56ad0f3439c502c246fc5cfcc3db92bb8b7219/src/libraries/PermitHash.sol", + "https://github.com/Uniswap/UniswapX/blob/eb7ce077036258b9510b42ad37aa920cf3aaf308/src/lib/V3DutchOrderLib.sol", + "https://github.com/Uniswap/UniswapX/blob/eb7ce077036258b9510b42ad37aa920cf3aaf308/src/lib/OrderInfoLib.sol", + "https://github.com/Uniswap/UniswapX/blob/eb7ce077036258b9510b42ad37aa920cf3aaf308/src/lib/DutchOrderLib.sol", + "https://arbiscan.io/tx/0x3c67c0eb31f12747d675fe1c65734b2ce7b3ce608dcc02be348285b7435e7855" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "PermitWitnessTransferFrom": [ + { + "name": "permitted", + "type": "TokenPermissions" + }, + { + "name": "spender", + "type": "address" + }, + { + "name": "nonce", + "type": "uint256" + }, + { + "name": "deadline", + "type": "uint256" + }, + { + "name": "witness", + "type": "V3DutchOrder" + } + ], + "NonlinearDutchDecay": [ + { + "name": "relativeBlocks", + "type": "uint256" + }, + { + "name": "relativeAmounts", + "type": "int256[]" + } + ], + "OrderInfo": [ + { + "name": "reactor", + "type": "address" + }, + { + "name": "swapper", + "type": "address" + }, + { + "name": "nonce", + "type": "uint256" + }, + { + "name": "deadline", + "type": "uint256" + }, + { + "name": "additionalValidationContract", + "type": "address" + }, + { + "name": "additionalValidationData", + "type": "bytes" + } + ], + "TokenPermissions": [ + { + "name": "token", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "V3DutchInput": [ + { + "name": "token", + "type": "address" + }, + { + "name": "startAmount", + "type": "uint256" + }, + { + "name": "curve", + "type": "NonlinearDutchDecay" + }, + { + "name": "maxAmount", + "type": "uint256" + }, + { + "name": "adjustmentPerGweiBaseFee", + "type": "uint256" + } + ], + "V3DutchOrder": [ + { + "name": "info", + "type": "OrderInfo" + }, + { + "name": "cosigner", + "type": "address" + }, + { + "name": "startingBaseFee", + "type": "uint256" + }, + { + "name": "baseInput", + "type": "V3DutchInput" + }, + { + "name": "baseOutputs", + "type": "V3DutchOutput[]" + } + ], + "V3DutchOutput": [ + { + "name": "token", + "type": "address" + }, + { + "name": "startAmount", + "type": "uint256" + }, + { + "name": "curve", + "type": "NonlinearDutchDecay" + }, + { + "name": "recipient", + "type": "address" + }, + { + "name": "minAmount", + "type": "uint256" + }, + { + "name": "adjustmentPerGweiBaseFee", + "type": "uint256" + } + ] + }, + "primaryType": "PermitWitnessTransferFrom", + "domain": { + "name": "Permit2", + "chainId": 42161, + "verifyingContract": "0x000000000022D473030F116dDEE9F6B43aC78BA3" + }, + "message": { + "permitted": { + "token": "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9", + "amount": "1226547455" + }, + "spender": "0xB274d5F4b833b61B340b654d600A864fB604a87c", + "nonce": "1993355115482027011983709557485874525075304680291794092761105090895583133443", + "deadline": "1791393631", + "witness": { + "info": { + "reactor": "0xB274d5F4b833b61B340b654d600A864fB604a87c", + "swapper": "0xD606742f4f6a05305B59174C9DA0B3BB30987556", + "nonce": "1993355115482027011983709557485874525075304680291794092761105090895583133443", + "deadline": "1791393631", + "additionalValidationContract": "0x0000000000000000000000000000000000000000", + "additionalValidationData": "0x" + }, + "cosigner": "0x4449Cd34d1eb1FEDCF02A1Be3834FfDe8E6A6180", + "startingBaseFee": "0", + "baseInput": { + "token": "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9", + "startAmount": "1226547455", + "curve": { + "relativeBlocks": "32", + "relativeAmounts": [ + "0" + ] + }, + "maxAmount": "1226547455", + "adjustmentPerGweiBaseFee": "0" + }, + "baseOutputs": [ + { + "token": "0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f", + "startAmount": "1446161", + "curve": { + "relativeBlocks": "32", + "relativeAmounts": [ + "7232" + ] + }, + "recipient": "0xD606742f4f6a05305B59174C9DA0B3BB30987556", + "minAmount": "1438929", + "adjustmentPerGweiBaseFee": "0" + }, + { + "token": "0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f", + "startAmount": "23514", + "curve": { + "relativeBlocks": "32", + "relativeAmounts": [ + "117" + ] + }, + "recipient": "0x147CF09E7373B8FDA6f12021F1b0f98D6da1A566", + "minAmount": "23397", + "adjustmentPerGweiBaseFee": "0" + } + ] + } + } + }, + "expected": { + "domain_separator": "8a6e6e19bdfb3db3409910416b47c2f8fc28b49488d6555c7fceaa4479135bc3", + "message_hash": "d4e97cc058c321e71216e131c51438117e2c106360aa5d893bc194c54b51bfe1", + "digest": "4ef893b03e07c41dad0a7811640b7fcd7eafd518099eea36a6191f7c56061595" + } + }, + { + "id": "uniswapx-V3DutchOrder-arbitrum-negative-curve", + "source": [ + "https://github.com/Uniswap/permit2/blob/cc56ad0f3439c502c246fc5cfcc3db92bb8b7219/src/libraries/PermitHash.sol", + "https://github.com/Uniswap/UniswapX/blob/eb7ce077036258b9510b42ad37aa920cf3aaf308/src/lib/V3DutchOrderLib.sol", + "https://github.com/Uniswap/UniswapX/blob/eb7ce077036258b9510b42ad37aa920cf3aaf308/src/lib/OrderInfoLib.sol", + "https://github.com/Uniswap/UniswapX/blob/eb7ce077036258b9510b42ad37aa920cf3aaf308/src/lib/DutchOrderLib.sol", + "https://arbiscan.io/tx/0xfa14890926a78bb4095b7453c97150b3dea12fe8d53d21d97fd7366dfb595b7a" + ], + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "PermitWitnessTransferFrom": [ + { + "name": "permitted", + "type": "TokenPermissions" + }, + { + "name": "spender", + "type": "address" + }, + { + "name": "nonce", + "type": "uint256" + }, + { + "name": "deadline", + "type": "uint256" + }, + { + "name": "witness", + "type": "V3DutchOrder" + } + ], + "NonlinearDutchDecay": [ + { + "name": "relativeBlocks", + "type": "uint256" + }, + { + "name": "relativeAmounts", + "type": "int256[]" + } + ], + "OrderInfo": [ + { + "name": "reactor", + "type": "address" + }, + { + "name": "swapper", + "type": "address" + }, + { + "name": "nonce", + "type": "uint256" + }, + { + "name": "deadline", + "type": "uint256" + }, + { + "name": "additionalValidationContract", + "type": "address" + }, + { + "name": "additionalValidationData", + "type": "bytes" + } + ], + "TokenPermissions": [ + { + "name": "token", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "V3DutchInput": [ + { + "name": "token", + "type": "address" + }, + { + "name": "startAmount", + "type": "uint256" + }, + { + "name": "curve", + "type": "NonlinearDutchDecay" + }, + { + "name": "maxAmount", + "type": "uint256" + }, + { + "name": "adjustmentPerGweiBaseFee", + "type": "uint256" + } + ], + "V3DutchOrder": [ + { + "name": "info", + "type": "OrderInfo" + }, + { + "name": "cosigner", + "type": "address" + }, + { + "name": "startingBaseFee", + "type": "uint256" + }, + { + "name": "baseInput", + "type": "V3DutchInput" + }, + { + "name": "baseOutputs", + "type": "V3DutchOutput[]" + } + ], + "V3DutchOutput": [ + { + "name": "token", + "type": "address" + }, + { + "name": "startAmount", + "type": "uint256" + }, + { + "name": "curve", + "type": "NonlinearDutchDecay" + }, + { + "name": "recipient", + "type": "address" + }, + { + "name": "minAmount", + "type": "uint256" + }, + { + "name": "adjustmentPerGweiBaseFee", + "type": "uint256" + } + ] + }, + "primaryType": "PermitWitnessTransferFrom", + "domain": { + "name": "Permit2", + "chainId": 42161, + "verifyingContract": "0x000000000022D473030F116dDEE9F6B43aC78BA3" + }, + "message": { + "permitted": { + "token": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", + "amount": "18453595142" + }, + "spender": "0xB274d5F4b833b61B340b654d600A864fB604a87c", + "nonce": "1993353428323324451238365100392469529508888071612295616155122962755034285057", + "deadline": "1791397885", + "witness": { + "info": { + "reactor": "0xB274d5F4b833b61B340b654d600A864fB604a87c", + "swapper": "0xd603a49886c9B500f96C0d798aed10068D73bF7C", + "nonce": "1993353428323324451238365100392469529508888071612295616155122962755034285057", + "deadline": "1791397885", + "additionalValidationContract": "0x0000000000000000000000000000000000000000", + "additionalValidationData": "0x" + }, + "cosigner": "0x4449Cd34d1eb1FEDCF02A1Be3834FfDe8E6A6180", + "startingBaseFee": "0", + "baseInput": { + "token": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", + "startAmount": "18361786211", + "curve": { + "relativeBlocks": "32", + "relativeAmounts": [ + "-91808931" + ] + }, + "maxAmount": "18453595142", + "adjustmentPerGweiBaseFee": "0" + }, + "baseOutputs": [ + { + "token": "0x0000000000000000000000000000000000000000", + "startAmount": "7165000000000000000", + "curve": { + "relativeBlocks": "32", + "relativeAmounts": [ + "0" + ] + }, + "recipient": "0xd603a49886c9B500f96C0d798aed10068D73bF7C", + "minAmount": "7165000000000000000", + "adjustmentPerGweiBaseFee": "0" + } + ] + } + } + }, + "expected": { + "domain_separator": "8a6e6e19bdfb3db3409910416b47c2f8fc28b49488d6555c7fceaa4479135bc3", + "message_hash": "b8c2d5a7b402683b9422031588d6231566d3813eb284905088fdab5bbbfb3e27", + "digest": "6e576a58ecf5e234ea6fc3eae0b97fe2ac8fa90c5a8e822da53fad929b5977b2" + } + }, + { + "id": "safe-SafeTx-multisend-4900", + "source": [ + "https://github.com/safe-global/safe-smart-account/blob/v1.3.0/contracts/GnosisSafe.sol", + "https://api.safe.global/tx-service/eth/api/v1/multisig-transactions/0x41bb8e482fadb98e15032ad92890e4289e3986030b7eee9ad061284481ceefc5/", + "https://etherscan.io/tx/0x9ab909ba050b277e8b426b90e299b6bd107a1baf8c59f95153b45e067475bf38" + ], + "requires_capability": "eip712-chunked-values", + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "SafeTx": [ + { + "name": "to", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + }, + { + "name": "data", + "type": "bytes" + }, + { + "name": "operation", + "type": "uint8" + }, + { + "name": "safeTxGas", + "type": "uint256" + }, + { + "name": "baseGas", + "type": "uint256" + }, + { + "name": "gasPrice", + "type": "uint256" + }, + { + "name": "gasToken", + "type": "address" + }, + { + "name": "refundReceiver", + "type": "address" + }, + { + "name": "nonce", + "type": "uint256" + } + ] + }, + "primaryType": "SafeTx", + "domain": { + "chainId": 1, + "verifyingContract": "0x849D52316331967b6fF1198e5E32A0eB168D039d" + }, + "message": { + "to": "0x40A2aCCbd92BCA938b02010E17A5b8929b49130D", + "value": "0", + "data": "0x8d80ff0a000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000012d20027d8bb2e33bc38a9ce93fdd90c80677b8436affb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000440c6c76b8475541524449414e2d4175726152656c6f636b657200000000000000000000000000000000000000000000005b2364fd757e262253423373e4d57c5c011ad7f40027d8bb2e33bc38a9ce93fdd90c80677b8436affb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011e47508dd98475541524449414e2d4175726152656c6f636b657200000000000000000000000000000000000000000000005b2364fd757e262253423373e4d57c5c011ad7f4d34640b20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000002c00000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004a0000000000000000000000000000000000000000000000000000000000000054000000000000000000000000000000000000000000000000000000000000005e00000000000000000000000000000000000000000000000000000000000000680000000000000000000000000000000000000000000000000000000000000072000000000000000000000000000000000000000000000000000000000000007c00000000000000000000000000000000000000000000000000000000000000860000000000000000000000000000000000000000000000000000000000000090000000000000000000000000000000000000000000000000000000000000009a00000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000ae00000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c200000000000000000000000000000000000000000000000000000000000000cc00000000000000000000000000000000000000000000000000000000000000d600000000000000000000000000000000000000000000000000000000000000e200000000000000000000000000000000000000000000000000000000000000ee00000000000000000000000000000000000000000000000000000000000000fa0000000000000000000000000000000000000000000000000000000000000106000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000", + "operation": 1, + "safeTxGas": "0", + "baseGas": "0", + "gasPrice": "0", + "gasToken": "0x0000000000000000000000000000000000000000", + "refundReceiver": "0x0000000000000000000000000000000000000000", + "nonce": "2372" + } + }, + "expected": { + "domain_separator": "561d71a273896bbd4ecfb3e135730658c966531ed15bdee93660d109a8970f01", + "message_hash": "0d579dc9c09d2e219fdeb0e2e000ca33371e6f426ebf26f2a73e0559dd5b8e78", + "digest": "41bb8e482fadb98e15032ad92890e4289e3986030b7eee9ad061284481ceefc5" + } + }, + { + "id": "safe-SafeTx-multisend-approve-unlimited", + "source": [ + "https://github.com/safe-global/safe-smart-account/blob/v1.3.0/contracts/GnosisSafe.sol", + "https://github.com/safe-global/safe-smart-account/blob/v1.3.0/contracts/libraries/MultiSendCallOnly.sol", + "https://api.safe.global/tx-service/eth/api/v1/multisig-transactions/0xc5a2fac8f82fb6185796bf07e1c1d17b52538414c6e87c3dbc7b4f1bb2e16c12/", + "https://etherscan.io/tx/0x171f08630810946c52d3b379839e66b2dcb67db91f1be9ab3acbe74bac16af06" + ], + "requires_capability": "eip712-chunked-values", + "unlimited_screen": "Allow 0xC92E8bdf79f0507f65a392b0ab4667716BFE0110 to spend ALL your WETH", + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + } + ], + "SafeTx": [ + { + "name": "to", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + }, + { + "name": "data", + "type": "bytes" + }, + { + "name": "operation", + "type": "uint8" + }, + { + "name": "safeTxGas", + "type": "uint256" + }, + { + "name": "baseGas", + "type": "uint256" + }, + { + "name": "gasPrice", + "type": "uint256" + }, + { + "name": "gasToken", + "type": "address" + }, + { + "name": "refundReceiver", + "type": "address" + }, + { + "name": "nonce", + "type": "uint256" + } + ] + }, + "primaryType": "SafeTx", + "domain": { + "chainId": 1, + "verifyingContract": "0x245cc372C84B3645Bf0Ffe6538620B04a217988B" + }, + "message": { + "to": "0x40A2aCCbd92BCA938b02010E17A5b8929b49130D", + "value": "0", + "data": "0x8d80ff0a0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000019200c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044095ea7b3000000000000000000000000c92e8bdf79f0507f65a392b0ab4667716bfe0110ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009008d19f58aabd9ed0d60971565aa8510560ab41000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a4ec6cb13f0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000380c22c8071c7af43fd1f72d8f076e5ca5ef1bc341cd07607f2eef6a63d5940c80245cc372c84b3645bf0ffe6538620b04a217988b692df75700000000000000000000000000000000000000000000", + "operation": 1, + "safeTxGas": 0, + "baseGas": 0, + "gasPrice": "0", + "gasToken": "0x0000000000000000000000000000000000000000", + "refundReceiver": "0x0000000000000000000000000000000000000000", + "nonce": "1802" + } + }, + "expected": { + "domain_separator": "962a762e4486fcd558237b6934e27ec2383bc843e1bba8996935225f84c910ec", + "message_hash": "9b200c822d235c9321d93e495fa4e3b53eb7aa570ea8746e886b96a8a72386f0", + "digest": "c5a2fac8f82fb6185796bf07e1c1d17b52538414c6e87c3dbc7b4f1bb2e16c12" + } + }, + { + "id": "snapshot-Proposal-body-3929", + "source": [ + "https://github.com/snapshot-labs/snapshot.js/blob/ae2a8209e03ca1fa133a9105949a9386f3b539ed/src/sign/types.ts", + "https://snapshot.box/#/s:arbitrumfoundation.eth/proposal/0xa69fce8c756ac96160ddb6ac09653d3254415d046fdd43e5876663e9f343f183", + "ipfs://bafkreibjtqf4eeo3lstytfcqaxeyr2ycxzxysjhtuyyxe7bkf5rzowfvtu" + ], + "requires_capability": "eip712-chunked-values", + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + } + ], + "Proposal": [ + { + "name": "from", + "type": "string" + }, + { + "name": "space", + "type": "string" + }, + { + "name": "timestamp", + "type": "uint64" + }, + { + "name": "type", + "type": "string" + }, + { + "name": "title", + "type": "string" + }, + { + "name": "body", + "type": "string" + }, + { + "name": "discussion", + "type": "string" + }, + { + "name": "choices", + "type": "string[]" + }, + { + "name": "labels", + "type": "string[]" + }, + { + "name": "start", + "type": "uint64" + }, + { + "name": "end", + "type": "uint64" + }, + { + "name": "snapshot", + "type": "uint64" + }, + { + "name": "plugins", + "type": "string" + }, + { + "name": "privacy", + "type": "string" + }, + { + "name": "app", + "type": "string" + } + ] + }, + "primaryType": "Proposal", + "domain": { + "name": "snapshot", + "version": "0.1.4" + }, + "message": { + "from": "0xb4c064f466931B8d0F637654c916E3F203c46f13", + "timestamp": 1781800138, + "space": "arbitrumfoundation.eth", + "title": "Extending DRIP\u2019s Mandate", + "body": "### Non-Constitutional\n\n## Abstract\n\nThis proposal extends the DRIP program's mandate end date from July 1st, 2026 to July 1st, 2027, giving the Season Selection Committee additional time to deploy remaining funds across future seasons. No additional funding is requested in this proposal. All other terms of the original DRIP proposal remain unchanged, such as the committee composition and the DAO's ability to terminate the program via an offchain vote.\n\n## Motivation\n\nAs background, when the DAO approved DRIP in June 2025, the proposal outlined a 1-year mandate to execute up to 4 seasons with a total budget of 80M ARB. Season durations were originally estimated to be ~3-months, despite the proposal acknowledging this length was somewhat [arbitrary](https://forum.arbitrum.foundation/t/defi-renaissance-incentive-program-drip/29049#:~:text=The%20committee%20will%20maintain%20the%20right%20to%20modify%2C%20extend%2C%20or%20discontinue%20a%20season%20during%20its%20lifecycle.%20The%20%E2%80%9C3%2Dmonth%E2%80%9D%20timeline%20is%20somewhat%20arbitrary%2C%20and%20is%20open%20to%20change%20dependent%20on%20perceived%20program%20success%20and%20market%20conditions.) and the Season Selection Committee retained the ability to modify or extend season lengths.\n\nWhen designing Season 1 in collaboration with the selected distribution partner, Merkl, it became clear that a 3-month season was likely too short of a time period to run an effective campaign. Going live in early September, Season 1 ultimately ran for approximately 5.5 months to fully utilize the distribution partnerships secured and to create a slower tapering of rewards. We believe these design decisions helped the campaign achieve an overall adjusted cost-effectiveness ratio of 51 (76 on USD assets specifically), the highest of any major Arbitrum incentive program to date, alongside yield-bearing stablecoin supply growth on Arbitrum from $130M to over $1B, as detailed in the season [retrospective](https://forum.arbitrum.foundation/t/drip-season-1-retrospective/30644).\n\nWe want to address the most obvious question upfront. Since DRIP Season 1 concluded on February 18, 2026, the program has been quiet. We recognize that work on the next season has taken longer than we anticipated and appreciate the DAO\u2019s patience.\n\nThere are several strategic developments in flight that materially affect what an effective Season 2 should be designed around. We judged it more prudent to wait than to deploy meaningful ARB in a shortened season that did not fully align with these developments should they be confirmed. Spending 15-20M ARB on the wrong campaign is a much worse outcome than waiting a few additional months to run the right one. We are not in a position to detail every development driving this judgment publicly, but the OAT, Offchain, and the Arbitrum Foundation have been looped in throughout, and we hope to be able to share more in the coming weeks. The remaining ~63.7M ARB budget continues to sit with the AF, with deployment subject to Season Selection Committee approval.\n\n## Specification\n\nExtend the DRIP mandate end date from July 1st, 2026 to July 1st, 2027.\n\nThe following language from the original proposal:\n\n> \"DRIP End Date (funds returned if not used or another proposal is not passed): July 1, 2026. An ongoing season may go past this date, but new seasons will not begin after this date.\"\n\nIs amended to:\n\n> \"DRIP End Date (funds returned if not used or another proposal is not passed): July 1, 2027. An ongoing season may go past this date, but new seasons will not begin after this date.\"\n\nAll other terms of the original DRIP proposal, including the 80M ARB total budget, season structure, Season Selection Committee composition and approval thresholds, and the DAO's ability to terminate the program remain unchanged.\n\n## Timeline\n\n- Forum: Thursday June 11th, 2026\n \n- Offchain vote: Thursday June 18th, 2026", + "type": "basic", + "discussion": "https://forum.arbitrum.foundation/t/extending-drips-mandate/30985/1", + "choices": [ + "For", + "Against", + "Abstain" + ], + "privacy": "", + "labels": [], + "start": 1781800800, + "end": 1782405600, + "snapshot": 474836218, + "plugins": "{}", + "app": "snapshot-v2" + } + }, + "expected": { + "domain_separator": "484fce18f892e8535a4b6700e197a8026f4213f809d23ae117da03b497e18670", + "message_hash": "19195d2352d10330a4ad01c832298eea9b353e113154932be82e856eb3aa87c1", + "digest": "a69fce8c756ac96160ddb6ac09653d3254415d046fdd43e5876663e9f343f183" + } + }, + { + "id": "evmos-MsgSend", + "source": [ + "https://github.com/evmos/evmosjs/blob/e47e44b1683ffa57737cee2f6abbd138436d9fc3/packages/eip712/src/messages/base.ts", + "https://github.com/evmos/evmosjs/blob/e47e44b1683ffa57737cee2f6abbd138436d9fc3/packages/eip712/src/messages/bank/send.ts", + "https://github.com/evmos/evmosjs/blob/e47e44b1683ffa57737cee2f6abbd138436d9fc3/packages/eip712/src/tests/utils.ts" + ], + "requires_capability": "eip712-chunked-values", + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "string" + }, + { + "name": "salt", + "type": "string" + } + ], + "Tx": [ + { + "name": "account_number", + "type": "string" + }, + { + "name": "chain_id", + "type": "string" + }, + { + "name": "fee", + "type": "Fee" + }, + { + "name": "memo", + "type": "string" + }, + { + "name": "msgs", + "type": "Msg[]" + }, + { + "name": "sequence", + "type": "string" + } + ], + "Fee": [ + { + "name": "feePayer", + "type": "string" + }, + { + "name": "amount", + "type": "Coin[]" + }, + { + "name": "gas", + "type": "string" + } + ], + "Coin": [ + { + "name": "denom", + "type": "string" + }, + { + "name": "amount", + "type": "string" + } + ], + "Msg": [ + { + "name": "type", + "type": "string" + }, + { + "name": "value", + "type": "MsgValue" + } + ], + "MsgValue": [ + { + "name": "from_address", + "type": "string" + }, + { + "name": "to_address", + "type": "string" + }, + { + "name": "amount", + "type": "TypeAmount[]" + } + ], + "TypeAmount": [ + { + "name": "denom", + "type": "string" + }, + { + "name": "amount", + "type": "string" + } + ] + }, + "primaryType": "Tx", + "domain": { + "name": "Cosmos Web3", + "version": "1.0.0", + "chainId": 9001, + "verifyingContract": "cosmos", + "salt": "0" + }, + "message": { + "account_number": "10", + "chain_id": "evmos_9001-2", + "fee": { + "feePayer": "evmos1pmk2r32ssqwps42y3c9d4clqlca403yd9wymgr", + "amount": [ + { + "denom": "aevmos", + "amount": "4000000000000000" + } + ], + "gas": "200000" + }, + "memo": "Transaction Memo", + "msgs": [ + { + "type": "cosmos-sdk/MsgSend", + "value": { + "from_address": "evmos1pmk2r32ssqwps42y3c9d4clqlca403yd9wymgr", + "to_address": "evmos12nml2w93uva0smjw3c36stczfay0k67ny94ecz", + "amount": [ + { + "denom": "aevmos", + "amount": "1000000000000000000" + } + ] + } + } + ], + "sequence": "6" + } + }, + "expected": { + "domain_separator": "1633cfb1cf33b8790808cb60604cfd1f261c59a367ccb3aaff568a000149ace9", + "message_hash": "57c04fd23163cd0f2f0d20d6e9228010f7b111e0a499c208bc798b6e1aae9d0c", + "digest": "a475e759cc3637f92de75029aeb2eee6e410efae4a0b1834d8529853f06cf5f8" + } + }, + { + "id": "injective-MsgSend-v2", + "source": [ + "https://github.com/InjectiveLabs/injective-ts/blob/f8373753d6fe0662c1a8af7fb88192ad126e2e2e/packages/sdk-ts/src/core/tx/eip712/eip712.spec.ts", + "https://github.com/InjectiveLabs/injective-ts/blob/f8373753d6fe0662c1a8af7fb88192ad126e2e2e/packages/sdk-ts/src/core/tx/eip712/utils.ts", + "https://github.com/InjectiveLabs/injective-ts/blob/f8373753d6fe0662c1a8af7fb88192ad126e2e2e/packages/utils/src/test-utils/mocks/index.ts" + ], + "requires_capability": "eip712-chunked-values", + "doc": { + "types": { + "EIP712Domain": [ + { + "name": "name", + "type": "string" + }, + { + "name": "version", + "type": "string" + }, + { + "name": "chainId", + "type": "uint256" + }, + { + "name": "verifyingContract", + "type": "address" + }, + { + "name": "salt", + "type": "string" + } + ], + "Tx": [ + { + "name": "context", + "type": "string" + }, + { + "name": "msgs", + "type": "string" + } + ] + }, + "primaryType": "Tx", + "domain": { + "name": "Injective Web3", + "version": "1.0.0", + "chainId": "0x5", + "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC", + "salt": "0" + }, + "message": { + "context": "{\"account_number\":11,\"chain_id\":\"injective-777\",\"fee\":{\"amount\":[{\"denom\":\"inj\",\"amount\":\"64000000000000\"}],\"gas\":400000,\"payer\":\"inj18j2myhaf2at75kwwaqxfstk4q28n4am45nlfg7\",\"granter\":\"inj1granter\"},\"memo\":\"\",\"sequence\":88,\"timeout_height\":1896}", + "msgs": "[{\"@type\":\"/cosmos.bank.v1beta1.MsgSend\",\"from_address\":\"inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku\",\"to_address\":\"inj14au322k9munkmx5wrchz9q30juf5wjgz2cfqku\",\"amount\":[{\"denom\":\"inj\",\"amount\":\"10000000000000000\"}]}]" + } + }, + "expected": { + "domain_separator": "a908147858193dcbc852a78aa9ab32d35da72e7229292dd41a6d1b02b305d1cd", + "message_hash": "699085c19a1eae36c57c33a44f907a1e805ce9f7c5ee1a0cdec62057839e85fb", + "digest": "0a599095745e1057fe40b2c5e36bcf753d38d1fcb8106f12c15c51aed3237e2e" + } + } +] diff --git a/tests/oled_text.py b/tests/oled_text.py index b67d0b7f..df8fa3f8 100644 --- a/tests/oled_text.py +++ b/tests/oled_text.py @@ -15,7 +15,8 @@ draw_string_walk() in lib/board/draw.c breaks them (a 44-character Solana address always wraps), each line whole -- nothing drawn just before or after it -- and the lines left-aligned on consecutive rows of ONE screen. A body -that pages is not found; assert each page's part instead. +that pages is not found; assert each page's part instead. shows_address() +finds an address or key the way the QR-code address screens draw it. """ from __future__ import print_function @@ -66,12 +67,12 @@ def _font(table): 7:00000000001f03303303301f003003 7:00000000003e03303303303e030030 6:00000000001f007003003003000000 7:00000000003e00301e03001f000000 6:00000600601f00600600601c000000 7:00000000003303303303303e000000 7:00000000003303301e01e00c000000 9:0000000000db0db0db0db07e000000 7:00000000003301e00c01e033000000 7:00000000003303303303303e03001e 7:00000000003f01800c00603f000000 6:00001c00600600300600601c000000 -3:000003003003003003003003000000 6:00000700c00c01800c00c007000000 7:00003e01f000000000000000000000 +3:003003003003003003003003003003 6:00000700c00c01800c00c007000000 7:00003e01f000000000000000000000 """) BODY_FONT = _font(""" 4:00000000000000000000 2:00010101010100010000 4:00050500000000000000 7:00123f12123f12000000 -6:041e05050e14140f0400 8:00422512082452210000 7:000609090629112e0000 2:00010100000000000000 +6:041e05050e14140f0400 8:00422512082452210000 7:000609090629112e0000 3:00020100000000000000 3:02010101010101010200 3:01020202020202020100 6:04150e15040000000000 6:000004041f0404000000 3:00000000000003030201 6:000000001f0000000000 3:00000000000003030000 8:00402010080402010000 6:000e11191513110e0000 3:00030202020202020000 6:000f10100e01011f0000 6:000f10100e10100f0000 @@ -93,7 +94,7 @@ def _font(table): 6:0000000f1111110f0101 6:0000001e1111111e1010 5:0000000d030101010000 6:0000001e010e100f0000 5:0002020f0202020c0000 6:000000111111111e0000 6:00000011110a0a040000 8:00000049494949360000 6:000000110a040a110000 6:000000111111111e100e 6:0000001f0804021f0000 5:000c02020102020c0000 -2:00010101010101010000 5:00030404080404030000 7:00404020201214080000 +2:01010101010101010101 5:00030404080404030000 7:00404020201214080000 """) @@ -145,16 +146,23 @@ def _render(line, font): return x, rows -def _at(rows, want, width, x, y, whole): +def _at(rows, want, width, x, y, whole, end=256): """`want` drawn at (x, y); if `whole`, with nothing lit within a glyph's - width on either side of it (a longer line is not this line).""" + width on either side of it (a longer line is not this line) -- short of + `end`, the wrap limit, past which the line cannot continue and an icon + may sit. A row with no ink in `want` is not compared: layout_address() + draws the QR code after the text, and its border may cover the line's + blank top row.""" mask = (1 << width) - 1 - if any((rows[y + r] >> x) & mask != want[r] for r in range(GLYPH_HEIGHT)): + if any(want[r] and (rows[y + r] >> x) & mask != want[r] + for r in range(GLYPH_HEIGHT)): return False if not whole: return True before = min(x, 9) - edges = ((1 << before) - 1) << (x - before) | 0x1ff << (x + width) + after = max(0, min(end - x - width, 9)) + edges = ((1 << before) - 1) << (x - before) | \ + ((1 << after) - 1) << (x + width) return not any(rows[y + r] & edges for r in range(GLYPH_HEIGHT)) @@ -170,19 +178,44 @@ def find_line(layout, line, font=BODY_FONT): return None -def shows(layout, text, font=BODY_FONT, width=BODY_WIDTH): - """Whether this screen shows `text` as confirm() draws a body.""" +def shows(layout, text, font=BODY_FONT, width=BODY_WIDTH, + pitch=BODY_LINE_PITCH): + """Whether this screen shows `text` as confirm() draws a body, or as + draw_string() draws it at another wrap width and line pitch.""" lines = [_render(line, font) for line in wrap(text, font, width)] rows = _rows(layout) - height = (len(lines) - 1) * BODY_LINE_PITCH + GLYPH_HEIGHT + height = (len(lines) - 1) * pitch + GLYPH_HEIGHT for y in range(64 - height + 1): for x in range(256 - lines[0][0] + 1): - if all(_at(rows, want, w, x, y + i * BODY_LINE_PITCH, True) + if all(_at(rows, want, w, x, y + i * pitch, True, x + width) for i, (w, want) in enumerate(lines)): return True return False +# How lib/firmware/app_layout.c draws an address or key beside its QR code, +# as (font, wrap width, line pitch): +ADDRESS_LAYOUTS = ( + # layout_address_notification(): bold while it fits TRANSACTION_WIDTH... + (TITLE_FONT, 250, BODY_LINE_PITCH), + # ...else the body font, its lines closed up to the font height. + (BODY_FONT, 250, GLYPH_HEIGHT), + # layout_{ethereum,cosmos,nano}_address_notification(); two lines fit. + (BODY_FONT, 140, BODY_LINE_PITCH), + # layout_osmosis_address_notification() + (BODY_FONT, 160, BODY_LINE_PITCH), + # confirm() bodies and layout_xpub_notification() (TRANSACTION_WIDTH - 25) + (BODY_FONT, BODY_WIDTH, BODY_LINE_PITCH), +) + + +def shows_address(layout, text): + """Whether this screen shows ALL of `text` in one of ADDRESS_LAYOUTS. A + layout that drops the lines past the bottom of the screen does not.""" + return any(shows(layout, text, font, width, pitch) + for font, width, pitch in ADDRESS_LAYOUTS) + + def find_text(screens, text, font=BODY_FONT, width=BODY_WIDTH, start=0): """Index of the first screen from `start` that shows `text`, or None.""" for i in range(start, len(screens)): diff --git a/tests/test_msg_cosmos_getaddress.py b/tests/test_msg_cosmos_getaddress.py index 86d6691e..ca619356 100644 --- a/tests/test_msg_cosmos_getaddress.py +++ b/tests/test_msg_cosmos_getaddress.py @@ -28,7 +28,9 @@ def test_standard(self): cosmos_proto.CosmosAddress(address=expected) ]) - self.assertEqual(expected, self.client.cosmos_get_address(path, show_display=True)) + self.assertEqual(expected, self.assert_shows_address( + lambda: self.client.cosmos_get_address(path, show_display=True), + expected)) with self.client: self.client.set_expected_responses([ @@ -61,7 +63,9 @@ def test_nonstandard(self): cosmos_proto.CosmosAddress(address=expected) ]) - self.assertEqual(expected, self.client.cosmos_get_address(path, show_display=True)) + self.assertEqual(expected, self.assert_shows_address( + lambda: self.client.cosmos_get_address(path, show_display=True), + expected)) with self.client: self.client.set_expected_responses([ @@ -85,10 +89,12 @@ def test_cosmos_get_address_sep(self): address = self.client.cosmos_get_address(parse_path(DEFAULT_BIP32_PATH)) assert address == "cosmos1jcwdsdelc4cwvall0twl974sfkpqmzrgkszu9l" - address = self.client.cosmos_get_address( - parse_path("m/44h/118h/1h/0/0"), show_display=True - ) - assert address == "cosmos1280uphuty5rxr2m05t6xujvylkkftlrvdnw0pp" + expected = "cosmos1280uphuty5rxr2m05t6xujvylkkftlrvdnw0pp" + address = self.assert_shows_address( + lambda: self.client.cosmos_get_address( + parse_path("m/44h/118h/1h/0/0"), show_display=True), + expected) + assert address == expected def test_onchain(self): self.requires_fullFeature() diff --git a/tests/test_msg_cosmos_signtx.py b/tests/test_msg_cosmos_signtx.py index 703ed36f..b04d5b35 100644 --- a/tests/test_msg_cosmos_signtx.py +++ b/tests/test_msg_cosmos_signtx.py @@ -5,11 +5,16 @@ from binascii import hexlify, unhexlify import keepkeylib.messages_pb2 as proto +import keepkeylib.messages_cosmos_pb2 as cosmos_proto import keepkeylib.types_pb2 as proto_types from keepkeylib.tools import parse_path DEFAULT_BIP32_PATH = "m/44h/118h/0h/0/0" +# Real 52-character operator addresses (valid bech32): three 140 px rows. +VALIDATOR = "cosmosvaloper1sjllsnramtg3ewxqwwrwjxfgc4n4ef9u2lcnj0" +VALIDATOR_2 = "cosmosvaloper1c4k24jzduc365kywrsvf5ujz4ya6mwympnc4en" + def make_send(from_address, to_address, amount): return { 'type': 'cosmos-sdk/MsgSend', @@ -127,5 +132,57 @@ def test_onchain2(self): self.assertEqual(hexlify(signature.signature), "71295606d64f1fa987fea1af2292d0b735a5c2d5104b7cc3f818a7208ea9b1a504a386c40011242c115f77268c67af841d29137af5d608d21361ebc7e0513a11") + def _sign_staking(self, **msg): + path = parse_path(DEFAULT_BIP32_PATH) + self.client.call(cosmos_proto.CosmosSignTx( + address_n=path, account_number=19637, chain_id="cosmoshub-4", + fee_amount=5000, gas=200000, memo="", sequence=3, msg_count=1)) + resp = self.client.call(cosmos_proto.CosmosMsgAck(**msg)) + self.assertIsInstance(resp, cosmos_proto.CosmosSignedTx) + return resp + + def _delegator(self): + self.setup_mnemonic_nopin_nopassphrase() + return self.client.cosmos_get_address(parse_path(DEFAULT_BIP32_PATH)) + + # 7.14.x drops the third row of a validator address: these skip there. + def test_delegate_shows_whole_validator(self): + self.requires_fullFeature() + self.requires_firmware("7.15.0") + me = self._delegator() + self.assert_shows_address(lambda: self._sign_staking( + delegate=cosmos_proto.CosmosMsgDelegate( + delegator_address=me, validator_address=VALIDATOR, + amount=1000000)), VALIDATOR) + + def test_undelegate_shows_whole_validator(self): + self.requires_fullFeature() + self.requires_firmware("7.15.0") + me = self._delegator() + self.assert_shows_address(lambda: self._sign_staking( + undelegate=cosmos_proto.CosmosMsgUndelegate( + delegator_address=me, validator_address=VALIDATOR, + amount=1000000)), VALIDATOR) + + def test_redelegate_shows_both_whole_validators(self): + self.requires_fullFeature() + self.requires_firmware("7.15.0") + me = self._delegator() + # Nested: the inner check sees the same screens as the outer one. + self.assert_shows_address(lambda: self.assert_shows_address( + lambda: self._sign_staking( + redelegate=cosmos_proto.CosmosMsgRedelegate( + delegator_address=me, validator_src_address=VALIDATOR, + validator_dst_address=VALIDATOR_2, amount=1000000)), + VALIDATOR), VALIDATOR_2) + + def test_rewards_shows_whole_validator(self): + self.requires_fullFeature() + self.requires_firmware("7.15.0") + me = self._delegator() + self.assert_shows_address(lambda: self._sign_staking( + rewards=cosmos_proto.CosmosMsgRewards( + delegator_address=me, validator_address=VALIDATOR)), VALIDATOR) + if __name__ == '__main__': unittest.main() diff --git a/tests/test_msg_display_disclosure.py b/tests/test_msg_display_disclosure.py index c7493380..62379388 100644 --- a/tests/test_msg_display_disclosure.py +++ b/tests/test_msg_display_disclosure.py @@ -243,6 +243,14 @@ def _assert_distinguishable(self, a_label, a_msg, b_label, b_msg): # ── the property, at each place an implementation stops looking ───── + def test_pipe_is_distinguishable_from_lowercase_l(self): + self._assert_distinguishable( + 'lowercase letters', b'allow', 'vertical bars', b'a||ow') + + def test_double_quote_is_distinguishable_from_two_apostrophes(self): + self._assert_distinguishable( + 'one double quote', b'"', 'two apostrophes', b"''") + def test_bytes_past_an_embedded_nul_are_disclosed(self): """A protobuf `bytes` field is not a C string. diff --git a/tests/test_msg_eip712_corpus.py b/tests/test_msg_eip712_corpus.py new file mode 100644 index 00000000..a288af64 --- /dev/null +++ b/tests/test_msg_eip712_corpus.py @@ -0,0 +1,126 @@ +# Real-world EIP-712 documents must sign. +# +# eip712_corpus.json holds one document per protocol (Permit2, UniswapX, +# Seaport, LooksRare, Blur, 1inch, CoW, 0x, Safe, EIP-2612/DAI, Hyperliquid, +# Polymarket, Compound, Aave, dYdX, Across, Snapshot, eth-sig-util, and the +# Ethermint chains Evmos and Injective), written +# from the type strings in each protocol's own source ("source" in each +# entry). It is generated by unittests/firmware/eip712_corpus_gen.py in the +# firmware repository, whose "expected" hashes were computed by a reference +# encoder and cross-checked against @metamask/eth-sig-util and ethers. +# +# Each document is its own test (test_doc_). Every one must be ACCEPTED: its hashes must equal both the embedded +# values and this suite's own independent encoder, its signature must +# recover to the device's address, and the final screen must name the whole +# primary type. A document with "requires_capability" (the max approvals) +# runs only where the firmware reports it; before 7.16 its value screen is +# titled UNLIMITED APPROVAL and shows "unlimited_screen". + +import json +import os +import re +import unittest + +import common +import oled_text +import test_msg_eip712_streaming as streaming +from keepkeylib import messages_ethereum_pb2 as eth +from keepkeylib import types_pb2 as types + +CORPUS = os.path.join(os.path.dirname(os.path.abspath(__file__)), + 'eip712_corpus.json') + + +def load_corpus(): + with open(CORPUS) as f: + return json.load(f) + + +class TestEip712CorpusReference(unittest.TestCase): + + def test_embedded_hashes_match_the_independent_encoder(self): + """The suite's own encoder agrees with the generator's values.""" + for entry in load_corpus(): + with self.subTest(entry['id']): + domain, message, digest = \ + streaming.reference_eip712_hashes(entry['doc']) + self.assertEqual(domain.hex(), + entry['expected']['domain_separator']) + self.assertEqual(message.hex(), + entry['expected']['message_hash']) + self.assertEqual(digest.hex(), entry['expected']['digest']) + + +class TestMsgEip712Corpus(common.KeepKeyTest): + + # The device-driven walk from the streaming suite; borrowed, not + # inherited, so its tests do not run twice. + _walk = streaming.TestMsgEip712Streaming._walk + _chunked_values = streaming.TestMsgEip712Streaming._chunked_values + + def setUp(self): + super(TestMsgEip712Corpus, self).setUp() + self.requires_firmware("7.15.0") + self.requires_fullFeature() + self.requires_structured_eip712() + self.setup_mnemonic_nopin_nopassphrase() + self.client.apply_policy('AdvancedMode', 0) + self.client.reset_screenshots() + + def _sign_and_check(self, entry): + needs = entry.get('requires_capability') + if needs and needs not in (self.firmware_capabilities() or ()): + self.skipTest("Staged release tree does not yet provide " + "capability: " + needs) + address = self.client.ethereum_get_address(streaming.PATH) + doc = entry['doc'] + resp = self._walk(doc, max_steps=2000) + self.assertIsInstance(resp, eth.EthereumTypedDataSignature, + getattr(resp, 'message', resp)) + self.assertEqual(resp.domain_separator_hash.hex(), + entry['expected']['domain_separator']) + self.assertEqual(resp.message_hash.hex(), + entry['expected']['message_hash']) + digest = bytes.fromhex(entry['expected']['digest']) + self.assertEqual( + streaming.recover_signer(resp.signature, digest).hex(), + address.hex()) + # The final screen (and its continuation pages) names the whole + # primary type, however long. + codes = [code for code, _ in self.frames] + self.assertEqual(codes.count(types.ButtonRequest_SignTx), 1) + final = codes.index(types.ButtonRequest_SignTx) + self.assertIsNotNone(oled_text.find_text( + [layout for _, layout in self.frames[final:]], + 'Sign ' + doc['primaryType'])) + warned = [layout for _, layout in self.frames + if oled_text.find_line(layout, 'UNLIMITED APPROVAL', + oled_text.TITLE_FONT) + is not None] + if 'unlimited_screen' not in entry: + self.assertEqual(warned, []) + elif not self.firmware_at_least("7.16.0"): + self.assertEqual(len(warned), 1) + self.assertTrue(oled_text.shows( + warned[0], entry['unlimited_screen'])) + + +# One test per document, so each gets its own timeout and failure line: +# test_doc_seaport_OrderComponents_bundle_10x6, ... +def _add_document_tests(): + for entry in load_corpus(): + spelled = entry['id'].replace('[]', '_array') + name = 'test_doc_' + re.sub(r'[^0-9A-Za-z]+', '_', spelled).strip('_') + assert not hasattr(TestMsgEip712Corpus, name), name + + def test(self, entry=entry): + self._sign_and_check(entry) + test.__name__ = name + test.__doc__ = entry['id'] + ' signs with the expected hashes.' + setattr(TestMsgEip712Corpus, name, test) + + +_add_document_tests() + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_msg_eip712_streaming.py b/tests/test_msg_eip712_streaming.py index 0acf531a..676a4133 100644 --- a/tests/test_msg_eip712_streaming.py +++ b/tests/test_msg_eip712_streaming.py @@ -158,6 +158,59 @@ def test_reference_encoder_reproduces_the_published_spec_hashes(self): self.assertEqual(domain.hex(), SPEC_DOMAIN_SEPARATOR) self.assertEqual(message.hex(), SPEC_MESSAGE_HASH) + def test_long_values_are_chunked_only_for_capable_firmware(self): + """Over 1 KB, a value goes in 1 KB chunks: the first names the total, + each later one echoes the offset asked for. Without the capability, + or in the domain, the host refuses rather than send a value an older + device would truncate.""" + doc = { + "types": { + "EIP712Domain": [{"name": "name", "type": "string"}], + "Msg": [{"name": "data", "type": "bytes"}, + {"name": "note", "type": "string"}, + {"name": "list", "type": "uint8[]"}], + }, + "primaryType": "Msg", + "domain": {"name": "x" * 1025}, + "message": {"data": "0x" + "ab" * 1025, "note": "y" * 1024, + "list": [1]}, + } + + def request(path, offset=None): + req = eth.EthereumTypedDataValueRequest(member_path=path) + if offset is not None: + req.value_offset = offset + return req + + with self.assertRaisesRegex(es.Eip712Error, 'chunked values'): + es.value_ack(doc, request([1, 0])) + first = es.value_ack(doc, request([1, 0]), chunked=True) + self.assertEqual(first.value, b'\xab' * 1024) + self.assertEqual(first.value_total_length, 1025) + self.assertFalse(first.HasField('value_offset')) + last = es.value_ack(doc, request([1, 0], 1024), chunked=True) + self.assertEqual((last.value, last.value_offset), (b'\xab', 1024)) + self.assertFalse(last.HasField('value_total_length')) + # A string is read a second time from 0. + again = es.value_ack(doc, request([1, 0], 0), chunked=True) + self.assertEqual((len(again.value), again.value_offset), (1024, 0)) + with self.assertRaises(es.Eip712Error): + es.value_ack(doc, request([1, 0], 1025), chunked=True) + # 1024 bytes still go whole, with or without the capability. + for chunked in (False, True): + whole = es.value_ack(doc, request([1, 1]), chunked) + self.assertEqual(whole.value, b'y' * 1024) + self.assertFalse(whole.HasField('value_total_length')) + with self.assertRaises(es.Eip712Error): + es.value_ack(doc, request([1, 1], 1024), chunked) + with self.assertRaisesRegex(es.Eip712Error, 'domain'): + es.value_ack(doc, request([0, 0]), chunked=True) + with self.assertRaises(es.Eip712Error): + es.value_ack(doc, request([1, 2], 0), chunked=True) + doc["message"]["data"] = "0x" + "00" * (es.MAX_VALUE_BYTES + 1) + with self.assertRaises(es.Eip712Error): + es.value_ack(doc, request([1, 0]), chunked=True) + def test_review_identifiers_are_exact_and_unambiguous(self): doc = { 'types': { @@ -243,6 +296,8 @@ def _walk(self, doc, max_steps=400, decline_final=False): msg.address_n.append(n) msg.primary_type = doc['primaryType'] msg.metamask_v4_compat = True + # Read before the walk: reading Features mid-walk would end it. + chunked = self._chunked_values() # (ButtonRequest code, framebuffer) for every screen, in order. self.frames = [] @@ -267,15 +322,15 @@ def _walk(self, doc, max_steps=400, decline_final=False): resp = self.client.call_raw( es.build_struct_ack(es.struct_members(doc, resp.name))) elif isinstance(resp, eth.EthereumTypedDataValueRequest): - r = es.resolve_member_path(doc, list(resp.member_path)) - ack = eth.EthereumTypedDataValueAck() - ack.value = (es.encode_array_length(r[1]) if r[0] == 'length' - else es.encode_value(r[1], r[2])) - resp = self.client.call_raw(ack) + resp = self.client.call_raw(es.value_ack(doc, resp, chunked)) else: return resp raise AssertionError('walk did not terminate') + def _chunked_values(self): + """Whether the firmware takes values over 1 KB in chunks.""" + return es.CHUNKED_VALUES in (self.firmware_capabilities() or ()) + def _assert_final_sign_screen(self, first_line): """Every typed-data signature ends with ONE "Sign Typed Data" screen (ButtonRequest_SignTx); only its own continuation pages follow it.""" @@ -329,6 +384,41 @@ def setUp(self): # The report entries describe typed-data fields, not the policy prompt. self.client.reset_screenshots() + def _assert_strings_have_distinct_screens(self, first, second): + doc = { + 'types': { + 'EIP712Domain': [], + 'Message': [{'name': 'note', 'type': 'string'}], + }, + 'primaryType': 'Message', 'domain': {}, 'message': {'note': first}, + } + responses, screens = [], [] + for value in (first, second): + doc['message']['note'] = value + response = self._walk(doc) + self._assert_reference_signature(doc, response) + responses.append(response) + screens.append(tuple(self.frames)) + self.assertNotEqual(responses[0].message_hash, responses[1].message_hash) + self.assertNotEqual(responses[0].signature, responses[1].signature) + self.assertFalse(screens[0] == screens[1], + 'Different signed values produced identical OLED screens') + + def test_pipe_is_distinguishable_from_lowercase_l(self): + self._assert_strings_have_distinct_screens('allow', 'a||ow') + + def test_pipe_after_chunk_boundary_is_distinguishable_from_lowercase_l(self): + if not self._chunked_values(): + self.skipTest('firmware does not support chunked EIP-712 values') + self._assert_strings_have_distinct_screens( + 'a' * 1024 + 'allow', 'a' * 1024 + 'a||ow') + + def test_distinct_visible_character_changes_review_pixels(self): + self._assert_strings_have_distinct_screens('allow', 'a!!ow') + + def test_double_quote_is_distinguishable_from_two_apostrophes(self): + self._assert_strings_have_distinct_screens('"', "''") + def test_spec_example_matches_the_published_hashes(self): """The device's own hashes equal the EIP-712 reference implementation's. @@ -749,6 +839,7 @@ def test_unlimited_permits_are_refused_before_the_amount_screen(self): instead (F-D, D-010): test_canonical_unlimited_permits_sign_after_a_ warning.""" self.requires_firmware_below("7.16.0") + self.requires_capability_absent("erc20-unlimited-permit-review") permit = copy.deepcopy(self.USDC_PERMIT) for doc, path, leaf, bits in ((permit, ("value",), "value", 256),): # A finite amount signs and shows the leaf; its position is where @@ -767,6 +858,41 @@ def test_unlimited_permits_are_refused_before_the_amount_screen(self): 'Unlimited ERC20 approval is disabled')) self.assertEqual(len(self.frames), before_leaf) + def test_unlimited_permits_sign_with_unlimited_on_the_value_screen(self): + """7.15 (owner decision 2026-10-07): an unlimited EIP-2612 value, a + DAI allowed=true and a Permit2 amount at its uint160 maximum are + signed. The value's own screen is titled UNLIMITED APPROVAL and reads + UNLIMITED; a finite value keeps the ordinary screen.""" + self.requires_firmware("7.15.0") + self.requires_firmware_below("7.16.0") + self.requires_release_capability("erc20-unlimited-permit-review") + usdc = copy.deepcopy(self.USDC_PERMIT) + usdc["message"]["value"] = str((1 << 256) - 1) + permit2 = copy.deepcopy(self.UNISWAP_PERMIT2) + cases = ((usdc, "value", "value\nuint256: UNLIMITED"), + (self.DAI_PERMIT, "allowed", + "allowed\nbool: UNLIMITED (allowed)"), + (permit2, "details.amount", + "details.amount\nuint160: UNLIMITED")) + for doc, leaf, body in cases: + self._assert_reference_signature(doc, self._walk(doc)) + warnings = [i for i, (_, layout) in enumerate(self.frames) + if oled_text.find_line(layout, 'UNLIMITED APPROVAL', + oled_text.TITLE_FONT) + is not None] + with self.subTest(leaf): + self.assertEqual(warnings, [self._leaf_index(leaf)]) + self.assertTrue(oled_text.shows(self.frames[warnings[0]][1], + body), body) + self._assert_reference_signature(self.USDC_PERMIT, + self._walk(self.USDC_PERMIT)) + self.assertIsNone(oled_text.find_text( + [layout for _, layout in self.frames], "value\nuint256: UNLIMITED")) + self.assertTrue(all( + oled_text.find_line(layout, 'UNLIMITED APPROVAL', + oled_text.TITLE_FONT) is None + for _, layout in self.frames)) + def test_canonical_unlimited_permits_sign_after_a_warning(self): """D-010 for permits (F-D): a canonical EIP-2612 permit of 2^255 or more, or a canonical DAI permit with allowed=true, is signed after @@ -826,11 +952,7 @@ def test_declining_the_unlimited_warning_signs_nothing(self): resp = self.client.call_raw( es.build_struct_ack(es.struct_members(doc, resp.name))) elif isinstance(resp, eth.EthereumTypedDataValueRequest): - r = es.resolve_member_path(doc, list(resp.member_path)) - ack = eth.EthereumTypedDataValueAck() - ack.value = (es.encode_array_length(r[1]) if r[0] == 'length' - else es.encode_value(r[1], r[2])) - resp = self.client.call_raw(ack) + resp = self.client.call_raw(es.value_ack(doc, resp)) else: break self.assertIsInstance(resp, proto.Failure) @@ -930,5 +1052,181 @@ def test_1024_byte_dynamic_bytes_leaf_signs(self): self._assert_reference_signature(doc, resp) + # -- Values over one ValueAck ------------------------------------------ + # Safe MultiSend data and Snapshot proposal bodies run past 1 KB. Firmware + # with CAPABILITY_EIP712_CHUNKED_VALUES takes them in 1 KB chunks and + # shows every byte, numbered over the whole value. + + def _walk_text(self, doc, tamper=None, decline=None, max_steps=600): + """The walk, recording each confirmation's (title, body) exactly as + formatted (once per confirmation, however it is paged). `tamper` + may rewrite a value answer; `decline` names a body prefix to reject.""" + msg = eth.EthereumSignTypedData(address_n=PATH, + primary_type=doc['primaryType'], + metamask_v4_compat=True) + screens = [] + resp = self.client.call_raw(msg) + for _ in range(max_steps): + if isinstance(resp, proto.ButtonRequest): + text = self.client.debug.read_confirm_text() + if not screens or screens[-1] != text: + screens.append(text) + if decline and text[1].startswith(decline): + self.client.debug.press_no() + else: + self.client.debug.press_yes() + resp = self.client.call_raw(proto.ButtonAck()) + elif isinstance(resp, eth.EthereumTypedDataStructRequest): + resp = self.client.call_raw( + es.build_struct_ack(es.struct_members(doc, resp.name))) + elif isinstance(resp, eth.EthereumTypedDataValueRequest): + ack = es.value_ack(doc, resp, chunked=True) + if tamper: + tamper(ack) + resp = self.client.call_raw(ack) + else: + return resp, screens + raise AssertionError('walk did not terminate') + + @staticmethod + def _escaped(data): + """A string as the review draws it: 0x21-0x7e as itself but a + backslash doubled, any other byte (a space too) as \\xNN.""" + return ''.join('\\\\' if b == 0x5c else chr(b) if 0x21 <= b <= 0x7e + else '\\x%02x' % b for b in data) + + def _parts(self, screens, path, type_name): + """The parts of `path`, checked to count 1..N in order, joined.""" + joined, total = '', None + for number, (_, body) in enumerate( + b for b in screens if b[1].startswith(path + ' (')): + head, _, rest = body.partition('\n') + index, of = head[len(path) + 2:-1].split('/') + self.assertEqual(int(index), number + 1) + self.assertIn(total, (None, int(of))) + total = int(of) + self.assertTrue(rest.startswith(type_name + ': '), body[:60]) + joined += rest[len(type_name) + 2:] + self.assertIsNotNone(total, 'no part of ' + path) + self.assertEqual(number + 1, total) + return joined, total + + def _assert_signed(self, doc, resp): + self.assertIsInstance(resp, eth.EthereumTypedDataSignature, + getattr(resp, 'message', resp)) + domain, message, digest = reference_eip712_hashes(doc) + self.assertEqual(resp.domain_separator_hash.hex(), domain.hex()) + self.assertEqual(resp.message_hash.hex(), message.hex()) + address = self.client.ethereum_get_address(PATH) + self.assertEqual(recover_signer(resp.signature, digest).hex(), + address.hex()) + + @staticmethod + def _blob(data_type, value): + return { + "types": { + "EIP712Domain": [{"name": "name", "type": "string"}], + "Blob": [{"name": "data", "type": data_type}, + {"name": "n", "type": "uint256"}], + }, + "primaryType": "Blob", + "domain": {"name": "Blob"}, + "message": {"data": value, "n": 7}, + } + + def test_values_over_1kb_sign_in_chunks(self): + """1024, 1025 and 2048 bytes, and a string with a three-byte + character split across the first chunk boundary: each signs with the + independent digest, every byte is shown once and in order, and the + part counter covers the whole value from its first screen.""" + self.requires_release_capability(es.CHUNKED_VALUES) + euro = 'a' * 1023 + '\u20ac' + 'b' * 500 + cases = [('bytes', bytes(range(256)) * 4), + ('bytes', bytes(range(256)) * 4 + b'\xfe'), + ('bytes', bytes(range(256)) * 8), + ('string', ('x' * 1025).encode()), + ('string', euro.encode('utf-8'))] + for data_type, data in cases: + with self.subTest(type=data_type, length=len(data)): + value = ('0x' + data.hex() if data_type == 'bytes' + else data.decode('utf-8')) + doc = self._blob(data_type, value) + resp, screens = self._walk_text(doc) + self._assert_signed(doc, resp) + shown, parts = self._parts(screens, 'data', data_type) + self.assertEqual(shown, '0x' + data.hex() + if data_type == 'bytes' + else self._escaped(data)) + self.assertGreater(parts, 1) + + def test_misframed_chunks_are_refused(self): + """A chunk at another offset than the one asked for, or one running + past the total, is refused, and the session is gone.""" + self.requires_release_capability(es.CHUNKED_VALUES) + doc = self._blob('bytes', '0x' + 'ab' * 1500) + + def wrong_offset(ack): + if ack.HasField('value_offset'): + ack.value_offset += 1 + + def past_total(ack): + if ack.HasField('value_offset'): + ack.value = ack.value + b'\xab' * 100 + + for tamper, error in ((wrong_offset, 'EIP-712 value chunk out of order'), + (past_total, + 'EIP-712 value chunk has the wrong length')): + with self.subTest(error=error): + resp, _ = self._walk_text(doc, tamper) + self.assertIsInstance(resp, proto.Failure) + self.assertEqual((resp.code, resp.message), + (types.Failure_SyntaxError, error)) + stale = self.client.call_raw(eth.EthereumTypedDataValueAck( + value=b'\xab' * 476, value_offset=1024)) + self.assertIsInstance(stale, proto.Failure) + self._assert_signed(doc, self._walk_text(doc)[0]) + + def test_declining_a_part_mid_value_signs_nothing(self): + """Rejecting a part of the second chunk cancels; the next document + signs with its own digest.""" + self.requires_release_capability(es.CHUNKED_VALUES) + doc = self._blob('bytes', '0x' + 'cd' * 3000) + resp, screens = self._walk_text(doc, decline='data (8/') + self.assertIsInstance(resp, proto.Failure) + self.assertEqual(resp.code, types.Failure_ActionCancelled) + self.assertTrue(screens[-1][1].startswith('data (8/')) + self._assert_signed(doc, self._walk_text(doc)[0]) + + def test_unlimited_approve_in_chunked_safe_data_warns_first(self): + """approve(spender, 2^256-1) heading a 3 KB SafeTx.data: the + UNLIMITED warning is read from the first chunk and shown before any + screen of the bytes.""" + self.requires_release_capability(es.CHUNKED_VALUES) + self.requires_release_capability("erc20-unlimited-approve-review") + spender = '68b3465833fb72a70ecdf485e0e4c7bd8665fc45' + data = ('095ea7b3' + '00' * 12 + spender + 'ff' * 32).ljust(6000, '0') + doc = { + "types": { + "EIP712Domain": [{"name": "chainId", "type": "uint256"}], + "SafeTx": [{"name": "to", "type": "address"}, + {"name": "data", "type": "bytes"}], + }, + "primaryType": "SafeTx", + "domain": {"chainId": 1}, + "message": {"to": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "data": "0x" + data}, + } + resp, screens = self._walk_text(doc) + self._assert_signed(doc, resp) + titles = [title for title, _ in screens] + self.assertEqual(titles.count('UNLIMITED approval'), 1) + warning = titles.index('UNLIMITED approval') + first = next(i for i, (_, body) in enumerate(screens) + if body.startswith('data (')) + self.assertLess(warning, first) + self.assertIn('to spend ALL your USDC', screens[warning][1]) + self.assertEqual(self._parts(screens, 'data', 'bytes')[0], + '0x' + data) + if __name__ == '__main__': unittest.main() diff --git a/tests/test_msg_eos_getpublickey.py b/tests/test_msg_eos_getpublickey.py index d1121ef3..75d82d58 100644 --- a/tests/test_msg_eos_getpublickey.py +++ b/tests/test_msg_eos_getpublickey.py @@ -51,6 +51,17 @@ def test(self): res = self.client.eos_get_public_key(path, show, legacy) self.assertEqual(res.wif_public_key, wif) + def test_show(self): + self.requires_fullFeature() + self.requires_message("EosGetPublicKey") + self.setup_mnemonic_nopin_nopassphrase() + for legacy, prefix in ((True, 'EOS'), (False, 'EOS_K1_')): + wif = prefix + EOS_ACCOUNT_0_PUBKEY + res = self.assert_shows_address( + lambda: self.client.eos_get_public_key( + EOS_ACCOUNT_0_PATH, True, legacy), wif) + self.assertEqual(res.wif_public_key, wif) + def test_trezor(self): self.requires_fullFeature() self.setup_mnemonic_abandon() diff --git a/tests/test_msg_eos_signtx.py b/tests/test_msg_eos_signtx.py index a59bcf5a..a939c7d6 100644 --- a/tests/test_msg_eos_signtx.py +++ b/tests/test_msg_eos_signtx.py @@ -247,7 +247,7 @@ def authorization(self, is_slip48): threshold=1, keys=[ proto.EosAuthorizationKey( - type=1, + type=0, address_n=parse_path("m/48'/4'/1'/0'/0'"), weight=1) ], @@ -267,7 +267,7 @@ def authorization(self, is_slip48): threshold=2, keys=[ proto.EosAuthorizationKey( - type=1, + type=0, address_n=parse_path("m/44'/194'/0'/0/0"), weight=2) ], @@ -331,7 +331,7 @@ def action_newaccount(self): threshold=1, keys=[ proto.EosAuthorizationKey( - type=1, + type=0, address_n=parse_path("m/44'/194'/0'/0/0"), weight=1) ], @@ -558,17 +558,16 @@ def test_updateauth(self): num_actions=1), [self.action_updateauth(False)]) - self.assertEqual(binascii.hexlify(res.hash), "0282c00575f451a47e99902ab2a51243499ea004df309148d1f2e23c007520b7") + self.assertEqual(binascii.hexlify(res.hash), "bf6f207d8f79500180aa5025d1f4a44d36bdd1136f093979d6975c20b2319a07") # Fork #568/#563: eos_hashAuthorization() used to emit accounts_count # wait entries instead of waits_count. This SLIP-48 vector has one # delegated account and zero waits, so older firmware hashes a phantom # 6-byte zero wait that was neither present nor confirmed on-device - # (the known-bad digest fb936ef1...). The fix is on the 7.15 and 7.16 + # (the known-bad digest d46ec843...). The fix is on the 7.15 and 7.16 # release heads; 7.14.3 is a bitcoin-only release and its full image - # keeps the 7.14.2 EOS serializer. 5938294e... is checked against two - # independent EOSIO ABI serializers and against mainnet updateauth - # transactions of the same shape. + # keeps the 7.14.2 EOS serializer. c94f1271... is checked against an + # independent EOSIO ABI serializer; the derived key is K1 (type 0). if not self.firmware_at_least("7.15.0"): self.skipTest("Firmware before 7.15.0 hashes a phantom updateauth " "wait (fork #568/#563)") @@ -581,7 +580,7 @@ def test_updateauth(self): num_actions=1), [self.action_updateauth(True)]) - self.assertEqual(binascii.hexlify(res.hash), "5938294e65cf9e8b5dd5f2b204503b4825f277e6f4a2d5ab7a55a31065a23af1") + self.assertEqual(binascii.hexlify(res.hash), "c94f1271f26492a4ca308a6cfae610ce41a3beb7354beb1747e2a2261c8c1973") def test_deleteauth(self): self.requires_fullFeature() @@ -637,7 +636,7 @@ def test_newaccount(self): num_actions=1), [self.action_newaccount()]) - self.assertEqual(binascii.hexlify(res.hash), "8e0accde9fb6529b5d72b4d9a9859e1dae0c6ae9a159bb1ea8c8f579f942c291") + self.assertEqual(binascii.hexlify(res.hash), "0f2c85cfc957eda7e37d6d006f98a56948fe4ab34ecea64d1a1462f4c6fbb387") def test_unknown_advanced(self): self.requires_fullFeature() @@ -1418,9 +1417,10 @@ def test_eos_signtx_newaccount(self): json.loads(data)) assert isinstance(actionResp, proto.EosSignedTx) - self.assertEqual(binascii.hexlify(actionResp.signature_r), "61317ec7dc5c6e62ef7e45b4961ad89fe748c5a9076f23e0c6afc90ad1f93f47") - self.assertEqual(binascii.hexlify(actionResp.signature_s), "056996515e6c6e28be136821859cf2092f719a8da25171ce6534c2bf9a013d3d") - self.assertEqual(actionResp.signature_v, 32) + self.assertEqual(binascii.hexlify(actionResp.hash), "584a5c3ded379ce4f3d3f6ea3364726e0e608214170eb9f7b25baa3010255cb1") + self.assertEqual(binascii.hexlify(actionResp.signature_r), "2db69cbe5f1600ca5d54c77b6f79426cde215531ee84d90eada8de310d07292f") + self.assertEqual(binascii.hexlify(actionResp.signature_s), "6d113bbdb017b95f4d9fb7e8fc3493b763576193409ed19d6e0d9b42c0cf754a") + self.assertEqual(actionResp.signature_v, 31) def test_eos_signtx_setcontract(self): self.requires_fullFeature() diff --git a/tests/test_msg_ethereum_clear_signing.py b/tests/test_msg_ethereum_clear_signing.py index 8893484c..0be2bc30 100644 --- a/tests/test_msg_ethereum_clear_signing.py +++ b/tests/test_msg_ethereum_clear_signing.py @@ -1032,9 +1032,12 @@ def _clearsign_flow(self, flow, chain_id=1): self.assertEqual(resp.classification, CLASSIFICATION_VERIFIED) if (flow['key'] == 'erc20-approve-unlimited' - and not self.firmware_at_least("7.16.0")): - # 7.15 refuses an unlimited approve. 7.16 reviews and signs it - # (D-010), handled by the common path below. + and not self.firmware_at_least("7.16.0") + and "erc20-unlimited-approve-review" not in + (self.firmware_capabilities() or ())): + # 7.15 refused an unlimited approve until + # erc20-unlimited-approve-review; from then it is signed after a + # warning, handled by the common path below. # Drive the wire directly: the policy is refused on the FIRST # response, before any ButtonRequest. Expected-response helpers # would raise their own exception text containing the expected diff --git a/tests/test_msg_ethereum_erc20_approve.py b/tests/test_msg_ethereum_erc20_approve.py index c3f29356..f3a5c9e7 100644 --- a/tests/test_msg_ethereum_erc20_approve.py +++ b/tests/test_msg_ethereum_erc20_approve.py @@ -24,6 +24,8 @@ import keepkeylib.messages_pb2 as proto import keepkeylib.types_pb2 as proto_types from keepkeylib.client import CallException +from oled_text import TITLE_FONT, find_line, shows +from test_msg_display_disclosure import ScreenRecorder class TestMsgEthereumtxERC20_approve(common.KeepKeyTest): @@ -68,11 +70,13 @@ def test_approve_cvc_0(self): self.assertEqual(binascii.hexlify(sig_s), '0bc7319762281d839c436adb41c35f8de5f4db1aec953f677c3a83062d93fc51') def test_approve_cvc_all_refused(self): - # 7.14.2 through 7.15.x refuse an unlimited approve outright. 7.16 - # reviews and signs it instead (D-010): test_approve_cvc_all. + # 7.14.2 through 7.15.x refuse an unlimited approve outright, until + # erc20-unlimited-approve-review: from then it is signed after an + # UNLIMITED warning (test_approve_cvc_all). self.requires_fullFeature() self.requires_firmware("7.14.2") self.requires_firmware_below("7.16.0") + self.requires_capability_absent("erc20-unlimited-approve-review") self.setup_mnemonic_nopin_nopassphrase() with self.assertRaises(CallException): @@ -91,23 +95,32 @@ def test_approve_cvc_all_refused(self): def test_approve_cvc_all(self): self.requires_fullFeature() if self.firmware_at_least("7.14.2"): - # Refused on 7.14.2-7.15.x (test_approve_cvc_all_refused); - # reviewed and signed from 7.16 (D-010). - self.requires_firmware("7.16.0") + # Refused on 7.14.2-7.15.x (test_approve_cvc_all_refused) until + # erc20-unlimited-approve-review; signed after a warning since. + self.requires_firmware("7.15.0") self.requires_release_capability("erc20-unlimited-approve-review") self.setup_mnemonic_nopin_nopassphrase() - sig_v, sig_r, sig_s = self.client.ethereum_sign_tx( - n=[2147483692,2147483708,2147483648,0,0], - nonce=1, - gas_price=20, - gas_limit=20, - value=0, - to=binascii.unhexlify('41e5560054824ea6b0732e656e3ad64e20e94e45'), - address_type=0, - chain_id=1, - data=binascii.unhexlify('095ea7b3' + '0000000000000000000000001d8ce9022f6284c3a5c317f8f34620107214e545' + 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff') - ) + recorder = ScreenRecorder(self.client) + with recorder: + sig_v, sig_r, sig_s = self.client.ethereum_sign_tx( + n=[2147483692,2147483708,2147483648,0,0], + nonce=1, + gas_price=20, + gas_limit=20, + value=0, + to=binascii.unhexlify('41e5560054824ea6b0732e656e3ad64e20e94e45'), + address_type=0, + chain_id=1, + data=binascii.unhexlify('095ea7b3' + '0000000000000000000000001d8ce9022f6284c3a5c317f8f34620107214e545' + 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff') + ) + if self.firmware_at_least("7.15.0"): + # The UNLIMITED warning is the first screen, full spender. + self.assertIsNotNone(find_line(recorder.screens[0], + 'UNLIMITED APPROVAL', TITLE_FONT)) + self.assertTrue(shows(recorder.screens[0], + 'Allow 0x1D8CE9022f6284c3A5c317f8f34620107214E545 ' + 'to spend ALL your CVC')) self.assertEqual(sig_v, 37) self.assertEqual(binascii.hexlify(sig_r), 'bb4c640b79f946e1399450dfc615b0a6024b6724f167cef70cf2530408fc6339') diff --git a/tests/test_msg_ethereum_erc20_uniswap_liquidity.py b/tests/test_msg_ethereum_erc20_uniswap_liquidity.py index 8c02ebeb..f5a50729 100644 --- a/tests/test_msg_ethereum_erc20_uniswap_liquidity.py +++ b/tests/test_msg_ethereum_erc20_uniswap_liquidity.py @@ -37,6 +37,7 @@ def test_sign_uni_approve_liquidity_ETH_refused(self): self.requires_fullFeature() self.requires_firmware_below("7.16.0") self.requires_release_capability("erc7730-runtime-review") + self.requires_capability_absent("erc20-unlimited-approve-review") self.setup_mnemonic_nopin_nopassphrase() self.client.apply_policy("AdvancedMode", 1) @@ -66,8 +67,6 @@ def test_sign_uni_approve_liquidity_ETH_refused(self): def test_sign_uni_approve_liquidity_ETH(self): self.requires_fullFeature() - self.requires_firmware("7.16.0") - self.requires_release_capability("erc7730-runtime-review") self.requires_release_capability("erc20-unlimited-approve-review") self.setup_mnemonic_nopin_nopassphrase() self.client.apply_policy("AdvancedMode", 1) diff --git a/tests/test_msg_ethereum_erc7730_runtime.py b/tests/test_msg_ethereum_erc7730_runtime.py index 5995b0a5..a7687fa6 100644 --- a/tests/test_msg_ethereum_erc7730_runtime.py +++ b/tests/test_msg_ethereum_erc7730_runtime.py @@ -665,6 +665,98 @@ def test_inner_call_is_clear_signed_with_its_own_definition(self): ]) self.assertIn("Inner signer", [s[0] for s in self.screens]) + APPROVE = "approve(address spender,uint256 amount)" + MAX = (1 << 256) - 1 + + def _exec_approve(self, amount, spender=None, with_definition=True): + """execTransaction carrying approve(OTHER_ADDRESS, amount) on USDC.""" + self._exec_setup() + inner = erc7730_compiler.compile_calldata( + {"display": {"formats": {self.APPROVE: { + "intent": "Approve", "fields": [ + {"path": "spender", "label": "Spender", + "format": "addressName"}, + {"path": "amount", "label": "Amount", "format": "raw"}]}}}}, + self.APPROVE, 1, self.USDC) + inner_def = erc7730.Definition(self._envelope(inner), 1, 1, self.USDC, + inner[38:42]) + outer_def = self._exec_outer[1] + call = (bytes.fromhex("095ea7b3") + + (spender or self._word(OTHER_ADDRESS)) + self._word(amount)) + arguments = (self._word(self.USDC) + self._word(0) + + self._word(128) + self._word(0) + + self._word(len(call)) + call + bytes(-len(call) % 32)) + catalog = erc7730.Catalog( + (outer_def, inner_def) if with_definition else (outer_def,)) + return arguments, catalog + + UNLIMITED = ("UNLIMITED approval", + "Allow 0x" + OTHER_ADDRESS.hex() + " to spend ALL your USDC") + + def _approve_screens(self): + return [s for s in self._first_pages() + if s[0] in ("UNLIMITED approval", "Contract action", + "Signer field", "Inner signer", "Inner action", + "Blind signature")] + + def test_inner_unlimited_approve_warns_before_the_inner_review(self): + self.requires_release_capability("erc20-unlimited-approve-review") + arguments, catalog = self._exec_approve(self.MAX) + self._exec_certified(arguments, catalog) + shown = self._approve_screens() + self.assertEqual(shown[:2], [ + ("Contract action", "sign multisig operation"), self.UNLIMITED]) + self.assertEqual(shown[2][0], "Signer field") + self.assertEqual(shown[3][0], "Inner signer") + self.assertEqual([s[0] for s in self._first_pages()].count( + "UNLIMITED approval"), 1) + + def test_declining_an_inner_unlimited_approve_signs_nothing(self): + self.requires_release_capability("erc20-unlimited-approve-review") + arguments, catalog = self._exec_approve(self.MAX) + outer, outer_def = self._exec_outer + + def preload(): + erc7730.preload(self.client, outer_def) + self._drop_setup_screenshots() + return b"" + self._declined(outer, arguments, "UNLIMITED approval", + preload=preload, catalog=catalog) + self.assertNotIn("Inner signer", [s[0] for s in self.screens]) + + def test_inner_finite_approve_shows_no_unlimited_warning(self): + arguments, catalog = self._exec_approve(self.MAX - 1) + self._exec_certified(arguments, catalog) + titles = [s[0] for s in self.screens] + self.assertNotIn("UNLIMITED approval", titles) + self.assertIn("Inner action", titles) + + def test_blind_inner_unlimited_approve_still_warns_in_715(self): + self.requires_firmware_below("7.16.0") # 7.16 refuses blind calls + self.requires_release_capability("erc20-unlimited-approve-review") + arguments, catalog = self._exec_approve(self.MAX, + with_definition=False) + self._exec_certified(arguments, catalog) + shown = self._approve_screens() + self.assertEqual(shown[:3], [ + ("Contract action", "sign multisig operation"), self.UNLIMITED, + ("Blind signature", "The inner call is not clear-signed")]) + + def test_inner_approve_with_a_dirty_spender_word_is_refused(self): + self.requires_release_capability("erc20-unlimited-approve-review") + arguments, catalog = self._exec_approve( + self.MAX, spender=b"\x01" + bytes(11) + OTHER_ADDRESS) + outer, outer_def = self._exec_outer + erc7730.preload(self.client, outer_def) + self._drop_setup_screenshots() + result, _, _, _ = self._walk( + self._audit_start(outer, 4 + len(arguments)), b"", + arguments=arguments, catalog=catalog) + assert_failure(self, result, types.Failure_SyntaxError, + "Invalid ERC-7730 embedded call") + self.assertNotIn("UNLIMITED approval", [s[0] for s in self.screens]) + self.assertNotIn(types.ButtonRequest_SignTx, self.button_codes) + def test_inner_call_without_a_definition_is_blind_in_715(self): self.requires_firmware_below("7.16.0") # 7.16 refuses instead start, arguments, outer_def, _ = self._exec_setup() diff --git a/tests/test_msg_ethereum_getaddress.py b/tests/test_msg_ethereum_getaddress.py index 501ad8d6..39f1f605 100644 --- a/tests/test_msg_ethereum_getaddress.py +++ b/tests/test_msg_ethereum_getaddress.py @@ -38,9 +38,11 @@ def test_ethereum_show_address(self): self.requires_fullFeature() self.setup_mnemonic_nopin_nopassphrase() # The legacy display response is empty after the ButtonAck; address - # correctness is covered above. This case exists to retain the actual - # operation-specific OLED sequence for visual review. - self.client.ethereum_get_address([], show_display=True) + # correctness is covered above. The screen must show the whole + # EIP-55 form of the first vector above. + self.assert_shows_address( + lambda: self.client.ethereum_get_address([], show_display=True), + '0x1D1C328764A41BdA0492b66bAA30C4A339FF85EF') if __name__ == '__main__': unittest.main() diff --git a/tests/test_msg_ethereum_signtx_integer_encoding.py b/tests/test_msg_ethereum_signtx_integer_encoding.py index ad186788..bb0b4bd6 100644 --- a/tests/test_msg_ethereum_signtx_integer_encoding.py +++ b/tests/test_msg_ethereum_signtx_integer_encoding.py @@ -17,6 +17,9 @@ import unittest import common +import rlp +from eth_keys import keys +from eth_utils import keccak from keepkeylib import messages_ethereum_pb2 as eth_proto TO = bytes.fromhex("1d1c328764a41bda0492b66baa30c4a339ff85ef") @@ -30,13 +33,34 @@ def setUp(self): # The stripping shipped in the same release block as this capability. self.requires_release_capability("evm-max-amount-review") self.setup_mnemonic_allallall() + self.path = self.client.expand_path("m/44'/60'/0'/0/0") + self.signer = self.client.ethereum_get_address(self.path) def _sign(self, **fields): resp = self.client.call(eth_proto.EthereumSignTx( - address_n=self.client.expand_path("m/44'/60'/0'/0/0"), + address_n=self.path, to=TO, chain_id=1, **fields)) self.assertIsInstance(resp, eth_proto.EthereumTxRequest) self.assertTrue(resp.HasField("signature_r")) + def integer(name): + return int.from_bytes(fields.get(name, b""), "big") + + if fields.get("type") == 2: + preimage = b"\x02" + rlp.encode([ + 1, integer("nonce"), integer("max_priority_fee_per_gas"), + integer("max_fee_per_gas"), integer("gas_limit"), TO, + integer("value"), b"", []]) + recovery_id = resp.signature_v + else: + preimage = rlp.encode([ + integer("nonce"), integer("gas_price"), integer("gas_limit"), + TO, integer("value"), b"", 1, 0, 0]) + recovery_id = resp.signature_v - 37 + signature = keys.Signature(vrs=( + recovery_id, int.from_bytes(resp.signature_r, "big"), + int.from_bytes(resp.signature_s, "big"))) + recovered = signature.recover_public_key_from_msg_hash(keccak(preimage)) + self.assertEqual(recovered.to_canonical_address(), self.signer) return resp.signature_v, resp.signature_r, resp.signature_s def _assert_same_signature(self, canonical, padded): @@ -68,6 +92,16 @@ def test_eip1559_fees_with_leading_zeros(self): max_priority_fee_per_gas=b"\x00\x3b\x9a\xca\x00", gas_limit=b"\x00\x00\x52\x08", value=b"\x00\x01")) + def test_eip1559_zero_value_in_every_spelling(self): + canonical = dict(type=2, nonce=b"", max_fee_per_gas=b"\x77\x35\x94\x00", + max_priority_fee_per_gas=b"", gas_limit=b"\x52\x08", + value=b"") + for zero in (b"\x00", b"\x00\x00\x00"): + with self.subTest(zero=zero): + self._assert_same_signature( + canonical, dict(canonical, nonce=zero, value=zero, + max_priority_fee_per_gas=zero)) + if __name__ == '__main__': unittest.main() diff --git a/tests/test_msg_ethereum_thorchain_deposit.py b/tests/test_msg_ethereum_thorchain_deposit.py index aa0f023d..027af7f5 100644 --- a/tests/test_msg_ethereum_thorchain_deposit.py +++ b/tests/test_msg_ethereum_thorchain_deposit.py @@ -213,5 +213,79 @@ def test_deposit_unpinned_chain_blind_sign_blocked(self): ) + # (router, chain_id) pins added with the BSC, Base and Arbitrum routers. + NEW_ROUTER_PINS = [ + ("b30ec53f98ff5947ede720d32ac2da7e52a5f56b", 56), # THORChain BSC + ("00dc6100103bc402d490aee3f9a5560cbd91f1d4", 8453), # THORChain Base + ("700e97ef07219440487840dc472e7120a7ff11f4", 42161), # Maya Arbitrum + ] + + def test_deposit_new_routers_native_and_token(self): + """Native and token deposits clear-sign on the BSC and Base THORChain + routers and Maya's Arbitrum router, each on its own chain. Each + signature is recovered against the EIP-155 pre-image.""" + self.requires_fullFeature() + self.requires_firmware("7.15.0") + self.requires_release_capability('thor-deposit-review') + self.setup_mnemonic_allallall() + + from keepkeylib.signed_metadata import eth_sighash_legacy, keccak256 + from ecdsa import VerifyingKey, SECP256k1, util + + memo = "=:ETH.ETH:0xabcdef1234567890abcdef1234567890abcdef12:0:t:0" + native = _build_deposit_with_expiry_calldata(memo) + token = bytearray(native) + token[4 + 32 + 12:4 + 64] = b"\x11" * 20 # asset = an ERC-20 + token = bytes(token) + + n = parse_path("m/44'/60'/0'/0/0") + me = self.client.ethereum_get_address(n) + nonce, gas_price, gas_limit = 6, 50000000000, 300000 + for router, chain_id in self.NEW_ROUTER_PINS: + to = binascii.unhexlify(router) + for data, value in ((native, 500000000000000000), (token, 0)): + sig_v, sig_r, sig_s = self.client.ethereum_sign_tx( + n=n, nonce=nonce, gas_price=gas_price, + gas_limit=gas_limit, to=to, value=value, + chain_id=chain_id, data=data, + ) + self.assertIn(sig_v, [2 * chain_id + 35, 2 * chain_id + 36]) + digest = eth_sighash_legacy(nonce, gas_price, gas_limit, to, + value, data, chain_id) + keys = VerifyingKey.from_public_key_recovery_with_digest( + sig_r + sig_s, digest, SECP256k1, hashfunc=None, + sigdecode=util.sigdecode_string, + ) + rec = sig_v - (35 + 2 * chain_id) + self.assertEqual(keccak256(keys[rec].to_string())[-20:], me) + + def test_deposit_new_routers_wrong_chain_blocked(self): + """Each new router is pinned to its own chain only: the same address + on another chain falls to the blind-sign gate.""" + self.requires_fullFeature() + self.requires_firmware("7.15.0") + self.requires_release_capability('thor-deposit-review') + self.setup_mnemonic_allallall() + + from keepkeylib.client import CallException + + memo = "=:ETH.ETH:0xabcdef1234567890abcdef1234567890abcdef12:0:t:0" + data = _build_deposit_with_expiry_calldata(memo) + bsc, base, arb = (r for r, _ in self.NEW_ROUTER_PINS) + for router, chain_id in ((bsc, 1), (bsc, 8453), (base, 1), (base, 56), + (base, 42161), (arb, 1), (arb, 8453)): + with self.assertRaises(CallException, + msg="router %s chain %d" % (router, chain_id)): + self.client.ethereum_sign_tx( + n=parse_path("m/44'/60'/0'/0/0"), + nonce=7, + gas_price=50000000000, + gas_limit=300000, + to=binascii.unhexlify(router), + value=500000000000000000, + chain_id=chain_id, + data=data, + ) + if __name__ == "__main__": unittest.main() diff --git a/tests/test_msg_getaddress_segwit.py b/tests/test_msg_getaddress_segwit.py index 8a9202a2..40353a59 100644 --- a/tests/test_msg_getaddress_segwit.py +++ b/tests/test_msg_getaddress_segwit.py @@ -28,7 +28,10 @@ class TestMsgGetaddressSegwit(common.KeepKeyTest): def test_show_segwit(self): self.setup_mnemonic_allallall() self.client.clear_session() - self.assertEqual(self.client.get_address("Testnet", parse_path("49'/1'/0'/1/0"), True, None, script_type=proto.SPENDP2SHWITNESS), '2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX') + address = '2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX' + self.assertEqual(self.assert_shows_address( + lambda: self.client.get_address("Testnet", parse_path("49'/1'/0'/1/0"), True, None, script_type=proto.SPENDP2SHWITNESS), + address), address) self.assertEqual(self.client.get_address("Testnet", parse_path("49'/1'/0'/0/0"), False, None, script_type=proto.SPENDP2SHWITNESS), '2N4Q5FhU2497BryFfUgbqkAJE87aKHUhXMp') self.assertEqual(self.client.get_address("Testnet", parse_path("44'/1'/0'/0/0"), False, None, script_type=proto.SPENDP2SHWITNESS), '2N6UeBoqYEEnybg4cReFYDammpsyDw8R2Mc') self.assertEqual(self.client.get_address("Testnet", parse_path("44'/1'/0'/0/0"), False, None, script_type=proto.SPENDADDRESS), 'mvbu1Gdy8SUjTenqerxUaZyYjmveZvt33q') @@ -37,7 +40,10 @@ def test_grs(self): self.requires_fullFeature() self.setup_mnemonic_allallall() self.client.clear_session() - self.assertEqual(self.client.get_address('Groestlcoin', parse_path("49'/17'/0'/0/0"), True, None, script_type=proto.SPENDP2SHWITNESS), '31inaRqambLsd9D7Ke4USZmGEVd3PHkh7P') + address = '31inaRqambLsd9D7Ke4USZmGEVd3PHkh7P' + self.assertEqual(self.assert_shows_address( + lambda: self.client.get_address('Groestlcoin', parse_path("49'/17'/0'/0/0"), True, None, script_type=proto.SPENDP2SHWITNESS), + address), address) self.assertEqual(self.client.get_address('Groestlcoin', parse_path("49'/17'/0'/1/0"), False, None, script_type=proto.SPENDP2SHWITNESS), '3NH9SuUAjw1ZocQdTDMuqm3My3Mcg3ovEV') self.assertEqual(self.client.get_address('Groestlcoin', parse_path("49'/17'/0'/1/1"), False, None, script_type=proto.SPENDP2SHWITNESS), '3D65LEJYJ2Yda6UJr8tYBWspP5MZSeR5wz') @@ -45,7 +51,10 @@ def test_tgrs(self): self.requires_fullFeature() self.setup_mnemonic_allallall() self.client.clear_session() - self.assertEqual(self.client.get_address('GRS Testnet', parse_path("49'/1'/0'/0/0"), True, None, script_type=proto.SPENDP2SHWITNESS), '2N4Q5FhU2497BryFfUgbqkAJE87aKDv3V3e') + address = '2N4Q5FhU2497BryFfUgbqkAJE87aKDv3V3e' + self.assertEqual(self.assert_shows_address( + lambda: self.client.get_address('GRS Testnet', parse_path("49'/1'/0'/0/0"), True, None, script_type=proto.SPENDP2SHWITNESS), + address), address) self.assertEqual(self.client.get_address('GRS Testnet', parse_path("49'/1'/0'/1/0"), False, None, script_type=proto.SPENDP2SHWITNESS), '2N1LGaGg836mqSQqiuUBLfcyGBhyZYBtBZ7') self.assertEqual(self.client.get_address('GRS Testnet', parse_path("49'/1'/0'/1/1"), False, None, script_type=proto.SPENDP2SHWITNESS), '2NFWLCJQBSpz1oUJwwLpX8ECifFWGxQyzGu') diff --git a/tests/test_msg_getaddress_segwit_native.py b/tests/test_msg_getaddress_segwit_native.py index 2cdd0a04..44bf9138 100644 --- a/tests/test_msg_getaddress_segwit_native.py +++ b/tests/test_msg_getaddress_segwit_native.py @@ -26,13 +26,22 @@ class TestMsgGetaddressSegwitNative(common.KeepKeyTest): def test_show_segwit(self): - self.requires_fullFeature() self.setup_mnemonic_allallall() self.client.clear_session() - self.assertEqual(self.client.get_address("Testnet", parse_path("49'/1'/0'/0/0"), True, None, script_type=proto.SPENDWITNESS), 'tb1qqzv60m9ajw8drqulta4ld4gfx0rdh82un5s65s') + address = 'tb1qqzv60m9ajw8drqulta4ld4gfx0rdh82un5s65s' + self.assertEqual(self.assert_shows_address( + lambda: self.client.get_address("Testnet", parse_path("49'/1'/0'/0/0"), True, None, script_type=proto.SPENDWITNESS), + address), address) self.assertEqual(self.client.get_address("Testnet", parse_path("49'/1'/0'/1/0"), False, None, script_type=proto.SPENDWITNESS), 'tb1q694ccp5qcc0udmfwgp692u2s2hjpq5h407urtu') self.assertEqual(self.client.get_address("Testnet", parse_path("44'/1'/0'/0/0"), False, None, script_type=proto.SPENDWITNESS), 'tb1q54un3q39sf7e7tlfq99d6ezys7qgc62a6rxllc') self.assertEqual(self.client.get_address("Testnet", parse_path("44'/1'/0'/0/0"), False, None, script_type=proto.SPENDADDRESS), 'mvbu1Gdy8SUjTenqerxUaZyYjmveZvt33q') + + def test_groestlcoin_segwit(self): + # Groestlcoin is not in bitcoin-only firmware; Bitcoin bech32 display + # above runs on every build. + self.requires_fullFeature() + self.setup_mnemonic_allallall() + self.client.clear_session() self.assertEqual(self.client.get_address("Groestlcoin", parse_path("84'/17'/0'/0/0"), False, None, script_type=proto.SPENDWITNESS), 'grs1qw4teyraux2s77nhjdwh9ar8rl9dt7zww8r6lne') self.assertEqual(self.client.get_address("GRS Testnet", parse_path("84'/1'/0'/0/0"), False, None, script_type=proto.SPENDWITNESS), 'tgrs1qkvwu9g3k2pdxewfqr7syz89r3gj557l3ued7ja') diff --git a/tests/test_msg_getaddress_show.py b/tests/test_msg_getaddress_show.py index 196aeea7..a6aa923a 100644 --- a/tests/test_msg_getaddress_show.py +++ b/tests/test_msg_getaddress_show.py @@ -28,9 +28,12 @@ class TestMsgGetaddress(common.KeepKeyTest): def test_show(self): self.setup_mnemonic_nopin_nopassphrase() - self.assertEqual(self.client.get_address('Bitcoin', [1], show_display=True), '1CK7SJdcb8z9HuvVft3D91HLpLC6KSsGb') - self.assertEqual(self.client.get_address('Bitcoin', [2], show_display=True), '15AeAhtNJNKyowK8qPHwgpXkhsokzLtUpG') - self.assertEqual(self.client.get_address('Bitcoin', [3], show_display=True), '1CmzyJp9w3NafXMSEFH4SLYUPAVCSUrrJ5') + for n, address in ((1, '1CK7SJdcb8z9HuvVft3D91HLpLC6KSsGb'), + (2, '15AeAhtNJNKyowK8qPHwgpXkhsokzLtUpG'), + (3, '1CmzyJp9w3NafXMSEFH4SLYUPAVCSUrrJ5')): + self.assertEqual(self.assert_shows_address( + lambda: self.client.get_address('Bitcoin', [n], show_display=True), + address), address) def test_show_multisig_3(self): self.setup_mnemonic_nopin_nopassphrase() @@ -45,7 +48,10 @@ def test_show_multisig_3(self): ) for i in [1, 2, 3]: - self.assertEqual(self.client.get_address('Bitcoin', [i], show_display=True, multisig=multisig), '3E7GDtuHqnqPmDgwH59pVC7AvySiSkbibz') + address = '3E7GDtuHqnqPmDgwH59pVC7AvySiSkbibz' + self.assertEqual(self.assert_shows_address( + lambda: self.client.get_address('Bitcoin', [i], show_display=True, multisig=multisig), + address), address) def test_show_multisig_15(self): self.setup_mnemonic_nopin_nopassphrase() @@ -63,7 +69,10 @@ def test_show_multisig_15(self): ) for i in range(15): - self.assertEqual(self.client.get_address('Bitcoin', [i], show_display=True, multisig=multisig), '3QaKF8zobqcqY8aS6nxCD5ZYdiRfL3RCmU') + address = '3QaKF8zobqcqY8aS6nxCD5ZYdiRfL3RCmU' + self.assertEqual(self.assert_shows_address( + lambda: self.client.get_address('Bitcoin', [i], show_display=True, multisig=multisig), + address), address) if __name__ == '__main__': unittest.main() diff --git a/tests/test_msg_getaddress_taproot.py b/tests/test_msg_getaddress_taproot.py index 650b8de6..aaec24a8 100644 --- a/tests/test_msg_getaddress_taproot.py +++ b/tests/test_msg_getaddress_taproot.py @@ -64,12 +64,13 @@ def test_show_taproot_address(self): self.requires_taproot() self.setup_mnemonic_abandon() self.client.clear_session() - address = self.client.get_address( - "Bitcoin", parse_path("86'/0'/0'/0/0"), True, None, - script_type=proto.SPENDTAPROOT) - self.assertEqual( - address, - 'bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr') + expected = 'bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr' + address = self.assert_shows_address( + lambda: self.client.get_address( + "Bitcoin", parse_path("86'/0'/0'/0/0"), True, None, + script_type=proto.SPENDTAPROOT), + expected) + self.assertEqual(address, expected) if __name__ == '__main__': diff --git a/tests/test_msg_getpublickey.py b/tests/test_msg_getpublickey.py index 4d43d5c6..596b0da8 100644 --- a/tests/test_msg_getpublickey.py +++ b/tests/test_msg_getpublickey.py @@ -51,7 +51,10 @@ def test_script_type(self): self.assertEqual(self.client.get_public_node([], coin_name="Bitcoin", script_type=proto_types.SPENDADDRESS).xpub, "xpub661MyMwAqRbcF1zGijBb2K6x9YiJPh58xpcCeLvTxMX6spkY3PcpJ4ABcCyWfskq5DDxM3e6Ez5ePCqG5bnPUXR4wL8TZWyoDaUdiWW7bKy") self.assertEqual(self.client.get_public_node([], coin_name="Bitcoin", script_type=proto_types.SPENDP2SHWITNESS).xpub, "ypub6QqdH2c5z7966KBPZ5yDEQCTKWrkLK4dsw8RRjpMLMtyvvZmJ3nNv7pKdQw6fnQkUrLm6XEeheSCGVSpoJCQGm6fofpt9RoHVJYH72ecmVm") self.assertEqual(self.client.get_public_node([], coin_name="Bitcoin", script_type=proto_types.SPENDWITNESS).xpub, "zpub6jftahH18ngZwcNWPSkqSVHxVV1CGw48o3eeD8iEiNGrz2NzYhwwYBUTectgfh4ftVTZqzqDAJnk9n4PWzcR4znGg1XJjLcmm2bvVc3Honv") - self.assertEqual(self.client.get_public_node([], coin_name="Bitcoin", script_type=proto_types.SPENDWITNESS, show_display=True).xpub, "zpub6jftahH18ngZwcNWPSkqSVHxVV1CGw48o3eeD8iEiNGrz2NzYhwwYBUTectgfh4ftVTZqzqDAJnk9n4PWzcR4znGg1XJjLcmm2bvVc3Honv") + zpub = "zpub6jftahH18ngZwcNWPSkqSVHxVV1CGw48o3eeD8iEiNGrz2NzYhwwYBUTectgfh4ftVTZqzqDAJnk9n4PWzcR4znGg1XJjLcmm2bvVc3Honv" + self.assertEqual(self.assert_shows_address( + lambda: self.client.get_public_node([], coin_name="Bitcoin", script_type=proto_types.SPENDWITNESS, show_display=True), + zpub).xpub, zpub) if __name__ == '__main__': unittest.main() diff --git a/tests/test_msg_hive.py b/tests/test_msg_hive.py index 688881c5..52cca18c 100644 --- a/tests/test_msg_hive.py +++ b/tests/test_msg_hive.py @@ -308,6 +308,23 @@ def test_hive_get_public_key_active(self): self.assertEqual(len(resp.raw_public_key), 33) self.assertIn(resp.raw_public_key[0], (2, 3), "compressed pubkey prefix") + def test_hive_show_public_key(self): + """The whole STM key is on the screen: confirm_ethereum_address() had + room for two 140 px rows and silently dropped the tail of the key.""" + self.requires_firmware("7.15.0") + self.requires_message("HiveGetPublicKey") + self.requires_release_capability("hive-release-review") + self.setup_mnemonic_nopin_nopassphrase() + + for role in (ROLE_OWNER, ROLE_ACTIVE, ROLE_MEMO, ROLE_POSTING): + expected = hive.get_public_key( + self.client, hive_path(role), show_display=False).public_key + resp = self.assert_shows_address( + lambda: hive.get_public_key( + self.client, hive_path(role), show_display=True), + expected) + self.assertEqual(resp.public_key, expected) + def test_hive_get_public_keys_all_roles(self): """All four role keys derive, are distinct, and STM-formatted.""" self.requires_firmware("7.15.0") diff --git a/tests/test_msg_mayachain_getaddress.py b/tests/test_msg_mayachain_getaddress.py index 372092e8..68439ec2 100644 --- a/tests/test_msg_mayachain_getaddress.py +++ b/tests/test_msg_mayachain_getaddress.py @@ -17,5 +17,16 @@ def test_mayachain_get_address(self): address = self.client.mayachain_get_address(parse_path(DEFAULT_BIP32_PATH), testnet=True) self.assertEqual(address, "smaya1ls33ayg26kmltw7jjy55p32ghjna09zp2mf0av") + def test_mayachain_show_address(self): + self.requires_firmware("7.9.1") + self.requires_fullFeature() + self.setup_mnemonic_nopin_nopassphrase() + expected = "smaya1ls33ayg26kmltw7jjy55p32ghjna09zp2mf0av" + address = self.assert_shows_address( + lambda: self.client.mayachain_get_address( + parse_path(DEFAULT_BIP32_PATH), show_display=True, testnet=True), + expected) + self.assertEqual(address, expected) + if __name__ == '__main__': unittest.main() diff --git a/tests/test_msg_mayachain_signtx.py b/tests/test_msg_mayachain_signtx.py index 12c99ed3..55ca1cde 100644 --- a/tests/test_msg_mayachain_signtx.py +++ b/tests/test_msg_mayachain_signtx.py @@ -138,6 +138,33 @@ def _sign_and_verify_send(self, memo, amount=10000, self.assertTrue(vk.verify_digest(resp.signature, digest, sigdecode=sigdecode_string)) + def _confirm_bodies(self): + bodies = [] + original = self.client.callback_ButtonRequest + + def capture(msg): + bodies.append(self.client.debug.read_confirm_text()[1]) + return original(msg) + + self.client.callback_ButtonRequest = capture + return bodies + def test_fee_is_shown_in_whole_cacao(self): + """fee_amount is in 1e-10 CACAO; the sign screen must not print the + raw count.""" + self.requires_fullFeature() + self.requires_firmware("7.15.0") + self.setup_mnemonic_nopin_nopassphrase() + bodies = self._confirm_bodies() + self.client.mayachain_sign_tx( + address_n=parse_path(DEFAULT_BIP32_PATH), account_number=92, + chain_id="mayachain", fee=2000000, gas=200000, + msgs=[make_send(self.client.mayachain_get_address( + parse_path(DEFAULT_BIP32_PATH)), + "maya1jvt443rvhq5h8yrna55yjysvhtju0el7mdujp3", + 10000)], + memo="foobar", sequence=3, testnet=False) + self.assertIn("Fee: 0.0002 cacao. Gas: 200000.", "\n".join(bodies)) + def test_mayachain_sign_tx(self): """Native CACAO MsgSend with a plain memo; the full raw memo is paged on the OLED before signing (thorchain_confirm_full_memo is the sole diff --git a/tests/test_msg_nano_getaddress.py b/tests/test_msg_nano_getaddress.py index 2ae17ac0..a3def5eb 100644 --- a/tests/test_msg_nano_getaddress.py +++ b/tests/test_msg_nano_getaddress.py @@ -47,7 +47,8 @@ def test(self): ] for path, show, address in vec: - res = self.client.nano_get_address('Nano', path, show) + call = lambda: self.client.nano_get_address('Nano', path, show) + res = self.assert_shows_address(call, address) if show else call() self.assertEqual(res.address, address) if __name__ == '__main__': diff --git a/tests/test_msg_osmosis_getaddress.py b/tests/test_msg_osmosis_getaddress.py new file mode 100644 index 00000000..98b5445d --- /dev/null +++ b/tests/test_msg_osmosis_getaddress.py @@ -0,0 +1,23 @@ +import unittest +import common + +from keepkeylib.tools import parse_path + + +class TestMsgOsmosisGetAddress(common.KeepKeyTest): + + def test_osmosis_show_address(self): + self.requires_fullFeature() + self.requires_firmware("7.7.0") + self.requires_message("OsmosisGetAddress") + self.setup_mnemonic_nopin_nopassphrase() + path = parse_path("m/44h/118h/0h/0/0") + expected = self.client.osmosis_get_address(path) + address = self.assert_shows_address( + lambda: self.client.osmosis_get_address(path, show_display=True), + expected) + self.assertEqual(address, expected) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_msg_ripple_get_address.py b/tests/test_msg_ripple_get_address.py index 8ac0dcd0..05b82577 100644 --- a/tests/test_msg_ripple_get_address.py +++ b/tests/test_msg_ripple_get_address.py @@ -39,8 +39,10 @@ def test_ripple_show_address(self): self.requires_fullFeature() self.requires_firmware("6.4.0") self.setup_mnemonic_allallall() - address = self.client.ripple_get_address( - parse_path("m/44'/144'/0'/0/0"), show_display=True) + address = self.assert_shows_address( + lambda: self.client.ripple_get_address( + parse_path("m/44'/144'/0'/0/0"), show_display=True), + "rNaqKtKrMSwpwZSzRckPf7S96DkimjkF4H") # 7.14.2 and later preserve the response across DebugLinkGetState # requests made during screenshot capture; the same fix is on all three # products, so the floor is the release the fix first shipped in. diff --git a/tests/test_msg_signtx_ethereum_erc20.py b/tests/test_msg_signtx_ethereum_erc20.py index 6567658e..0b557f1e 100644 --- a/tests/test_msg_signtx_ethereum_erc20.py +++ b/tests/test_msg_signtx_ethereum_erc20.py @@ -25,6 +25,8 @@ import keepkeylib.messages_pb2 as proto import keepkeylib.types_pb2 as proto_types from keepkeylib.client import CallException +from oled_text import TITLE_FONT, find_line, shows +from test_msg_display_disclosure import ScreenRecorder from keepkeylib.tools import int_to_big_endian class TestMsgEthereumSigntxERC20(common.KeepKeyTest): @@ -68,11 +70,13 @@ def test_approve_some(self): self.assertEqual(binascii.hexlify(sig_s), '5b8b0e5b7b8f6d5269ce4dc266e6901f3284079fa1f0cd358d2987336dc8ba3a') def test_approve_all_refused(self): - # 7.14.2 through 7.15.x refuse an unlimited approve outright. 7.16 - # reviews and signs it instead (D-010): test_approve_all. + # 7.14.2 through 7.15.x refuse an unlimited approve outright, until + # erc20-unlimited-approve-review: from then it is signed after an + # UNLIMITED warning (test_approve_all). self.requires_fullFeature() self.requires_firmware("7.14.2") self.requires_firmware_below("7.16.0") + self.requires_capability_absent("erc20-unlimited-approve-review") self.setup_mnemonic_nopin_nopassphrase() with self.assertRaises(CallException): @@ -90,22 +94,31 @@ def test_approve_all_refused(self): def test_approve_all(self): self.requires_fullFeature() if self.firmware_at_least("7.14.2"): - # Refused on 7.14.2-7.15.x (test_approve_all_refused); - # reviewed and signed from 7.16 (D-010). - self.requires_firmware("7.16.0") + # Refused on 7.14.2-7.15.x (test_approve_all_refused) until + # erc20-unlimited-approve-review; signed after a warning since. + self.requires_firmware("7.15.0") self.requires_release_capability("erc20-unlimited-approve-review") self.setup_mnemonic_nopin_nopassphrase() - sig_v, sig_r, sig_s = self.client.ethereum_sign_tx( - n=[2147483692,2147483708,2147483648,0,0], - nonce=1, - gas_price=20, - gas_limit=20, - value=0, - to=binascii.unhexlify('41e5560054824ea6b0732e656e3ad64e20e94e45'), - chain_id=1, - data=binascii.unhexlify('095ea7b3000000000000000000000000' + '1d1c328764a41bda0492b66baa30c4a339ff85ef' + 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'), - ) + recorder = ScreenRecorder(self.client) + with recorder: + sig_v, sig_r, sig_s = self.client.ethereum_sign_tx( + n=[2147483692,2147483708,2147483648,0,0], + nonce=1, + gas_price=20, + gas_limit=20, + value=0, + to=binascii.unhexlify('41e5560054824ea6b0732e656e3ad64e20e94e45'), + chain_id=1, + data=binascii.unhexlify('095ea7b3000000000000000000000000' + '1d1c328764a41bda0492b66baa30c4a339ff85ef' + 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'), + ) + if self.firmware_at_least("7.15.0"): + # The UNLIMITED warning is the first screen, full spender. + self.assertIsNotNone(find_line(recorder.screens[0], + 'UNLIMITED APPROVAL', TITLE_FONT)) + self.assertTrue(shows(recorder.screens[0], + 'Allow 0x1D1C328764A41BdA0492b66bAA30C4A339FF85EF ' + 'to spend ALL your CVC')) self.assertEqual(sig_v, 37) self.assertEqual(binascii.hexlify(sig_r), '3671acb6aed5241948de56635ef64554d5e834355e99d806c4ae30bf463eae57') diff --git a/tests/test_msg_solana_getaddress.py b/tests/test_msg_solana_getaddress.py index 8a5abfb7..db767fc9 100644 --- a/tests/test_msg_solana_getaddress.py +++ b/tests/test_msg_solana_getaddress.py @@ -72,13 +72,17 @@ def test_solana_show_address(self): self.requires_message("SolanaGetAddress") self.setup_mnemonic_allallall() - resp = self.client.call( - solana_proto.SolanaGetAddress( - address_n=[H + 44, H + 501, H + 0, H + 0], - show_display=True, - ) - ) + expected = self.client.solana_get_address( + [H + 44, H + 501, H + 0, H + 0]).address + resp = self.assert_shows_address( + lambda: self.client.call( + solana_proto.SolanaGetAddress( + address_n=[H + 44, H + 501, H + 0, H + 0], + show_display=True, + ) + ), expected) self.assertIsInstance(resp, solana_proto.SolanaAddress) + self.assertEqual(resp.address, expected) def test_solana_different_accounts(self): """Different account indices must produce different addresses.""" diff --git a/tests/test_msg_solana_lut_attestation.py b/tests/test_msg_solana_lut_attestation.py index 265ec93c..8455de8a 100644 --- a/tests/test_msg_solana_lut_attestation.py +++ b/tests/test_msg_solana_lut_attestation.py @@ -146,7 +146,8 @@ def test_attested_accounts_are_shown_and_blind_sign_still_follows(self): self._load_signer() pk = self._raw_pubkey() raw = self._build_lut_tx(pk) - accounts = [b'\x51' * 32, b'\x52' * 32] + # Exactly the one account the message's lookup table loads. + accounts = [b'\x51' * 32] base_codes, _ = self._screens(raw_tx=raw) # Reload: identities are RAM-only and a completed signing tears the @@ -164,6 +165,23 @@ def test_attested_accounts_are_shown_and_blind_sign_still_follows(self): self.assertEqual(len(att_codes), len(base_codes) + 1 + len(accounts)) self.assertEqual(att_codes[-len(base_codes):], base_codes) + def test_partial_or_padded_list_degrades_to_todays_flow(self): + """A valid attestation is shown only when it lists every account the + message loads: one more or one fewer would make "describes N + account(s)" a misleading claim, so nothing is added.""" + self._load_signer() + pk = self._raw_pubkey() + raw = self._build_lut_tx(pk) # loads exactly one account + base_codes, _ = self._screens(raw_tx=raw) + for accounts in ([b'\x51' * 32, b'\x52' * 32], []): + self._load_signer() + codes, resp = self._screens( + raw_tx=raw, lut_account=accounts, + lut_signature=self._attest(raw, accounts), + lut_signer_key_id=SLOT) + self.assertEqual(len(resp.signature), 64) + self.assertEqual(codes, base_codes) + def test_bad_signature_degrades_to_todays_flow(self): """A signature that does not verify must change NOTHING.""" self._load_signer() diff --git a/tests/test_msg_solana_signtx.py b/tests/test_msg_solana_signtx.py index 0ee75dfa..da04a031 100644 --- a/tests/test_msg_solana_signtx.py +++ b/tests/test_msg_solana_signtx.py @@ -451,6 +451,42 @@ def test_solana_sign_stake_withdraw(self): address_n=parse_path("m/44'/501'/0'/0'"), raw_tx=raw_tx)) self.assertEqual(len(resp.signature), 64) + def test_solana_stake_addresses_fit_one_page(self): + """A base58 address is at most 44 characters and fits the body, so a + stake authorize or withdraw screen must not page it. A forced line + break before "to" once pushed the address tail onto a second page + on its own. A paged confirm asks once per page, so a repeated body + is a page split.""" + self.requires_fullFeature() + self.requires_firmware("7.15.0") + self.setup_mnemonic_allallall() + from_pubkey = self._get_from_pubkey() + sysvars = [b'\xC1' * 32, b'\xC2' * 32] + cases = [ + ([sysvars[0], b'\x77' * 32], + struct.pack(' 0, "TON address must be non-empty") def test_ton_show_address(self): - """Display TON address on OLED (triggers ButtonRequest for screenshot). + """The whole TON address is on the screen, and in the response. - In screenshot mode, DebugLink read_layout() can race with the - show_display response. Known issue: raw_address field causes - UnicodeDecodeError. Address correctness verified by test_ton_get_address. + The handler builds its response before the confirm. Before 7.15.0 a + DebugLink read during the confirm wiped it (firmware 88ae1c3be fixed + that; this test used to swallow the resulting raw_address + UnicodeDecodeError), so it runs from 7.15.0. """ - self.requires_firmware("7.14.0") + self.requires_firmware("7.15.0") self.requires_message("TonGetAddress") self.setup_mnemonic_allallall() - try: - resp = self.client.ton_get_address( + expected = self.client.ton_get_address( + parse_path(TON_DEFAULT_PATH), show_display=False) + resp = self.assert_shows_address( + lambda: self.client.ton_get_address( parse_path(TON_DEFAULT_PATH), show_display=True - ) - self.assertIsNotNone(resp) - except (UnicodeDecodeError, Exception): - pass # raw_address proto bug or screenshot race + ), expected.address) + self.assertEqual(resp.address, expected.address) + self.assertEqual(resp.raw_address, expected.raw_address) def test_ton_different_accounts(self): """Different derivation paths must produce different addresses.""" diff --git a/tests/test_msg_tron_getaddress.py b/tests/test_msg_tron_getaddress.py index 21bdabb4..da3dd089 100644 --- a/tests/test_msg_tron_getaddress.py +++ b/tests/test_msg_tron_getaddress.py @@ -45,23 +45,24 @@ def test_tron_get_address(self): self.assertTrue(address.startswith('T'), "Tron address must start with 'T', got '%s'" % address) def test_tron_show_address(self): - """Display TRON address on OLED (triggers ButtonRequest for screenshot). + """The whole TRON address is on the screen, and in the response. - In screenshot mode, DebugLink read_layout() can race with the - show_display response. Address correctness verified by test_tron_get_address. + The handler builds its response before the confirm. Before 7.15.0 a + DebugLink read during the confirm wiped it (fixed by firmware + 88ae1c3be), so it runs from 7.15.0. """ - self.requires_firmware("7.14.0") + self.requires_firmware("7.15.0") self.requires_message("TronGetAddress") self.setup_mnemonic_allallall() - try: - resp = self.client.tron_get_address( + expected = self.client.tron_get_address( + parse_path(TRON_DEFAULT_PATH)).address + resp = self.assert_shows_address( + lambda: self.client.tron_get_address( parse_path(TRON_DEFAULT_PATH), show_display=True - ) - self.assertIsNotNone(resp) - except Exception: - pass # Screenshot race -- OLED display still worked + ), expected) + self.assertEqual(resp.address, expected) def test_tron_different_accounts(self): """Different derivation paths must produce different addresses.""" diff --git a/tests/test_msg_tron_signtx.py b/tests/test_msg_tron_signtx.py index 6d9d8659..315e02ba 100644 --- a/tests/test_msg_tron_signtx.py +++ b/tests/test_msg_tron_signtx.py @@ -16,13 +16,66 @@ _has_tron = False import common import binascii +import hashlib import struct +from ecdsa import SECP256k1, VerifyingKey +from ecdsa.util import sigdecode_string + from keepkeylib import messages_pb2 as messages from keepkeylib import messages_tron_pb2 as tron_messages from keepkeylib import types_pb2 as types from keepkeylib.client import CallException -from keepkeylib.tools import parse_path +from keepkeylib.signed_metadata import keccak256 +from keepkeylib.tools import b58decode, b58encode, parse_path + + +USDT = "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t" # tether.to supported-protocols +TRIGGER_URL = b"type.googleapis.com/protocol.TriggerSmartContract" + + +def _varint(value): + out = bytearray() + while value >= 0x80: + out.append((value & 0x7F) | 0x80) + value >>= 7 + out.append(value) + return bytes(out) + + +def _field(number, payload): + """Length-delimited protobuf field.""" + return _varint(number << 3 | 2) + _varint(len(payload)) + payload + + +def _uint(number, value): + return _varint(number << 3) + _varint(value) + + +def _tron_raw(address): + """21-byte TRON address from Base58Check.""" + raw = b58decode(address, None) + payload, checksum = raw[:-4], raw[-4:] + assert hashlib.sha256(hashlib.sha256(payload).digest()).digest()[:4] == checksum + assert len(payload) == 21 and payload[0] == 0x41 + return payload + + +def _tron_address(raw21): + checksum = hashlib.sha256(hashlib.sha256(raw21).digest()).digest()[:4] + return b58encode(raw21 + checksum) + + +def _trc20_transfer_raw_data(owner, contract, to, amount, fee_limit): + """protocol.Transaction.raw for one TriggerSmartContract transfer().""" + calldata = (binascii.unhexlify("a9059cbb") + b"\0" * 12 + to[1:] + + amount.to_bytes(32, "big")) + trigger = _field(1, owner) + _field(2, contract) + _field(4, calldata) + contract_msg = _uint(1, 31) + _field(2, _field(1, TRIGGER_URL) + + _field(2, trigger)) + return (_field(1, b"\xab\xcd") + _field(4, b"\x42" * 8) + + _uint(8, 1700000000000) + _field(11, contract_msg) + + _uint(14, 1699999990000) + _uint(18, fee_limit)) @unittest.skipUnless(_has_tron, "TRON protobuf messages not available in this build") @@ -164,6 +217,71 @@ def test_tron_sign_trc20_transfer(self): self.assertGreater(len(resp.serialized_tx), 0) + def _walk_sign(self, msg): + """Approve every screen, recording (title, body) as the device drew it.""" + screens = [] + response = self.client.call_raw(msg) + while isinstance(response, messages.ButtonRequest): + screens.append(self.client.debug.read_confirm_text()) + self.client.debug.press_yes() + response = self.client.call_raw(messages.ButtonAck()) + return response, screens + + def _trc20_request(self, contract): + path = parse_path("m/44'/195'/0'/0/0") + owner = self.client.call(tron_messages.TronGetAddress( + address_n=path, show_display=False)).address + to = b"\x41" + b"\x22" * 20 + raw_data = _trc20_transfer_raw_data(_tron_raw(owner), contract, to, + 1500000, 30000000) + return owner, to, raw_data, tron_messages.TronSignTx( + address_n=path, raw_data=raw_data) + + def test_tron_sign_trc20_usdt_clear_signs(self): + """USDT is in the firmware's trusted TRC-20 table: the transfer + clear-signs without AdvancedMode, in token units, and the signature + covers sha256(raw_data) under the account's own key.""" + self.requires_fullFeature() + self.requires_firmware("7.15.0") + self.requires_release_capability("tron-trc20-review") + self.setup_mnemonic_allallall() + self.client.apply_policy("AdvancedMode", 0) + + owner, to, raw_data, msg = self._trc20_request(_tron_raw(USDT)) + response, screens = self._walk_sign(msg) + + self.assertIsInstance(response, tron_messages.TronSignedTx) + self.assertEqual(screens[0], ("TRC-20 Transfer", + "Send 1.5 USDT to %s?" % _tron_address(to))) + self.assertEqual(screens[1][1], + "Energy fee limit 30 TRX\nBandwidth fees are extra") + self.assertEqual(len(screens), 2) + + signature = response.signature + self.assertEqual(len(signature), 65) + digest = hashlib.sha256(raw_data).digest() + candidates = VerifyingKey.from_public_key_recovery_with_digest( + signature[:64], digest, SECP256k1, sigdecode=sigdecode_string) + signers = set() + for key in candidates: + point = key.to_string() # 64-byte uncompressed X || Y + signers.add(_tron_address(b"\x41" + keccak256(point)[-20:])) + self.assertIn(owner, signers) + + def test_tron_sign_trc20_unknown_contract_needs_advanced_mode(self): + """A transfer() call to a contract outside the trusted table is not + clear-signed: without AdvancedMode it is refused before any screen.""" + self.requires_fullFeature() + self.requires_firmware("7.15.0") + self.requires_release_capability("tron-trc20-review") + self.setup_mnemonic_allallall() + self.client.apply_policy("AdvancedMode", 0) + + _, _, _, msg = self._trc20_request(b"\x41" + b"\x33" * 20) + response = self.client.call_raw(msg) + self.assertIsInstance(response, messages.Failure) + self.assertEqual(response.message, "Enable AdvancedMode to blind-sign") + def test_tron_sign_empty_raw_data(self): """Signing with empty raw_data should be rejected by firmware.""" self.requires_fullFeature() diff --git a/tests/test_msg_zcash_display_address.py b/tests/test_msg_zcash_display_address.py index ebcd24a1..3de0e109 100644 --- a/tests/test_msg_zcash_display_address.py +++ b/tests/test_msg_zcash_display_address.py @@ -40,12 +40,16 @@ def test_zcash_display_address_basic(self): # The device derives its OWN unified address from address_n/account # (the host does not supply address/FVK — those fields are reserved). - resp = self.client.call( - zcash_proto.ZcashDisplayAddress( - address_n=[H + 32, H + 133, H + 0], - account=0, - ) - ) + # No message returns the UA without displaying it and there is no + # independent vector, so this proves only that the screen shows all of + # the address the device returns. + resp = self.assert_shows_address( + lambda: self.client.call( + zcash_proto.ZcashDisplayAddress( + address_n=[H + 32, H + 133, H + 0], + account=0, + ) + ), lambda resp: resp.address) # Device returns the confirmed UA bound to its seed. self.assertIsInstance(resp, zcash_proto.ZcashAddress) diff --git a/tests/test_msg_zcash_sign_pczt_device.py b/tests/test_msg_zcash_sign_pczt_device.py index 0dfff364..07999cb5 100644 --- a/tests/test_msg_zcash_sign_pczt_device.py +++ b/tests/test_msg_zcash_sign_pczt_device.py @@ -11,12 +11,11 @@ came from a shielded flow, which is how a confirm that could not physically fit its amount line shipped unnoticed. -The note fixtures are the known-answer vectors from -unittests/firmware/zcash.cpp (OrchardNoteCommitment_KnownVectorAndProgress, -IronwoodNoteCommitment_V3KnownVector, OrchardReceiverToUnifiedAddress_KnownVector), -so the device's own cmx recomputation accepts them. Same note under both pools, -with a different commitment each -- which is what lets us prove the device -actually honours shielded_pool instead of ignoring it. +The note fixture is note 0 of the zcash-test-vectors Orchard note-encryption +vectors, with a real ciphertext, so the device's cmx recomputation and its +note-ciphertext check both accept it. Same note under both pools, with a +different commitment and ciphertext each -- which is what lets us prove the +device actually honours shielded_pool instead of ignoring it. """ import hashlib @@ -34,26 +33,70 @@ H = 0x80000000 ADDRESS_N = [H + 32, H + 133, H] -# --- known-answer note, from unittests/firmware/zcash.cpp ------------------- +# --- note 0 of zcash-test-vectors orchard_note_encryption.py --------------- +# As carried by the orchard 0.15.4 crate (src/test_vectors/note_encryption.rs). +# The device recomputes cmx AND decrypts the note ciphertext, so every field +# below must be a real encryption of this note; rho is the vector's nf_old. +# The Ironwood (V3, lead byte 0x03) cmx and ciphertext re-encrypt the same note +# with orchard 0.15.4's IronwoodNoteEncryption; epk is unchanged. RECIPIENT = bytes.fromhex( - '3c150e6098b861716cc7f62835f69feb302193c92660444f26624fd13e00ea7a' - 'c774cd55074d6367efef37') # 43 bytes -RHO = bytes.fromhex( - '112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00') -RSEED = bytes.fromhex( - 'cafebabedeadbeef0102030405060708090a0b0c0d0e0f101112131415161718') -VALUE = 12345678 - -CMX_ORCHARD = bytes.fromhex( - '02defb39c8f2e1ecc945189373cf2a8e21d4e154398efa1621d5fb989e1deb36') -CMX_IRONWOOD = bytes.fromhex( - '896ee345d8b0409872172537666a482409661a22ad77c09896a3e71765f18633') - -# OrchardReceiverToUnifiedAddress_KnownVector. 106 characters -- three full -# body rows on their own, which is the entire reason the confirm needs two -# screens instead of one. -EXPECTED_UA = ('u1ut4h93zg5670tyqss7tneru3t7h6dk62r9hhyxyrpv3nwwe9dnyj5l0ruwygf' - '74gp5f3zklj5xly4h8h54un3asugt9mn6gwfqsq3wq7') + '56e84b1adc9423c3676c0463f7125df4836fd2816b024ee70efe09fb9a7b3863' + 'c6eacdf95e03894950692c') # d || pk_d, 43 bytes +RHO = bytes.fromhex('c596fbd32ebbcbadae60d285c7d75fa836f9d2fa86100ab858ea2de1f11c8306') +RSEED = bytes.fromhex('bf69b8250c18ef41294ca97993db546c1fe01f7e9c8e36d6a5e29d4e30a73594') +VALUE = 8567075990963576717 + +CMX_ORCHARD = bytes.fromhex('a5706f3d1b688e9dc634eee4e65b028a43eeaed2435bea2ae3d5160575c11a3b') +CMX_IRONWOOD = bytes.fromhex('07a8d0edab5130bcdb265d8efed333514c2c9b180df70ba3963ca8fc1166bd14') +EPK = bytes.fromhex('addb47b6ac5dfc16558923d3a8f376095c695c047c4e3266ae676987f7e31381') +# enc_ciphertext = compact (52) || memo (512) || AEAD tag (16). +C_ENC_ORCHARD = bytes.fromhex( + '1a9adb142498e3dcc76fed778614dd316c02fbb8ba9244ae4c2e32a07daeeca4' + '1226b98bfe74f9fcb228cfc100f3180f5775ece38be7ed45d94021f4401b2a4d' + '7582b428d49ec7f5b5a498973e60e38e74f5c3e577827c382857d8166b54e64f' + '66ef5c7e8c9baa2a3fa9e37d087717d5e96bc2f73d031450dc2432ba49d8b74d' + 'b213099ea9ba04eb63b6574d46c03ce7900d4ac4bb188ee9030d7f69c895a94f' + 'c182f225a94f0cde1b49886871a376341ea94171befd95a830fa18407097dca5' + '11025463d437e9695caa079a2f68cdc7f2c13267bff4195137fa8953252a81b2' + 'afa1582b9bfb4ac96037ed2991d3cbc7d54aff6e621b06a7b2b9caf2955efaf4' + 'ea8efcfd023a3c1748df3cbd43e0b9a8b0945688d52056c1d16eea37e798ba31' + 'dc3e5d4952bd51ec769d5788b6e35fe9042b95d4d21781400eaff58616ad5627' + '96636a50b8ed6c7f981dc7ba814eff152cb228a2ead2f832662fa4a4a50797b0' + 'f85b62d08b1dd2d8e43b4a5bfbb159ed578ef7475de0ada13e17ad87cc230567' + '2bcc55a8881317fdc1bfc459b68b2df70cad3770ed0fd02d64b96f2bbf6f8f63' + '2e866ca5d196d248ad05c3de644148a80b51ada95bd08d73cdbb45264f3bd113' + '835b46f9be7b6d23a43bddfe1e7408c97031e1a8214bab46391044b700d38f51' + '92c57fe6f87159b55512094e29d2cebab868c8f1adbad57077cbeb5e69658582' + 'bf98d19d64f44b0d50c7e2209ab3fc56b4f409123aaeb0263a22451bc14ed756' + 'd048385aedbb86a84677bb2d21c52cc9494147bf0fb102745282990909726228' + '186e02c8') +C_ENC_IRONWOOD = bytes.fromhex( + '1b9adb142498e3dcc76fed778614dd316c02fbb8ba9244ae4c2e32a07daeeca4' + '1226b98bfe74f9fcb228cfc100f3180f5775ece38be7ed45d94021f4401b2a4d' + '7582b428d49ec7f5b5a498973e60e38e74f5c3e577827c382857d8166b54e64f' + '66ef5c7e8c9baa2a3fa9e37d087717d5e96bc2f73d031450dc2432ba49d8b74d' + 'b213099ea9ba04eb63b6574d46c03ce7900d4ac4bb188ee9030d7f69c895a94f' + 'c182f225a94f0cde1b49886871a376341ea94171befd95a830fa18407097dca5' + '11025463d437e9695caa079a2f68cdc7f2c13267bff4195137fa8953252a81b2' + 'afa1582b9bfb4ac96037ed2991d3cbc7d54aff6e621b06a7b2b9caf2955efaf4' + 'ea8efcfd023a3c1748df3cbd43e0b9a8b0945688d52056c1d16eea37e798ba31' + 'dc3e5d4952bd51ec769d5788b6e35fe9042b95d4d21781400eaff58616ad5627' + '96636a50b8ed6c7f981dc7ba814eff152cb228a2ead2f832662fa4a4a50797b0' + 'f85b62d08b1dd2d8e43b4a5bfbb159ed578ef7475de0ada13e17ad87cc230567' + '2bcc55a8881317fdc1bfc459b68b2df70cad3770ed0fd02d64b96f2bbf6f8f63' + '2e866ca5d196d248ad05c3de644148a80b51ada95bd08d73cdbb45264f3bd113' + '835b46f9be7b6d23a43bddfe1e7408c97031e1a8214bab46391044b700d38f51' + '92c57fe6f87159b55512094e29d2cebab868c8f1adbad57077cbeb5e69658582' + 'bf98d19d64f44b0d50c7e2209ab3fc56b4f409123aaeb0263a22451bc14ed756' + 'd048385aedbb86a84677bb2d21c52cc9494147bfa197dd4326a43baa347044f2' + 'bdb49861') + +# RECIPIENT as an Orchard-only mainnet unified address, encoded with +# librustzcash's zcash_address 0.13.0. 106 characters -- three full body rows +# on their own, which is the entire reason the confirm needs two screens +# instead of one. +EXPECTED_UA = ('u17j4lvw84jd238ev9ukr0lvqhv4z32v98pxcglctaj3aqfqj7rr2wwvh73247ek' + 'czw4smyrvm2wf2v5nfxvn3sl0ycc6w4455yg49yf2m') ORCHARD_TX = dict(tx_version=5, version_group_id=0x26A7270A, branch_id=0x5437F330) IRONWOOD_TX = dict(tx_version=6, version_group_id=0xD884B698, branch_id=0x37A5165B) @@ -62,6 +105,1154 @@ FLAGS = 3 +# --- a real NU6.3 Orchard bundle ------------------------------------------- +# Built by the orchard 0.16.0 crate (Builder with BundleVersion::orchard_v3() +# and Flags::CROSS_ADDRESS_DISABLED, then build_for_pczt) for the "all" seed, +# account 0: a 100000-zat spend and a 90000-zat change output, fee 10000. +# With cross-address transfers disabled the builder pairs the spend with a +# fabricated zero-valued output to the spent note's own receiver whose +# enc_ciphertext is random bytes (ZIP 326), and the change with a fabricated +# zero-valued wallet spend. Both spends are the wallet's, so rk is this seed's +# ak re-randomized by alpha and the device signs both actions. +FABRICATED_BUNDLE = [ + { + 'nullifier': bytes.fromhex('aed05ebddc392dda842311207fbc3fa84fb454f43fcfac292d87a3e8300ee112'), + 'rk': bytes.fromhex('2c1b8779ac1aca3abec73dfe9b8635be2fae970dfe76237495042fed96c3849f'), + 'alpha': bytes.fromhex('f081a5920a807a9189bc48f6ef5916b48effd77745c905def34316c2af87290c'), + 'cv_net': bytes.fromhex('e80cb524dfe437bebaaeffec6c4543a7f64f48fa4bfa03e1847641b184c3da1d'), + 'cmx': bytes.fromhex('6685ca96b57a11cae02c5c562b3f999713d06fadc697444e4c34f022a1df752a'), + 'epk': bytes.fromhex('e56229ea7072ff2dac9e9d0d3545bc13511e55b849089d3244e3d6667466872c'), + 'enc': bytes.fromhex( + '8807db653fc5d70f3382f580c2283ed388a87134aec35d3f1108efea6df55ef0' + 'b61eaa33b79f8d53b6a3fb791c83b75876186f6e404ca22e3246bd3d6ee956f6' + '983d2f7efb6cbb27571832127afd4f48136bdab4ebc68bc2a7c667a4ab231030' + '19ecd43212a1b6e47307949de23f82998fb33d3f3d15abefaa8052026b17d172' + '1a508d8af11baa74df8f2f67c3be1a92bea530039b4920a0efedc8ee934485b2' + 'aecd88b5af781c8614d968236504d40d58d64875a808aae0995bb14577c89a26' + '564f7be2d8a8e871ca8caaeb04c7af0023b25d6930745b0fce3d1b01575d68b9' + '8965500c6de13f84b14052e24cca3bbe8aa0570ca4196b18a4b2cada1ddd039c' + '4d6038c809426d1eed7674efb6990b040035cc1b92952dae4d642f9c4c613572' + '59dc961c5f208a14387b7d8f9b4f5e502a09aa1d292d33e72b489bb5e5cf4ede' + '7e239d96d07139f9270ec5a3305da1013f0a5b6de6860af11a212c77fe5c1cb9' + '73888cbc1100e0e07423e879e40365844c2ca9a75b16ed4d032127470ca0e0bd' + '5de907a32b3aea36512929f5b83863bc1d63b40fce26dc4d58472ec15f2fadd2' + '24c16985bd5ab01e388502dd22596fe85012a9f74e2ea6c9b9aca2b7bc2298ed' + '779c61285753e6ba92f0a1a963f33750c105122c7e5ec92d95e2f454e0556682' + '25ebf956231f22a139c3c31fdb7e4a4a214d296765353e0e45269cef2eebdbf7' + 'e53e3743c4266eb705d30ea2cb567e370eda979b44f33ee2f6233dc8e1f5e844' + 'ff66891d37165675e63b2a10722381a55a92b006dd793ca832010a002d3021ab' + '5e526af9'), + 'out': bytes.fromhex( + 'a5fe4a96ac820c57db11db73741c6fee879c90635e16c5fd60967be70c58f27d' + '85e4a135ac87ecc858d88b34df846b2af6035683c138b97876c373328076e8ce' + 'f61c5989e4fee41ed2334b932f947f82'), + 'recipient': bytes.fromhex( + 'da973031634a8938ad1c480f978780693ec7709ba5caf58d8a7eb945586cbed6' + '45520f17387437bcfdc216'), + 'rseed': bytes.fromhex('c29d5ab216448f6ebf6388a6251160e7c9fe2413c85ac1cd2340363807ba8840'), + 'value': 0, + }, + { + 'nullifier': bytes.fromhex('31aafc80063db2af87ffdee21267ccd1f8a6eda982f7c5816b8f1d99ee580217'), + 'rk': bytes.fromhex('defbdcf42d021aa013d14a391b3cefa8ce94ac9cac96481bfddecab3f2065e06'), + 'alpha': bytes.fromhex('a16c066adf9a10e1696c4fa884a67f93b24d858e8cf06743304ad6cae69a1b06'), + 'cv_net': bytes.fromhex('fd260057cb02e71c9d37554c7fb496b48d5412c1c2707fcf0c8601946dd04c12'), + 'cmx': bytes.fromhex('e35568cf21a2befafa3d8bbd2bf6a19bcdbfe6b6234c303004ba38ba76afed3f'), + 'epk': bytes.fromhex('9b9efea983df2470cfc8d28bcf8c5bfd4f714e6bc08b0a15ab3611b0c7b56101'), + 'enc': bytes.fromhex( + 'b82f1b13e501868055a3f88433481172ee1173402227637b46be3e63cd3fa939' + '93af3074450b558a4d6ff8ee65bdb04962077060b5c258b3d0f7bc21ec7df69a' + 'a0898c47b6d913186a13fa21c420f0da48e72d167bc3e08bffa1f16d99a11aad' + '65cf98cc0a0ce37ec679c03dc7c6f1fe9feb619b4eca0c5823f6d413c7a5be12' + '2aee48f070770d163fde8ad4862df692d4433afe053e6b9e1a50e6cc8cbd37aa' + '54ce3e014e3dd342496855226cd65896442300161e242a8c4d7b2c19c83df04f' + 'f3ab7c7afcb9fb486d28bda503260b758ac473b618cce25b9d0daf8bafbe64ee' + '3d52f804c33ee78e25fe5bd6a105d4a1cde143e2d047f0fee8e9cb3645964688' + '2eb5ade60a1ff79284b81ee817d638ad5e1da8052266171b320a8bf4ec337df3' + 'ebcf087de768b46404f45a23208c8358c644e626152d67cf4e2efa94ff9ac2dd' + 'b8e3c670360523c238f1cc3b961dedade8e90de90927841745c5398f140ac053' + '8d48561bb372a367933147d239c500c238cf294d05e93c473378f59708f5aefb' + '375d23df2d0fc1a8f0de90c8fdb6cbb0036eef778c1bdca2731c7fe23a0331ee' + '4ceb357a52ce552ca0626891f5362c1983fb2656f91b372f0559de8943a9e555' + '30bc009ede7c222f8748ade9762270f937725a25401ad5a4fdc01a3f1f100289' + 'c5a291b9bfc3bc696e0af71e7199f6555b53ed875aa7ebdfeba1cd3f8c711190' + 'c6d5c64059483983834faf47283ca15682c4966070425d0f305cad882901d70f' + 'd222a8bfeb2077541449b73ce56a8d08aa623c06aa8b38e675eb17fd162b862d' + '5f777396'), + 'out': bytes.fromhex( + '28c960f201269936a006ae1cc2cd358b29f981dc52d10448a3c02479855bf89c' + 'ff2a654493f29035ff20daf3ce97d13d514bca41d0d298d0c40834248d1f617f' + '3db9516428eeca01be53af1da897071e'), + 'recipient': bytes.fromhex( + 'ddae703de8aee25d4e439b8a646b2a5a86f57f802890996e2b3c1f41ff2348a0' + 'f0bb27c032b2e7718c962e'), + 'rseed': bytes.fromhex('c53e0dc6ce5562fbf35fd57698514207df3cb42161093b070ba16bffcb93fdd9'), + 'value': 90000, + }, +] + + +# The same spend and change as an NU6.2 bundle (orchard 0.16.0, +# BundleVersion::orchard_v2(), Flags::ENABLED), as wallets build today. The +# builder pads it with a dummy spend (dummy_sk, host-signed) and a dummy +# zero-valued output to a random address whose ciphertext really decrypts. +PADDING_BUNDLE = [ + { + 'nullifier': bytes.fromhex('aed05ebddc392dda842311207fbc3fa84fb454f43fcfac292d87a3e8300ee112'), + 'rk': bytes.fromhex('2c1b8779ac1aca3abec73dfe9b8635be2fae970dfe76237495042fed96c3849f'), + 'alpha': bytes.fromhex('f081a5920a807a9189bc48f6ef5916b48effd77745c905def34316c2af87290c'), + 'cv_net': bytes.fromhex('ba35dd670b2f19d39a44f2fb871e35ec8b9a444d49bf84a8e9bf6c5556e69d0c'), + 'cmx': bytes.fromhex('087796ff6b2f7943ea69464410a8b2710c2b90316fd5c748f41e3a4793b59d0a'), + 'epk': bytes.fromhex('81f9bbeaf78f326630fd4526ab67289a44d0d09972ef30682d4f5ffeb9417798'), + 'enc': bytes.fromhex( + '7635af9d8406383ee8dd92f37ef87a8216b57a8004ea779251263d8665916e2c' + 'ad6139ad2266484d70f79806e431c7531de4c5d620b14b585070871e1c50aeca' + 'dda4ae9a45216132c33e3ec304c1edaa29d1a18687e546b95139bce8f57de0f1' + '1e200bad146f9580434d6471084df7b0cb8b54f09098923e821939c6769f33f4' + '1add1d82c3660dcf065c8bf43e3f69925270ef175fa2f595166dbeeb00d2eed8' + 'd19280580081a541ff0db45894f0af53c82f85c4d83e139a98dd99b5544ab23a' + '0ee74c33a416bc4ab28d28d5717463f9e100f7cbe2f7334d93a6f8715e49791f' + '3e1efb1a6c285b9e9aaca988ea3d4dd90ec5307a7e8067d7926bbc664c049968' + 'aac677fd0497c68555809c7f34888b5aae50ba8c4bc509a1a5773eecfaf57e32' + '7bbcc042059d61e60c37bbe6b9981f8c862c08714ced7143e480d33373bc2871' + '0a6cc670f85d68400fc49e5581b2a918bdac988ec720a9fc2196a0833db5026e' + '753924001effd0ca209bdf8fab61c4cbb8e666d408979ad351f9de8e3551a032' + 'a471b1842cb2534c8f98996d964b67344a96f5baa24db77ebc581a252d242933' + 'd413c4cfe3dc9b60b7821d4f02d95a09321cbd677e9311f0acfb6e2e97d54ca7' + '3280e64c2d216e3b190a44b5b6c26da1a9f8ec1dac3d5d494e4c650562ad5594' + '6736bb8ea447b4905a1602a67c988c5aba1fa81c03e33b1af82f60de2c23d1ac' + 'afcd6dcfb1dddbe12b695295a694e893f2279a271039ba3eb1ab48446047bef2' + '9efa519bb08cb6f0c0a753f9a70c2b683e55b783a8a79310e990cb9fbef3d1fa' + '255602bc'), + 'out': bytes.fromhex( + '72d9526061fc8f2088c225996dde720ab8f19502950b052f9c8d9e8e00f06532' + 'ba4ffff2ecd176e5836af72a44a1d58cefd03dd089b66b4dc0d92d3860e1d437' + '5595655e7abbb43afcea3a8b570f1987'), + 'recipient': bytes.fromhex( + 'ddae703de8aee25d4e439b8a646b2a5a86f57f802890996e2b3c1f41ff2348a0' + 'f0bb27c032b2e7718c962e'), + 'rseed': bytes.fromhex('c29d5ab216448f6ebf6388a6251160e7c9fe2413c85ac1cd2340363807ba8840'), + 'value': 90000, + }, + { + 'nullifier': bytes.fromhex('82b4ace6f48bca884543cca25633e137f3791e3ed655c775f8b6f84187c8082d'), + 'rk': bytes.fromhex('ffc4c2218a0382a530909566f44a7ab4421df95cd12e0590a19c01eb6e06b83e'), + 'alpha': bytes.fromhex('14de74940160f3450f3f8fad83c3d50dc9fc766bcdd4d5968a13ad8245613138'), + 'cv_net': bytes.fromhex('21f87ec22c92674f97585415535b5cdade848408fb729765bdcf2c36118e463f'), + 'cmx': bytes.fromhex('b46b4f684d39569dcd24db0db912406dff3fbc78466e590260d729313499230d'), + 'epk': bytes.fromhex('a7d08787142ac449a74203ccf11ad1e927b8fb4356f33ae8f81b1c9e7b3c01a6'), + 'enc': bytes.fromhex( + '43fed1e4afbd93923651a18623245c91b2717cbbf89ef9a4905bd0da58f3a578' + 'bd2330a347bc32526261273feeb11120746ce964aac12d82209183195eeafa8d' + '54ac7b02e4c107aee4ec1db2452a50bcf53ebb7902827bfef0ba144ca16c0f9a' + '1ef79116b5f86a740a68c46b28f5b1235235ed347244ff7beb65898e74f139d5' + '975965a2f786e60a9b081f96f576a087070bb7a8e1a182fbf7366467005a051e' + '28ed1509aa2177a684417e618e0a07a4f157f1152308ef7f6757533f5f45cd67' + 'a21cb1b26944fb266fd2bd6e892bc9bc672d2eed09afcd7119074b0c8639b13c' + '548df077595390a7aa4b4181341804c793644d9bd19b92e0e322d87b64075eac' + '7e6a908c9fee485175ec7c85ffd3e010a85fb67adf6435bd66f45464f7ace727' + '7471eed60135e19d420fb5b9af89957b23f33e458e09c393a02d9403eabef6c8' + 'f11f4002cd2c877197f573bc0146bd6eef0bc00283f29ad0ae500ea80c84e221' + '81f9470a4d1e8c60b4680efbd5dd47fa73cf82de930b304afe0686d11b963c8b' + 'e5a3731e7f74b245958c46c3e0b591278ec8e4206f291a80193ec325f06742ee' + '3de56bd11121df9432eb2456ae090f64e840d2ea17365abb6c6ec9fd51f94036' + 'c0ace903ae39ef5a0824799b1b4ba529c3403d240d7f18cb90559af4252f1fd2' + '27eefabfcb830b94c3c3e5114e41265cef100aad103bd25505279a39cb294db4' + '0ccfe4d4b8c13539b975564008c113da36d67d50568769751fb9c775f363c969' + '4d834ba1ea03e956a6036dc2a676918044a1fc76c777caad479de213ef856055' + '5407b7ca'), + 'out': bytes.fromhex( + 'e41a17506e1af63acd8edc563c195819e26e740b5f3fb4830242d804bcee8a56' + '2572f52e73d190ef270ecf7aaf309e93b2ab9eb6200b8466cd1aa7889b42cfcc' + '2fa9b853f9e136be5e04f9020ac82d4f'), + 'recipient': bytes.fromhex( + 'df8789f215ca59a4fc59ce4e9b694f87b354d01cc397c47b594db69dc0fd4ad0' + '0e11a41d7751189db93210'), + 'rseed': bytes.fromhex('983d2f7efb6cbb27571832127afd4f48136bdab4ebc68bc2a7c667a4ab231030'), + 'value': 0, + }, +] + + +# An NU6.2 bundle (orchard_v2, Flags::ENABLED) built the same way: one +# 100000-zat spend, fee 10000, and four outputs in action order -- 20000 zat +# to this account's own external address 0 (a self-send), 30000 zat to +# account 1's internal address 0 (another account's change), 40000 zat change +# to this account's internal address 0, and a zero-valued send to account 1's +# external address 0 whose memo reads "thanks for lunch!". Only action 0 +# spends a real note; the other spends are dummies. +MEMO_BUNDLE = [ + { + 'nullifier': bytes.fromhex('0b396499eafbba166a936684287c6a9a93c35684059661a365e715c6bdb80903'), + 'rk': bytes.fromhex('0a1d22eb81961326e4d6c5dc1208f1e166cde2d52d7a4ab65b26c74d6281cd0f'), + 'alpha': bytes.fromhex('3b977876ce497d64ec92c71e7e8c0ba25c6e831636d6f0942b7cb944cec18f35'), + 'cv_net': bytes.fromhex('bd26a17d837f604b0834a4f6c4e0b04128d72b98d0d783ff6ad7087feb2e4d10'), + 'cmx': bytes.fromhex('9e926d6a1e046c426c00e41c618e42040dbcb8a4122aeaec30a1558b56e3cb3d'), + 'epk': bytes.fromhex('5d8fe257f17e600c74f9ba9bcc221c85c7074e1ef6adaf23ad884bdb52eea72a'), + 'enc': bytes.fromhex( + '8b0075c256cacbebdf9dcf8db1c780c3149e9130d03fd8b509201130604d5848' + 'ac64ec54a133fb72f09083efedd825a3b08f5f7bf5f54a85a2390ab2e37eaad0' + '28a3a245ce7279f4afe13e5ade9e6eda947119b68ebdc9f86fff852cbe1f0217' + 'd4119815506d9bf3e4530c80c357e0a4910392d59b4d531ff6c318de528fb6b0' + '5fae9aee00fcfe88661ca4b181a96b4255a0a81ad38f21f629e47bbefe5efd1d' + '829d93542f4d6f6fc8e9cc9a5ae91adeeb657c0b3427a86654ee502c944ba189' + '95d9bb4d40de6fbf581d4a89e407e27a968cc0c168ae7f3dcf5afe3272f1dd0d' + 'd805f01b367d93ffd8557e69d39957540e1e70e8cacb7d7a844ff234bc49c403' + '1f39598fcd696606eacbb267172c90f5b438dd4652e6f2ac83913bce4ca7d2ef' + 'd1d04a4fa7eb66f8342bc2b84ff03e64c21139de5c6dc257518c0d20f48c705e' + '512a474d25185e54187af3d650b56ad12539b7797550bb117d12ac6d6ee9c691' + '684fd3c86bbfa004484d6f08574f0bb4031aa27e0599e15f8ce2b00711281f85' + 'cb92e63fb66d0794e4dee0ce15b7e0c3851266ba8c49c9cf2abd22a488e95578' + '693a9c0d5e27ca808de4fc81cafeadbbbff7f83dbc4debba908510279941613c' + 'f9ee909eb5b922b2333f48422cd0bceb61625d21c6b3107cb676e60ad681c4a1' + '51c1b24734ed1f3ec096785c45641fdad75697abdf66e9553ec51af468f90ec8' + 'aeec7cc04e1f6c03656da3389a4fdb287bde0e01bfde5f125803f604a5f38d12' + '482155475a651f76c56eff1777403c5a48499cb196fe7bb0c98e59af720c6090' + '48939155'), + 'out': bytes.fromhex( + '93d14b5a4bc9dd72c1559c0073dd621c184af991a87c75215fecc816f20b83bf' + '3673bab907166ef00ac8b8f67b2be681ebec1b8f49ea0918a0796bbe4ae02925' + '8a6fec6129eb71fc611a7944b9625b7f'), + 'recipient': bytes.fromhex( + 'da973031634a8938ad1c480f978780693ec7709ba5caf58d8a7eb945586cbed6' + '45520f17387437bcfdc216'), + 'rseed': bytes.fromhex('19d1dbfb752c1bbc9ec9a5c44fd2d8a9d79c404e299127d3ad5f34a2b52f4a94'), + 'value': 20000, + }, + { + 'nullifier': bytes.fromhex('f8ba50efc52be70daca605a52065c1f1f58feeff3fdb41ce608a18e529326905'), + 'rk': bytes.fromhex('7282993aed2a09e3d374bc473dd16ec6a760fd8a667b3cb32521f50b80fc3928'), + 'alpha': bytes.fromhex('1cb2601e62e5bf33186b33ea9acbe76d31509cc5e5826ab7b549189b55cc903f'), + 'cv_net': bytes.fromhex('34fd5c6923a81270493d8d8e517044305f7595217d8e3bea2f473b35b0a78017'), + 'cmx': bytes.fromhex('9b020d8c509de25cb2c04955725669284951e081ca602d27b6986f4c0349e93e'), + 'epk': bytes.fromhex('85f4e893d37fbbee4ea43e7cb447c38d1f31669930f8d800e39d3fcac48ae3a9'), + 'enc': bytes.fromhex( + '54d68d62720be92d6c4697751bde5ab39c3de61aaafab88161765cf4aa27a151' + 'b0f5be29d7fcc7f30c6a9301cbfbc4dc348a30a8821fe56c73c8e9c799cf9f50' + '64f8c5778a218123bcacd4b43d971d2a96452a69de0c48b3d9b6cb7a11967851' + '04c7077ae08d0be113696c6f34c41f339c5cee68611856f627553f41e511ff43' + '90a80c74fc31dcc4d1a10b8bc02706ecd187d02aef6fc39f166815c7a12afd39' + 'b6fbde42959672fb508df5432848e5061acf62263046784e3f252a57604f4d3c' + 'c8a295e5bacbaab6f4b0f5aa7b3790abf576260b7d40da6266818f22b4e75a53' + '1b6e565a87ceb0f2a01d70c764de4545c4d5707394af31752b2c30f0fcfd64c3' + '5102558160449a78e3887053d63f015650dcc7f1f56114739bd6f1e730eaf0d8' + 'e2a5755c3424ba6b205145ded3620702c853226945fd8dfddffb359016c24784' + 'c8ce7edac0f02345f6240b4a055b712777f344e4f176082ec27e07ada09473cc' + '7868836a98f7f1de99cade6bb9c1daa9e54c591202f83e90eee76054e76b45e9' + '89caac1005cc961af5111a46c11a41311f6e94540e67f2005d618e731d4792f0' + '5b31ef94ed6d73216991c1ffbd0645bfeafb64554ad082fad7286af5e88ca721' + 'ebb6e89a8aaa097c33c3d3c00b645a5b6e9d892417624d9b58e5157c4f9406e7' + 'ec81cd89028d8969f54feffb4825017676044d5e3ae6603f058f772953c714b1' + '1ed1523d2aa37d36f51bec1a36268bb0953f6836534df86ab196929d5b916781' + '071680fb04d6d27f38399a952bcdb7a459f4fb74d5dfd73c6a0a51c58ea00a53' + 'bc4fb482'), + 'out': bytes.fromhex( + 'b95c75498fd39fe8ffb67803469bb183e6746b7126550c0d56f248d5a3bb2485' + '19ffbac31035d28a29b5295e929bc026f8f321bab87245f47ad4c4604bdd6efe' + '4f77fcbe2fdaa78a5ebd58263a7f6d0e'), + 'recipient': bytes.fromhex( + 'e96953bda73d114cb7bc026036b695c23fb2b80b0c34f217ed3b4e6fd3766efc' + '090a17663191a15eba81ba'), + 'rseed': bytes.fromhex('b7a8c118ceb43470d6a78bcb0eabecdf96b3977bb99506442df3c1db52a0b58c'), + 'value': 30000, + }, + { + 'nullifier': bytes.fromhex('a75bf6e26992c5a04856020a69caa517ba5b0f6dc026e8e8713ae606f2be330e'), + 'rk': bytes.fromhex('b0aba46130d9dfa7e5a1260d134958d5caefed021551c1832fe07cea52ade4ba'), + 'alpha': bytes.fromhex('a16c4408414428dc4e614b56f9bcb7bff36ed395ff25f556327ed877556fef3d'), + 'cv_net': bytes.fromhex('7cc907eea8e6bb1eec198132f122fb9ff7f0797df56fecf63b7d2f2e4fd283b3'), + 'cmx': bytes.fromhex('15c4fafb44b3aa5ef021ec25208136a785139f61a2dc69c1bfa2280e7dc46f08'), + 'epk': bytes.fromhex('34737234bf9190c4a909a96b58f66843fc1ae968851d9dcfe8b9d8a0b1b8042f'), + 'enc': bytes.fromhex( + 'd2c52957269904d95aad1058335d2b431d46e3702b28496752c5d07fb5fdac1f' + 'bbb6e798057939f1b732416f0717f72a037402e6cb6c520c785f87c5eea9655a' + '654936d982329d9f637998e6909b947ede5f3c0844c72d291607bc2dfc0d37e0' + '1e32cb8637244aa02c33ffb95e9b9b99e2936614cc8c95bed046b44fe18c2aad' + 'bb2dfa950de507fd49774343f24ae5329904e7e4b526769a7c3dcebb473d2224' + '76c480d96335b9f3be0e8ae62137d43dc508c7dbe44cd402514aabc2fa8fa81f' + 'cec38e74aefe8ad0defbcdccb091b50b27c0f2abd5622f3cf9d6a0272b7700fe' + 'df22cdcd208c0b6eb94f7ecacbf6af61be4d581efae66b30b7b39d3806ec247c' + '4e16282839725d0eb0836f26500552c7bd98795325888f8626f0214eaf429c6a' + '55cfd7fc564e468103fc577bcf69a5d9f64894262d80731629977972ccf9c962' + '871720149b9db9e4088f061ccae62619827e31b7ae7a7d878bc51b9d63e73613' + 'dd0352e4dffc62fbcf6435b72ff1c2460bf9c5609db734a59ab3a274e0de8dd5' + '2002f787135b9120c02947e62c0fdc4d633248f0098cafecfc8b5ff165392292' + '205c68d13f6e8bc261b6863770c1fdf9715ab0553f8cacf07b20146f815af9a3' + '6664e90df7bacb0ad412e4cd363cbb2a0936d89afd5a228687f9b192b4043a54' + '1341ab18a82405a57e24986d227d8e5c285c0708843adbf2a29293d30e4e9b61' + 'ceddff354e24427e6d2a34cbc1bc6057ec6748387305ecb9ca7b70926e672104' + '900779a167ff00024e3cc6e1cf05636eb7cfb34a2c289bab49f411a9cee2701f' + 'd44d2d13'), + 'out': bytes.fromhex( + '8e6250a506ea4b52188f10ac0ee0e0210ced8f7f8ccda7069f70ed8ed675a953' + 'cae9a37666f191921050a3da74636c907e3c7c36a75ec459255c9ed828718a8c' + 'b31e6ffeb3946f1fbcee60568ccceffe'), + 'recipient': bytes.fromhex( + 'ddae703de8aee25d4e439b8a646b2a5a86f57f802890996e2b3c1f41ff2348a0' + 'f0bb27c032b2e7718c962e'), + 'rseed': bytes.fromhex('2a6913ff3dcb6d496a92b8d5cfccd29afba7b48fc1e21940b55739c5ff950d6d'), + 'value': 40000, + }, + { + 'nullifier': bytes.fromhex('9c8426bcbc3202267606069136500c06aa2e40c378ba22a898aeff0626c75036'), + 'rk': bytes.fromhex('9e74449a938707718574712d19923a0a48820aa17f53491007f873fc3f902902'), + 'alpha': bytes.fromhex('a6e1c02c22a34f14a0a82c221489f26136081ed39b3ef34ac2df17c08aa2e235'), + 'cv_net': bytes.fromhex('15fb882089e16d2f696b2964c8d13fcfbbe66a1e645bf08afdfef2a15352a3a4'), + 'cmx': bytes.fromhex('5d491d6e064e67343e179ee680182a04eca8a9c73b504e17439f695b989d8d35'), + 'epk': bytes.fromhex('266dcf5ffab1cadd4fbc6f030b702f535c49b0971c79f6d581491b5e727eb797'), + 'enc': bytes.fromhex( + '8c7b608859f1c6b4a1b3e304f9ac0319680d53950d98ad1e36216abf62870bc8' + '69195aae61e811cc559a3a06df605489027763cc10731e262dc477c40589c9ac' + '6350ead8f31d6f37d8eb698c7afdb8f835b108d554e97753a8838fb47f0fc1cd' + '989ed1190517a4f455267458b8c9329f846bed3993db930520ab71ade3e5256d' + 'ac93ebdb7abff16cf88030df72fa90db30d3745480c914d501579a6ab93b8472' + 'a52137f13917657037fc458546a1e41af7f12d8b5b492e69c9d595d4e886627c' + '6656b5a3ee37ebc3689290bc88707c91e026d95859d88c5e2187339e4b3e6bff' + '924a0934468e64b86dec35b26c6d2cb750d13f21101e1992cf64eae8547ab462' + '9ad4c7e88264c4a2f04adcbd2cd050038239498b306572494920bdfc7a1bbee9' + 'b190ba82f88e670d7c690b069bfd073c9c4222da760bd347c4e4d321fcddc057' + '88114a34b9bf3b4054381c8595c7ec80140968741d55f1939a9121b3369afaef' + '4c5ce10e662e13b2c0ecd8deb4469a92b66ee8ec2ddc0c600700f1e39cfca631' + 'fef6920a7af021715fe51c178b1665c5d0a261dbcc5ad171613402ff29d883f5' + '12f8a488d23bd4401781997e4dc0d7b62b8bb66f64ace822c08177544dab0a46' + '930ab73eb589460e9e19a77eed8f0a494b92f41dc1dc70572548e755a2023444' + '9ec6d30af18d58d1f0a2752bb8d8a4d201232d3bb3ec3d6fe3fff3cbbcc7e350' + 'e65808cb45bd1d367e447b728ac6a1445a6c7bae6eece7e2b3ecaab583a9ca58' + 'e41cca24d08366be4516fea9dbce82e4de6845b268708b96a572d619e808bb11' + '06ae8a55'), + 'out': bytes.fromhex( + 'eacafd6869e89e8312a0a7caff1e8baf61be383e17db1e61017eaa5842091a05' + 'ec776f4b7fdf85b1f90aa0197118d355ed1f73ac5795f8296afc5f4b87916b2a' + '7cad4d62b2f8c75acafec1ed5bc5248d'), + 'recipient': bytes.fromhex( + '8ee82cdff5120a00cb089ff8acdaa517958971d69d1852dca01fd25e88609ff9' + 'ca7b154dcb2c01a8bc18aa'), + 'rseed': bytes.fromhex('337ce21a2c63debee0bfed8ad8c373d7d5f3fbfd44bed30f2addd92130ef5605'), + 'value': 0, + }, +] +# The Orchard-only mainnet Unified Address of the memo send's receiver +# (zcash_address 0.13.0): the address the user entered. +MEMO_USER_ADDRESS = ( + 'u1u2e4d2ctdr0sq2rtglp3myfzpewgtslzjss0p4jtldylakd8dm5n9rtflehnykkq6c0g5rf' + 'zrswl5tx02uzulwa4xqdpmm9pnuuslzs8') + + +def fabricated_action(v): + return { + 'alpha': v['alpha'], + 'nullifier': v['nullifier'], + 'cmx': v['cmx'], + 'epk': v['epk'], + 'enc_compact': v['enc'][:52], + 'enc_memo': v['enc'][52:564], + 'enc_noncompact': v['enc'][564:], + 'cv_net': v['cv_net'], + 'rk': v['rk'], + 'out_ciphertext': v['out'], + 'is_spend': True, + 'value': v['value'], + 'recipient': v['recipient'], + 'rseed': v['rseed'], + } + + +# ZIP 318 migration transactions built by librustzcash's zcash_pool_migration +# (build_transfer_pczt, build_prep_tx; orchard 0.16.0) for the "all" seed, +# account 0: v6, NU6.3 branch, lock time 0, expiry 69120. The transfer moves a +# 1,015,000-zat Orchard note into 1,000,000 zat at the account's internal +# Ironwood address (fee 15,000): a 2-action Orchard bundle and a 1-action +# Ironwood bundle in one transaction. The preparation transaction splits one +# note into fifteen 1,015,000-zat notes (fee 80,000) in exactly 16 Orchard +# actions. is_spend is False for a protocol dummy, which the host signs; the +# sighash is librustzcash's (also checked by the firmware unit tests). +MIGRATION_TRANSFER = { + 'expiry': 69120, + 'sighash': bytes.fromhex('37d64f27ae739dcb68087da7d8a2d61abdb2fb1fb89e3d4f0e029d80965f4edf'), + 'orchard': { + 'flags': 0x03, 'value_balance': 1015000, + 'actions': [ + { + 'is_spend': False, + 'nullifier': bytes.fromhex('1864599aa7e56f8c0399922334bc322b1e5c0e9614056e705f5dca13652e3e30'), + 'rk': bytes.fromhex('8e0da71eb98174f038bcce8dd232ccf690e8fcdc68e2c571310626f44d897307'), + 'alpha': bytes.fromhex('d60207f13eebd372f8f9e79b966230dac87839f33a68c21b1a7adf5602b1c024'), + 'cv_net': bytes.fromhex('ccb4e6427d30b8b910fc733ba30a1a4a6f43bc339ba4e7d38e731aa8c79553ab'), + 'cmx': bytes.fromhex('e8a96150abbdd4a657639d23e8202c621eb422a46f115a4f9b329203783daa27'), + 'epk': bytes.fromhex('76b0f4ff80bf7a981e2f127086358c3eb65cf4ecf855dc7153f50d41421648b7'), + 'enc': bytes.fromhex( + '8087f8103c81159a18755a0dc6506283ee6872d2ec050051f9c52403b831aa74' + '2965708f3c466aedd08dd8db5d2df018ef5ba744a23ea84822b715e4b1c89524' + '49264e6d548e4cfabc9dee6d5ded01f80c137f5b08282ab151356382e8fa7c70' + '722d6d4f8de0503eca664b27bfe415a0f9413898b39215669179f4f2ec0a80d9' + '4c624179133386574e2aa4a4c9702c697493c95ae442996cbcae044eea1b1d0d' + 'df037aa81b779f894dc86c17965ce4362b60cb2e314634a49398e1f43ad80c94' + 'e64573bfb2bbc5d5f398c5c9dc57133a9b6d3ce5a7392ff9d0e716f8b6f0f3c2' + '5732e8c108f4bdfc316eccb9202d1455316b32d4a5bb5f427d2ad69a8f1d1a0c' + 'b87ae8ddd870ba00d37e246b758845e147ce19ebad1485617bf0e51d92f9f9fe' + '0aa9804091e0ae89dcb815f3238df56accf9b3a25703f481462d8ca43d3a1673' + 'a1e9053fed093ef5bc3c74e31c99cc0343d8aa6fb8ca56f63676b07e4ec898ae' + 'c8b82eb90194d47b914669435a4b3161e76724774cdf3bab2390a3d31fe18a16' + '06fb060728b6db876472f7d75cbfb6e2f75065ef7b8507a54a5fb219e01e2bf5' + '81af63ba475347a0a75bb8b6cc16652188fd315b73e8155492e6b1bf78ad79da' + '6ddb9b19599d9e2ed73b17ca2f5281c78bedcd215918290c3c3ee7bb44ab3ae3' + 'a88f5065a7585905bacf2c1af0ed7a98aac974b992945faddf8e07f11aa259ee' + 'c891e55cfc9924d44da5fef14b823e7c2c246c4daf1ac01e4e1ecfd00d1efdda' + 'bb181a2b9598ebb42edb69d116a77820b46482034ee7f54bf0f556bc9cccf2db' + '3d16f60a'), + 'out': bytes.fromhex( + '608c408a0545c24615106484531cfaea8fdd107f2ccd5007cc3a74640c1a058b' + 'b3e8e52a668aca85c8be3780496ef53bcc0a768496ef089c3db2382f75904882' + '9e1447576fc7df7626a1e76db2a620af'), + 'recipient': bytes.fromhex( + '937bcbdf0e9bbc3a056d4b840825fa3adf31c338eef5d0a57d56e432455cbdc5' + 'daa4f738338166c7b9ed07'), + 'rseed': bytes.fromhex('809144435bbd53c9d16a3944e5355a512a875cd5177d6f97ce291debc4684229'), + 'value': 0, + }, + { + 'is_spend': True, + 'nullifier': bytes.fromhex('489a7ca2cfced841420598f2dc0236f637652fc3fa410fbe448e28aadb5b9c0f'), + 'rk': bytes.fromhex('a618a687af32bb8d148bd5745c8b6f8b8f40d18d5b2bbe733d10e3b024966b01'), + 'alpha': bytes.fromhex('b3abb9d87a35fe5d9697cf96d9eca2e802988bd6bc2de2ebba30eda0eb10a31e'), + 'cv_net': bytes.fromhex('a122f0fc50ec9b8653a3ddcd4e12bd9d9910f879f6a4881f958852b0797f7e2d'), + 'cmx': bytes.fromhex('eb709cbf300754e5f17f1d6947d0854575305e487d96344b55ff2de9821b5f36'), + 'epk': bytes.fromhex('1374c5379cc8daa943f521558d7a4c0a7ac8ae21ab311f275b051a8631f799a4'), + 'enc': bytes.fromhex( + 'f714bbc0dc6f64674d579ff6a85de299a4a98788b2cf473d687b142e2501ae94' + '9309bd2295c8b93afa7d0607e8663f516e855c9104341f09dd649e406bf8f21c' + '687c5706b1d5afd74fd8e063921a05ebaa89cee7f7251d518aa271533c5ce752' + '4074b7f32dcabfb6fb4309bf86e9cc00b3cb2424b7a2ae6ecb83e14b4c4fc4bf' + '86d494b2d528d7d9281a8f7af1e78fb674327782b178d1469119199b3d9de1d9' + 'd381a4600b85323cdc93f43f89ffa9cdc94e0095eaed60ee68047b015b57c362' + '159f43a0bbfa21c4be1856dc1256a04b27d3ae52962bd9a8661b74f0bd7a4a9b' + 'f7e53fd02b7b33038f824e20a3d21f3d6b152df460bbb720f7597d267707cd00' + '14d4099952ad1195076d521da378de8b14261efac4e1bd2b3deae15c899de20f' + '090210d3ab853d7f25dc01522b725574282f45bbc78c0213fbe6f040f2b3355a' + 'ff909180bfdc21dd8c1cbcb7ace23d4a5575633bfe561ca018f23beba644761e' + '70e87d03280b6677d1e7af24783d23476a6e5958789eca3f738cdd6683a2b762' + '3606de12b9a75ce127169c02fb37e22549451ce3d1912d0f6d546b541c2a5e93' + '5e18d924d43629c5a0ae13b20498592cbf6daf2f180acb7c7cfe401b37e808dc' + 'e2fc54227a523fd8b973a4f261ee6dc3c48ea4ad10d2d4a07807723b6a8ade44' + 'fa3a236fbba8a0f7f8b7b62e82985b6a6e63ca95f01cf597eba7c839571d5d77' + '31eeeb9a90961537bb0301497c20ae735f21715bc37ca3ca1626aec076ec3b73' + 'a8001204d3d59ba1a078c996bcc97ad89f7ac7890b89145e4527bcd76355bef7' + '43eae3ac'), + 'out': bytes.fromhex( + 'fa9051ee2d97442f3618721452e5433399d53c5f3b42ecbbb6e5ab0cd4ca6457' + 'e7444ccece08e96d282fc184fe08e23d3b8084bf63a5061e21f7fae609987704' + 'd50c3954228af752f5e00abb61b65f3c'), + 'recipient': bytes.fromhex( + 'da973031634a8938ad1c480f978780693ec7709ba5caf58d8a7eb945586cbed6' + '45520f17387437bcfdc216'), + 'rseed': bytes.fromhex('259c76a04a44a10defc8b3de279aaa2f57f453c4843932e07ab89e8d08a7045d'), + 'value': 0, + }, + ], + }, + 'ironwood': { + 'flags': 0x07, 'value_balance': -1000000, + 'actions': [ + { + 'is_spend': False, + 'nullifier': bytes.fromhex('436effc6778e973a5cc77c202d0a396e5b932905346443ddaaadc8253ab4db27'), + 'rk': bytes.fromhex('6c05eb42cca028e4ed2740bb176d1bc6ea64a72d8012437d3ee4e488c0116e06'), + 'alpha': bytes.fromhex('ca3ea1b2ed99993558b786870350dd0b3a6bb2c096e9f3d9e6d744743ad7563f'), + 'cv_net': bytes.fromhex('8ea1ceccc9a86e011ecfabe68f68b6aaeff93e57d7fd16fef5befd15edc5a382'), + 'cmx': bytes.fromhex('a8cb867f1ae569fef09e6b6642f4795e37992ece4e4fbdc33f1354b379c97c20'), + 'epk': bytes.fromhex('ae9f613cf5a2bc3c5e480a4af39b36e6d40c8bf7a664edb0548c4fd2a5bf8414'), + 'enc': bytes.fromhex( + '75022c701b77054ebe6886efba031ceb9d0a48c46f34a58b9a9f4b4dbaaa63ef' + 'e9445158db413bf37b22901cf4334f1bdc8acf15626e8f442998fbd1ac7e42d5' + '6639800df728a431f3496d1235dc1888ef296d4f8b63db81721a8e4895b43886' + 'ed342c7226c0265281a7e5701d1946ce25e06f521ded2a9be3db6b926ec554f6' + '83821c46fd19a342d7b883c1bf7e385643e947ec0dc4d7f41de7f54131ea60f5' + 'fbc1c9f9e454dc1a5434bea7956f7a6e404aaaef73b481ce8184c44cb0fe9bd3' + '2ee18a8d7da8e2493fc88c9e6c6dcd601073f7ba8b0fc77cc6f6fb9ce74962ae' + '6dfd10fba03197e2a488633e479cebace7d99a5fb55c73114db764bc9ac54264' + '0e4747fc2d81ed02f8297cc4fe52fc1fa9e5402fbe9ba2f6ec74c59f1102d082' + '2d4d3c0a0a371dfacd541477f8c920e36cfe8f9e7d712b6bb2230963e07b16a6' + '439b116b6d510e5e4f3ca5af8da8597fde93dfe2bad94570786367da4de38937' + '797ade29d01a762edd85e01fae2cd8d8ce3161ae9dafa80121579e20076e6293' + 'c25de93a3b7ba07f3be7a305c6193ee53668d6039d4aebc56207ea22582f3d68' + '4c7df5fd48c726d9fe0179015cdf7f88572adfd1897150c38d059a02204b2b72' + 'ad982e83400f75a397eb2ba67a793a8d1a179c3355b2a9f4ce2bdc0124ceffe2' + '93fe0d00f9fcc072be2fb0b279b6bc6c67e03ca396dcd0827dd9485d1a518399' + '2ae4425ac5cf3f7629c6cd0cfdda397b1098a1a41e386c223182af6823e847fb' + '753a18610d24ffd130cc015d569cae682273e20498f7240972a9c26f26981159' + 'edf6104c'), + 'out': bytes.fromhex( + '86d9ffaf8df7203a5db69ec59ebeb544b34a5863dc7f4db848c70bb8678b959f' + 'f86c5224265c690e5ec56910c66dd513fba56a4c946f63d7009a0f86f9537b54' + '8bb3e19cb69d2ce349246b2c352adf88'), + 'recipient': bytes.fromhex( + 'ddae703de8aee25d4e439b8a646b2a5a86f57f802890996e2b3c1f41ff2348a0' + 'f0bb27c032b2e7718c962e'), + 'rseed': bytes.fromhex('7ecfb512ece0d14ff72733c55f85dcb3717ec0196cb6248fee63c590ebc6e8ba'), + 'value': 1000000, + }, + ], + }, +} + +MIGRATION_PREP = { + 'expiry': 69120, + 'sighash': bytes.fromhex('9ef92705d1598a058ba70b3254653e7c0c2efa108cf8cf611b0a71266d7d12de'), + 'orchard': { + 'flags': 0x03, 'value_balance': 80000, + 'actions': [ + { + 'is_spend': True, + 'nullifier': bytes.fromhex('054ec0e73431e55a5c9282a41ebd2af81a3dc0515c849dadb4817c7c397a9b24'), + 'rk': bytes.fromhex('49f1ba4aa6ac6a111632ec4c1a799988cd0f595d10379a2980f45b0ebad74f32'), + 'alpha': bytes.fromhex('e2b209a4c7ece0b87a6d0149b919dc636e89accc183c03489a75781e7abcac30'), + 'cv_net': bytes.fromhex('026b83c63c03b0eafa8bb82f70e2f557136ca082d35563bdf1e044d667c805b7'), + 'cmx': bytes.fromhex('5e2d87ac1d8a59bed84174c856e713acf1bcf806aefdff44725c88bc517d4025'), + 'epk': bytes.fromhex('9639beb15a85b79ae394cd9b394ed82364908b33a54908ede023f88aa1822280'), + 'enc': bytes.fromhex( + '405978bbdac91023104dd3885b96a8355108413bc16e82db5fb5c2728b941a5b' + '07447a4b52c1e3bde81eb3ebf44f2481598779059dec907d310a633703181059' + 'b52a010b2a0b4f8ecbdd1a04108bfd4971fbc326209229219bd951a8806428e8' + 'af01859da5a5941a5183b292cc03a7ba7f69bc4359e33bb4cb6d843e261ffb07' + '77bf92f6841e4fb646cd9e65d1443cf582138a2c8472dd4701a0a5ebe1396c42' + '3315b630ef409388a3db83ba35ff52ab7ecd3155048f05411c06d73aafc6d747' + 'f94e6806faec548fcab05a630217f520a2cdada7906d14406fa93211529c3edd' + 'd5f3803aca5fa86527668a5a19d01fa5f7b9091d09048b9292ea195fc001a002' + 'd709a57c94b7ff4e043337f392b59831a8467c61a9b358528f4427a1d78e0556' + '4e5a570d6afcc995ec737a62de866d8989c3fd652d7174444319dfa8e5493250' + 'c6018149fb15507f2a35f13d58bd8a695fabcc8a07174b3f6e675ab0ee95480d' + '2308aaa7a3c5e3a5affecece3375ce4fc2d0a6c6e156fa7764fa6a68fbf89c84' + '640daba42cf345408d18bb88eff1a13f3567688a46fba77720047f255a792af2' + 'c4046a50bb904b4e2bd885f82bb7085979d11b8502dc09ada9291ca9bcd1017f' + '0a5e6a09344bf783976d69ef787ba6b394a6ee2c6563fba02bc0ff7ae7d6f499' + 'da6ba692cc5eca6fb2a1eb6c1e9e2c9f05209675278d3e0d51302927dd6eca2e' + 'c10918646f9ffd5b1e57640464fb75d33034132933fd1526d8c28ce6d6e70667' + '8d044a52659bc654559e90d440b546f317b295b1183fdeb26dba6bd7ae7ed937' + '9fddd84a'), + 'out': bytes.fromhex( + '1e2d399e94df4bc9369536a5640049af19013052ca97c9c3446ab25da81cf049' + '8a0b71bb55c66ba5f435c190a3ea047f49e617dff4a6ee3e765bc9c696cf1361' + '23bc52f37fb084443d8c2ca5e52d7e73'), + 'recipient': bytes.fromhex( + 'ddae703de8aee25d4e439b8a646b2a5a86f57f802890996e2b3c1f41ff2348a0' + 'f0bb27c032b2e7718c962e'), + 'rseed': bytes.fromhex('4472e5d068978450f247eba631f080a34ca5265be231e1ea01d76b1fa0ad022f'), + 'value': 1015000, + }, + { + 'is_spend': True, + 'nullifier': bytes.fromhex('1e9167c36ccddea1bfeae395089b3c9c084ec497f1cc1a6064163eca850c920c'), + 'rk': bytes.fromhex('0ba435bf58e44f0fc5df77904f7500ae6173bd5b115ec49a17b2948ba9c362a0'), + 'alpha': bytes.fromhex('99188cc6049c504b58fb3107a5095270083002032d24923353ea1b5ac238e721'), + 'cv_net': bytes.fromhex('ac8bc004cff0fa6ada12acd1c2b67629dccd83305f6292c1d46306d614b03b23'), + 'cmx': bytes.fromhex('6c8b9235b5ab488414e47cbb78a1471d5523b62228bc469980e8288d3e0bea34'), + 'epk': bytes.fromhex('6adcdd0c83ea1841e96ee48c1c820f4366e5672646742999810783c9da6d7b92'), + 'enc': bytes.fromhex( + '5b19ca83d72fe4914b5a0eb56508f186cfd3417d72764b09b2923da9554b4f44' + '8f76bcfcb2bbb1df591b1cc83d8d92a748cef4d8e401fd9ad62e824768bba2a1' + 'f72c54553365dcc119863ddb43b262948cfa19ede52c0159a3f7f5b6f8bd265d' + 'dd642fd50dffc2ab8e1767c6e94f278c2ad09583825388239f0230d0cbb50e83' + 'fe19c0da47b450a94ab7b3cc8ad03ba14ed6144249d61660e2ef177e1f2d1ffc' + 'bef9142ff2cd192ee059363bf67bf1d267b3db1616b238399c7829c95c914780' + '0fb6946a3d3560c85f4acee07b3dde868bc5068ee169a30bd9a1cb8be4e1451a' + '123036f6644fe5cf372ef9f14a5fdb5b7a22bc44b2bcd1fef077960b367247de' + 'd0f3e6f7b0a2bd59418059c03713d9458f9b2bbb1c01d13948c0ae2824017710' + 'ded86dea4f2e2bbb28ffcbee53b2cb2d9348998d62a99d7094e85b49ca5ba583' + 'f5394c7407bc8d8a356334993b13bf490c2fcb554dea2120e1724deb3fa2ecf4' + 'bfd120e6557f0ba0d3f5d0c8e6934357751b13dc3c2d301297d02f336eae4534' + '06bfae54262ad3e4abad97b00c0da2048acdb7686c4d3cd9057e9744e108b4dc' + 'c394579b602735ee1b4d3692057fff978e274f2ba9cd73b096999cc9336ac263' + '7c88542d087b3990881e3a92cd823fbaa497bd9af6017f0f32c82fea44c2c167' + 'af21df07910c2fc92c6fc6509695bc7b6f6b36e760c7b8f890f68f2143577bea' + '2b52b4e79e4e1a46ce46a7aebfc9e0694b4b27fde0ce0e369f8e072644ab1042' + 'dca5c6cd3c9a6d3e0e2c7f75f5d395bc5344dd11ae36da88e854c8d87d1faa30' + '9e1f4942'), + 'out': bytes.fromhex( + 'bffa9f4a10c74c0921509df29e7d2d48d33eb0bb9a4bccc39025fa02bc59d9fc' + '8ef211d81dea3a431c81d5f4d300144853e480ae179562bb3562ffad91ed1139' + 'ab45b62e3895ce45599de0ce4ed53c8e'), + 'recipient': bytes.fromhex( + 'ddae703de8aee25d4e439b8a646b2a5a86f57f802890996e2b3c1f41ff2348a0' + 'f0bb27c032b2e7718c962e'), + 'rseed': bytes.fromhex('df5ffe7fb55357586aff35971495391edc50b0f3aa13b2e86301e7e51a72b62f'), + 'value': 1015000, + }, + { + 'is_spend': True, + 'nullifier': bytes.fromhex('bd279975aa116b7a6ab041d9b7025d5d7d711510657413469c4fec8482469d0c'), + 'rk': bytes.fromhex('3a3bbaf10cba4710f6b6aa292570b8618fc918a1bd6acce6a76cbb3fdf3fa1af'), + 'alpha': bytes.fromhex('aac41becf3358cd8f0c1e9833ba9303398436077ed870e471598e6f0a9af8325'), + 'cv_net': bytes.fromhex('7e741c1968cfe1a44879f786827d09bc8d4c1784090dbf15ca7dcc87f151babe'), + 'cmx': bytes.fromhex('10fd8bebba556d433f407718ac2753c2be129c8d76da8c56a484bb14503a7117'), + 'epk': bytes.fromhex('4ffdf1afd2e75c0e2104e18061f338a3d3071fd5af823c9b634264dde4a2b31d'), + 'enc': bytes.fromhex( + 'de190d24706ff2cbae88088d97490349ab087c40fc5a0785dea63b5cb5749f14' + 'a2fb2bdf3538c17d198d4486e7c0c2eb8cd4f39cbcb7aaa721c7608abcb6120e' + 'd9bceb204f0c5c67c25cc3caf0b77f099e95a9644adf9adae0ae7ceef8f5e343' + '1aa83a705bbfd751901e8ce9adb9c080130021caeab3150de2b10716791219a4' + '44dbe13e861d0c1c0eba7dc52b16d59ca84b7044e88917a7e0a5bd5c21ae814a' + '7b61754662bccc774ece3e83ae3dc40bbde4044601291fa4611be64122ba75c5' + '7c396b13745a097a5b0622423d35a53d81606a0e4e0d8a5508baeebade8e2a84' + '7a1292f18b7c8f763fa39ae54a725707efb1282fe2fc380550c8e201b304c2a4' + '28631f04602249f35cb04b92d89d3f5ee0687f15f581fd1421e5aa3504f4fa6c' + '560253bac75b3951df2b871090e077835dbbba5c083ad8fa6e16529d6cd764f0' + 'e970ab155e61789a3c95a9889639a3479766f5cb75c03133636cb915a5fa86be' + '71bcc1a4fa561074fd5b2f9a48a9654733a9d472901197c96b8a54e40cdd9f9e' + '4ae9a1c82af52b45f0b02c82956c250546f732cf1ed22abf01523714b21f3c1a' + 'f3868a236343cca4ad81d227f46eae69e95f966cbed0331bd195ff23451896bf' + '95405921fe1e0ba8cdf010807cb6c10d1ab22d0e2a0e6368af8c77dc266319e7' + '13b552df2c0f6912915e6cfacee9eef6c752897de533419ff0c1b6b2be63322a' + 'eaa6c246989916123d45aa7669487bc30576a9c2727c6bb6c07daa58d07a0931' + '3b5858d75b2d48b94fcab0a8d4fd2fb7ee6af73ca8d116f3353455f9600b70e8' + 'e36b3361'), + 'out': bytes.fromhex( + '465b8b2660a00bc32d67f26c501fa6ddc2457664c49e1f6e7fc09e8e371cc7b3' + '807a800fceb01c6afc79b0d153b23d6b85276c703b41e371d2f3f741964d5843' + 'e2f4cb7c403d75664c536acb6dfaff08'), + 'recipient': bytes.fromhex( + 'ddae703de8aee25d4e439b8a646b2a5a86f57f802890996e2b3c1f41ff2348a0' + 'f0bb27c032b2e7718c962e'), + 'rseed': bytes.fromhex('f3cc731a88be61db608e0e647d65669174778a9c7523d86e9ce96960af2404d1'), + 'value': 1015000, + }, + { + 'is_spend': True, + 'nullifier': bytes.fromhex('46ec8306c0fe282e2ffebe4a7dfb99bb5d66594376402310e6d329ad1fa72039'), + 'rk': bytes.fromhex('9a7515f062b707fb218b763b2af09fcb696af3ee5e72acbfa569130c5e8bab8e'), + 'alpha': bytes.fromhex('134a9c395fb85dacaf5394c35be9df6f4ff69d5e967ac21b22fc1e2a1b06681b'), + 'cv_net': bytes.fromhex('32671fedf628dee6bdbcc4c861949b9dfb7aca84d2cb09f3b7276facd33166ae'), + 'cmx': bytes.fromhex('a6bf790e0eff686ef6561743880e609aa2ac9ac2fafb809cb536428387155034'), + 'epk': bytes.fromhex('38a2115c524ac490a5c656742e85ec3f4870a6c6207576b35ce35f5e9a304c00'), + 'enc': bytes.fromhex( + '4d653b68299ecaedc541dfe5e48498a7d8d363d56554e851030ac55781178d0e' + 'cbe7ba151f99195e49ea6898676ac4eda0e12f55e56bd6909fff7bd4c4a3de8f' + 'c34fa83472065f620db37d16f7efa36e024366062b11ef9e7cd33da638e906bf' + 'ea92031869fcbd8d4e37f3094484993e67574116033c1a80ee1212fd01cb938a' + '0e671134e42ef954a4568e23f672f58ef64d937273e7a6a0b8d0673c2fa9eba1' + 'f060db60cc7344cd81778e04a2049fbaf3dc160acd039c5c4fa1d2b93eb851e1' + 'ab34f64e9a562a72a5dcd7c8f2ae9b991760a26cf9f966fafb272a82e7da0c9e' + 'bfddba790abc62691bc6c9739224764911d941f68c5f9209f0047356f2c7d042' + '06156872a3ef82394739d5a7921ce81de2d2b4a5bacc84a864bf75d0dcdc8b1a' + 'ab6eb5eeccbaee53518c491dc88672ed1774b950e39cd26590d8bf7894ad5790' + '2cf4ffb611650fbda399dfca0049829a278a5de46921f6e8bf9c358be2d1dbfd' + '806e89bc619c2492ef13fd09ee925fdb0bfc54581bda16828415e3ce4873c05f' + '7f555382ea943125b673b233b9612a9b63e6e78ddb27c180f69fcbe60e2d9d64' + '29cf273c1245c2b4cc56c9daed238a962e283eb1bcb5b31a81b7e42d4da91f02' + '0e4b51f20232d77ffae9e387515e99daf456a61cfc141bf0390257380797b154' + '567d335ef6376101b2d9feff939768f81ffd3f97f34bb92f8d6439a51801af33' + '8dfabf9c9779de2cd587381f58835ce491704359e15e668a3606f80c51fb95fa' + '45524400320920ce3c32668bc9bea9000053e2de0607e37608d649630af0991d' + '2b26a11a'), + 'out': bytes.fromhex( + '17527eab850e901d0fca69dfd95d0bdabeeae5a05f20a8ba8ad6bce615f8a1f1' + '0166a0777aed3bb3536eaa639e9b9cac6056508a5fb8f585182b48b9c166beeb' + 'b0f30af96885078502cdc000181a698f'), + 'recipient': bytes.fromhex( + 'da973031634a8938ad1c480f978780693ec7709ba5caf58d8a7eb945586cbed6' + '45520f17387437bcfdc216'), + 'rseed': bytes.fromhex('b28fb566a83a3e62b49a4577d3a299d1c5e9692649917f4a495da4f590e45069'), + 'value': 0, + }, + { + 'is_spend': True, + 'nullifier': bytes.fromhex('84b1e3f25066dc3531ec282f8ea0a1fd2f8cbec31e0a5c60ce1b5eaeb820521d'), + 'rk': bytes.fromhex('88a5cc84f7483c9f775bb0d5c70409d05a44db5e6262f4a687468d4349a7d58c'), + 'alpha': bytes.fromhex('3527420fcbab8f9580730144813546c1cb50f608d06aab0c145f59634f7bdd2f'), + 'cv_net': bytes.fromhex('85c7f1af6a5226cf953e4dcc5ce531205fdc1594f8aab38ff62b497e80413f17'), + 'cmx': bytes.fromhex('94988df15b79910e7c217b069e8175588b3844c839b1cd07b4bb238552acc22b'), + 'epk': bytes.fromhex('6fff64e1409564630a7efddbe75f4f7f6a5411126cee98a6a184187b218a7793'), + 'enc': bytes.fromhex( + '9523ee3dfd23d9d418333d4d4f541d6e1ffb6708a57847858944ef9c043da78e' + 'b2a834dda0dd3c26704566cd823928438af12b279851a73204795d370efb3928' + '2e41ecec65eace5b96f7e79cf0bbf763bde3aa2672976899e487fea37fbcf250' + '179f895ba59ca2cb33699cabd073b05af5585e2f34c88d5432dd39c9e28622a3' + '12f2fb32fc7dcc3445b9f8044ceaac5e3828a36339576c502004e1b619cfa2b2' + '148f8b4d04c8f8df85b9e32496b15f2ba6c398b502f9bc1394fe99a4d3538b2e' + '5a22d86afc32d6704820a80495be317dcc97ac9a8932f8e2e5a1c7bbef99a613' + 'f51374ba41d6fa0d7a45f2a4cf9450a888e6b586c7371c91afae1c30067b6019' + '74ca0494458efd07b26fe402fa5e9fb2e9ed45072f0de676329d0acd34de67f0' + '0e5cb863798568991cfeb3a3647b516cbf80442ed830966035ced2e8153ef7bc' + '9e7c848c08f5106e507c198f4c463cf5cf33147d2eb0285ea23d978bbbb2f2e4' + '653c75c3a67f31048d2ad7458ec3bcfe65ccf33e08d7f869d4c10b5e8dc51797' + 'b4b4aba646ae031ce13503d37c23202322f68a1de641539ab8906ca1cc2116bb' + '02f3e23b2484a50ad557ca59beb12210ad6af7c3361a915baf8da33021893eb7' + '3ecfbaa020a5800332ce1ebdb3678d25dea61f32f04596ca6e672023288c59e5' + '61e451ba05cc7b382c25248d5ade7af1c7304f26b230f60fc73cb1655175a8af' + 'db4d0734f001ee35661433b2928526482079d11d485be8c8fa3a066f12e4b213' + '5d738667bdf461d78466d0f88f72d10163ca7e7f53f0e36ff4061e6a15824144' + 'ca80aee2'), + 'out': bytes.fromhex( + 'dc650d9efce2e1fdccce0e0631c7513ac9cdc3967d66b91de7899ef244f76c9d' + '211b2a01d51da32fd1cde8ad79e93b7f95e74125443a30c07e2a51f7c7f0c596' + 'd13b074003319a0d4d73869c06e6de24'), + 'recipient': bytes.fromhex( + 'ddae703de8aee25d4e439b8a646b2a5a86f57f802890996e2b3c1f41ff2348a0' + 'f0bb27c032b2e7718c962e'), + 'rseed': bytes.fromhex('fe195185577caffc9b3214d0e82bef90ff91a1e2164ffec23bfca96b4e2da6b7'), + 'value': 1015000, + }, + { + 'is_spend': True, + 'nullifier': bytes.fromhex('2eecf6557ebe7d63d7e8c8e2d8c63e73a4a626a4ed7be4dcda98a5ecd3de0a08'), + 'rk': bytes.fromhex('c3bec9b4b5453deda20a3b8c88a4b1f99047b74ba2004aab2c93c243088da713'), + 'alpha': bytes.fromhex('5a02fc4ecc2201be9955971281892dfc183eeab06488d07fcdcbfd5afa8a462e'), + 'cv_net': bytes.fromhex('fafb1a6b93bb4868690dede7f7d76e3639ee37e9ed020e166c2eb20cdf3feebe'), + 'cmx': bytes.fromhex('982d0cec5df92480e143a33b672a5fcc9860ab0589919beb24072b102e01802e'), + 'epk': bytes.fromhex('d5d01af305d54fd71f9b0eb44f44b00b61bcbd8cb0811d70f97af5a9e9a09225'), + 'enc': bytes.fromhex( + '67884b80a71f55d3160a7e8026497c433aebd9f73b9499e3eebc19b48268c32f' + '3d2303bd2d47c298a29b0ca51678b7f416ae1527c9e297beb539333cbcbade4b' + '0358c9da9be0c8d23bebf6b01cfb292d9071307e41c07cc27027807dadd1b729' + '144ec0033a6d31a7a3969e5ce0b0217768a3a8a746df3c87967a378b98ae200b' + 'c398c17681916fb41c702966e51d61c09711405f2056053d98bbf97641b232e0' + 'bf789215e0f95d11e10fdb1a4c1893d370eaf1784750132d2a0206cf30f98d66' + 'e832fa03305f6f06dcd4f084dd5a70d62f5e9170062882ae165bfc8878842c03' + '64b97575e72df61bbcccefad9b85a68df47a984761e6a0f0c792ff89208bfd45' + '1ae6ca32eea30eef4f8e23e08246cd848d335d2d86cf44e6e3348e3cfb8d35f8' + '609609ff5fd4469d2dbb38a5e204f4065b3dbcb1e1835dafc9314a56aee71278' + '319ad917fe547eaf4b6105d8d3b9c7680e3a1ae426d952ea90fb8cc013d7ec47' + 'fad46d554c105726d27496d1af967675ef665922c2fb647b29bba606da802cd6' + '36a54b3dd42a19be2e6801003a7765b9a9b466ac85040fe1479b1fac30e47f7f' + '349dc867f0eecbd693128975dc1fd4015a4c253ddb5164fffb0556ffc77db5a2' + '5fbfc692ac6d710c4b96050bcf56a4a03ca881c2f7901cec7b878ea8c056e3eb' + 'bb8d40b9ad16ef66fb8a48793f27d54847b020a2922a41297475d2d48656ba2e' + 'dccad8140c68014eafc307bc1446ffc8549b03067cdfb52ea7763f4eb0e337eb' + 'd22093c41aea70fd5b5d8b35eeca6d15b876b8abf01c4a8192ef3961a01eefcb' + '70acfd14'), + 'out': bytes.fromhex( + 'c10219cf368ddfb680e526e11a1b5e7359215b84e4a64d57ba00b04512a717ae' + '4daba78f715883e538483a46907e77bbb113308e6d26bd69ce6ce069e055b685' + 'f3e36f9e0c14a5d7d1abb77b23a7f5e0'), + 'recipient': bytes.fromhex( + 'ddae703de8aee25d4e439b8a646b2a5a86f57f802890996e2b3c1f41ff2348a0' + 'f0bb27c032b2e7718c962e'), + 'rseed': bytes.fromhex('01dba523114310d50eb4e53c91820c72a69eb9152c87d5f109993481ba973971'), + 'value': 1015000, + }, + { + 'is_spend': True, + 'nullifier': bytes.fromhex('93230114c4c52e75ec9dc038aaca803fb603e93a97d93fccee4828efb45a153e'), + 'rk': bytes.fromhex('9d66f8dc6fd1a77a333218e706d32bc39cec8762d1d03d1d1875618c654d0e80'), + 'alpha': bytes.fromhex('7cb83df4bace45f805b2b3fd11cc619e4fa3680bf02b1ffab81b9597307ba50d'), + 'cv_net': bytes.fromhex('e096705eb994c3a642b5ad9cf6101f97ae21f598f6df2dd92b4065e0aa410f8a'), + 'cmx': bytes.fromhex('1fcc601ca83b576c969a946cc0fc839fa5f4a5c79028e401e57ae28a876f0421'), + 'epk': bytes.fromhex('98e9e62857ecbf63fa5ac554771da098fbbc0916b229581454bf2ed4110e9812'), + 'enc': bytes.fromhex( + '3250ad1c60f1431694c2cf131eb22762386d0caaaeab3e8e3d204098f2ee9a7a' + '71b1c0c442b32812f09715fe328fa2be96a049d0551cecaab3f53fbf1e06c67f' + '506b68987986448df8fc52738722d4c6974b9ded1980488e7afe0ada81ff9ea7' + 'c9b1a487735c5c793b6942e61ccb4c60a32dc3c481112d781948db61130f4af8' + '21eb5cf087f18eb64899026a14d5841db228ce27c9496db2272c06b2d9f97fcf' + '9070358c7627a5711e34870510c92895761f7520a3d8e465e8536694f54a5352' + '73390a4aa53aa861edadeb6bd2cb490615c0c9a162ddd981f96d968ef7957e31' + '2c7da312c3038944aeeda1f111345f57557e103f8503d5d6144a0ebdd873115a' + '1bff4fcb83791d5c4f1c5d21c71b316f2daa868fd2bd100b82c3ed86505db9c3' + '9a2f2aa618eb77791b4a10a7e5a8e59c63aa5cfa211591651af39a2208fffb87' + '2b4d42e0183fd8a4a7c00575cbd5f3d6ef4e0ed10505d8af5eecc75bb8b576b7' + '7c8ea652f6454151666438bea8c325ef65a8c8d2bcf262be8d11e6e2aae117e2' + '8020b31faca1ea6b56ee0ed0eaa0d55e10242a77a3b95be92597ef8b2584d9a8' + '5f8f9f0df5c142ae50b106913c0a64fa2ff5eec1d2c475fd2e82f57fd4512160' + '60cb7030e4e5696d1bb5e33c5b2065474b596e55ab818cd7a5426493618f0775' + '7c13382f6c50931230a0e9fe5f1bbadc8713c057db04b7c8e3139a0eed550bfd' + '634533e279b9fe9dc3ecd6489119db4e3181dc912c567a29cb237f940ccefa77' + 'f01c3c5e835a1bdef8596348fd6070eadfc9773d875292a5adf3baacbe1321d6' + 'ab6c75e9'), + 'out': bytes.fromhex( + '9e205080da9edb1fd3b6e085573af34227aec4ecad864410de66490b60c8a62c' + 'd4a47033b4e4cd8588ab3179001ff4c2d740e0a6d3bf07e6876385a46a5ef69b' + '65d5a6779a8f93ade6be5d06e1b562e9'), + 'recipient': bytes.fromhex( + 'ddae703de8aee25d4e439b8a646b2a5a86f57f802890996e2b3c1f41ff2348a0' + 'f0bb27c032b2e7718c962e'), + 'rseed': bytes.fromhex('f6acf873f135d7e04bf21774693489e45932921041c3199618800927f88314a3'), + 'value': 1015000, + }, + { + 'is_spend': True, + 'nullifier': bytes.fromhex('a8f517b0c5ad9c9661b5cbb54575e35debebf8494330d3de71b21d35f8f18735'), + 'rk': bytes.fromhex('d9580d672676562530ffb3c2af3c930d51486210c17ecbb0d2719f37fbac06a5'), + 'alpha': bytes.fromhex('b9400ad4f74f9b3bab7dba7490fe19e1658f376c4d05176f1f55a46c98ee6d17'), + 'cv_net': bytes.fromhex('434b0e3c18eccc0c9537b2182cdc06f37f567ca8ce83546bd00c5d2d0ad8f098'), + 'cmx': bytes.fromhex('7b45c8f7a62254eb30e6d0d650314276487a57d596e9fc2876f3768bc6cfea17'), + 'epk': bytes.fromhex('9dfbabd58f6d0efe50d452a99ef1e4641013f9e06927354f00de88939ce87486'), + 'enc': bytes.fromhex( + '432df485cecaeb63e5951044143da40415e2312a340e4d907b3466f7393f22c2' + '9aa7cc39d3f39fb0e33dd6ca0a888565f112c3bdcec136d585e399637384cc4b' + '3f98e55d2eedc76b13bf7b8eed1cdcbe06032a1be7a6c0fdff3d53b745a93e74' + '79aaf87585d9a7c05d8243be062d5a067e179fd1b1ca433317ac6152bc45b72a' + 'edb5cfed7cabbecdbf67f51636de3763d597b11c6c2ebfe15ab0879293e96320' + '652732a93fe627df9760c095bd72cec8e11c3a007148e4d6b787a1c4ebb990b8' + 'f5c2ee794b3feabdc443b21e50262798dfd4bc2e7e20be77daf4ac1a250c38ef' + '3fbf43514c62bfe2c58e17cdf3f6a3209ece9b38052a9bd5b396a2e817b80bb2' + '70646ff00cac2d6e03ce396809dd8f71d4f943f2d6c11cd9265c3a8d3f51503c' + '91d5f028b5cf68fec248621f38a17a71dfee52e25ad6660b8a1825ffb9f8fbbf' + '391e4038d4ba51e06e38972ef597ecfd62bba8a43fd92847b9bd56dc6a1370d0' + '463e1a70642098d68b673d530f8400ae5b083506db5b6b613740c371bb1e6180' + '9398b72e1859b3d723ca8bfd3ecfffa22f14838a0d9047be360aa795f0f60a9d' + '368ced599ca8e899e3c2313c08a2162a5e748168b44f5014564e34b4679db0d2' + '9f9ed884b31884ad561c137feab5e94f2abead3a4f7845293ecc8cb55c33e995' + '4b82fd4e5db3f3ae072e542049249aa55b6f9d4b779e22d305b6d722f11ea90f' + '47931532e763aac84f8475e3f16fd761c51a1c1c6c2f8d5607a9b8e878451825' + '5f1f492083ecfdb8ee096407cb960f85594908801d0e158bc1706fbce13d4435' + 'ad4b716e'), + 'out': bytes.fromhex( + 'b9e292eb7b5a72ef9ff2eb20781bea6cade7b2e08a48c76b16428ff68cd5958f' + 'a2fc90eaab442d6ca2308c79b4f6c06084fdfd95feeb6368eeb8104fde692e7c' + 'f4fc22fff2a6169052589a0e90717198'), + 'recipient': bytes.fromhex( + 'ddae703de8aee25d4e439b8a646b2a5a86f57f802890996e2b3c1f41ff2348a0' + 'f0bb27c032b2e7718c962e'), + 'rseed': bytes.fromhex('ea010bd93d0fc3dab9df9dda4c97d5eb97239ef14125990db577b7d2e6255a48'), + 'value': 1015000, + }, + { + 'is_spend': True, + 'nullifier': bytes.fromhex('8be3f4d69956566229a1c9eb93706d6cfacea806d84c10917f74e188a9cc943c'), + 'rk': bytes.fromhex('80c9e3061bf4459060267edf1dae4c65ffef5d195877f0db23731543663f2f82'), + 'alpha': bytes.fromhex('f082eabd7c9c5f61b451344c08464e50b80b5e37aed95f2f91c4b72452e5f114'), + 'cv_net': bytes.fromhex('8921d8eb9dadbf0305ef3fc6181aab0eb5279349e6230a72fbdd3527c1a7e088'), + 'cmx': bytes.fromhex('366eba72bbf033716b9c8bddfcd0d1e1579beb762c75c20ebaa1889de454a307'), + 'epk': bytes.fromhex('4d70467ce11de44d408fa3d70615365116075dad52a88ced8b626652d10f692d'), + 'enc': bytes.fromhex( + 'd1c554ff7a8a890588b74863ced1524c9c8c70f7b40596869c694df71970ff09' + '5bf8033f956c3f89ca53ddc6fcd8b55335483a4a7c93431b739d66ed1531a792' + '0ba2a7067d21ebd12119560fe7de48aa729e96daec16e4b7873528252e2f14f9' + '06851bd05df7a80745fc83ba8658434054063536c93c9947cfdd143c9f44d02d' + 'ca9fd3cdc8379ba1fcbc985220ee2c91210f33f6a6f7190b4a48f9084a54ec55' + '0e6359acd7ec940d1434ed6c6b56d5e297592f4b03925e0e5fdd646052ab458b' + '85cad33b27ab5f5bfb719b92010f58b136e14672bf4e5ba5d864979fbb50fa60' + '965de41f9d605f20a42f23274dab99002bb469a72f6a89e77417abdaa1a59b7f' + '7ceb374d3876496359672a55ba8fb366273041d48713a06177eec5c9f5780184' + 'e4ce2ac57a6d54a4e2092ff8216786536d2e142bd67433d35278b459cbe40f58' + 'd4260691e19b5233f9ebac6f4f834c58fbccc3a6f2396f0644979a9b9098cacf' + '06b96fcf275df4b4e9dd927a8be3fbcd24c1e16e0fc8df973034691989d10057' + '99e2242496d3e1654015479eaa948dc5bae0c71f8b7f3105ce3c77020b7da5be' + '55e55d5ed3fcf764f0f5a405fe89f3470ad8b2d912efe99c8923a208fe6ab155' + '60a246bb18b01b1afe31d3902f2ccfae9c2fddd346058ba94b82f5baff187576' + '3b3befca7fead99325f80cf6dfcc23723356b855106fdf259bf7fb8504826ea4' + 'cd29ec1e695f3049c24f42cd919ac3553acfe75004febac20c35d92d1a21c12f' + 'b6d906e18741fb8bbfbd3dbd1293fbff197385f55adf1e6b3ef3af80edc63110' + 'caabf9c3'), + 'out': bytes.fromhex( + 'c17ba0c208ed0dd0411da64971b00cf404eb980599c45faebc6b3f1cbae311b7' + 'c262a8a222b20d386e990c657dcca6471e79fa5b36edd7acc40a6d5294ef7aa2' + 'f8b18f3f7566218067227cb7574ef6c0'), + 'recipient': bytes.fromhex( + 'ddae703de8aee25d4e439b8a646b2a5a86f57f802890996e2b3c1f41ff2348a0' + 'f0bb27c032b2e7718c962e'), + 'rseed': bytes.fromhex('f1d5593b77bb5d5918c0bdecc5651d301e6a7b435461809626a741d119bb0b35'), + 'value': 1015000, + }, + { + 'is_spend': True, + 'nullifier': bytes.fromhex('1b54c34cc8292f6b79f51d2f91b5c9bda3627beb0e675add3fb37b3ab939c516'), + 'rk': bytes.fromhex('4e3b84aa7957fa0a0ba3c22782067599a2b70003878393f914f07f19eeadc832'), + 'alpha': bytes.fromhex('98e18b95741626e10f4872c434db7ec7390750689b51803adcf291d1318d4f0b'), + 'cv_net': bytes.fromhex('22ce1208b3d6638d0cecce265a815cdb57d5bfaec4bac5a14a2ef992417c303f'), + 'cmx': bytes.fromhex('9f65f0016b01015217c5abb05fcae0b1a1d2822057add19b35076b2e05f0192c'), + 'epk': bytes.fromhex('7ab81a60e6d8c6a2490f8ecd724c46711c542375dadfbcd1e5c70019420c2282'), + 'enc': bytes.fromhex( + '6c802a261b0941f99873b3e209466b249a272a139963bafadd71cc5b64afc98d' + 'b6f2706189467a74c05ae8a02ad328de8aa12d4e5dee060135e3b94e1cc0efbc' + '5866c91b3301724f7131ead81efd7a0c520cd1474028e3407488893b6b45b9de' + 'f8f753122f7ec2cd0c49a3eb06b64d4d2835e94c380051af5486012f401b8c81' + '4c6331b976b0b65527d56e136655766cd08084f4fd7399a17171c1879330bb98' + 'afbb5cc756168c44e4b0df9b52ab7fa35bc193c99f5ce6df6313e5da0b445d94' + 'fc12f631a3bd231fdf0c0be8fd2cc98df50b4fc5c4853177f4f22e270c59c6d0' + '7556ec5f5e82244bd5ee9bc148ca02daa3ae2bc460c65ac73b0d5a803878ec6e' + 'ba1e91ce0574b386d28a1738d004ac2bd93f4c9c1d5f90fa1e6ade99a87635c0' + '711a7f740dcc0c45210f06adb4ca90f54e8668fcd1a45260de2f3fd967ca4986' + 'ee9c90767f9734e448061d72886f800b20a783989a33b46c960078fd5beb0638' + 'db8d24907b5d8c15ee8eda056fc187d8eceb2d1245c5f7cba5b98b9bd1b56c2d' + 'f35757f87ed07dc5e6214ea25f1d8384afc00b60894fae3e17ee619975794cdd' + '6de4eb21c3d92d57d019b2bc3c98f08d35c1cd12382cab10f9f7532736767bb2' + 'a2e8cf5c6d51c8526652c00598e97695d8ba522dda0c50e8eb1b446e6d00c2ca' + '820fddde2c4c5b4902cb9aff51d7d102cfa7bcee0202fe0d958e88a00373d5b4' + '69af521e264d6b6a201c0f6559d89884acb4a481d9b56fabafb4e59c70d846c2' + '815a090dcc98cbe5a7d0cfa5287d9315056581cd89667a9c085c6e77ab7577af' + '30ed55b8'), + 'out': bytes.fromhex( + '9644bb917c9eebd52f057e1a863889f4992574bf57b5166073b245f2aa6bbcc8' + '4dca318ea3d0b80e193e382938c8b41fcec4757929dac9d443c67000b29f7eec' + '6c7ce44a19afab60dbed39300731fecd'), + 'recipient': bytes.fromhex( + 'ddae703de8aee25d4e439b8a646b2a5a86f57f802890996e2b3c1f41ff2348a0' + 'f0bb27c032b2e7718c962e'), + 'rseed': bytes.fromhex('b7de09450e2fed78853c39a0fc18af601066bccb870003c4db47aed37040bb00'), + 'value': 1015000, + }, + { + 'is_spend': True, + 'nullifier': bytes.fromhex('762eba63803d81c90d7d38e08f9c62ae3de0ea98495cebfbc212fcb0b625f231'), + 'rk': bytes.fromhex('de1c617b2474661d10fa5e472538f2c289ca63a39c637f8988c3532172364816'), + 'alpha': bytes.fromhex('526f668e2286b53400e4f4bc12fa99559319be6d14f15ffc00086c7215b9a314'), + 'cv_net': bytes.fromhex('a062251a60672e947dcdb248efe064196c2f1ed962708672f67a28c0ea541d1a'), + 'cmx': bytes.fromhex('e0e01ee861405e4f11b27828183084a1a76006719679e8dfe05c06b2d9b9c81d'), + 'epk': bytes.fromhex('8f9acad54e4c4ceb63626ce76d7dccb975480934ae7348137d01f98636c4bdae'), + 'enc': bytes.fromhex( + '378ac9089167edecc577b1b28c02580ca55f8c64acd6a747eb21a9fb59375b70' + '7ab5ad0cd0a7b5c59fae6fd0b8047206d97c59fca7ec148cf31907bad0080204' + '72ea9a00c2df60df5ca53402671edd36902573d6a91d81b10486dcbfb5f49736' + '858f913f65233143b58bf06aea901994440b94d6b1dba85be0c453c45bd8a88b' + '4378559d4f68cd5e65ed2a57182adb0ae93728c912cb3ab513f037f7c5216095' + '4db465d49eaa6c6f3025fbe703c37b4c9bd0d354bf0016527a69c64c2adf4e43' + '0a4ceabd84b0f021df50cd5f40d197d07e414e9e9743ae9350f17d37abd688b6' + 'a2316a63d6863972f07b2a400969f3e558c9ebe375e31096fecc3c05c8e55f83' + '5d7d40a7e1f9b26d4f8a0669a5eda32e7c7317c5fc9799986acd96c52b565094' + '9d44932609978ef3ff85fb9f62072213d493b5a6e8343132aac03396c706de43' + '11ebece4ac91e1b6c361a1cc244e8af083657bf84bc9ebb09dc617c339c23e1d' + '7e763fd1413f0e5182ee523b6fc3438eaef2ba931574bd72dbd45ac6eba2d161' + '43ed70093c7e2fd7e1db14054c9cfb7ec6bc89f3bb7e99ab9aff08467c624072' + '5ed0bf560bc30687921500b4b4b030984a2d3b186517e7d19493d2ef6a566711' + '153c020b3b3859a4eef0929348016997139608167db4c84b5854869454548357' + 'f324dfd8ee8c4b19b0ce6dab70954c87160c0f9828abea8eb05841c08646d725' + '32ce65bae94ecd1a48f3a0114b65eeee4aec7003687ca8dd28800cb1ce80c759' + '0b1b62becf1be211375b4fe438710d38fbd7889096995e35347f91eca6b5e8e5' + 'fec6ba19'), + 'out': bytes.fromhex( + '88e413bcd8f75391cf3df89bd64ce8dc7a0d741679223f02c8546d50856a3cf4' + '48365f976b567eea5aa1219a66b30eb04ee2e3c472a6e45aff2ea22b0eb1d14b' + '9e6fbb2a1b5e699d05e3036b28d832a3'), + 'recipient': bytes.fromhex( + 'ddae703de8aee25d4e439b8a646b2a5a86f57f802890996e2b3c1f41ff2348a0' + 'f0bb27c032b2e7718c962e'), + 'rseed': bytes.fromhex('211558a82b0684b453222b1171beef68aeda93b143b9368b5a0c40b1df7322cb'), + 'value': 1015000, + }, + { + 'is_spend': True, + 'nullifier': bytes.fromhex('05aa1878dfd335dbce602e1a8cd23986ee6a85c83e77e886c6acc5f2330f682c'), + 'rk': bytes.fromhex('4e54d29b80fa7f535d2a8c5a2784f7ad152c44a2a87b2d817ae3361fccb0d4a1'), + 'alpha': bytes.fromhex('f133a7eb65d87ff41ba8f909d0fac69cebf863f40d3225c559a823def2772b04'), + 'cv_net': bytes.fromhex('c3c2670c08676d45b580a8ccfa206e3683feb88a5f9406e20ed30eb355190409'), + 'cmx': bytes.fromhex('057543e8f38759e6cf094ccae696826f4eac83e64779ecf3f74ffba3b6a41c16'), + 'epk': bytes.fromhex('7aceaf5b50896ae5c8e5856313b0313b9257e89c4140feab46cfffd2261b2a81'), + 'enc': bytes.fromhex( + 'd0295cdb43aead4bafd89cd3e796ed7d205576af427f1665fcf890fddac1d94a' + '1b422fee2b1a39631fcc49056bf3fb333c2dd9aa7096bd8382c48a614be6b35a' + '5f236a6b3a7148d2c2259be05db67fbf008106e4277f39b8ccf479e4c132e4cb' + '6d38b956eedbf98b1f33ca2da57949dcc305460b7e279cba6ad6b189e0a74dbe' + '52ce18f32fc9096b3eb58a71637b472b1da4d0359a654101fa0ab40412212134' + '903ee4a996d877b43f292381c01919484a54d927dbb6bfab98fbaf4a5d655241' + '4ee223155459322855ba6b4dc8d28336ecc9b4ba66580bfd93541f0d2100ce6e' + '272ba130a05d73c7190f11148f4443181e6ef2214e96af0a4a79c5c61e84c946' + '2aa6a4b552f6364051a87c674e9306bd06256c2f3cfb382980b57cc9f542cf24' + 'b122763931c17ec1083b2056a55f50383421e56d9c293a919c40684cc9d2c60e' + '4d0b83a1b80abbd373e35028cb01e11bb2eb6a6dc1f4210090e1edb8ba318b12' + '56081c5f861ca3d005b72fb3fef89032703c12a4e0f4c314c214e77b87a12af4' + '2b72289d61334aac4e6abf13ee47ebe459ec2a5a14253a58687c7b52fe67d919' + 'c2484f933374e09d746da0d16929151a5fd22dd39955fd1feebc7d648f3924ef' + '93b309990d9ce740d388caef3e0f5935e34c17670241393702f1b8d9fc7efa38' + '83d67eed63b477887c3dc8356fdeabd11574b108a06695801457bd53eb9fcf2b' + '1360423b82eab0401b89fb956f8fd2615d037d2380b2c6e1cdbc33c3fe376601' + 'be0eefdc6e98e5ce2929cd7e7c70ee4ff8ef7988b57e4da5b5b17b5da29fd03a' + 'f6d75d99'), + 'out': bytes.fromhex( + '61a814cb4fbe7c77bc339a4f3bff21ce26a9dee3c8ea1ad8b886ee424601f976' + 'a956e84c22097081763ed29f3a8b11a8a88824015424c29958c5d8b7cacd0962' + 'd1e9310d25cf0a2694f883eb0007cb78'), + 'recipient': bytes.fromhex( + 'ddae703de8aee25d4e439b8a646b2a5a86f57f802890996e2b3c1f41ff2348a0' + 'f0bb27c032b2e7718c962e'), + 'rseed': bytes.fromhex('c857fac23f3c2410be8c8a1000915edd2e1b781493e0b4e4a07f539da5f9355f'), + 'value': 1015000, + }, + { + 'is_spend': True, + 'nullifier': bytes.fromhex('80bd69243039fd9f893a1db9bfa2a90bb42b0435c68a4de69c44ee96397e7217'), + 'rk': bytes.fromhex('b75f29780411e873a54f66e2196e6dfbb2692b74f880a0c16622211ef2cf690c'), + 'alpha': bytes.fromhex('06509facde7313b6f42003afc3ada326f487c1bb51daede42037fd2a1c313106'), + 'cv_net': bytes.fromhex('84f5d51ecc7d7f6861c295d83b4cfd5a12cd25c97be1d194cbe4eb048d0764a7'), + 'cmx': bytes.fromhex('b3fd458b9111b4944613a695c8396c19be004562e41aeb9e2d091e1457d3f83f'), + 'epk': bytes.fromhex('be4d055f42218ccbe8be8bf130b950fe6672243d49d2ca91a9056e08e5554f2e'), + 'enc': bytes.fromhex( + '88b493cbe854943130f7d811e2003fd70fb606e12ebcd3fa5e920d949743dffd' + 'a421643863cf8e51c71c894173b213e8d59479674fc1a4493397b14bc81467c6' + 'ee4f97f29a938bae7646b89e8900f0d9ee043b1e19bd0aa56c14496ce88794a0' + '59723ef024431c0279b49fceaf6bb81370998520a5c710f1349e53dbc567463c' + '339553e375c575eea58dac685350c389b3b1658d0221432ed3722c94ccf5d6df' + '0fa7fe60a1b4615ef9b7667cbb9bb012f1a4fbdc54e47ade84393514fc4ac359' + '2159af250081a3a8317b9904928959553224017b709f7819e1bc676baf44dc51' + '1710988d90c2dd14f8fa30e81efea9ef7ff3d748ae2de43f0ff8726d88f140ef' + 'd178611768224388f62ad1cd4893650d352d1fdab6c7825e1e6fa08125f9cc98' + '862eb48fc4e5de2dfe7e5297a7ba2cf2ccc94b37d06fac064c4a4a20d4c61352' + '2ee7251fd22e8a3cf6ac9cbfdb631cca65ca201615d10637fc5326ebd1732e44' + '1f342bfc5fd510e99a83ecb10a1e5e1f4cb75e2062f851de7828f317af783321' + '0459a8784a52d01a5405ad28ae93b509d672d3376c7cf1386426992e32fe1191' + '69eb5ceab02f44d1bf2fb7c1d8f7d9cb5edf47fe68cd91091e34879a00a834e8' + '77d8ed8841ae776259ae2225f4d93614896630e74635655fff3eafaf3317039f' + '53afae9aed77b71cc33098ca84bf8df70d7e10133ac5b40f05fd1b5a81eb3772' + '1e3448d624ff301c69f69cdacbca8ec077033939af9fadb05b601514b024f476' + '373afe9dc31334eb2afffeb47bc1b79245d064324ef1e6185bdf865ea71e43a3' + 'f4d5a341'), + 'out': bytes.fromhex( + 'c5153d598e573e369a83048eeb7f7a33fbcae9fc38c01cc86450cbbb79ddc15a' + '38768fe782efbdc2d595c7ac047669c5da4f12ad60f8e83ac679c6931089304e' + '7e00ed59ef7aa2943ed9b57e6b5e6c48'), + 'recipient': bytes.fromhex( + 'ddae703de8aee25d4e439b8a646b2a5a86f57f802890996e2b3c1f41ff2348a0' + 'f0bb27c032b2e7718c962e'), + 'rseed': bytes.fromhex('fccf09a55f9a8bcd8cef78fda81e7327042fc4b5cb89f98d082e1536bdb134b8'), + 'value': 1015000, + }, + { + 'is_spend': True, + 'nullifier': bytes.fromhex('9626584a16d66fe07ebf4f3c882686e408209f3b0466dc1acff98bdb5083881a'), + 'rk': bytes.fromhex('3d193701dd72c6e5b91c5ce173283391a9b838db3e322f8726e7b9f70f8f0830'), + 'alpha': bytes.fromhex('ff5e8f768ac3da0c5fe125323d57b107348dfae35f7814038c57bf9b72a50229'), + 'cv_net': bytes.fromhex('46877a8ce2afb3ded4da748f3165368d1e6161ac95fc40c3841a093107a3970f'), + 'cmx': bytes.fromhex('959c475be8bf479932a20fc31ea661c23c47d5f4ca6a9634e9efad8da528c70e'), + 'epk': bytes.fromhex('c5aa46b209c2bb664a085844288d2712b1358c0e134cd6de9e8341bbbbf3bd33'), + 'enc': bytes.fromhex( + 'f3cee24d5ea281f27a88653b3d81079e339e6c54427c88444b9843a4818a6dd4' + 'e2f0de12b80e02fe95801d3cc2032c68395625a84763daca66f4803405ac2633' + 'abd46fe0b5b2d1f1ddffe1b9e459e5ec55562ace3d4a1d282ffe55bdbe5edab1' + 'a09efb2556d3642922c25dc9827601a6257ee34d07f03ed5495e8f7a5e808e4d' + 'c63b8cae4755079f99775e7ac7242cd3793352a813c13381fb5758d798be1899' + 'ef901d6c715303e66ee7506ca15d84a78461518aec81cfcb820c998e73838213' + '5c99d9daac438d71d24f732a92d2e139c824650cc73a8cb0e3c0430cfe46d375' + '3ee7b8ba452fa54dafe52d84946b9bec8c42d2d9e434c2ca62fd6fba7f1decb5' + 'c14de077b2aabc1a83e80eb78c300fef35e0e781cb0d7727bcebe09efe1f0985' + 'ef9cf15ea4814d3a7836207ee6769ba72b5ca957100739587c1b9fe9473b0f74' + '05eb94e2c5d4b3f4ae886815da966ad7338529e05cb1a1733e6266a530c4302b' + '8a9c3601f7ba26ee9756938983b7bd41b3405794c2768c6c9dded0500f4dbdd4' + 'f0eaa9161e553674c0791c13ed7f8b233778b3a93ab366166bb0fb2ab3a03e47' + 'a5decfef4c224640458d5b4d85cc91edcb799e445b1331e49e0e8325c41103fb' + 'd54e4dd45a9f71c445323e99a65db21e9aace73e1cf8d9b91dcd481714bd8c3f' + '133132c30a3f3613eb6b08d905f104244c3952b953439c237c59dec6596164da' + '45d3d456d8c283b8759f7367ed232c7b3e7ea23c5d401dc09f3a8717b8e3a621' + '489c2095c1198268237b589ac9831f43dc082f14aea899d807ba60ffeb56e7d5' + '6256542e'), + 'out': bytes.fromhex( + '662b7206d372e142414db811f3bf16a63147976e8ebba60a006676c92639634d' + '65581d26fdeada20db03b26b6ad1dc617daf3c4b26b177eff9193ba6c8aa8304' + '3680feb5f3e25273658ccb5ec54207d6'), + 'recipient': bytes.fromhex( + 'ddae703de8aee25d4e439b8a646b2a5a86f57f802890996e2b3c1f41ff2348a0' + 'f0bb27c032b2e7718c962e'), + 'rseed': bytes.fromhex('6701cfd14370c25c7bf281f3ac777386621102d8ea16e0e124ca72c49a08943f'), + 'value': 1015000, + }, + { + 'is_spend': True, + 'nullifier': bytes.fromhex('b717ab43b4030e502789837104b0f1d17c52fc85e9feb67597cc37ea6fefdb06'), + 'rk': bytes.fromhex('4b383511daa4696049c4a62841907f4b2a9f73391f399fb5028d8c4f3bea7117'), + 'alpha': bytes.fromhex('e621c7864db5823238401a62fcaa693cba9b0a8d207b0e43a34e9e9ec4d1b536'), + 'cv_net': bytes.fromhex('b7458fa5c8f2a3e9ca396d936220f7dedb5a8461d5964525179ccef4e39a6f09'), + 'cmx': bytes.fromhex('de7008c29a058bd3ca41759f3d3d45da1b7aff891e79abcd592004437a7a0617'), + 'epk': bytes.fromhex('d1136d16826a6ea26d99f2a54ff4b8f1c3c6c615d8bb325ca798eda9de93113b'), + 'enc': bytes.fromhex( + '39d375985cad35237c13c10db3d8b11f8670b49a9de9dcde98ce544129cb83da' + '345b5393e2949ac27d6efbb02b37e23a1db879fb4678f38e46c2e6b9925c4c04' + '8fd9193b4a46cfe0d6fb5d211e9f18955aa8c66ea362508abf10aa77b019da10' + '435c8a68dafab7a9647af4773a3dd01e36587d184c32efb6f4dc93a9f1ccec76' + '9c6307f1280ccca365cd736b298ece2212193de887ca3a79a064931ff0bf65f4' + 'dab1876205388fd4238f9a47f431d1534ba716de658671368260a1eec4606589' + 'c6a0727ab692d0cfddc5c4ca317d3e5e19109c2952629282d53f1b6fc6afd2bc' + 'f09e2d18a2510689dc087564813a8e27161a49569f311ae8672f648229cea4f3' + 'f8fe6f1e4b7f6b00c67c8ba9b392b66a3f275c6488c048e5cc50900551090a06' + 'b2432b717cf09a7b23dd9d872af1bc967dcaf03e50032ec55938aebe011fe6b0' + '27497fd69caeeffdd0b1dab2eadc28b362bc845a9a409b94ed428bd7601b6520' + 'e5992534ecbbff182de27914255658ac9f7cc6d30d5ec413c44a4f24f2d51425' + '47e0e27fda435b89008160eab76874016396c996a3a16d78a8903e1195bb8045' + '01a2053556cda4ae5ecfae92a02939f06b028727c09d874b5b403a17fe04880c' + 'e579b628e619af2f506e12207dd3a9cc5f0e08839945c42d912db74d325a1dc7' + '161e978b9ddb39fa6944f1776c946f2c7ac450e6e533cd8535a0150547746257' + 'dae1bae72232adf3eeab141f99d40aaacfd30f26714a1ac0f78d4793de75fff5' + '848b71d81440eb9e772dbde5cb3ca5d7c7b10fb39420b443a210abfe29d0ed77' + '1e44a561'), + 'out': bytes.fromhex( + 'aae26bb3b088a37a3442125fe2bc61d0699a77bc86b82a224096c82c60296711' + '12b3e888482afdd1085e11bfc08ac01fbf1cc359420bc7f99f9b47d1237e12f0' + '3757fa7bf2ffd0967c6e23b60009f9aa'), + 'recipient': bytes.fromhex( + 'ddae703de8aee25d4e439b8a646b2a5a86f57f802890996e2b3c1f41ff2348a0' + 'f0bb27c032b2e7718c962e'), + 'rseed': bytes.fromhex('e4ee1456a223dfa31cb714824dfeb95a2234ce811ea308b63a4fe4786407a33b'), + 'value': 1015000, + }, + { + 'is_spend': True, + 'nullifier': bytes.fromhex('e1e8dabd82a6bcba2107fc4a8be64f0ede30355e5eed5bd365db848908fda23b'), + 'rk': bytes.fromhex('64b31d813e4fa32ad2413109882805a1b6d825eed19dc58a86b4486a4671e39e'), + 'alpha': bytes.fromhex('f08196949dd1c2293d8f45a1919ba6d3d51e03e4a79ffce03df30a9aa6c6a527'), + 'cv_net': bytes.fromhex('0cb9920d9da9d1ab56dc2fe03fe7ba0e99d6680319dab7e79480b38ab781751c'), + 'cmx': bytes.fromhex('df52e0d1e9ef1a81c53c00dfdd98ec1063caeb40f796607dacc0a940ce3c2a0b'), + 'epk': bytes.fromhex('a9d9c634dea3e7077601a14ec78ed750260202728d517eae494670da0cbda6a8'), + 'enc': bytes.fromhex( + 'b01527e05660d0d77f0f23cd2192bf470ea7104ac9219ea44c9992ec5090cce3' + '0b930b56cf37e77c034b6ff110f09b8894796e5840309b92071896d5b44674ec' + '8af09965c555fe34eb6df782a992c3b1bcccbd6bafefda52095061d3f26ca90b' + '000e8096a350a00422d1f85b39c73ddb22b8138bb88ea1b5a69c71c51d487a7e' + '1c3b7be3e11c18341483e2df8151505c05eb3315d717b973874a22e2f9164d7b' + 'cca4cd6465845075084bc4647065df093ba4f521332196fc22488b53f22ce39e' + '8088cbff2b5a320c44191472c72d07d343e057c37ccfc2c30e44759ee53fab33' + 'c3c1a69a63567a862415b0116a6199b0d0a3155a72e9d67295955d835201b65d' + '3d5267bcafaaef444f4c7cabc2dfa444ca4589eb0b7a595370a8ffb172c47f7e' + '1a87745b78badc91840ec56ae11463b12b10450573891b2edbbec61c5e8b5443' + 'bf23feb0649c434860d01d2bc3d07a6879ef38a01d09de4b3a1b9ec173accb3b' + '682c6476e24c9accbd71d9aad42a1a52871d906b7878cd72d1e90b38665f1900' + '258d12da147e1ac2156af74bc8823b9fadb47ba20d369c5c54f575640abb383d' + '5723378a9357086241f43c01133081f7d6fdc3aeaaf4f763478c0f6ef20030a2' + 'a128bfef33b05ea8e3b9565c2b35b49745aeeb9ab43f543469c79ffb28f63673' + '645ff957db246104df1984b26de1ef5de5eb0e98562822c21750ff97efa716e4' + 'a050d027244fc2d76fb1e521547caf6f19f05ae5d6cbdbaef872a2cee284859a' + 'd173fe53d282c4598725a069c7490963b1524e1ca01bc9890fe42e58fcbdc80b' + '8d3af351'), + 'out': bytes.fromhex( + '892b762b0d42e42da9a64a52c82c1e609cb94efe8089c75c8b93cf85464748af' + '812446c0d38a737e2450d1ac9560b2a7bfca9835a3aad344c04ee19f3ab3e491' + '44af0486105188941f2e2294a05f915d'), + 'recipient': bytes.fromhex( + 'ddae703de8aee25d4e439b8a646b2a5a86f57f802890996e2b3c1f41ff2348a0' + 'f0bb27c032b2e7718c962e'), + 'rseed': bytes.fromhex('bdd6672d18bc9ddbe590b177c010c17470a5263b05c9b770448173b7a336debe'), + 'value': 1015000, + }, + ], + }, +} + + +def migration_action(v): + action = fabricated_action(v) + action['is_spend'] = v['is_spend'] + return action + + +def migration_kwargs(tx, fee): + lock_time, expiry = 0, tx['expiry'] + orchard = [migration_action(v) for v in tx['orchard']['actions']] + kwargs = { + 'address_n': ADDRESS_N, + 'actions': orchard, + 'account': 0, + 'fee': fee, + 'lock_time': lock_time, + 'expiry_height': expiry, + 'orchard_flags': tx['orchard']['flags'], + 'orchard_value_balance': tx['orchard']['value_balance'], + 'orchard_anchor': ANCHOR, + 'header_digest': header_digest(IRONWOOD_TX['tx_version'], + IRONWOOD_TX['version_group_id'], + IRONWOOD_TX['branch_id'], lock_time, expiry), + 'orchard_digest': bundle_digest( + orchard, False, 6, flags=tx['orchard']['flags'], + value_balance=tx['orchard']['value_balance']), + } + kwargs.update(IRONWOOD_TX) + if 'ironwood' in tx: + ironwood = [migration_action(v) for v in tx['ironwood']['actions']] + kwargs.update( + ironwood_actions=ironwood, + ironwood_flags=tx['ironwood']['flags'], + ironwood_value_balance=tx['ironwood']['value_balance'], + ironwood_digest=bundle_digest( + ironwood, True, 6, flags=tx['ironwood']['flags'], + value_balance=tx['ironwood']['value_balance'])) + return kwargs + + def _b2b(person, data): return hashlib.blake2b(data, digest_size=32, person=person).digest() @@ -85,7 +1276,9 @@ def bundle_digest(actions, ironwood, tx_version, b'ZTxIdIrnActNH_v6', b'ZTxIdIronwd_H_v6') else: pc, pm, pn, pb = (b'ZTxIdOrcActCHash', b'ZTxIdOrcActMHash', - b'ZTxIdOrcActNHash', b'ZTxIdOrchardHash') + b'ZTxIdOrcActNHash', + b'ZTxIdOrchardH_v6' if tx_version == 6 + else b'ZTxIdOrchardHash') compact = _b2b(pc, b''.join( a['nullifier'] + a['cmx'] + a['epk'] + a['enc_compact'] for a in actions)) @@ -100,7 +1293,8 @@ def bundle_digest(actions, ironwood, tx_version, return _b2b(pb, body) -def note_action(cmx, recipient=RECIPIENT, value=VALUE, rseed=RSEED): +def note_action(cmx, recipient=RECIPIENT, value=VALUE, rseed=RSEED, + c_enc=C_ENC_ORCHARD): """One action carrying real output metadata. Every field is size-checked by the firmware (fsm_msg_zcash.h:1068-1088) and @@ -112,10 +1306,10 @@ def note_action(cmx, recipient=RECIPIENT, value=VALUE, rseed=RSEED): 'alpha': b'\x01' * 32, 'nullifier': RHO, # the firmware feeds this in as rho 'cmx': cmx, - 'epk': b'\x02' * 32, - 'enc_compact': b'\x03' * 52, - 'enc_memo': b'\x04' * 512, - 'enc_noncompact': b'\x05' * 16, + 'epk': EPK, + 'enc_compact': c_enc[:52], + 'enc_memo': c_enc[52:564], + 'enc_noncompact': c_enc[564:], 'cv_net': b'\x06' * 32, 'rk': b'\x07' * 32, 'out_ciphertext': b'\x08' * 80, @@ -293,6 +1487,23 @@ def test_note_commitment_binds_the_recipient(self): self.client.zcash_sign_pczt(**sign_kwargs(actions)) self.assertIn('commitment mismatch', str(caught.exception)) + def test_corrupted_note_ciphertext_is_refused(self): + """A note the recipient cannot decrypt must not be signed. + + The commitment alone does not reach the recipient: a host could keep a + valid cmx and corrupt the ciphertext, recomputing the bundle digest to + match, and the payment would be invisible to normal wallet scanning. + The device decrypts with the key derived from rseed and rho and must + refuse before the output screens. + """ + c_enc = bytearray(C_ENC_ORCHARD) + c_enc[52 + 100] ^= 0x01 # one memo bit + actions = [note_action(CMX_ORCHARD, c_enc=bytes(c_enc))] + + with self.assertRaises(Exception) as caught: + self.client.zcash_sign_pczt(**sign_kwargs(actions)) + self.assertIn('ciphertext mismatch', str(caught.exception)) + # Canonical release/7.15 includes Ironwood handlers and the corresponding # native commitment vectors. These regressions apply to that product. IRONWOOD_FIRMWARE = "7.15.0" @@ -327,7 +1538,7 @@ def test_ironwood_rejects_a_non_empty_orchard_bundle(self): Orchard bundle's valueBalance never enters the device's fee check. """ self.requires_firmware(self.IRONWOOD_FIRMWARE) - actions = [note_action(CMX_IRONWOOD)] + actions = [note_action(CMX_IRONWOOD, c_enc=C_ENC_IRONWOOD)] kwargs = sign_kwargs(actions, ironwood=True) # Anything but the ZIP-229 v6 empty-bundle digest must be refused. kwargs['orchard_digest'] = bytes([0x11]) * 32 @@ -343,7 +1554,7 @@ def test_ironwood_note_is_accepted(self): selected by shielded_pool rather than one path serving both. """ self.requires_firmware(self.IRONWOOD_FIRMWARE) - actions = [note_action(CMX_IRONWOOD)] + actions = [note_action(CMX_IRONWOOD, c_enc=C_ENC_IRONWOOD)] screens = self._capture_button_screens() result = self.client.zcash_sign_pczt(**sign_kwargs(actions, ironwood=True)) @@ -354,6 +1565,283 @@ def test_ironwood_note_is_accepted(self): self.assertTrue(len(outputs) == 2, "expected 2 ConfirmOutput screens, got %d" % len(outputs)) + # ZIP 374 user_address. Both addresses are real librustzcash output: + # MULTI_RECEIVER_UA is RECIPIENT plus a Sapling and a P2PKH receiver + # (zcash_address 0.13.0); OTHER_ORCHARD_UA is the "all" seed's account-0 + # address at diversifier index 1 (zcash_keys 0.16.1), a valid mainnet UA + # whose Orchard receiver is not RECIPIENT. + USER_ADDRESS_FIRMWARE = "7.15.0" + MULTI_RECEIVER_UA = ( + 'u16065qzvddm89jcmzufxjs5pe6dr006tezvd7pap2nc58cctca8tt373s2he7xx76cn' + 'lyfatutph9kfl5g35cnuw6szxlf0qhpqajh0xrujjny6rxh6wej6mx6x5zuz4auaffd5' + 'hd56t8kwxnnquasruhg8qv3344cn6dauw00waq8ak2lmlyn8r84jumahr2nrd246gdxw' + '932t8uvgs') + OTHER_ORCHARD_UA = ( + 'u1elnjt36zcqfelwj62v8lujthlqefztqcy02jfm2p5vs9phrzr8fj68j3mpzmvlktay' + 'k9fdz4zd4k3x6f7z3n62dw09w8sr9a8a0ka5m6xktd8hl6x5ekd0qky8h8t0an6p8eqk' + '3ggwnl30dkv7txlw5r2qef330j94r0lftqktn0ev70kc78h8ev43ja5x7de27rvvhf0h' + '4ku663uw6') + + def _capture_confirm_text(self): + """(code, title, body) of each confirmation, as the firmware formatted it.""" + screens = [] + original = self.client.callback_ButtonRequest + + def capture(msg): + title, body = self.client.debug.read_confirm_text() + screens.append((msg.code, title, body)) + return original(msg) + + self.client.callback_ButtonRequest = capture + return screens + + def test_user_address_is_checked_then_shown(self): + """The address the user pasted is shown once it holds the recipient. + + The device decodes the Unified Address, finds its single Orchard + receiver equal to the output's recipient, and shows the user's own + string -- not the Orchard-only address it would otherwise rebuild. + Ironwood outputs use the same Orchard receiver type. + """ + self.requires_firmware(self.USER_ADDRESS_FIRMWARE) + for ironwood in (False, True): + action = (note_action(CMX_IRONWOOD, c_enc=C_ENC_IRONWOOD) + if ironwood else note_action(CMX_ORCHARD)) + action['user_address'] = self.MULTI_RECEIVER_UA + screens = self._capture_confirm_text() + + result = self.client.zcash_sign_pczt( + **sign_kwargs([action], ironwood=ironwood)) + + self.assertIsInstance(result, zcash_proto.ZcashSignedPCZT) + shown = [(title, body) for code, title, body in screens + if code == proto_types.ButtonRequest_ConfirmOutput + and title == 'Shielded recipient'] + self.assertEqual(shown, + [('Shielded recipient', self.MULTI_RECEIVER_UA)]) + + def test_uppercase_user_address_is_shown_in_lowercase(self): + """An all-uppercase address, as a QR code carries it, is accepted. + + BIP 350 allows all-uppercase bech32m and forbids only mixed case. The + device checks it like the lowercase form and shows the lowercase form + wallets display. + """ + self.requires_firmware(self.USER_ADDRESS_FIRMWARE) + action = note_action(CMX_ORCHARD) + action['user_address'] = self.MULTI_RECEIVER_UA.upper() + screens = self._capture_confirm_text() + + result = self.client.zcash_sign_pczt(**sign_kwargs([action])) + + self.assertIsInstance(result, zcash_proto.ZcashSignedPCZT) + shown = [(title, body) for code, title, body in screens + if code == proto_types.ButtonRequest_ConfirmOutput + and title == 'Shielded recipient'] + self.assertEqual(shown, + [('Shielded recipient', self.MULTI_RECEIVER_UA)]) + + def test_mismatched_user_address_is_refused(self): + """A valid address that does not hold the recipient refuses signing. + + Nothing about the output is shown: the refusal comes before the output + screens, so the user is never asked to approve the wrong address. + """ + self.requires_firmware(self.USER_ADDRESS_FIRMWARE) + action = note_action(CMX_ORCHARD) + action['user_address'] = self.OTHER_ORCHARD_UA + screens = self._capture_confirm_text() + + with self.assertRaises(Exception) as caught: + self.client.zcash_sign_pczt(**sign_kwargs([action])) + self.assertIn('does not match output', str(caught.exception)) + self.assertEqual([c for c, _, _ in screens + if c == proto_types.ButtonRequest_ConfirmOutput], []) + + def test_absent_user_address_shows_the_orchard_address(self): + """Without user_address the device rebuilds an Orchard-only address. + + It is labelled as exactly that, since it is not what the user pasted. + """ + self.requires_firmware(self.USER_ADDRESS_FIRMWARE) + screens = self._capture_confirm_text() + + self.client.zcash_sign_pczt(**sign_kwargs([note_action(CMX_ORCHARD)])) + + shown = [(title, body) for code, title, body in screens + if code == proto_types.ButtonRequest_ConfirmOutput + and title == 'Orchard address'] + self.assertEqual(shown, [('Orchard address', EXPECTED_UA)]) + + + FABRICATED_OUTPUT_FIRMWARE = "7.15.0" + + def test_fabricated_zero_value_output_signs(self): + """A real NU6.3 wallet transaction is not refused. + + From NU6.3 every Orchard spend is paired with a fabricated zero-valued + output whose ciphertext is random bytes (ZIP 326), so it cannot decrypt + to its note. Its cmx still binds value 0, so it pays no one: the device + accepts it without a screen. The change, proven to pay this account's + internal address, is shown as the change total; then the fee, and + both wallet spends are signed. + """ + self.requires_firmware(self.FABRICATED_OUTPUT_FIRMWARE) + actions = [fabricated_action(v) for v in FABRICATED_BUNDLE] + kwargs = sign_kwargs(actions, fee=10000, orchard_value_balance=10000, + total_amount=90000) + kwargs['orchard_digest'] = bundle_digest(actions, False, 5, + value_balance=10000) + screens = self._capture_confirm_text() + + result = self.client.zcash_sign_pczt(**kwargs) + + self.assertIsInstance(result, zcash_proto.ZcashSignedPCZT) + self.assertEqual(len(result.signatures), 2) + outputs = [body for code, _, body in screens + if code == proto_types.ButtonRequest_ConfirmOutput] + self.assertEqual(outputs, ['Change back to your wallet:\n0.00090000 ZEC']) + for _, _, body in screens: + self.assertNotIn('0.00000000 ZEC', body) + + def test_zero_value_padding_output_is_not_shown(self): + """A padding dummy output is not shown, even though it decrypts. + + Wallets pad an Orchard bundle with a dummy zero-valued output to a + random address (protocol spec 4.8.3). Its cmx binds value 0, so like + Keystone and Ledger the device does not show it: only the change total + and the fee, and it signs only the wallet spend. + """ + self.requires_firmware(self.FABRICATED_OUTPUT_FIRMWARE) + actions = [fabricated_action(v) for v in PADDING_BUNDLE] + actions[1]['is_spend'] = False # the dummy spend carries dummy_sk + kwargs = sign_kwargs(actions, fee=10000, orchard_value_balance=10000, + total_amount=90000) + kwargs['orchard_digest'] = bundle_digest(actions, False, 5, + value_balance=10000) + screens = self._capture_confirm_text() + + result = self.client.zcash_sign_pczt(**kwargs) + + self.assertIsInstance(result, zcash_proto.ZcashSignedPCZT) + self.assertEqual(len(result.signatures), 1) + outputs = [body for code, _, body in screens + if code == proto_types.ButtonRequest_ConfirmOutput] + self.assertEqual(outputs, ['Change back to your wallet:\n0.00090000 ZEC']) + for _, _, body in screens: + self.assertNotIn('0.00000000 ZEC', body) + + MIGRATION_FIRMWARE = "7.15.0" + + def test_migration_transfer_signs_both_pools(self): + """A ZIP 318 Orchard to Ironwood transfer signs. + + From NU6.3 Orchard funds can only leave the Orchard pool. The transfer + spends an Orchard note and creates an Ironwood note in one v6 + transaction; the device verifies both bundles. The Ironwood note pays + the account's own internal address (ZIP 318), so it is shown as change + back to the wallet, then the fee, and the one wallet spend is signed. + """ + self.requires_firmware(self.MIGRATION_FIRMWARE) + screens = self._capture_confirm_text() + + result = self.client.zcash_sign_pczt( + **migration_kwargs(MIGRATION_TRANSFER, fee=15000)) + + self.assertIsInstance(result, zcash_proto.ZcashSignedPCZT) + self.assertEqual(len(result.signatures), 1) + outputs = [body for code, _, body in screens + if code == proto_types.ButtonRequest_ConfirmOutput] + self.assertEqual(outputs, ['Change back to your wallet:\n0.01000000 ZEC']) + for _, _, body in screens: + self.assertNotIn('0.00000000 ZEC', body) + + def test_migration_preparation_signs_sixteen_actions(self): + """A ZIP 318 note-preparation transaction of 16 actions signs. + + Every action carries a wallet spend (one real, fifteen fabricated), so + the device returns sixteen signatures. All fifteen notes pay the + account's internal address and are shown as one change total. + """ + self.requires_firmware(self.MIGRATION_FIRMWARE) + screens = self._capture_confirm_text() + + result = self.client.zcash_sign_pczt( + **migration_kwargs(MIGRATION_PREP, fee=80000)) + + self.assertIsInstance(result, zcash_proto.ZcashSignedPCZT) + self.assertEqual(len(result.signatures), 16) + outputs = [body for code, _, body in screens + if code == proto_types.ButtonRequest_ConfirmOutput] + self.assertEqual(outputs, ['Change back to your wallet:\n0.15225000 ZEC']) + + def test_migration_preparation_needs_three_confirmations(self): + """The 16-action preparation transaction is three confirmations. + + The summary, the change total and the fee: its fifteen notes all return + to the wallet's internal address, so none is reviewed on its own (it + was 32 confirmations when each note took two screens). + """ + self.requires_firmware(self.MIGRATION_FIRMWARE) + screens = self._capture_confirm_text() + + self.client.zcash_sign_pczt( + **migration_kwargs(MIGRATION_PREP, fee=80000)) + + self.assertEqual([title for _, title, _ in screens], + ['Zcash Shielded', 'Zcash Change', 'Zcash Fee']) + self.assertIn('0.00080000 ZEC', screens[2][2]) + + def test_only_proven_change_is_folded_and_memo_send_is_shown(self): + """Only an output proven to pay this account's change address is hidden. + + The device recomputes the account's internal-scope viewing key and + folds an output into the change total only if its recipient is that + key's address. A self-send to the account's external address, and a + payment to another account's change address, are shown like any other + output. A zero-valued memo-only send that carries the address the user + entered is shown with it, at 0 ZEC; the same output without it is + taken for padding and not shown. + """ + self.requires_firmware(self.FABRICATED_OUTPUT_FIRMWARE) + for with_user_address in (True, False): + actions = [fabricated_action(v) for v in MEMO_BUNDLE] + for action in actions[1:]: + action['is_spend'] = False # dummy spends carry dummy_sk + if with_user_address: + actions[3]['user_address'] = MEMO_USER_ADDRESS + kwargs = sign_kwargs(actions, fee=10000, orchard_value_balance=10000, + total_amount=90000) + kwargs['orchard_digest'] = bundle_digest(actions, False, 5, + value_balance=10000) + screens = self._capture_confirm_text() + + result = self.client.zcash_sign_pczt(**kwargs) + + self.assertIsInstance(result, zcash_proto.ZcashSignedPCZT) + self.assertEqual(len(result.signatures), 1) + outputs = [(title, body) for code, title, body in screens + if code == proto_types.ButtonRequest_ConfirmOutput] + expected = [ + ('Zcash Output', 'Send shielded ZEC?\nAmount: 0.00020000 ZEC'), + ('Orchard address', None), + ('Zcash Output', 'Send shielded ZEC?\nAmount: 0.00030000 ZEC'), + ('Orchard address', None), + ] + if with_user_address: + expected += [ + ('Zcash Output', 'Send shielded ZEC?\nAmount: 0.00000000 ZEC'), + ('Shielded recipient', MEMO_USER_ADDRESS), + ] + expected.append(('Zcash Change', + 'Change back to your wallet:\n0.00040000 ZEC')) + self.assertEqual([t for t, _ in outputs], [t for t, _ in expected]) + for (_, body), (_, want) in zip(outputs, expected): + if want is not None: + self.assertEqual(body, want) + # The two rebuilt addresses differ: neither output was folded. + self.assertNotEqual(outputs[1][1], outputs[3][1]) + if __name__ == '__main__': unittest.main() diff --git a/tests/test_msg_zcash_tex.py b/tests/test_msg_zcash_tex.py new file mode 100644 index 00000000..cbfe23d7 --- /dev/null +++ b/tests/test_msg_zcash_tex.py @@ -0,0 +1,409 @@ +"""ZIP 320 TEX payments. + +A TEX address (tex1..., bech32m) wraps a P2PKH key hash and takes only +transparent funds, so a wallet pays it from shielded funds in two +transactions: one to its own one-time address m/44'/133'/account'/2/index, +then a transparent-only one from that address to the TEX recipient. + +Both transactions are built by librustzcash (zcash_primitives +Builder::build_for_pczt, pczt Creator + IoFinalizer; orchard 0.16.0) for the +"all" seed, account 0, on regtest, and the sighashes are librustzcash's pczt +Signer sighashes: + + step 1 (v6, NU6.3): one 1,025,000-zat Orchard note to the one-time address, + 1,010,000 zat, fee 15,000, a 2-action Orchard bundle; + step 2 (v6 NU6.3 and v5 NU6.2): that output to the ZIP 320 example address + tex1s2rt77ggv6q989lr49rkgzmh5slsksa9khdgte, 1,000,000 zat, fee 10,000, + with no shielded bundle at all. +""" + +import hashlib + +import ecdsa +from ecdsa import SECP256k1, VerifyingKey +from ecdsa.util import sigdecode_der + +import common +from keepkeylib import messages_pb2 as proto +from keepkeylib import types_pb2 as proto_types +from keepkeylib import messages_zcash_pb2 as zcash_proto +from keepkeylib.client import CallException + +from test_msg_zcash_sign_pczt_device import ( + ADDRESS_N, + ANCHOR, + IRONWOOD_TX, + ORCHARD_TX, + bundle_digest, + header_digest, + migration_action, +) +from test_msg_zcash_transparent_shielding import ( + _b2b, + _outputs_digest, + _prevouts_digest, + _sequences_digest, + _transparent_sig_digest, +) + +H = 0x80000000 +ONE_TIME_PATH = [H + 44, H + 133, H, 2, 0] +TEX_FIRMWARE = "7.15.0" + +ONE_TIME_SCRIPT = bytes.fromhex( + '76a9142875b160968fae11ca7fdd0174825c812f24f05688ac') +ONE_TIME_T1 = 't1MZY2TFhahiyGL9fscjCAjhppXGn48oHMM' +TEX_SCRIPT = bytes.fromhex('76a9148286bf790866805397e3a947640b77a43f0b43a588ac') +TEX_ADDRESS = 'tex1s2rt77ggv6q989lr49rkgzmh5slsksa9khdgte' +TEX_T1 = 't1VmmGiyjVNeCjxDZzg7vZmd99WyzVby9yC' # the same key hash (ZIP 320) +EMPTY_SAPLING = hashlib.blake2b(b'', digest_size=32, + person=b'ZTxIdSaplingHash').digest() + +STEP1 = { + 'sighash': bytes.fromhex('981da2d23dcdd6c04e5d36aa00cca4eb6d21cd4aa1af6547bacc5ab8d9764e7d'), + 'actions': [ + { + 'is_spend': False, + 'nullifier': bytes.fromhex('a593b9cd40c49a4f447d87ed1f01b5896b1135ee7739d7fdb04ad1a6eeda232f'), + 'rk': bytes.fromhex('6742b6a24175e6157151140a7ed464e4236a78785183c58a0eadc9a00e22dea4'), + 'alpha': bytes.fromhex('0b9ad8d7306dba1cb592962db3ffec30ca18fe3cdcef51c199eaad4615b57d3e'), + 'cv_net': bytes.fromhex('a41f06ec4122d79c0442c06a04c8d9a623c87d94a1e994787ec2acfb13288587'), + 'cmx': bytes.fromhex('ff61e8171bc34a00c43a2824b016c089b467313e51e02d776dcbc13c4dc7d10f'), + 'epk': bytes.fromhex('676ed987d25b96b7ff4ef38bf414f74e884e79012ba1db7d6090e37d7e9cb126'), + 'enc': bytes.fromhex( + 'ffd7c80499607ed7ff8ccf36ea23890a40dbfbe7e1e2f4c4ecc9c719ec38bfd3' + '7022afc69a91121396c96183645bc6f2cf4a8b2c1455fb81ce815ed964e2788e' + '7db82875c8d9a6ac4235b5d1ac954b906c7181b97ed1aae6641b2d2ed4a41d20' + '5b61d2bf0faabfa6512ffdaff000525efb96acf524120155847b45e3938e30c8' + '310202deb697351458742efe591c95865f2348c220d17318dcacf183e4ae6e15' + '302a4bcea524810ae1c70d50ee0aa9dd90546e7a6345922297220454c6a97b44' + '4a926be368679a31535c95932daeb1aed9fcda3000cf0963c4105fd9bc6fd24b' + '84062be96d06debd41f20332dc4d4291ec2b2f9364ba0f6cbc6f90da6729d0ee' + 'c6417a722c38c893f7e9113698f4ecde3ec560c37d88a8bd6bd04f2b1d86a06e' + '84695c69b0333913ae81492981b4bff367998995ea689a705113346cb81ccdad' + '6cbc5fc0733b97cefb92ce0b335bab1f492ac38da4c2384c005d7e2a352467d2' + 'e8544f9664df46950a3207edcfefd983e8495f53c214f19a9024c0c54a15fa75' + 'b80166313f550dbe42fa71704620bb78ed7273d5e5af8760b330278306da8098' + 'da3cbf3a640dc60aea3642e2b59a7902e61f89d3396c25d4692881f7de250e51' + 'e72300866c789036f550c3008b3865c89101b8925fee8abcddbd08b72ae9933f' + '812f52f5d7705a105f66d0b4dfd16bde4211a08c6740c3887b1356a1744ddd81' + '6f7c6e9dd2d682df1d14603ad69aa684587ea09c2fd25f746798c604fa3d7b07' + 'cb1ab7170a18b380cdd2fd3d539039d21a1e264d4cc9803170c3931408d2fd2c' + '16310cf7'), + 'out': bytes.fromhex( + '8e54a7b6418db19c27eb768c3c754113eaa575de83023862634fb40ccb87c17c' + '043be6f0d883754e2fd337dae19d79fe27c4904ab28ffc360681ffb6f8e871ed' + 'fd6684d6b5e23c4e0ec28d3a951f5d3f'), + 'recipient': bytes.fromhex( + '66faa653531d4a8acdf5096f756577b19962df6615641e5fe2db3a324970a7ff' + 'e546a1f97b073e94f7b238'), + 'rseed': bytes.fromhex('716070a992fff0e13dd67cc3ddaef4ada426aa5f4ec0f13668a6f4f537ad545e'), + 'value': 0, + }, + { + 'is_spend': True, + 'nullifier': bytes.fromhex('0440da65e51ce699977111262432473c28e06b12c3e5e38fc742f35b0fd02429'), + 'rk': bytes.fromhex('fec66ad4c564961f7af701ffbc1f1e2eb3abf8b4bbf1404d60aa9efc0881e585'), + 'alpha': bytes.fromhex('83969789048b1dc71a91d523c61624cc84894ddd64c4b8dc4380e08a327f4820'), + 'cv_net': bytes.fromhex('c7343ce3e707ccdbfac1e3cae1acbef5701e793e107efe264d027af10ab73e31'), + 'cmx': bytes.fromhex('a34f6a687d5ad6aae53f0225144324a070a7de1066a9c592af9d51ea0da78b1b'), + 'epk': bytes.fromhex('0e4237147546d913c2273bb3a70f6e3cbbd8b9f839c89cc1f8a26ecaa2aba986'), + 'enc': bytes.fromhex( + 'd878f9142e82cfdcc5abb5f3d6b4b32978a6b8f3163cf48cd167abfb8512e352' + '04e7edd316c39e5c9a01be0efab1707355bb93d9b968c50820f27b6bb20415a6' + '0213dbf69f95554b56bac05cceae2f2f227b7c03925e87374fb1f9c3c0d723e8' + '9fc80fa61c863fc04aa061c91cc81c484d086d2ab66125532d89a530ee6f07e6' + '7941805f62784c8a8dec22a230506f9cb74e4c7dcaff00c4224543b052aa9f6b' + '6db1837090f7fd87536d326866a8694dbe41b3b388cca38e6e546af80af68e9f' + '8b24abb381fe57b6731dd686c179bea116a8e3be9fe041488d46634bda302abd' + '027249fb2508bfc5260b286f0ab66a9c32c07fe1796c767b266d30d752e77840' + '320ba9d7669c0ed9fe5b3c488856e84ab3674e4deed92225c4be2f31f56d4963' + 'b4bfc5f0fe686fc01950a9c5b6a95024086c566bfa7f1ce88fd6785660e60cbc' + '0b2e881a4dacfdea6b9158717dd5d0aba72b30dd067f7c32b1e08f9a714a5965' + '6567ea0fa3dbc31c12cdacbcefb9c42d832ae8cfea003fea36a32327f44ce8ac' + '0d9aff4bccf03539cf037d5c2dfb114c2b027328660b0abbab07554015b9ab8d' + '284db47c04b117e2a4365cd14f10c0416082d8615e36fa1bc5243c9d76902b99' + 'c87fb5d635b94157915fd979747247b5294006d2a74dce6c7c666e3d9c1bea5f' + 'b0124b846b22e217c6732817a13b72111395f496220af07bc8732e7d4a0f353c' + 'ff5b4c453915b5bee84ec00f817f51ff05d09138e7460727637641b178982a53' + '3ca4618a251b2f92d7b73e5d31f3d56693964a014418d767dc23c6b522d2a695' + '2a3d3200'), + 'out': bytes.fromhex( + '93148f0d468fa8c829f1499a4fa7acb16a99a2cd42b958397dffb46b2e34370e' + 'a2168063cfe245932eb4d828a461ad6a1f9951f2752b2ff9333893aa9045008a' + '1b0bf265077c00d84d6617524e341439'), + 'recipient': bytes.fromhex( + 'da973031634a8938ad1c480f978780693ec7709ba5caf58d8a7eb945586cbed6' + '45520f17387437bcfdc216'), + 'rseed': bytes.fromhex('ab6fed1774ced71e695168fc591b9cfc196b7297ac0486db880fb455b1a0f3ee'), + 'value': 0, + }, + ], +} + +STEP2 = { + 6: dict(IRONWOOD_TX, + prevout_txid=bytes.fromhex( + '981da2d23dcdd6c04e5d36aa00cca4eb6d21cd4aa1af6547bacc5ab8d9764e7d'), + sighash=bytes.fromhex( + '03e328bb6a70c20bd803375f2da51bcd56d1e46fba7f6408752de160fc7234a5')), + 5: dict(ORCHARD_TX, + prevout_txid=bytes.fromhex( + '7d2c9e83172282b3d4521c9c16632bae0ef19dbaaa8188cb46761f510574b621'), + sighash=bytes.fromhex( + '89c5074214b150ff73a3d80fa893e1b66c41e96be1f67b504740a27b16a4f6e6')), +} + + +def transparent_digest_no_inputs(outputs): + """ZIP-244 T.2: with no transparent input the shielded sighash commits to + the transparent txid digest, not the S.2 signature digest.""" + return _b2b(b'ZTxIdTranspaHash', _prevouts_digest([]) + + _sequences_digest([]) + _outputs_digest(outputs)) + + +def step1_kwargs(output): + actions = [migration_action(v) for v in STEP1['actions']] + tx = IRONWOOD_TX + kwargs = dict(tx) + kwargs.update({ + 'address_n': ADDRESS_N, + 'actions': actions, + 'account': 0, + 'fee': 15000, + 'lock_time': 0, + 'expiry_height': 69120, + 'orchard_flags': 0x03, + 'orchard_value_balance': 1025000, + 'orchard_anchor': ANCHOR, + 'header_digest': header_digest(tx['tx_version'], tx['version_group_id'], + tx['branch_id'], 0, 69120), + 'orchard_digest': bundle_digest(actions, False, 6, flags=0x03, + value_balance=1025000), + 'transparent_outputs': [output], + 'transparent_digest': transparent_digest_no_inputs([output]), + }) + return kwargs + + +def step2_parts(version): + tx = STEP2[version] + output = {'amount': 1000000, 'script_pubkey': TEX_SCRIPT, 'is_tex': True} + inp = { + 'address_n': ONE_TIME_PATH, + 'amount': 1010000, + 'prevout_txid': tx['prevout_txid'], + 'prevout_index': 0, + 'sequence': 0xffffffff, + 'script_pubkey': ONE_TIME_SCRIPT, + } + return tx, output, inp + + +def step2_kwargs(version, output, inp): + tx = STEP2[version] + kwargs = {k: tx[k] for k in ('tx_version', 'version_group_id', 'branch_id')} + kwargs.update({ + 'address_n': ADDRESS_N, + 'actions': [], + 'account': 0, + 'fee': 10000, + 'lock_time': 0, + 'expiry_height': 69121, + 'orchard_flags': 0, + 'orchard_value_balance': 0, + 'orchard_anchor': ANCHOR, + 'header_digest': header_digest(tx['tx_version'], tx['version_group_id'], + tx['branch_id'], 0, 69121), + # The empty bundle digest: ZIP 229 for v6, ZIP 244 for v5. + 'orchard_digest': hashlib.blake2b( + b'', digest_size=32, + person=b'ZTxIdOrchardH_v6' if version == 6 + else b'ZTxIdOrchardHash').digest(), + 'sapling_digest': EMPTY_SAPLING, + 'transparent_outputs': [output], + 'transparent_inputs': [inp], + 'transparent_digest': _transparent_sig_digest([inp], [output]), + 'return_transparent_signatures': True, + }) + return kwargs + + +class TestZcashTex(common.KeepKeyTest): + + def setUp(self): + super(TestZcashTex, self).setUp() + self.requires_firmware(TEX_FIRMWARE) + self.requires_fullFeature() + self.requires_message("ZcashSignPCZT") + self.setup_mnemonic_allallall() + + def _capture_confirm_text(self): + screens = [] + original = self.client.callback_ButtonRequest + + def capture(msg): + # A paged confirmation asks once per page; keep each one once. + title, body = self.client.debug.read_confirm_text() + if not screens or screens[-1][1:] != (title, body): + screens.append((msg.code, title, body)) + return original(msg) + + self.client.callback_ButtonRequest = capture + return screens + + def _one_time_pubkey(self): + node = self.client.get_public_node(ONE_TIME_PATH, coin_name='Zcash').node + return bytes(node.public_key) + + def _refused(self, kwargs, message): + with self.assertRaises(CallException) as ctx: + self.client.zcash_sign_pczt(**kwargs) + self.assertEqual(ctx.exception.args[1], message) + + def test_one_time_address_matches_librustzcash(self): + """The fixture's one-time address is the device's own key at + m/44'/133'/0'/2/0 (TransparentKeyScope::EPHEMERAL).""" + pubkey = self._one_time_pubkey() + self.assertEqual( + ONE_TIME_SCRIPT, + b'\x76\xa9\x14' + hashlib.new( + 'ripemd160', hashlib.sha256(pubkey).digest()).digest() + + b'\x88\xac') + + def test_step1_pays_the_own_one_time_address(self): + """With its path, the output is proven to pay the account's one-time + address and is shown as a transfer to yourself; the one wallet spend + is signed.""" + self.requires_firmware(TEX_FIRMWARE) + screens = self._capture_confirm_text() + output = {'amount': 1010000, 'script_pubkey': ONE_TIME_SCRIPT, + 'address_n': ONE_TIME_PATH} + + result = self.client.zcash_sign_pczt(**step1_kwargs(output)) + + self.assertIsInstance(result, zcash_proto.ZcashSignedPCZT) + self.assertEqual(len(result.signatures), 1) + self.assertEqual( + [(title, body) for code, title, body in screens + if code == proto_types.ButtonRequest_ConfirmOutput], + [('Zcash Output', 'To your one-time address:\n%s\n' + 'Amount: 0.01010000 ZEC' % ONE_TIME_T1)]) + self.assertEqual(screens[-1][1:], + ('Zcash Fee', + 'Confirm transaction fee?\n0.00015000 ZEC')) + + def test_step1_without_a_path_is_a_plain_send(self): + """Without a path the device cannot know the address is the user's own, + so it is shown as a payment to that t1 address.""" + self.requires_firmware(TEX_FIRMWARE) + screens = self._capture_confirm_text() + output = {'amount': 1010000, 'script_pubkey': ONE_TIME_SCRIPT} + + result = self.client.zcash_sign_pczt(**step1_kwargs(output)) + + self.assertEqual(len(result.signatures), 1) + self.assertEqual( + [body for code, _, body in screens + if code == proto_types.ButtonRequest_ConfirmOutput], + ['Send transparent ZEC?\n%s\nAmount: 0.01010000 ZEC' % ONE_TIME_T1]) + + def test_step1_refuses_a_path_that_does_not_pay_the_script(self): + self.requires_firmware(TEX_FIRMWARE) + for path, message in ( + (ONE_TIME_PATH[:4] + [1], + 'Transparent output script does not match path'), + (ONE_TIME_PATH[:3] + [0, 0], + 'Output path must be a one-time address'), + ([H + 44, H + 133, H + 1, 2, 0], + 'Account does not match approved session')): + output = {'amount': 1010000, 'script_pubkey': ONE_TIME_SCRIPT, + 'address_n': path} + self._refused(step1_kwargs(output), message) + + def test_step2_signs_a_transparent_only_transaction(self): + """No shielded action: the TEX recipient is shown as tex1..., then the + fee and the input, and the one ECDSA signature verifies under + librustzcash's sighash, in v6 and v5.""" + self.requires_firmware(TEX_FIRMWARE) + pubkey = self._one_time_pubkey() + key = VerifyingKey.from_string(pubkey, curve=SECP256k1) + for version in (6, 5): + tx, output, inp = step2_parts(version) + screens = self._capture_confirm_text() + + result, signatures = self.client.zcash_sign_pczt( + **step2_kwargs(version, output, inp)) + + self.assertIsInstance(result, zcash_proto.ZcashSignedPCZT) + self.assertEqual(len(result.signatures), 0) + self.assertEqual(len(signatures), 1) + self.assertTrue(key.verify_digest(signatures[0], tx['sighash'], + sigdecode=sigdecode_der)) + self.assertEqual( + [(title, body) for _, title, body in screens], + [('Zcash Transparent', 'Send transparent ZEC?\n' + 'Fee: 0.00010000 ZEC\nInputs: 1\nOutputs: 1'), + ('Zcash Output', 'Send to TEX address?\n%s\n' + 'Amount: 0.01000000 ZEC' % TEX_ADDRESS), + ('Zcash Fee', 'Confirm transaction fee?\n0.00010000 ZEC'), + ('Sign Input', + 'Sign transparent input?\nInput 1: 0.01010000 ZEC')]) + + def test_step2_without_the_hint_shows_the_t1_address(self): + """is_tex is only a display hint: without it the same key hash is shown + in its t1 form, and the transaction signs the same.""" + self.requires_firmware(TEX_FIRMWARE) + tx, output, inp = step2_parts(6) + del output['is_tex'] + screens = self._capture_confirm_text() + + _, signatures = self.client.zcash_sign_pczt( + **step2_kwargs(6, output, inp)) + + self.assertEqual(len(signatures), 1) + self.assertEqual( + [body for code, _, body in screens + if code == proto_types.ButtonRequest_ConfirmOutput], + ['Send transparent ZEC?\n%s\nAmount: 0.01000000 ZEC' % TEX_T1]) + + def test_transparent_only_refusals(self): + """A transparent-only request is refused with no signature when it + claims a shielded bundle, a non-empty Sapling digest, or an input path + outside the session account or past the one-time scope.""" + self.requires_firmware(TEX_FIRMWARE) + tx, output, inp = step2_parts(6) + other_account = dict(inp, address_n=[H + 44, H + 133, H + 1, 2, 0]) + change_3 = dict(inp, address_n=ONE_TIME_PATH[:3] + [3, 0]) + cases = ( + ({'orchard_digest': b'\x01' * 32}, + 'Transparent transaction must have empty shielded bundles'), + ({'orchard_value_balance': 5000}, + 'Transparent transaction must have empty shielded bundles'), + ({'sapling_digest': b'\x11' * 32}, 'Sapling not supported'), + ({'transparent_inputs': [other_account], + 'transparent_digest': _transparent_sig_digest( + [other_account], [output])}, + 'Account does not match approved session'), + ({'transparent_inputs': [change_3], + 'transparent_digest': _transparent_sig_digest( + [change_3], [output])}, + 'Change must be 0, 1 or 2'), + ) + for overrides, message in cases: + kwargs = step2_kwargs(6, output, inp) + kwargs.update(overrides) + self._refused(kwargs, message) + + def test_no_action_needs_a_transparent_input(self): + """n_actions 0 with nothing to sign is refused before any screen.""" + self.requires_firmware(TEX_FIRMWARE) + tx, output, inp = step2_parts(6) + kwargs = step2_kwargs(6, output, inp) + for key in ('actions', 'transparent_outputs', 'transparent_inputs', + 'return_transparent_signatures'): + del kwargs[key] + kwargs.update(n_actions=0, n_transparent_outputs=1) + response = self.client.call_raw(zcash_proto.ZcashSignPCZT(**kwargs)) + self.assertIsInstance(response, proto.Failure) + self.assertEqual(response.message, 'No actions specified') diff --git a/tests/test_msg_zcash_transparent_shielding.py b/tests/test_msg_zcash_transparent_shielding.py index cd65e193..730c9026 100644 --- a/tests/test_msg_zcash_transparent_shielding.py +++ b/tests/test_msg_zcash_transparent_shielding.py @@ -326,7 +326,7 @@ def test_rejects_short_path(self): def test_rejects_bad_change(self): self._assert_path_rejected( - [H + 44, H + 133, H, 7, 0], "change must be 0 or 1") + [H + 44, H + 133, H, 7, 0], "change must be 0") def test_rejects_hardened_index(self): self._assert_path_rejected( diff --git a/tests/test_storage_version_gate.py b/tests/test_storage_version_gate.py index 437e8957..0950dca1 100644 --- a/tests/test_storage_version_gate.py +++ b/tests/test_storage_version_gate.py @@ -482,6 +482,10 @@ def _free_port_pair(): raise RuntimeError("no free UDP port pair for the emulator") +class _PortTaken(Exception): + pass + + class Emulator(object): """One kkemu process over one flash image, restartable. @@ -511,7 +515,21 @@ def _ping(self): s.close() def boot(self): + # _free_port_pair() can only say the pair was free a moment ago; + # another process may bind it before kkemu does. kkemu then exits + # with "Failed to bind socket", and the image is untouched, so try + # a fresh pair rather than fail the test on a port race. + for _ in range(5): + try: + return self._boot_once() + except _PortTaken: + self.port = _free_port_pair() + raise RuntimeError("emulator could not bind a UDP port pair") + + def _boot_once(self): assert self.proc is None, "already booted" + log_path = os.path.join(self.workdir, "emu.log") + log_start = os.path.getsize(log_path) if os.path.exists(log_path) else 0 env = dict(os.environ, KEEPKEY_UDP_PORT=str(self.port)) with open(os.path.join(self.workdir, "emu.log"), "ab") as log: self.proc = subprocess.Popen( @@ -524,6 +542,10 @@ def boot(self): for _ in range(100): time.sleep(0.1) if self.proc.poll() is not None: + with open(log_path, "rb") as log: + log.seek(log_start) + if b"Failed to bind socket" in log.read(): + raise _PortTaken() raise RuntimeError( "emulator exited rc=%s before answering; see %s" % (self.proc.returncode, os.path.join(self.workdir, "emu.log"))) diff --git a/tests/unit/test_eos_updateauth_vector.py b/tests/unit/test_eos_updateauth_vector.py index 6762f8c8..690a6220 100644 --- a/tests/unit/test_eos_updateauth_vector.py +++ b/tests/unit/test_eos_updateauth_vector.py @@ -33,7 +33,7 @@ def var(x): auth = ( struct.pack('