4141# the full value: v = 2 * chain_id + 35 + v_bit
4242MAX_CHAIN_ID = (0xFFFF_FFFF - 36 ) // 2
4343
44+ DATA_LEFT : bytearray | None = None
45+
4446
4547@with_keychain_from_chain_id
4648async def sign_tx (
@@ -217,10 +219,15 @@ async def sign_tx(
217219 rlp .write_header (sha , data_total , rlp .STRING_HEADER_BYTE , data )
218220 sha .extend (data )
219221
220- while data_left > 0 :
221- resp = await send_request_chunk (ctx , data_left )
222- data_left -= len (resp .data_chunk )
223- sha .extend (resp .data_chunk )
222+ global DATA_LEFT
223+ if DATA_LEFT is not None :
224+ sha .extend (DATA_LEFT )
225+ DATA_LEFT = None
226+ else :
227+ while data_left > 0 :
228+ resp = await send_request_chunk (ctx , data_left )
229+ data_left -= len (resp .data_chunk )
230+ sha .extend (resp .data_chunk )
224231
225232 # eip 155 replay protection
226233 rlp .write (sha , msg .chain_id )
@@ -360,7 +367,7 @@ def is_safe_exec_transaction(msg: EthereumSignTxAny) -> bool:
360367 if (
361368 len (msg .to ) in (40 , 42 )
362369 and len (msg .value ) == 0
363- and 437 <= msg .data_length <= 1024
370+ and 437 <= msg .data_length
364371 and msg .data_initial_chunk [:16 ]
365372 == b"\x6a \x76 \x12 \x02 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 "
366373 # 0x6a761202 == keccak("execTransaction(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,bytes)")[:4].hex()
@@ -369,6 +376,15 @@ def is_safe_exec_transaction(msg: EthereumSignTxAny) -> bool:
369376 return False
370377
371378
379+ def get_remaining_data () -> bytearray | None :
380+ return DATA_LEFT
381+
382+
383+ def reset_data_left () -> None :
384+ global DATA_LEFT
385+ DATA_LEFT = None
386+
387+
372388async def handle_safe_tx (
373389 ctx : wire .Context , msg : EthereumSignTxAny , from_addr : str , is_eip1559 : bool = True
374390) -> None :
@@ -391,7 +407,17 @@ async def handle_safe_tx(
391407 data_len = int .from_bytes (data [308 :340 ], "big" )
392408 call_data = None
393409 call_method = None
394- if data_len > 0 :
410+ data_left = msg .data_length - len (msg .data_initial_chunk )
411+ global DATA_LEFT
412+ if data_left > 0 :
413+ DATA_LEFT = bytearray (data_left )
414+ DATA_LEFT [:] = bytes ()
415+ while data_left > 0 :
416+ resp = await send_request_chunk (ctx , data_left )
417+ data_left -= len (resp .data_chunk )
418+ DATA_LEFT .extend (resp .data_chunk )
419+
420+ if data_len > 0 and DATA_LEFT is None :
395421 nest_data = data [340 : 340 + data_len ]
396422 if (
397423 len (nest_data ) == 68
@@ -455,9 +481,18 @@ async def handle_safe_tx(
455481 else :
456482 call_data = hexlify (nest_data ).decode ()
457483 call_method = None
458- assert signature_pos >= 340 + data_len
459- signatures_len = int .from_bytes (data [signature_pos : signature_pos + 20 ], "big" )
460- signatures = data [signature_pos + 20 : signature_pos + 20 + signatures_len ]
484+ assert signature_pos >= 340 + data_len , "invalid call data"
485+ if DATA_LEFT is not None :
486+ remaining_data = data [340 :] + DATA_LEFT
487+ nest_data = remaining_data [:data_len ]
488+ call_data = hexlify (nest_data ).decode ()
489+ call_method = None
490+ signature_data = remaining_data [signature_pos - 340 :]
491+ else :
492+ signature_data = data [signature_pos :]
493+ signatures_len = int .from_bytes (signature_data [:20 ], "big" )
494+ assert len (signature_data ) >= 20 + signatures_len , "invalid call data length"
495+ signatures = signature_data [20 : 20 + signatures_len ]
461496 if not is_eip1559 :
462497 from ..layout import require_confirm_safe_exec_transaction
463498
@@ -617,7 +652,7 @@ def check(msg: EthereumSignTx) -> None:
617652
618653 if len (msg .gas_price ) + len (msg .gas_limit ) > 30 :
619654 raise wire .DataError ("Fee overflow" )
620-
655+ reset_data_left ()
621656 check_common_fields (msg )
622657
623658
0 commit comments