Skip to content

Commit 119c3e2

Browse files
feat: adding test case for non bitgo recovery of songbird
Ticket: WIN-5187 TICKET: WIN-5187
1 parent b6c1977 commit 119c3e2

File tree

3 files changed

+93
-2
lines changed

3 files changed

+93
-2
lines changed

modules/sdk-coin-sgb/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@
4343
"@bitgo/abstract-eth": "^24.1.0",
4444
"@bitgo/sdk-core": "^32.1.0",
4545
"@bitgo/statics": "^51.7.0",
46-
"@ethereumjs/common": "^2.6.5"
46+
"@ethereumjs/common": "^2.6.5",
47+
"@ethereumjs/tx": "^3.3.0"
4748
},
4849
"devDependencies": {
4950
"@bitgo/sdk-api": "^1.61.5",

modules/sdk-coin-sgb/test/resources.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,47 @@ export const mockDataUnsignedSweep = {
4242
getBalanceRequest: getBalanceRequestUnsignedSweep,
4343
getBalanceResponse: getBalanceResponseUnsignedSweep,
4444
};
45+
46+
const getTxListRequestNonBitGoRecovery: Record<string, string> = {
47+
module: 'account',
48+
action: 'txlist',
49+
address: '0xf0eb7b6448b4822bab6d1862f33d5b691e8af76d',
50+
};
51+
52+
const getTxListResponseNonBitGoRecovery: Record<string, unknown> = {
53+
status: '1',
54+
result: [
55+
{
56+
hash: '0xede855d43d70ea1bb75db63d4f75113dae0845f0d4bdb0b2d8bda55249c70812',
57+
nonce: '23',
58+
from: '0xf0eb7b6448b4822bab6d1862f33d5b691e8af76d',
59+
},
60+
],
61+
message: 'OK',
62+
};
63+
64+
const getBalanceRequestNonBitGoRecovery: Record<string, string> = {
65+
module: 'account',
66+
action: 'balance',
67+
address: '0xf0eb7b6448b4822bab6d1862f33d5b691e8af76d',
68+
};
69+
70+
const getBalanceResponseNonBitGoRecovery: Record<string, unknown> = {
71+
status: '1',
72+
result: '100000000000000000',
73+
message: 'OK',
74+
};
75+
76+
export const mockDataNonBitGoRecovery = {
77+
recoveryDestination: '0x07efb1aa5e41b70b21facd3d287548ebf632a165',
78+
userKeyData:
79+
'{"iv":"6aXzf67jGhzF9DETi5fSYA==","v":1,"iter":10000,"ks":256,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"GH7WVWtq29w=","ct":"7Q4XFo963IJDtxbSUl/GQMSESIh8G7Wnlp6cj4aTNdSrPgvXKauP/ZdyeRogniIIw6fs3Xv7q09rBpv5r3vLiAURWHqoUmzEvl2Qs0XqFHT5X5qsf/neax7Bs53PgUvAxQNIq+OkAKANDYrF7MgehyPrws4lbraOXeN2kmTfxDuJK4r8ptcZzI+v+4iASLxfelXhfVz95lOi+9yhlfZjEmC6j0B7So+QTFtszeCESA93Wy3bZA0TnCSdl16i3JdRX5ZdAe+Dc+OSX8wVmOXRG7mf+IQDgB4MJSLkhlGM1AOrbTCuOLbZcUy8EqZoEwFZBoTFhAASpROwVyNgz/kjVVNiMaMCh+Lhmofb2arOg+OftBKgxF0cY4gXZ/bE+vGHjxRfA6HbeGHubo6nQev/QbWYS1TlSzGSuY4/XPvpuEvYWJW6FX8pi+u7X3yBBuQ2xzo8gA8pS0v2cTVdnxmRRXjKHZrRiAeWv1iMGK6lqkWmRZDp7xKJ69Yi07OHX/wSA9ZGTeUYxmNkAgg2WSC5CUIXrDjGrvwY9+Gf08HILOKIKdghwnO1P5nGr7Wa2/frnUafPWiR92FeDjS3/bYQQroD4+n2QFpL78lltn6O60ybQJG9y8wXG3bK1howSuIkxPJW7vsFl+/7gfEGxeTm47I6ug1ILIAkzgN8EdhvJ6wtaZ+imqoQO++YWMnI7ZaKnD/F1g10euVmujW8pYqR83m6/OzwunM7bwltEhCEc8RmUXB3imGpQgJz9jjSVBpckVV7EsUeU8RIA0ArhgOWEjtZjB7VgGD8pG1CnDNfxaP89ZEG1D8jq96L+xTwm8Lht2pf0XLzcJgsXaDFbSbKUSxdDbBWqiyXqPbQM+baaGSmuuTgIRtG5YDzRVuLfSZ8Jwk3vjQRgnEjaesI4TIzDvlCtB8qFRUzoOFQUdbyRTyu1MfURms6F0g/SZbe1VUQ67JytNcqqsdUVkjgrS29KhhXy4vfux3RBGkZh6iKQ9FDBmFYCXmo1cKHkusuBNDSnh5yCEWjsivAnjWc0qHjvOv79BaF/cUqbiHj7bZXoszNAyOn4prXVvAOVQQVun5OL83VH2DHQIM="}',
80+
backupKeyData:
81+
'{"iv":"IITI4f9oCjp4dgo4h6aL5Q==","v":1,"iter":10000,"ks":256,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"0dEc0kZi+3E=","ct":"hf8s5Se1rdb1lh0gXyanqAP4TrQTxK7TJtgJfZ/naN75yWwF5cC/vyFfJ4FNudXaFZ7yw0aFN+VUpp2HczFuPspw3yBpejfqjFZSijD1p2VZnNEIVZE7i+KVR0f3V+Oah+KQXCpWucT2eXSTSXAGxT3FtuS5Ro9FzltNj2xz0SM8OcunXb/0h69tisjZYOGSjSLgWFHIkhc46qukD+Ay2A1u/kSTC9l7/UTG1PncbRTlHM+Rx3I9bmCgbrNxqXpEEm2Uz3q+xQRTeC1q46sMnCfNz82GEntp5Z6SeMhlq63tZR2VIDC1lPR9ZIz1eygtK+ibT6yzFpRhBBy3QOSJPL7c9NYGGSQcNsjxsynghYBeL/K/qcPGQn18cDmGSFQmAAmUpHqPU68tQgbT6YF83Wsu5oHjDBQufdJeNH+rfWrj/qQNmwmpMkrm6EKD0tLK/8Dx4YdvvjfmB3kkniO6OFz1pQXTHn3esBL7PctjMyslNCOAP/yKFEQbUdSoGfWTIiJ1bJ8CZquCQGiRgmSE6Xv/uU81xW8BmVmmddaI0kfUTL8Uyhevbi4h8WWL15yi21fhMu0ioXmMtAfm26yubGojlMSkspVKyyDtvHzypSEde+MGp2OgTPm6JntDKzGu29MQSveTH4Y0Sz7oeocTDOfnY63xV+hKZI4C0xI6cNNDh1JyJHzO1srDrG8RfXk0o+d0vD7m/tSvsC2DnnT5kEQK+Mvs88fbi/32wu20DZYk/p3+7ZDeynGsmdzNVjPVDpI5Au4zoI4skFwzjQ/wk1HYRWK6SJizeiMgvtTubJsCFWGWdKs07CtBkaJwqxeHiVUdjYZ50hpRpiZ8SkCzQjJsiAnS8mMplBVw2zEUyIOxRbbOjzLDAI+tbrPk/SqLxFcS9DAA+mXzmmGCR4pSfJx15G0d7RlNu8wcjjCSj/f8imGkW6R2EiFlPvKgKjaqUmO+Wfe2A5ek0TxyHe2cDEKuHO4Oum/yFzCgGNGntgvT6qzybunLSM0XBMvqTEOClpcuZS/DPbk4F7w6DMCR5Yg6zEw58wDWqZjOpWP7s/j5F5TFZBfvNzGakgTYRNxg"}',
82+
walletPassphrase: 'prithvishet2503',
83+
walletRootAddress: '0xf0eb7b6448b4822bab6d1862f33d5b691e8af76d',
84+
getTxListRequest: getTxListRequestNonBitGoRecovery,
85+
getTxListResponse: getTxListResponseNonBitGoRecovery,
86+
getBalanceRequest: getBalanceRequestNonBitGoRecovery,
87+
getBalanceResponse: getBalanceResponseNonBitGoRecovery,
88+
};

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

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ import { BitGoAPI } from '@bitgo/sdk-api';
55

66
import { Sgb, Tsgb } from '../../src/index';
77
import { UnsignedSweepTxMPCv2 } from '@bitgo/abstract-eth';
8-
import { mockDataUnsignedSweep } from '../resources';
8+
import { mockDataUnsignedSweep, mockDataNonBitGoRecovery } from '../resources';
99
import nock from 'nock';
1010
import { common } from '@bitgo/sdk-core';
11+
import { FeeMarketEIP1559Transaction } from '@ethereumjs/tx';
12+
import { stripHexPrefix } from '@ethereumjs/util';
1113

1214
const bitgo: TestBitGoAPI = TestBitGo.decorate(BitGoAPI, { env: 'test' });
1315

@@ -96,3 +98,47 @@ describe('Build Unsigned Sweep for Self-Custody Cold Wallets - (MPCv2)', functio
9698
tx.unsignedTx.parsedTx?.should.have.property('outputs');
9799
});
98100
});
101+
102+
describe('Non Bitgo Recovery for Hot Wallets', function () {
103+
const bitgo = TestBitGo.decorate(BitGoAPI, { env: 'test' });
104+
const explorerUrl = common.Environments[bitgo.getEnv()].sgbExplorerBaseUrl as string;
105+
const maxFeePerGasvalue = 20000000000;
106+
const maxPriorityFeePerGasValue = 10000000000;
107+
const chain_id = 16;
108+
const gasLimitvalue = 500000;
109+
110+
it('should generate a signed non-bitgo recovery tx', async () => {
111+
nock(explorerUrl)
112+
.get('/api')
113+
.twice()
114+
.query(mockDataNonBitGoRecovery.getTxListRequest)
115+
.reply(200, mockDataNonBitGoRecovery.getTxListResponse);
116+
nock(explorerUrl)
117+
.get('/api')
118+
.query(mockDataNonBitGoRecovery.getBalanceRequest)
119+
.reply(200, mockDataNonBitGoRecovery.getBalanceResponse);
120+
121+
const baseCoin: any = bitgo.coin('tsgb');
122+
const transaction = await baseCoin.recover({
123+
userKey: mockDataNonBitGoRecovery.userKeyData,
124+
backupKey: mockDataNonBitGoRecovery.backupKeyData,
125+
walletContractAddress: mockDataNonBitGoRecovery.walletRootAddress,
126+
walletPassphrase: mockDataNonBitGoRecovery.walletPassphrase,
127+
recoveryDestination: mockDataNonBitGoRecovery.recoveryDestination,
128+
isTss: true,
129+
eip1559: { maxFeePerGas: maxFeePerGasvalue, maxPriorityFeePerGas: maxPriorityFeePerGasValue },
130+
gasLimit: gasLimitvalue,
131+
replayProtectionOptions: {
132+
chain: chain_id,
133+
hardfork: 'london',
134+
},
135+
});
136+
should.exist(transaction);
137+
transaction.should.have.property('id');
138+
transaction.should.have.property('tx');
139+
const tx = FeeMarketEIP1559Transaction.fromSerializedTx(Buffer.from(stripHexPrefix(transaction.tx), 'hex'));
140+
tx.getSenderAddress().toString().should.equal(mockDataNonBitGoRecovery.walletRootAddress);
141+
const jsonTx = tx.toJSON();
142+
jsonTx.to?.should.equal(mockDataNonBitGoRecovery.recoveryDestination);
143+
});
144+
});

0 commit comments

Comments
 (0)