@@ -3031,6 +3031,34 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
30313031 return txPrebuild . coin === nativeCoin ;
30323032 }
30333033
3034+ /**
3035+ * Generate transaction explanation for error reporting
3036+ * @param txPrebuild - Transaction prebuild containing txHex and fee info
3037+ * @returns Stringified JSON explanation
3038+ */
3039+ private async getTxExplanation ( txPrebuild ?: TransactionPrebuild ) : Promise < string | undefined > {
3040+ if ( ! txPrebuild ?. txHex || ! txPrebuild ?. gasPrice ) {
3041+ return undefined ;
3042+ }
3043+
3044+ try {
3045+ const explanation = await this . explainTransaction ( {
3046+ txHex : txPrebuild . txHex ,
3047+ feeInfo : {
3048+ fee : txPrebuild . gasPrice . toString ( ) ,
3049+ } ,
3050+ } ) ;
3051+ return JSON . stringify ( explanation , null , 2 ) ;
3052+ } catch ( e ) {
3053+ const errorDetails = {
3054+ error : 'Failed to parse transaction explanation' ,
3055+ txHex : txPrebuild . txHex ,
3056+ details : e instanceof Error ? e . message : String ( e ) ,
3057+ } ;
3058+ return JSON . stringify ( errorDetails , null , 2 ) ;
3059+ }
3060+ }
3061+
30343062 /**
30353063 * Verify if a tss transaction is valid
30363064 *
@@ -3045,8 +3073,16 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
30453073 const { txParams, txPrebuild, wallet } = params ;
30463074
30473075 // Helper to throw TxIntentMismatchRecipientError with recipient details
3048- const throwRecipientMismatch = ( message : string , mismatchedRecipients : Recipient [ ] ) : never => {
3049- throw new TxIntentMismatchRecipientError ( message , undefined , [ txParams ] , txPrebuild ?. txHex , mismatchedRecipients ) ;
3076+ const throwRecipientMismatch = async ( message : string , mismatchedRecipients : Recipient [ ] ) : Promise < never > => {
3077+ const txExplanation = await this . getTxExplanation ( txPrebuild ) ;
3078+ throw new TxIntentMismatchRecipientError (
3079+ message ,
3080+ undefined ,
3081+ [ txParams ] ,
3082+ txPrebuild ?. txHex ,
3083+ mismatchedRecipients ,
3084+ txExplanation
3085+ ) ;
30503086 } ;
30513087
30523088 if (
@@ -3077,12 +3113,13 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
30773113 const txJson = tx . toJson ( ) ;
30783114 if ( txJson . data === '0x' ) {
30793115 if ( expectedAmount !== txJson . value ) {
3080- throwRecipientMismatch ( 'the transaction amount in txPrebuild does not match the value given by client' , [
3081- { address : txJson . to , amount : txJson . value } ,
3082- ] ) ;
3116+ await throwRecipientMismatch (
3117+ 'the transaction amount in txPrebuild does not match the value given by client' ,
3118+ [ { address : txJson . to , amount : txJson . value } ]
3119+ ) ;
30833120 }
30843121 if ( expectedDestination . toLowerCase ( ) !== txJson . to . toLowerCase ( ) ) {
3085- throwRecipientMismatch ( 'destination address does not match with the recipient address' , [
3122+ await throwRecipientMismatch ( 'destination address does not match with the recipient address' , [
30863123 { address : txJson . to , amount : txJson . value } ,
30873124 ] ) ;
30883125 }
@@ -3112,13 +3149,14 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
31123149 }
31133150
31143151 if ( expectedTokenAmount !== amount . toString ( ) ) {
3115- throwRecipientMismatch ( 'the transaction amount in txPrebuild does not match the value given by client' , [
3116- { address : addHexPrefix ( recipientAddress . toString ( ) ) , amount : amount . toString ( ) } ,
3117- ] ) ;
3152+ await throwRecipientMismatch (
3153+ 'the transaction amount in txPrebuild does not match the value given by client' ,
3154+ [ { address : addHexPrefix ( recipientAddress . toString ( ) ) , amount : amount . toString ( ) } ]
3155+ ) ;
31183156 }
31193157
31203158 if ( expectedRecipientAddress !== addHexPrefix ( recipientAddress . toString ( ) ) . toLowerCase ( ) ) {
3121- throwRecipientMismatch ( 'destination address does not match with the recipient address' , [
3159+ await throwRecipientMismatch ( 'destination address does not match with the recipient address' , [
31223160 { address : addHexPrefix ( recipientAddress . toString ( ) ) , amount : amount . toString ( ) } ,
31233161 ] ) ;
31243162 }
@@ -3149,8 +3187,16 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
31493187 }
31503188
31513189 // Helper to throw TxIntentMismatchRecipientError with recipient details
3152- const throwRecipientMismatch = ( message : string , mismatchedRecipients : Recipient [ ] ) : never => {
3153- throw new TxIntentMismatchRecipientError ( message , undefined , [ txParams ] , txPrebuild ?. txHex , mismatchedRecipients ) ;
3190+ const throwRecipientMismatch = async ( message : string , mismatchedRecipients : Recipient [ ] ) : Promise < never > => {
3191+ const txExplanation = await this . getTxExplanation ( txPrebuild ) ;
3192+ throw new TxIntentMismatchRecipientError (
3193+ message ,
3194+ undefined ,
3195+ [ txParams ] ,
3196+ txPrebuild ?. txHex ,
3197+ mismatchedRecipients ,
3198+ txExplanation
3199+ ) ;
31543200 } ;
31553201
31563202 if ( ! txParams ?. recipients || ! txPrebuild ?. recipients || ! wallet ) {
@@ -3180,7 +3226,7 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
31803226 const expectedHopAddress = optionalDeps . ethUtil . stripHexPrefix ( decodedHopTx . getSenderAddress ( ) . toString ( ) ) ;
31813227 const actualHopAddress = optionalDeps . ethUtil . stripHexPrefix ( txPrebuild . recipients [ 0 ] . address ) ;
31823228 if ( expectedHopAddress . toLowerCase ( ) !== actualHopAddress . toLowerCase ( ) ) {
3183- throwRecipientMismatch ( 'recipient address of txPrebuild does not match hop address' , [
3229+ await throwRecipientMismatch ( 'recipient address of txPrebuild does not match hop address' , [
31843230 { address : txPrebuild . recipients [ 0 ] . address , amount : txPrebuild . recipients [ 0 ] . amount . toString ( ) } ,
31853231 ] ) ;
31863232 }
@@ -3200,17 +3246,18 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
32003246 if ( txParams . tokenName ) {
32013247 const expectedTotalAmount = new BigNumber ( 0 ) ;
32023248 if ( ! expectedTotalAmount . isEqualTo ( txPrebuild . recipients [ 0 ] . amount ) ) {
3203- throwRecipientMismatch ( 'batch token transaction amount in txPrebuild should be zero for token transfers' , [
3204- { address : txPrebuild . recipients [ 0 ] . address , amount : txPrebuild . recipients [ 0 ] . amount . toString ( ) } ,
3205- ] ) ;
3249+ await throwRecipientMismatch (
3250+ 'batch token transaction amount in txPrebuild should be zero for token transfers' ,
3251+ [ { address : txPrebuild . recipients [ 0 ] . address , amount : txPrebuild . recipients [ 0 ] . amount . toString ( ) } ]
3252+ ) ;
32063253 }
32073254 } else {
32083255 let expectedTotalAmount = new BigNumber ( 0 ) ;
32093256 for ( let i = 0 ; i < recipients . length ; i ++ ) {
32103257 expectedTotalAmount = expectedTotalAmount . plus ( recipients [ i ] . amount ) ;
32113258 }
32123259 if ( ! expectedTotalAmount . isEqualTo ( txPrebuild . recipients [ 0 ] . amount ) ) {
3213- throwRecipientMismatch (
3260+ await throwRecipientMismatch (
32143261 'batch transaction amount in txPrebuild received from BitGo servers does not match txParams supplied by client' ,
32153262 [ { address : txPrebuild . recipients [ 0 ] . address , amount : txPrebuild . recipients [ 0 ] . amount . toString ( ) } ]
32163263 ) ;
@@ -3223,7 +3270,7 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
32233270 ! batcherContractAddress ||
32243271 batcherContractAddress . toLowerCase ( ) !== txPrebuild . recipients [ 0 ] . address . toLowerCase ( )
32253272 ) {
3226- throwRecipientMismatch ( 'recipient address of txPrebuild does not match batcher address' , [
3273+ await throwRecipientMismatch ( 'recipient address of txPrebuild does not match batcher address' , [
32273274 { address : txPrebuild . recipients [ 0 ] . address , amount : txPrebuild . recipients [ 0 ] . amount . toString ( ) } ,
32283275 ] ) ;
32293276 }
@@ -3234,25 +3281,27 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
32343281 }
32353282 const expectedAmount = new BigNumber ( recipients [ 0 ] . amount ) ;
32363283 if ( ! expectedAmount . isEqualTo ( txPrebuild . recipients [ 0 ] . amount ) ) {
3237- throwRecipientMismatch (
3284+ await throwRecipientMismatch (
32383285 'normal transaction amount in txPrebuild received from BitGo servers does not match txParams supplied by client' ,
32393286 [ { address : txPrebuild . recipients [ 0 ] . address , amount : txPrebuild . recipients [ 0 ] . amount . toString ( ) } ]
32403287 ) ;
32413288 }
32423289 if ( this . isETHAddress ( recipients [ 0 ] . address ) && recipients [ 0 ] . address !== txPrebuild . recipients [ 0 ] . address ) {
3243- throwRecipientMismatch (
3290+ await throwRecipientMismatch (
32443291 'destination address in normal txPrebuild does not match that in txParams supplied by client' ,
32453292 [ { address : txPrebuild . recipients [ 0 ] . address , amount : txPrebuild . recipients [ 0 ] . amount . toString ( ) } ]
32463293 ) ;
32473294 }
32483295 }
32493296 // Check coin is correct for all transaction types
32503297 if ( ! this . verifyCoin ( txPrebuild ) ) {
3298+ const txExplanation = await this . getTxExplanation ( txPrebuild ) ;
32513299 throw new TxIntentMismatchError (
32523300 'coin in txPrebuild did not match that in txParams supplied by client' ,
32533301 undefined ,
32543302 [ txParams ] ,
3255- txPrebuild ?. txHex
3303+ txPrebuild ?. txHex ,
3304+ txExplanation
32563305 ) ;
32573306 }
32583307 return true ;
0 commit comments