Skip to content

Commit 64a865a

Browse files
committed
feat(sdk-coin-flr): handle tss wallets flow and add unit tests
Ticket: WIN-7886
1 parent 8789bdb commit 64a865a

File tree

2 files changed

+237
-1
lines changed

2 files changed

+237
-1
lines changed

modules/sdk-coin-flr/src/flr.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,13 @@ export class Flr extends AbstractEthLikeNewCoins {
215215
* @returns {Promise<boolean>}
216216
*/
217217
async verifyTransaction(params: VerifyFlrTransactionOptions): Promise<boolean> {
218-
const { txParams, txPrebuild, wallet } = params;
218+
const { txParams, txPrebuild, wallet, walletType } = params;
219+
220+
// For TSS wallets, use the parent class's TSS-specific verification
221+
if (walletType === 'tss') {
222+
return super.verifyTransaction(params);
223+
}
224+
219225
if (!txParams?.recipients || !txPrebuild?.recipients || !wallet) {
220226
throw new Error(`missing params`);
221227
}

modules/sdk-coin-flr/test/unit/flr.ts

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)