@@ -271,7 +271,7 @@ export class StakingWallet implements IStakingWallet {
271271 // default to verifying a transaction unless explicitly skipped
272272 const skipVerification = signOptions . transactionVerificationOptions ?. skipTransactionVerification ?? false ;
273273 if ( ! isStakingTxRequestPrebuildResult ( builtTx . result ) && ! skipVerification ) {
274- await this . validateBuiltStakingTransaction ( transaction , builtTx ) ;
274+ await this . validateBuiltStakingTransaction ( builtTx . transaction , builtTx ) ;
275275 }
276276 return await this . sign ( signOptions , builtTx ) ;
277277 }
@@ -371,55 +371,100 @@ export class StakingWallet implements IStakingWallet {
371371 }
372372
373373 const explainedTransaction = await coin . explainTransaction ( result ) ;
374+ const mismatchErrors : string [ ] = [ ] ;
374375
375- if ( buildParams ?. recipients ) {
376+ if ( buildParams ?. recipients && buildParams . recipients . length > 0 ) {
376377 const userRecipientMap = new Map (
377378 buildParams . recipients . map ( ( recipient ) => [ recipient . address . toLowerCase ( ) , recipient ] )
378379 ) ;
379380 const platformRecipientMap = new Map (
380381 ( explainedTransaction ?. outputs ?? [ ] ) . map ( ( recipient ) => [ recipient . address . toLowerCase ( ) , recipient ] )
381382 ) ;
382383
383- const mismatchErrors : string [ ] = [ ] ;
384-
385- for ( const [ recipientAddress , recipientInfo ] of platformRecipientMap ) {
386- if ( userRecipientMap . has ( recipientAddress ) ) {
387- const userRecipient = userRecipientMap . get ( recipientAddress ) ;
388- if ( ! userRecipient ) {
389- console . error ( 'Unable to determine recipient address' ) ;
390- return ;
391- }
392- const matchResult = transactionRecipientsMatch ( userRecipient , recipientInfo ) ;
393- if ( ! matchResult . exactMatch ) {
394- if ( ! matchResult . tokenMatch ) {
395- mismatchErrors . push (
396- `Invalid token ${ recipientInfo . tokenName } transfer with amount ${ recipientInfo . amount } to ${ recipientInfo . address } found in built transaction, specified ${ userRecipient . tokenName } `
397- ) ;
398- }
399- if ( ! matchResult . amountMatch ) {
400- mismatchErrors . push (
401- `Invalid recipient amount for ${ recipientInfo . address } , specified ${ userRecipient . amount } got ${ recipientInfo . amount } `
402- ) ;
403- }
404- }
405- } else {
406- mismatchErrors . push ( `Invalid recipient address: ${ recipientAddress } ` ) ;
384+ for ( const [ address ] of platformRecipientMap ) {
385+ if ( ! userRecipientMap . has ( address ) ) {
386+ mismatchErrors . push ( `Unexpected recipient address found in built transaction: ${ address } ` ) ;
407387 }
408388 }
409389
410- const missingRecipientAddresses = Array . from ( userRecipientMap . keys ( ) ) . filter (
411- ( address ) => ! platformRecipientMap . has ( address )
390+ for ( const [ address , userRecipient ] of userRecipientMap ) {
391+ const platformRecipient = platformRecipientMap . get ( address ) ;
392+ if ( ! platformRecipient ) {
393+ mismatchErrors . push ( `Expected recipient address not found in built transaction: ${ address } ` ) ;
394+ continue ;
395+ }
396+
397+ const matchResult = transactionRecipientsMatch ( userRecipient , platformRecipient ) ;
398+
399+ if ( ! matchResult . amountMatch ) {
400+ mismatchErrors . push (
401+ `Recipient ${ address } amount mismatch. Expected: ${ userRecipient . amount } , Got: ${ platformRecipient . amount } `
402+ ) ;
403+ }
404+ if ( ! matchResult . tokenMatch ) {
405+ mismatchErrors . push (
406+ `Recipient ${ address } token mismatch. Expected: ${ userRecipient . tokenName ?? 'native coin' } , Got: ${
407+ platformRecipient . tokenName ?? 'native coin'
408+ } `
409+ ) ;
410+ }
411+ }
412+ }
413+ if ( buildParams ?. memo && ( explainedTransaction as any ) . memo !== buildParams . memo ) {
414+ mismatchErrors . push (
415+ `Memo mismatch. Expected: '${ JSON . stringify ( buildParams . memo ) } ', Got: '${ JSON . stringify (
416+ ( explainedTransaction as any ) . memo
417+ ) } '`
418+ ) ;
419+ }
420+
421+ if ( buildParams ?. gasLimit && String ( ( explainedTransaction as any ) . gasLimit ) !== String ( buildParams . gasLimit ) ) {
422+ mismatchErrors . push (
423+ `Gas Limit mismatch. Expected: ${ buildParams . gasLimit } , Got: ${ ( explainedTransaction as any ) . gasLimit } `
424+ ) ;
425+ }
426+
427+ if ( buildParams ?. type && ( explainedTransaction as any ) . type !== buildParams . type ) {
428+ mismatchErrors . push (
429+ `Transaction type mismatch. Expected: '${ buildParams . type } ', Got: '${ ( explainedTransaction as any ) . type } '`
412430 ) ;
431+ }
413432
414- if ( missingRecipientAddresses . length > 0 ) {
415- mismatchErrors . push ( `Missing recipient address(es): ${ missingRecipientAddresses . join ( ', ' ) } ` ) ;
433+ if ( buildParams ?. solInstructions ) {
434+ if (
435+ JSON . stringify ( ( explainedTransaction as any ) . solInstructions ) !== JSON . stringify ( buildParams . solInstructions )
436+ ) {
437+ mismatchErrors . push (
438+ `Solana instructions mismatch. Expected: ${ JSON . stringify (
439+ buildParams . solInstructions
440+ ) } , Got: ${ JSON . stringify ( ( explainedTransaction as any ) . solInstructions ) } `
441+ ) ;
416442 }
417- if ( mismatchErrors . length > 0 ) {
418- console . error ( mismatchErrors . join ( ', ' ) ) ;
419- return ;
443+ }
444+
445+ if ( buildParams ?. aptosCustomTransactionParams ) {
446+ if (
447+ JSON . stringify ( ( explainedTransaction as any ) . aptosCustomTransactionParams ) !==
448+ JSON . stringify ( buildParams . aptosCustomTransactionParams )
449+ ) {
450+ mismatchErrors . push (
451+ `Aptos custom transaction parameters mismatch. Expected: ${ JSON . stringify (
452+ buildParams . aptosCustomTransactionParams
453+ ) } , Got: ${ JSON . stringify ( ( explainedTransaction as any ) . aptosCustomTransactionParams ) } `
454+ ) ;
420455 }
421- } else {
422- debug ( `Cannot validate staking transaction ${ transaction . stakingRequestId } without specified build params` ) ;
456+ }
457+
458+ if ( mismatchErrors . length > 0 ) {
459+ const errorMessage = `Staking transaction validation failed before signing: ${ mismatchErrors . join ( '; ' ) } ` ;
460+ debug ( errorMessage ) ;
461+ throw new Error ( errorMessage ) ;
462+ }
463+
464+ if ( ! buildParams ) {
465+ debug (
466+ `Cannot perform deep validation for staking transaction ${ transaction . stakingRequestId } without specified build params`
467+ ) ;
423468 }
424469 }
425470}
0 commit comments