@@ -5,7 +5,7 @@ import { BitGoAPI } from '@bitgo/sdk-api';
55import { TestBitGoAPI , TestBitGo } from '@bitgo/sdk-test' ;
66import { Trx , Ttrx } from '../../src' ;
77import { Utils } from '../../src/lib' ;
8- import { UnsignedBuildTransaction } from '../resources' ;
8+ import { UnsignedBuildTransaction , UnsignedAccountPermissionUpdateContractTx } from '../resources' ;
99
1010describe ( 'TRON Verify Transaction:' , function ( ) {
1111 const bitgo : TestBitGoAPI = TestBitGo . decorate ( BitGoAPI , { env : 'test' } ) ;
@@ -417,4 +417,162 @@ describe('TRON Verify Transaction:', function () {
417417 } ) ;
418418 } ) ;
419419 } ) ;
420+
421+ describe ( 'TSS Wallet Verification' , ( ) => {
422+ /**
423+ * Helper to build a raw_data_hex (protobuf) for a TransferContract.
424+ * For TSS, txPrebuild.txHex is the raw_data_hex directly (not a JSON string).
425+ */
426+ function buildTssTransferTxHex ( params : {
427+ ownerAddress : string ;
428+ toAddress : string ;
429+ amount : number ;
430+ timestamp ?: number ;
431+ expiration ?: number ;
432+ } ) : string {
433+ const timestamp = params . timestamp || Date . now ( ) ;
434+ const transferContract = {
435+ parameter : {
436+ value : {
437+ amount : params . amount ,
438+ owner_address : params . ownerAddress ,
439+ to_address : params . toAddress ,
440+ } ,
441+ type_url : 'type.googleapis.com/protocol.TransferContract' ,
442+ } ,
443+ type : 'TransferContract' ,
444+ } ;
445+
446+ const transformedRawData = {
447+ contract : [ transferContract ] as any ,
448+ refBlockBytes : 'c8cf' ,
449+ refBlockHash : '89177fd84c5d9196' ,
450+ expiration : params . expiration || timestamp + 3600000 ,
451+ timestamp : timestamp ,
452+ } ;
453+
454+ return Utils . generateRawDataHex ( transformedRawData ) ;
455+ }
456+
457+ describe ( 'TransferContract' , ( ) => {
458+ it ( 'should validate a valid TSS TransferContract' , async function ( ) {
459+ const ownerHex = '4173a5993cd182ae152adad8203163f780c65a8aa5' ;
460+ const toHex = '41d6cd6a2c0ff35a319e6abb5b9503ba0278679882' ;
461+ const amount = 1000000 ;
462+
463+ const rawDataHex = buildTssTransferTxHex ( { ownerAddress : ownerHex , toAddress : toHex , amount } ) ;
464+
465+ const params = {
466+ txParams : {
467+ recipients : [
468+ {
469+ // TSS path: recipients use base58 addresses
470+ address : Utils . getBase58AddressFromHex ( toHex ) ,
471+ amount : amount . toString ( ) ,
472+ } ,
473+ ] ,
474+ } ,
475+ txPrebuild : {
476+ // TSS path: txHex is the raw protobuf hex, not a JSON string
477+ txHex : rawDataHex ,
478+ } ,
479+ wallet : { } ,
480+ walletType : 'tss' ,
481+ } ;
482+
483+ const result = await basecoin . verifyTransaction ( params ) ;
484+ assert . strictEqual ( result , true ) ;
485+ } ) ;
486+
487+ it ( 'should fail TSS verification when amount does not match' , async function ( ) {
488+ const ownerHex = '4173a5993cd182ae152adad8203163f780c65a8aa5' ;
489+ const toHex = '41d6cd6a2c0ff35a319e6abb5b9503ba0278679882' ;
490+
491+ const rawDataHex = buildTssTransferTxHex ( { ownerAddress : ownerHex , toAddress : toHex , amount : 2000000 } ) ;
492+
493+ const params = {
494+ txParams : {
495+ recipients : [
496+ {
497+ address : Utils . getBase58AddressFromHex ( toHex ) ,
498+ amount : '1000000' , // mismatch: txHex has 2000000
499+ } ,
500+ ] ,
501+ } ,
502+ txPrebuild : {
503+ txHex : rawDataHex ,
504+ } ,
505+ wallet : { } ,
506+ walletType : 'tss' ,
507+ } ;
508+
509+ await assert . rejects ( basecoin . verifyTransaction ( params ) , {
510+ message : 'transaction amount in txPrebuild does not match the value given by client' ,
511+ } ) ;
512+ } ) ;
513+
514+ it ( 'should fail TSS verification when destination address does not match' , async function ( ) {
515+ const ownerHex = '4173a5993cd182ae152adad8203163f780c65a8aa5' ;
516+ const toHex = '41d6cd6a2c0ff35a319e6abb5b9503ba0278679882' ;
517+
518+ const rawDataHex = buildTssTransferTxHex ( { ownerAddress : ownerHex , toAddress : toHex , amount : 1000000 } ) ;
519+
520+ const params = {
521+ txParams : {
522+ recipients : [
523+ {
524+ // Different address than what's in the transaction
525+ address : 'TTsGwnTLQ4eryFJpDvJSfuGQxPXRCjXvZz' ,
526+ amount : '1000000' ,
527+ } ,
528+ ] ,
529+ } ,
530+ txPrebuild : {
531+ txHex : rawDataHex ,
532+ } ,
533+ wallet : { } ,
534+ walletType : 'tss' ,
535+ } ;
536+
537+ await assert . rejects ( basecoin . verifyTransaction ( params ) , {
538+ message : 'destination address does not match with the recipient address' ,
539+ } ) ;
540+ } ) ;
541+ } ) ;
542+
543+ it ( 'should return true for non-Transfer contract types in TSS' , async function ( ) {
544+ // For non-Transfer contracts (e.g., AccountPermissionUpdate), TSS path returns true
545+ // without detailed validation.
546+ const rawDataHex = UnsignedAccountPermissionUpdateContractTx . raw_data_hex ;
547+
548+ const params = {
549+ txParams : {
550+ recipients : [ ] ,
551+ } ,
552+ txPrebuild : {
553+ txHex : rawDataHex ,
554+ } ,
555+ wallet : { } ,
556+ walletType : 'tss' ,
557+ } ;
558+
559+ const result = await basecoin . verifyTransaction ( params ) ;
560+ assert . strictEqual ( result , true ) ;
561+ } ) ;
562+
563+ it ( 'should throw error when txHex is missing for TSS wallet' , async function ( ) {
564+ const params = {
565+ txParams : {
566+ recipients : [ { address : 'TQFxDSoXy2yXRE5HtKwAwrNRXGxYxkeSGk' , amount : '1000000' } ] ,
567+ } ,
568+ txPrebuild : { } ,
569+ wallet : { } ,
570+ walletType : 'tss' ,
571+ } ;
572+
573+ await assert . rejects ( basecoin . verifyTransaction ( params ) , {
574+ message : 'missing txHex in txPrebuild' ,
575+ } ) ;
576+ } ) ;
577+ } ) ;
420578} ) ;
0 commit comments