22
33from trezor .utils import BufferReader
44from trezor .wire import DataError
5+ from trezor import log
56
67from .yielding_vaults import lookup_vault
78
1920FUNC_SIG_DEPOSIT = b"\x6e \x55 \x3f \x65 "
2021FUNC_SIG_WITHDRAW = b"\xb4 \x60 \xaf \x94 "
2122FUNC_SIG_REDEEM = b"\xba \x08 \x76 \x52 "
23+ FUNC_SIG_CLAIM = b"\x71 \xee \x95 \xc0 "
2224
2325if __debug__ :
2426 from trezor .crypto .hashlib import sha3_256
3537 FUNC_SIG_REDEEM
3638 == sha3_256 (b"redeem(uint256,address,address)" , keccak = True ).digest ()[:4 ]
3739 )
38-
40+ assert (
41+ FUNC_SIG_CLAIM
42+ == sha3_256 (b"claim(address[],address[],uint256[],bytes32[][])" , keccak = True ).digest ()[:4 ]
43+ )
3944
4045def get_approver (
4146 msg : MsgInSignTx ,
47+ initial_data : AnyBytes ,
4248 network : EthereumNetworkInfo ,
4349 address_bytes : AnyBytes ,
4450 maximum_fee : str ,
4551 fee_items : Iterable [StrPropertyType ],
4652 sender_bytes : AnyBytes ,
4753) -> tuple [ConfirmDataFn , Coroutine [Any , Any , None ]] | None :
4854
55+ log .debug ("SS DEBUG" , "inside yielding get_approver" )
56+ log .debug ("SS DEBUG" , "data_length=%d initial_data_len=%d" , msg .data_length , len (initial_data ))
57+ log .debug ("SS DEBUG" , "to=%s chain_id=%d" , msg .to , network .chain_id )
58+ log .debug ("SS DEBUG" , "sender_bytes=%s" , sender_bytes )
59+
4960 from .clear_signing import SC_FUNC_SIG_BYTES
5061 from .helpers import get_progress_indicator
5162
52- if msg .data_length > len (msg .data_initial_chunk ):
63+ if msg .data_length > len (initial_data ):
64+ log .debug ("SS DEBUG" , "get_approver: data exceeds buffer, returning None (data_length=%d > initial_data=%d)" , msg .data_length , len (initial_data ))
5365 return None
5466
55- data_reader = BufferReader (msg . data_initial_chunk )
67+ data_reader = BufferReader (initial_data )
5668 if data_reader .remaining_count () < SC_FUNC_SIG_BYTES :
69+ log .debug ("SS DEBUG" , "get_approver: not enough data for func sig, remaining=%d" , data_reader .remaining_count ())
5770 return None
5871
5972 is_known_vault , vault_str , asset_token , vault_token = lookup_vault (
6073 network , address_bytes
6174 )
75+ log .debug ("SS DEBUG" , "lookup_vault: is_known=%s vault_str=%s" , is_known_vault , vault_str )
76+ log .debug ("SS DEBUG" , "lookup_vault: asset_token=%s vault_token=%s" , asset_token .symbol if asset_token else None , vault_token .symbol if vault_token else None )
6277
6378 handler = None
6479 func_sig = data_reader .read_memoryview (SC_FUNC_SIG_BYTES )
80+ log .debug ("SS DEBUG" , "func_sig=%s" , func_sig )
81+ log .debug ("SS DEBUG" , "func_sig matches DEPOSIT=%s WITHDRAW=%s REDEEM=%s CLAIM=%s" ,
82+ func_sig == FUNC_SIG_DEPOSIT ,
83+ func_sig == FUNC_SIG_WITHDRAW ,
84+ func_sig == FUNC_SIG_REDEEM ,
85+ func_sig == FUNC_SIG_CLAIM ,
86+ )
6587 if func_sig in (FUNC_SIG_DEPOSIT , FUNC_SIG_WITHDRAW , FUNC_SIG_REDEEM ):
6688 token = vault_token if func_sig == FUNC_SIG_REDEEM else asset_token
6789 handler = _prepare_vault_tx (
@@ -76,10 +98,25 @@ def get_approver(
7698 token = token ,
7799 func_sig = func_sig ,
78100 )
101+ elif func_sig == FUNC_SIG_CLAIM :
102+ log .debug ("SS DEBUG" , "get_approver: routing to _prepare_claim_rewards" )
103+ handler = _prepare_claim_rewards (
104+ data_reader = data_reader ,
105+ msg = msg ,
106+ network = network ,
107+ maximum_fee = maximum_fee ,
108+ fee_items = fee_items ,
109+ sender_bytes = sender_bytes ,
110+ is_known_vault = is_known_vault ,
111+ )
112+ else :
113+ log .debug ("SS DEBUG" , "get_approver: func_sig not recognized, handler=None -> blind signing" )
79114
115+ log .debug ("SS DEBUG" , "get_approver: handler=%s" , handler )
80116 if handler is not None :
81117 progress_indicator = get_progress_indicator (msg .data_length )
82118 return progress_indicator , handler
119+ log .debug ("SS DEBUG" , "get_approver: returning None -> will fall through to blind/clear signing" )
83120 return None
84121
85122
@@ -119,7 +156,7 @@ def _prepare_vault_tx(
119156 ):
120157 raise ValueError
121158 except (ValueError , EOFError , InvalidFunctionCall ):
122- raise DataError ("Invalid data for ERC-4626 vault transaction" )
159+ raise DataError (f "Invalid data for ERC-4626 vault transaction. Remaining data count: { data_reader . remaining_count () } , amount: { amount } , eth_Value: { int . from_bytes ( msg . value , 'big' ) } " )
123160
124161 if not _is_vault_tx_safe (is_known_vault , sender_bytes , receiver_bytes , owner_bytes ):
125162 return None
@@ -135,22 +172,126 @@ def _prepare_vault_tx(
135172 )
136173
137174
175+ def _prepare_claim_rewards (
176+ data_reader : BufferReader ,
177+ msg : MsgInSignTx ,
178+ network : EthereumNetworkInfo ,
179+ maximum_fee : str ,
180+ fee_items : Iterable [StrPropertyType ],
181+ sender_bytes : AnyBytes ,
182+ is_known_vault : bool ,
183+ ) -> "Coroutine[Any, Any, None] | None" :
184+ from .clear_signing import InvalidFunctionCall , parse_address
185+ from .layout import require_confirm_claim_rewards
186+ from .yielding_vaults import get_token_label
187+
188+ log .debug ("SS DEBUG" , "_prepare_claim_rewards: entered, is_known_vault=%s" , is_known_vault )
189+ log .debug ("SS DEBUG" , "_prepare_claim_rewards: sender_bytes=%s" , sender_bytes )
190+
191+ # claim(address[] users, address[] tokens, uint256[] amounts, bytes32[][] proofs)
192+ # All 4 params are dynamic; first 128 bytes are their ABI offsets.
193+ try :
194+ data = data_reader .read_memoryview (data_reader .remaining_count ())
195+ log .debug ("SS DEBUG" , "_prepare_claim_rewards: data len=%d" , len (data ))
196+
197+ if len (data ) < 128 :
198+ log .debug ("SS DEBUG" , "_prepare_claim_rewards: data too short (<128), raising InvalidFunctionCall" )
199+ raise InvalidFunctionCall
200+
201+ users_param_offset = int .from_bytes (data [0 :32 ], "big" )
202+ tokens_param_offset = int .from_bytes (data [32 :64 ], "big" )
203+ amounts_param_offset = int .from_bytes (data [64 :96 ], "big" )
204+ proofs_param_offset = int .from_bytes (data [96 :128 ], "big" )
205+ log .debug ("SS DEBUG" , "offsets: users=%d tokens=%d amounts=%d proofs=%d" , users_param_offset , tokens_param_offset , amounts_param_offset , proofs_param_offset )
206+
207+ if proofs_param_offset + 32 > len (data ):
208+ log .debug ("SS DEBUG" , "_prepare_claim_rewards: proofs_param_offset=%d + 32 > data len=%d, raising InvalidFunctionCall" , proofs_param_offset , len (data ))
209+ raise InvalidFunctionCall
210+
211+ users_array_length = int .from_bytes (data [users_param_offset : users_param_offset + 32 ], "big" )
212+ tokens_array_length = int .from_bytes (data [tokens_param_offset : tokens_param_offset + 32 ], "big" )
213+ amounts_array_length = int .from_bytes (data [amounts_param_offset : amounts_param_offset + 32 ], "big" )
214+ proofs_array_length = int .from_bytes (data [proofs_param_offset : proofs_param_offset + 32 ], "big" )
215+ log .debug ("SS DEBUG" , "array lengths: users=%d tokens=%d amounts=%d proofs=%d" , users_array_length , tokens_array_length , amounts_array_length , proofs_array_length )
216+
217+ if (
218+ users_array_length != tokens_array_length
219+ or tokens_array_length != amounts_array_length
220+ or amounts_array_length != proofs_array_length
221+ ):
222+ log .debug ("SS DEBUG" , "_prepare_claim_rewards: array length mismatch! users=%d tokens=%d amounts=%d proofs=%d" , users_array_length , tokens_array_length , amounts_array_length , proofs_array_length )
223+ raise ValueError
224+
225+ user_address = parse_address (data [users_param_offset + 32 : users_param_offset + 64 ])
226+ log .debug ("SS DEBUG" , "user_address[0]=%s type=%s" , user_address , type (user_address ))
227+ if not isinstance (user_address , bytes ):
228+ log .debug ("SS DEBUG" , "_prepare_claim_rewards: user_address is not bytes, raising InvalidFunctionCall" )
229+ raise InvalidFunctionCall
230+
231+ # Check if all users are the same. We validate if it's the sender in _is_vault_tx_safe()
232+ # If either of these conditions are unmet, we revert to blind signing (return None).
233+ for i in range (1 , users_array_length ):
234+ addr_start = users_param_offset + 32 + i * 32
235+ other = parse_address (data [addr_start : addr_start + 32 ])
236+ log .debug ("SS DEBUG" , "users[%d]=%s == users[0]=%s -> %s" , i , other , user_address , other == user_address )
237+ if other != user_address :
238+ log .debug ("SS DEBUG" , "_prepare_claim_rewards: user[%d] != user[0], returning None (blind sign)" , i )
239+ return None
240+
241+ token_labels : list [str ] = []
242+ for i in range (tokens_array_length ):
243+ addr_start = tokens_param_offset + 32 + i * 32
244+ addr = parse_address (data [addr_start : addr_start + 32 ])
245+ if not isinstance (addr , bytes ):
246+ log .debug ("SS DEBUG" , "_prepare_claim_rewards: token[%d] addr not bytes, raising InvalidFunctionCall" , i )
247+ raise InvalidFunctionCall
248+ label = get_token_label (addr , network )
249+ log .debug ("SS DEBUG" , "token[%d] addr=%s label=%s" , i , addr , label )
250+ token_labels .append (label )
251+
252+ except (ValueError , EOFError , InvalidFunctionCall ):
253+ raise DataError ("Invalid data for claim rewards transaction" )
254+
255+ log .debug ("SS DEBUG" , "_prepare_claim_rewards: token_labels=%s" , token_labels )
256+ log .debug ("SS DEBUG" , "_prepare_claim_rewards: calling _is_vault_tx_safe sender=%s user_address=%s" , sender_bytes , user_address )
257+
258+ if not _is_vault_tx_safe (is_known_vault , sender_bytes , user_address ):
259+ log .debug ("SS DEBUG" , "_prepare_claim_rewards: _is_vault_tx_safe returned False, returning None" )
260+ return None
261+
262+ log .debug ("SS DEBUG" , "_prepare_claim_rewards: all checks passed, returning confirm coroutine" )
263+ return require_confirm_claim_rewards (
264+ address_n = msg .address_n ,
265+ maximum_fee = maximum_fee ,
266+ fee_info_items = fee_items ,
267+ token_labels = token_labels ,
268+ )
269+
138270def _is_vault_tx_safe (
139271 is_known_vault : bool ,
140272 sender_bytes : AnyBytes ,
141273 receiver_bytes : AnyBytes ,
142274 owner_bytes : AnyBytes | None = None ,
143275) -> bool :
144276
277+ log .debug ("SS DEBUG" , "_is_vault_tx_safe: is_known_vault=%s" , is_known_vault )
278+ log .debug ("SS DEBUG" , "_is_vault_tx_safe: sender_bytes=%s" , sender_bytes )
279+ log .debug ("SS DEBUG" , "_is_vault_tx_safe: receiver_bytes=%s" , receiver_bytes )
280+ log .debug ("SS DEBUG" , "_is_vault_tx_safe: sender==receiver -> %s" , receiver_bytes == sender_bytes )
281+
145282 is_calldata_safe = receiver_bytes == sender_bytes
146283 if owner_bytes is not None :
147284 # Withdraw/redeem transaction
285+ log .debug ("SS DEBUG" , "_is_vault_tx_safe: owner_bytes=%s sender==owner -> %s" , owner_bytes , owner_bytes == sender_bytes )
148286 is_calldata_safe = is_calldata_safe and owner_bytes == sender_bytes
149287
288+ log .debug ("SS DEBUG" , "_is_vault_tx_safe: is_calldata_safe=%s" , is_calldata_safe )
150289 if is_calldata_safe :
151290 return True
152291 else :
153292 # Hard fail for known (Trezor) vaults, blind sign for unknown vaults
154293 if is_known_vault :
294+ log .debug ("SS DEBUG" , "_is_vault_tx_safe: known vault mismatch -> raising DataError" )
155295 raise DataError ("Vault tx: Signer receiver mismatch" )
296+ log .debug ("SS DEBUG" , "_is_vault_tx_safe: unknown vault mismatch -> returning False (blind sign)" )
156297 return False
0 commit comments