@@ -29,6 +29,7 @@ import {
2929 Recipient ,
3030 SignTransactionOptions as BaseSignTransactionOptions ,
3131 TxIntentMismatchError ,
32+ TxIntentMismatchRecipientError ,
3233 TransactionParams ,
3334 TransactionPrebuild as BaseTransactionPrebuild ,
3435 TransactionRecipient ,
@@ -2768,14 +2769,14 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
27682769 * @param {TransactionPrebuild } params.txPrebuild - prebuild object returned by server
27692770 * @param {Wallet } params.wallet - Wallet object to obtain keys to verify against
27702771 * @returns {boolean }
2771- * @throws {TxIntentMismatchError } if transaction validation fails
2772+ * @throws {TxIntentMismatchRecipientError } if transaction recipients don't match user intent
27722773 */
27732774 async verifyTssTransaction ( params : VerifyEthTransactionOptions ) : Promise < boolean > {
27742775 const { txParams, txPrebuild, wallet } = params ;
27752776
2776- // Helper to throw TxIntentMismatchError with consistent context
2777- const throwTxMismatch = ( message : string ) : never => {
2778- throw new TxIntentMismatchError ( message , undefined , [ txParams ] , txPrebuild ?. txHex ) ;
2777+ // Helper to throw TxIntentMismatchRecipientError with recipient details
2778+ const throwRecipientMismatch = ( message : string , mismatchedRecipients : Recipient [ ] ) : never => {
2779+ throw new TxIntentMismatchRecipientError ( message , undefined , [ txParams ] , txPrebuild ?. txHex , mismatchedRecipients ) ;
27792780 } ;
27802781
27812782 if (
@@ -2785,13 +2786,13 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
27852786 ( txParams . type && [ 'acceleration' , 'fillNonce' , 'transferToken' , 'tokenApproval' ] . includes ( txParams . type ) )
27862787 )
27872788 ) {
2788- throwTxMismatch ( ` missing txParams` ) ;
2789+ throw new Error ( ' missing txParams' ) ;
27892790 }
27902791 if ( ! wallet || ! txPrebuild ) {
2791- throwTxMismatch ( ` missing params` ) ;
2792+ throw new Error ( ' missing params' ) ;
27922793 }
27932794 if ( txParams . hop && txParams . recipients && txParams . recipients . length > 1 ) {
2794- throwTxMismatch ( ` tx cannot be both a batch and hop transaction` ) ;
2795+ throw new Error ( ' tx cannot be both a batch and hop transaction' ) ;
27952796 }
27962797
27972798 if ( txParams . type && [ 'transfer' ] . includes ( txParams . type ) ) {
@@ -2806,21 +2807,29 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
28062807 const txJson = tx . toJson ( ) ;
28072808 if ( txJson . data === '0x' ) {
28082809 if ( expectedAmount !== txJson . value ) {
2809- throwTxMismatch ( 'the transaction amount in txPrebuild does not match the value given by client' ) ;
2810+ throwRecipientMismatch ( 'the transaction amount in txPrebuild does not match the value given by client' , [
2811+ { address : txJson . to , amount : txJson . value } ,
2812+ ] ) ;
28102813 }
28112814 if ( expectedDestination . toLowerCase ( ) !== txJson . to . toLowerCase ( ) ) {
2812- throwTxMismatch ( 'destination address does not match with the recipient address' ) ;
2815+ throwRecipientMismatch ( 'destination address does not match with the recipient address' , [
2816+ { address : txJson . to , amount : txJson . value } ,
2817+ ] ) ;
28132818 }
28142819 } else if ( txJson . data . startsWith ( '0xa9059cbb' ) ) {
28152820 const [ recipientAddress , amount ] = getRawDecoded (
28162821 [ 'address' , 'uint256' ] ,
28172822 getBufferedByteCode ( '0xa9059cbb' , txJson . data )
28182823 ) ;
28192824 if ( expectedAmount !== amount . toString ( ) ) {
2820- throwTxMismatch ( 'the transaction amount in txPrebuild does not match the value given by client' ) ;
2825+ throwRecipientMismatch ( 'the transaction amount in txPrebuild does not match the value given by client' , [
2826+ { address : addHexPrefix ( recipientAddress . toString ( ) ) , amount : amount . toString ( ) } ,
2827+ ] ) ;
28212828 }
28222829 if ( expectedDestination . toLowerCase ( ) !== addHexPrefix ( recipientAddress . toString ( ) ) . toLowerCase ( ) ) {
2823- throwTxMismatch ( 'destination address does not match with the recipient address' ) ;
2830+ throwRecipientMismatch ( 'destination address does not match with the recipient address' , [
2831+ { address : addHexPrefix ( recipientAddress . toString ( ) ) , amount : amount . toString ( ) } ,
2832+ ] ) ;
28242833 }
28252834 }
28262835 }
@@ -2838,6 +2847,7 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
28382847 * @param {Wallet } params.wallet - Wallet object to obtain keys to verify against
28392848 * @returns {boolean }
28402849 * @throws {TxIntentMismatchError } if transaction validation fails
2850+ * @throws {TxIntentMismatchRecipientError } if transaction recipients don't match user intent
28412851 */
28422852 async verifyTransaction ( params : VerifyEthTransactionOptions ) : Promise < boolean > {
28432853 const ethNetwork = this . getNetwork ( ) ;
@@ -2847,29 +2857,29 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
28472857 return this . verifyTssTransaction ( params ) ;
28482858 }
28492859
2850- // Helper to throw TxIntentMismatchError with consistent context
2851- const throwTxMismatch = ( message : string ) : never => {
2852- throw new TxIntentMismatchError ( message , undefined , [ txParams ] , txPrebuild ?. txHex ) ;
2860+ // Helper to throw TxIntentMismatchRecipientError with recipient details
2861+ const throwRecipientMismatch = ( message : string , mismatchedRecipients : Recipient [ ] ) : never => {
2862+ throw new TxIntentMismatchRecipientError ( message , undefined , [ txParams ] , txPrebuild ?. txHex , mismatchedRecipients ) ;
28532863 } ;
28542864
28552865 if ( ! txParams ?. recipients || ! txPrebuild ?. recipients || ! wallet ) {
2856- throwTxMismatch ( ` missing params` ) ;
2866+ throw new Error ( ' missing params' ) ;
28572867 }
28582868
28592869 const recipients = txParams . recipients ! ;
28602870
28612871 if ( txParams . hop && recipients . length > 1 ) {
2862- throwTxMismatch ( ` tx cannot be both a batch and hop transaction` ) ;
2872+ throw new Error ( ' tx cannot be both a batch and hop transaction' ) ;
28632873 }
28642874 if ( txPrebuild . recipients . length > 1 ) {
2865- throwTxMismatch (
2875+ throw new Error (
28662876 `${ this . getChain ( ) } doesn't support sending to more than 1 destination address within a single transaction. Try again, using only a single recipient.`
28672877 ) ;
28682878 }
28692879 if ( txParams . hop && txPrebuild . hopTransaction ) {
28702880 // Check recipient amount for hop transaction
28712881 if ( recipients . length !== 1 ) {
2872- throwTxMismatch ( `hop transaction only supports 1 recipient but ${ recipients . length } found` ) ;
2882+ throw new Error ( `hop transaction only supports 1 recipient but ${ recipients . length } found` ) ;
28732883 }
28742884
28752885 // Check tx sends to hop address
@@ -2879,7 +2889,9 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
28792889 const expectedHopAddress = optionalDeps . ethUtil . stripHexPrefix ( decodedHopTx . getSenderAddress ( ) . toString ( ) ) ;
28802890 const actualHopAddress = optionalDeps . ethUtil . stripHexPrefix ( txPrebuild . recipients [ 0 ] . address ) ;
28812891 if ( expectedHopAddress . toLowerCase ( ) !== actualHopAddress . toLowerCase ( ) ) {
2882- throwTxMismatch ( 'recipient address of txPrebuild does not match hop address' ) ;
2892+ throwRecipientMismatch ( 'recipient address of txPrebuild does not match hop address' , [
2893+ { address : txPrebuild . recipients [ 0 ] . address , amount : txPrebuild . recipients [ 0 ] . amount . toString ( ) } ,
2894+ ] ) ;
28832895 }
28842896
28852897 // Convert TransactionRecipient array to Recipient array
@@ -2897,16 +2909,19 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
28972909 if ( txParams . tokenName ) {
28982910 const expectedTotalAmount = new BigNumber ( 0 ) ;
28992911 if ( ! expectedTotalAmount . isEqualTo ( txPrebuild . recipients [ 0 ] . amount ) ) {
2900- throwTxMismatch ( 'batch token transaction amount in txPrebuild should be zero for token transfers' ) ;
2912+ throwRecipientMismatch ( 'batch token transaction amount in txPrebuild should be zero for token transfers' , [
2913+ { address : txPrebuild . recipients [ 0 ] . address , amount : txPrebuild . recipients [ 0 ] . amount . toString ( ) } ,
2914+ ] ) ;
29012915 }
29022916 } else {
29032917 let expectedTotalAmount = new BigNumber ( 0 ) ;
29042918 for ( let i = 0 ; i < recipients . length ; i ++ ) {
29052919 expectedTotalAmount = expectedTotalAmount . plus ( recipients [ i ] . amount ) ;
29062920 }
29072921 if ( ! expectedTotalAmount . isEqualTo ( txPrebuild . recipients [ 0 ] . amount ) ) {
2908- throwTxMismatch (
2909- 'batch transaction amount in txPrebuild received from BitGo servers does not match txParams supplied by client'
2922+ throwRecipientMismatch (
2923+ 'batch transaction amount in txPrebuild received from BitGo servers does not match txParams supplied by client' ,
2924+ [ { address : txPrebuild . recipients [ 0 ] . address , amount : txPrebuild . recipients [ 0 ] . amount . toString ( ) } ]
29102925 ) ;
29112926 }
29122927 }
@@ -2917,26 +2932,37 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
29172932 ! batcherContractAddress ||
29182933 batcherContractAddress . toLowerCase ( ) !== txPrebuild . recipients [ 0 ] . address . toLowerCase ( )
29192934 ) {
2920- throwTxMismatch ( 'recipient address of txPrebuild does not match batcher address' ) ;
2935+ throwRecipientMismatch ( 'recipient address of txPrebuild does not match batcher address' , [
2936+ { address : txPrebuild . recipients [ 0 ] . address , amount : txPrebuild . recipients [ 0 ] . amount . toString ( ) } ,
2937+ ] ) ;
29212938 }
29222939 } else {
29232940 // Check recipient address and amount for normal transaction
29242941 if ( recipients . length !== 1 ) {
2925- throwTxMismatch ( `normal transaction only supports 1 recipient but ${ recipients . length } found` ) ;
2942+ throw new Error ( `normal transaction only supports 1 recipient but ${ recipients . length } found` ) ;
29262943 }
29272944 const expectedAmount = new BigNumber ( recipients [ 0 ] . amount ) ;
29282945 if ( ! expectedAmount . isEqualTo ( txPrebuild . recipients [ 0 ] . amount ) ) {
2929- throwTxMismatch (
2930- 'normal transaction amount in txPrebuild received from BitGo servers does not match txParams supplied by client'
2946+ throwRecipientMismatch (
2947+ 'normal transaction amount in txPrebuild received from BitGo servers does not match txParams supplied by client' ,
2948+ [ { address : txPrebuild . recipients [ 0 ] . address , amount : txPrebuild . recipients [ 0 ] . amount . toString ( ) } ]
29312949 ) ;
29322950 }
29332951 if ( this . isETHAddress ( recipients [ 0 ] . address ) && recipients [ 0 ] . address !== txPrebuild . recipients [ 0 ] . address ) {
2934- throwTxMismatch ( 'destination address in normal txPrebuild does not match that in txParams supplied by client' ) ;
2952+ throwRecipientMismatch (
2953+ 'destination address in normal txPrebuild does not match that in txParams supplied by client' ,
2954+ [ { address : txPrebuild . recipients [ 0 ] . address , amount : txPrebuild . recipients [ 0 ] . amount . toString ( ) } ]
2955+ ) ;
29352956 }
29362957 }
29372958 // Check coin is correct for all transaction types
29382959 if ( ! this . verifyCoin ( txPrebuild ) ) {
2939- throwTxMismatch ( `coin in txPrebuild did not match that in txParams supplied by client` ) ;
2960+ throw new TxIntentMismatchError (
2961+ 'coin in txPrebuild did not match that in txParams supplied by client' ,
2962+ undefined ,
2963+ [ txParams ] ,
2964+ txPrebuild ?. txHex
2965+ ) ;
29402966 }
29412967 return true ;
29422968 }
0 commit comments