@@ -371,6 +371,236 @@ describe('flr', function () {
371371 . should . be . rejectedWith ( 'coin in txPrebuild did not match that in txParams supplied by client' ) ;
372372 } ) ;
373373
374+ describe ( 'TSS Transaction Verification' , function ( ) {
375+ it ( 'should verify a TSS transfer transaction without txPrebuild.recipients' , async function ( ) {
376+ const wallet = new Wallet ( bitgo , tflrCoin , { } ) ;
377+
378+ const txParams = {
379+ recipients : [ { amount : '100000000000000000' , address : '0x4e1e3d4856ad8b33352eb3add5ff12ea3206169a' } ] ,
380+ type : 'transfer' ,
381+ isTss : true ,
382+ } ;
383+
384+ // TSS txPrebuild typically has buildParams.recipients but not recipients directly
385+ const txPrebuild = {
386+ walletId : 'fakeWalletId' ,
387+ txRequestId : 'fake-tx-request-id' ,
388+ txHex :
389+ '02f17281d902850ba43b740283061a80944e1e3d4856ad8b33352eb3add5ff12ea3206169a88016345785d8a000080c0808080' ,
390+ buildParams : {
391+ apiVersion : 'full' ,
392+ recipients : [ { address : '0x4e1e3d4856ad8b33352eb3add5ff12ea3206169a' , amount : '100000000000000000' } ] ,
393+ type : 'transfer' ,
394+ } ,
395+ feeInfo : { fee : 10000000000800000 , feeString : '10000000000800000' } ,
396+ coin : 'tflr' ,
397+ } ;
398+
399+ const verification = { } ;
400+
401+ // When walletType is 'tss', it should delegate to parent's verifyTransaction
402+ // which handles TSS transactions without requiring txPrebuild.recipients
403+ const isTransactionVerified = await tflrCoin . verifyTransaction ( {
404+ txParams,
405+ txPrebuild : txPrebuild as any ,
406+ wallet,
407+ verification,
408+ walletType : 'tss' ,
409+ } ) ;
410+ isTransactionVerified . should . equal ( true ) ;
411+ } ) ;
412+
413+ it ( 'should verify TSS consolidation transaction when txPrebuild has consolidateId' , async function ( ) {
414+ const wallet = new Wallet ( bitgo , tflrCoin , {
415+ coinSpecific : {
416+ baseAddress : '0x174cfd823af8ce27ed0afee3fcf3c3ba259116be' ,
417+ } ,
418+ } ) ;
419+
420+ // txParams without recipients (as in consolidation flow)
421+ const txParams = {
422+ wallet : wallet ,
423+ walletPassphrase : 'fakeWalletPassphrase' ,
424+ } ;
425+
426+ // txPrebuild with consolidateId (set by server during consolidation build)
427+ const txPrebuild = {
428+ consolidateId : '68a7d5d0c66e74e216b97173bd558c6d' ,
429+ txHex : '0x' ,
430+ coin : 'tflr' ,
431+ walletId : 'fakeWalletId' ,
432+ } ;
433+
434+ const verification = { } ;
435+
436+ const isTransactionVerified = await tflrCoin . verifyTransaction ( {
437+ txParams : txParams as any ,
438+ txPrebuild : txPrebuild as any ,
439+ wallet,
440+ verification,
441+ walletType : 'tss' ,
442+ } ) ;
443+ isTransactionVerified . should . equal ( true ) ;
444+ } ) ;
445+
446+ it ( 'should verify TSS transaction when txParams.type is consolidate' , async function ( ) {
447+ const wallet = new Wallet ( bitgo , tflrCoin , {
448+ coinSpecific : {
449+ baseAddress : '0x174cfd823af8ce27ed0afee3fcf3c3ba259116be' ,
450+ } ,
451+ } ) ;
452+
453+ const txParams = {
454+ type : 'consolidate' ,
455+ wallet : wallet ,
456+ walletPassphrase : 'fakeWalletPassphrase' ,
457+ } ;
458+
459+ const txPrebuild = {
460+ txHex : '0x' ,
461+ coin : 'tflr' ,
462+ walletId : 'fakeWalletId' ,
463+ } ;
464+
465+ const verification = { } ;
466+
467+ const isTransactionVerified = await tflrCoin . verifyTransaction ( {
468+ txParams : txParams as any ,
469+ txPrebuild : txPrebuild as any ,
470+ wallet,
471+ verification,
472+ walletType : 'tss' ,
473+ } ) ;
474+ isTransactionVerified . should . equal ( true ) ;
475+ } ) ;
476+
477+ it ( 'should verify TSS transaction with acceleration type' , async function ( ) {
478+ const wallet = new Wallet ( bitgo , tflrCoin , {
479+ coinSpecific : {
480+ baseAddress : '0x174cfd823af8ce27ed0afee3fcf3c3ba259116be' ,
481+ } ,
482+ } ) ;
483+
484+ const txParams = {
485+ type : 'acceleration' ,
486+ wallet : wallet ,
487+ walletPassphrase : 'fakeWalletPassphrase' ,
488+ } ;
489+
490+ const txPrebuild = {
491+ txHex : '0x' ,
492+ coin : 'tflr' ,
493+ walletId : 'fakeWalletId' ,
494+ } ;
495+
496+ const verification = { } ;
497+
498+ const isTransactionVerified = await tflrCoin . verifyTransaction ( {
499+ txParams : txParams as any ,
500+ txPrebuild : txPrebuild as any ,
501+ wallet,
502+ verification,
503+ walletType : 'tss' ,
504+ } ) ;
505+ isTransactionVerified . should . equal ( true ) ;
506+ } ) ;
507+
508+ it ( 'should verify TSS transaction with fillNonce type' , async function ( ) {
509+ const wallet = new Wallet ( bitgo , tflrCoin , {
510+ coinSpecific : {
511+ baseAddress : '0x174cfd823af8ce27ed0afee3fcf3c3ba259116be' ,
512+ } ,
513+ } ) ;
514+
515+ const txParams = {
516+ type : 'fillNonce' ,
517+ wallet : wallet ,
518+ walletPassphrase : 'fakeWalletPassphrase' ,
519+ } ;
520+
521+ const txPrebuild = {
522+ txHex : '0x' ,
523+ coin : 'tflr' ,
524+ walletId : 'fakeWalletId' ,
525+ } ;
526+
527+ const verification = { } ;
528+
529+ const isTransactionVerified = await tflrCoin . verifyTransaction ( {
530+ txParams : txParams as any ,
531+ txPrebuild : txPrebuild as any ,
532+ wallet,
533+ verification,
534+ walletType : 'tss' ,
535+ } ) ;
536+ isTransactionVerified . should . equal ( true ) ;
537+ } ) ;
538+
539+ it ( 'should reject TSS transaction without recipients, consolidateId, or valid type' , async function ( ) {
540+ const wallet = new Wallet ( bitgo , tflrCoin , {
541+ coinSpecific : {
542+ baseAddress : '0x174cfd823af8ce27ed0afee3fcf3c3ba259116be' ,
543+ } ,
544+ } ) ;
545+
546+ const txParams = {
547+ wallet : wallet ,
548+ walletPassphrase : 'fakeWalletPassphrase' ,
549+ } ;
550+
551+ const txPrebuild = {
552+ txHex : '0x' ,
553+ coin : 'tflr' ,
554+ walletId : 'fakeWalletId' ,
555+ } ;
556+
557+ const verification = { } ;
558+
559+ await tflrCoin
560+ . verifyTransaction ( {
561+ txParams : txParams as any ,
562+ txPrebuild : txPrebuild as any ,
563+ wallet,
564+ verification,
565+ walletType : 'tss' ,
566+ } )
567+ . should . be . rejectedWith ( 'missing txParams' ) ;
568+ } ) ;
569+
570+ it ( 'should still use FLR-specific verification for non-TSS wallets' , async function ( ) {
571+ const wallet = new Wallet ( bitgo , tflrCoin , { } ) ;
572+
573+ const txParams = {
574+ recipients : [ { amount : '1000000000000' , address : '0x1374a2046661f914d1687d85dbbceb9ac7910a29' } ] ,
575+ wallet : wallet ,
576+ walletPassphrase : 'fakeWalletPassphrase' ,
577+ } ;
578+
579+ const txPrebuild = {
580+ recipients : [ { amount : '1000000000000' , address : '0x1374a2046661f914d1687d85dbbceb9ac7910a29' } ] ,
581+ nextContractSequenceId : 0 ,
582+ gasPrice : 20000000000 ,
583+ gasLimit : 500000 ,
584+ isBatch : false ,
585+ coin : 'tflr' ,
586+ walletId : 'fakeWalletId' ,
587+ walletContractAddress : 'fakeWalletContractAddress' ,
588+ } ;
589+
590+ const verification = { } ;
591+
592+ // Without walletType or with walletType: 'onchain', should use FLR's own verification
593+ const isTransactionVerified = await tflrCoin . verifyTransaction ( {
594+ txParams,
595+ txPrebuild : txPrebuild as any ,
596+ wallet,
597+ verification,
598+ walletType : 'onchain' ,
599+ } ) ;
600+ isTransactionVerified . should . equal ( true ) ;
601+ } ) ;
602+ } ) ;
603+
374604 describe ( 'Hop export tx verify' , ( ) => {
375605 const wallet = new Wallet ( bitgo , tflrCoin , { } ) ;
376606 const hopDestinationAddress =
0 commit comments