@@ -5,8 +5,13 @@ use ton_contracts::wallet::v4r2::{WalletV4R2Op, WalletV4R2SignBody};
55use crate :: error:: WasmTonError ;
66use crate :: transaction:: Transaction ;
77
8- /// Body parse result: (opcode, memo, jetton_transfer)
9- type BodyParseResult = ( Option < u32 > , Option < String > , Option < JettonTransferFields > ) ;
8+ /// Body parse result: (opcode, memo, jetton_transfer, withdraw_amount)
9+ type BodyParseResult = (
10+ Option < u32 > ,
11+ Option < String > ,
12+ Option < JettonTransferFields > ,
13+ Option < u64 > ,
14+ ) ;
1015
1116/// Transaction type enum
1217#[ derive( Debug , Clone , PartialEq , Eq ) ]
@@ -65,6 +70,8 @@ pub struct ParsedSendAction {
6570 pub state_init : bool ,
6671 pub memo : Option < String > ,
6772 pub jetton_transfer : Option < JettonTransferFields > ,
73+ /// Withdraw amount encoded in the message body (SingleNominator/Whales withdrawal types).
74+ pub withdraw_amount : Option < u64 > ,
6875}
6976
7077/// A fully parsed TON transaction
@@ -143,7 +150,8 @@ fn parse_sign_body_actions(
143150 let state_init = msg. init . is_some ( ) ;
144151
145152 // Parse body
146- let ( body_opcode, memo, jetton_transfer) = parse_message_body ( & msg. body ) ?;
153+ let ( body_opcode, memo, jetton_transfer, withdraw_amount) =
154+ parse_message_body ( & msg. body ) ?;
147155
148156 parsed. push ( ParsedSendAction {
149157 mode : action. mode ,
@@ -159,6 +167,7 @@ fn parse_sign_body_actions(
159167 state_init,
160168 memo,
161169 jetton_transfer,
170+ withdraw_amount,
162171 } ) ;
163172 }
164173 Ok ( parsed)
@@ -173,12 +182,12 @@ fn parse_message_body(body: &Cell) -> Result<BodyParseResult, WasmTonError> {
173182
174183 // Empty body
175184 if bits_left == 0 {
176- return Ok ( ( None , None , None ) ) ;
185+ return Ok ( ( None , None , None , None ) ) ;
177186 }
178187
179188 // Need at least 32 bits for opcode
180189 if bits_left < 32 {
181- return Ok ( ( None , None , None ) ) ;
190+ return Ok ( ( None , None , None , None ) ) ;
182191 }
183192
184193 let opcode: u32 = parser
@@ -196,16 +205,34 @@ fn parse_message_body(body: &Cell) -> Result<BodyParseResult, WasmTonError> {
196205 } ;
197206 }
198207 let memo = String :: from_utf8_lossy ( & bytes) . to_string ( ) ;
199- return Ok ( ( Some ( 0 ) , Some ( memo) , None ) ) ;
208+ return Ok ( ( Some ( 0 ) , Some ( memo) , None , None ) ) ;
200209 }
201210
202211 if opcode == JETTON_TRANSFER_OPCODE {
203212 let jetton = parse_jetton_transfer_body ( & mut parser) ?;
204- return Ok ( ( Some ( opcode) , None , Some ( jetton) ) ) ;
213+ return Ok ( ( Some ( opcode) , None , Some ( jetton) , None ) ) ;
214+ }
215+
216+ if opcode == WHALES_WITHDRAW_OPCODE || opcode == SINGLE_NOMINATOR_WITHDRAW_OPCODE {
217+ let withdraw_amount = parse_withdraw_amount_body ( & mut parser) ?;
218+ return Ok ( ( Some ( opcode) , None , None , Some ( withdraw_amount) ) ) ;
205219 }
206220
207221 // Other known opcodes
208- Ok ( ( Some ( opcode) , None , None ) )
222+ Ok ( ( Some ( opcode) , None , None , None ) )
223+ }
224+
225+ /// Parse query_id + amount from a withdrawal message body (Whales or SingleNominator).
226+ fn parse_withdraw_amount_body (
227+ parser : & mut tlb_ton:: de:: CellParser < ' _ > ,
228+ ) -> Result < u64 , WasmTonError > {
229+ let _query_id: u64 = parser
230+ . unpack ( ( ) )
231+ . map_err ( |e| WasmTonError :: new ( & format ! ( "withdraw: failed to read query_id: {e}" ) ) ) ?;
232+ let amount_big: BigUint = parser
233+ . unpack_as :: < _ , Grams > ( ( ) )
234+ . map_err ( |e| WasmTonError :: new ( & format ! ( "withdraw: failed to read amount: {e}" ) ) ) ?;
235+ Ok ( biguint_to_u64 ( & amount_big) )
209236}
210237
211238fn parse_jetton_transfer_body (
0 commit comments