@@ -6,24 +6,27 @@ import should = require('should');
66import { randomBytes } from 'crypto' ;
77import * as sinon from 'sinon' ;
88import { TestBitGo , TestBitGoAPI } from '@bitgo/sdk-test' ;
9- import { BitGoAPI } from '@bitgo/sdk-api' ;
9+ import { BitGoAPI , encrypt } from '@bitgo/sdk-api' ;
1010import {
11- rawTx ,
12- enterpriseAccounts as accounts ,
13- privateKeys ,
14- publicKeys ,
15- wrwUser ,
16- consolidationWrwUser ,
1711 address ,
12+ consolidationWrwUser ,
1813 endpointResponses ,
19- testnetUTXO ,
14+ enterpriseAccounts as accounts ,
2015 ovcResponse ,
2116 ovcResponse2 ,
17+ privateKeys ,
18+ publicKeys ,
19+ rawTx ,
20+ testnetUTXO ,
21+ wrwUser ,
2222} from '../resources' ;
2323import * as _ from 'lodash' ;
2424import { Ada , KeyPair , Tada } from '../../src' ;
2525import { Transaction } from '../../src/lib' ;
2626import { TransactionType } from '../../../sdk-core/src/account-lib/baseCoin/enum' ;
27+ import assert from 'assert' ;
28+ import { common , Wallet } from '@bitgo/sdk-core' ;
29+ import nock from 'nock' ;
2730
2831describe ( 'ADA' , function ( ) {
2932 const coinName = 'ada' ;
@@ -245,6 +248,174 @@ describe('ADA', function () {
245248 const validTransaction = await basecoin . verifyTransaction ( { txParams, txPrebuild } ) ;
246249 validTransaction . should . equal ( true ) ;
247250 } ) ;
251+
252+ it ( 'should verify a valid consolidation transaction' , async ( ) => {
253+ const consolidationTx = {
254+ txRequestId : '1b5c79c5-ab7c-4f47-912b-de6a95fb0779' ,
255+ walletId : '64fa31a94db65a0007c9691b' ,
256+ txHex :
257+ '84a40081825820db46c7c76ea54fec2ca0a2f94b77a238931a8dce2387c99a12b08dd8aac21c4f000181825839004601fc016ac38580916d3520bc76b659298156008738d347aa93142f4601fc016ac38580916d3520bc76b659298156008738d347aa93142f1a3b984357021a000286a9031a060e37eea0f5f6' ,
258+ feeInfo : {
259+ fee : 165545 ,
260+ feeString : '165545' ,
261+ } ,
262+ txInfo : {
263+ minerFee : '165545' ,
264+ spendAmount : '999834455' ,
265+ spendAmounts : [
266+ {
267+ coinName : 'tada' ,
268+ amountString : '999834455' ,
269+ } ,
270+ ] ,
271+ payGoFee : '0' ,
272+ outputs : [
273+ {
274+ address :
275+ 'addr_test1qprqrlqpdtpctqy3d56jp0rkkevjnq2kqzrn356842f3gt6xq87qz6krskqfzmf4yz78ddje9xq4vqy88rf5025nzshsjdmg2s' ,
276+ value : 999834455 ,
277+ wallet : '64fa31a94db65a0007c9691b' ,
278+ wallets : [ '64fa31a94db65a0007c9691b' ] ,
279+ enterprise : '62cc59b727443a0007089033' ,
280+ enterprises : [ '62cc59b727443a0007089033' ] ,
281+ valueString : '999834455' ,
282+ coinName : 'tada' ,
283+ walletType : 'hot' ,
284+ walletTypes : [ 'hot' ] ,
285+ } ,
286+ ] ,
287+ inputs : [
288+ {
289+ value : 1000000000 ,
290+ address :
291+ 'addr_test1qqlzxfl7tlgp999x4a7334pchycpkk72pykrsr3mryl3yj6xq87qz6krskqfzmf4yz78ddje9xq4vqy88rf5025nzshsvpgl8w' ,
292+ valueString : '1000000000' ,
293+ } ,
294+ ] ,
295+ type : '0' ,
296+ } ,
297+ consolidateId : '68b9fc18558006aab53785615fea7c28' ,
298+ coin : 'tada' ,
299+ } ;
300+
301+ const mockedWallet = {
302+ coinSpecific : ( ) => {
303+ return {
304+ rootAddress :
305+ 'addr_test1qprqrlqpdtpctqy3d56jp0rkkevjnq2kqzrn356842f3gt6xq87qz6krskqfzmf4yz78ddje9xq4vqy88rf5025nzshsjdmg2s' ,
306+ } ;
307+ } ,
308+ } ;
309+
310+ try {
311+ const isVerified = await basecoin . verifyTransaction ( {
312+ txParams : { } ,
313+ txPrebuild : consolidationTx ,
314+ wallet : mockedWallet ,
315+ verification : {
316+ consolidationToBaseAddress : true ,
317+ } ,
318+ } ) ;
319+ isVerified . should . equal ( true ) ;
320+ } catch ( e ) {
321+ assert . fail ( 'Transaction should pass verification' ) ;
322+ }
323+ } ) ;
324+
325+ it ( 'should fail to sign a spoofed consolidation transaction' , async function ( ) {
326+ // Set up wallet data
327+ const walletData = {
328+ id : '5b34252f1bf349930e34020a00000000' ,
329+ coin : 'tada' ,
330+ keys : [
331+ '5b3424f91bf349930e34017500000000' ,
332+ '5b3424f91bf349930e34017600000000' ,
333+ '5b3424f91bf349930e34017700000000' ,
334+ ] ,
335+ coinSpecific : {
336+ rootAddress :
337+ 'addr_test1qprqrlqpdtpctqy3d56jp0rkkevjnq2kqzrn356842f3gt6xq87qz6krskqfzmf4yz78ddje9xq4vqy88rf5025nzshsjdmg2s' ,
338+ } ,
339+ multisigType : 'tss' ,
340+ } ;
341+ const fakePrv = encrypt ( 'password' , 'prv' ) ;
342+
343+ const walletObj = new Wallet ( bitgo , basecoin , walletData ) ;
344+ const bgUrl = common . Environments [ 'mock' ] . uri ;
345+
346+ nock ( bgUrl )
347+ . get ( '/api/v2/tada/key/5b3424f91bf349930e34017500000000' )
348+ . reply ( 200 , [
349+ {
350+ encryptedPrv : fakePrv ,
351+ } ,
352+ ] ) ;
353+
354+ // Mock the API response for buildAccountConsolidations
355+ nock ( bgUrl )
356+ . post ( '/api/v2/tada/wallet/5b34252f1bf349930e34020a00000000/consolidateAccount/build' )
357+ . reply ( 200 , [
358+ {
359+ txRequestId : '1b5c79c5-ab7c-4f47-912b-de6a95fb0779' ,
360+ walletId : '64fa31a94db65a0007c9691b' ,
361+ txHex :
362+ '84a40081825820db46c7c76ea54fec2ca0a2f94b77a238931a8dce2387c99a12b08dd8aac21c4f01018282581d6033c378cee41b2e15ac848f7f6f1d2f78155ab12d93b713de898d855f1a00989680825839004601fc016ac38580916d3520bc76b659298156008738d347aa93142f4601fc016ac38580916d3520bc76b659298156008738d347aa93142f1b0000000217acebe9021a00028db5031a060e3b41a0f5f6' ,
363+ feeInfo : {
364+ fee : 165545 ,
365+ feeString : '165545' ,
366+ } ,
367+ txInfo : {
368+ minerFee : '165545' ,
369+ spendAmount : '999834455' ,
370+ spendAmounts : [
371+ {
372+ coinName : 'tada' ,
373+ amountString : '999834455' ,
374+ } ,
375+ ] ,
376+ payGoFee : '0' ,
377+ outputs : [
378+ {
379+ address :
380+ 'addr_test1qprqrlqpdtpctqy3d56jp0rkkevjnq2kqzrn356842f3gt6xq87qz6krskqfzmf4yz78ddje9xq4vqy88rf5025nzshsjdmg2s' ,
381+ value : 999834455 ,
382+ wallet : '64fa31a94db65a0007c9691b' ,
383+ wallets : [ '64fa31a94db65a0007c9691b' ] ,
384+ enterprise : '62cc59b727443a0007089033' ,
385+ enterprises : [ '62cc59b727443a0007089033' ] ,
386+ valueString : '999834455' ,
387+ coinName : 'tada' ,
388+ walletType : 'hot' ,
389+ walletTypes : [ 'hot' ] ,
390+ } ,
391+ ] ,
392+ inputs : [
393+ {
394+ value : 1000000000 ,
395+ address :
396+ 'addr_test1qqlzxfl7tlgp999x4a7334pchycpkk72pykrsr3mryl3yj6xq87qz6krskqfzmf4yz78ddje9xq4vqy88rf5025nzshsvpgl8w' ,
397+ valueString : '1000000000' ,
398+ } ,
399+ ] ,
400+ type : '0' ,
401+ } ,
402+ consolidateId : '68b9fc18558006aab53785615fea7c28' ,
403+ coin : 'tada' ,
404+ } ,
405+ ] ) ;
406+
407+ // Call the function to test
408+ await assert . rejects (
409+ async ( ) => {
410+ await walletObj . sendAccountConsolidations ( {
411+ walletPassphrase : 'password' ,
412+ } ) ;
413+ } ,
414+ {
415+ message : 'tx outputs does not match with expected address' ,
416+ }
417+ ) ;
418+ } ) ;
248419 } ) ;
249420
250421 describe ( 'Explain Transactions:' , ( ) => {
@@ -640,4 +811,91 @@ describe('ADA', function () {
640811 sandBox . assert . calledTwice ( basecoin . getDataFromNode ) ;
641812 } ) ;
642813 } ) ;
814+
815+ describe ( 'Verify token consolidation transaction:' , ( ) => {
816+ it ( 'should fail to verify a spoofed token consolidation transaction with incorrect address' , async ( ) => {
817+ const consolidationTx = {
818+ txRequestId : '4fdd0cae-2563-43b1-b5cf-94865158ca10' ,
819+ walletId : '63068ed4efa63a000877f02fd4b0fa6d' ,
820+ txHex :
821+ '84a400818258204bd0f991c1532cffe31d4a10db492b43175ec326765b6b29ceee598df2b61f470001818258390087379ebc5533ebe621963c915c3cbc5f08537fcdca4af8f8ae08ed4c87379ebc5533ebe621963c915c3cbc5f08537fcdca4af8f8ae08ed4c1a05f359ff021a00028701031a024972e1a10081825820bbacb13431b99208e6e8cdbf710147feaf06a39d71565e60b411ce9e4fa3f137584001a4ab8236563f69ff309e5786e8f39c629ed57676c692159cb2e0494c9e663355384c13c749d04c17a80ba2a45cc127df480fc64a43199a772f11acd5b14a0ff5f6' ,
822+ feeInfo : {
823+ fee : 10000 ,
824+ feeString : '10000' ,
825+ } ,
826+ txInfo : {
827+ inputs : [
828+ {
829+ address : '8iLa26KSbdpBUzNK7uYq8FvyuyA5h4k4erDHsDcPbHus' ,
830+ value : 2.0173228e10 ,
831+ valueString : '20173228000' ,
832+ } ,
833+ {
834+ address : '8P2kX7Tyh9eS3RKdaBhqbEtQGAX58DXzL7mhDQABGX2d' ,
835+ value : 10000 ,
836+ valueString : '10000' ,
837+ } ,
838+ ] ,
839+ minerFee : '10000' ,
840+ outputs : [
841+ {
842+ address : 'addr_test1vr8rakm66rcfv4fcxqykg5lf0yv7lsyk9mvapx369jpvtcgfcuk7f' ,
843+ coinName : 'tada:usdt' ,
844+ enterprise : {
845+ $oid : '5553ba8ae7a5c77006719661' ,
846+ } ,
847+ enterprises : [
848+ {
849+ $oid : '5553ba8ae7a5c77006719661' ,
850+ } ,
851+ ] ,
852+ value : 2.0173228e10 ,
853+ valueString : '20173228000' ,
854+ wallet : {
855+ $oid : '62f4c3720d92c50008257eb5' ,
856+ } ,
857+ walletType : 'hot' ,
858+ wallets : [
859+ {
860+ $oid : '62f4c3720d92c50008257eb5' ,
861+ } ,
862+ ] ,
863+ } ,
864+ ] ,
865+ payGoFee : '0' ,
866+ spendAmount : '20173228000' ,
867+ spendAmounts : [
868+ {
869+ amountString : '20173228000' ,
870+ coinName : 'tada:usdt' ,
871+ } ,
872+ ] ,
873+ type : 'Send' ,
874+ } ,
875+ consolidateId : '6712d7fda6de4906d658c04aebbf8f9b' ,
876+ coin : 'tada' ,
877+ } ;
878+
879+ // Mock the wallet with a different address than the transaction's output
880+ const mockedWallet = {
881+ coinSpecific : ( ) => {
882+ return {
883+ rootAddress :
884+ 'addr_test1qqnnvptrc3rec64q2n9jh572ncu5wvdtt8uvg4g3aj96s5dwu9nj70mlahzglm9939uevupsmj8dcdqv25d5n5r8vw8sn7prey' ,
885+ } ;
886+ } ,
887+ } ;
888+
889+ await basecoin
890+ . verifyTransaction ( {
891+ txParams : { } ,
892+ txPrebuild : consolidationTx ,
893+ wallet : mockedWallet ,
894+ verification : {
895+ consolidationToBaseAddress : true ,
896+ } ,
897+ } )
898+ . should . be . rejectedWith ( 'tx outputs does not match with expected address' ) ;
899+ } ) ;
900+ } ) ;
643901} ) ;
0 commit comments