Skip to content

Commit 3902e57

Browse files
authored
Merge pull request #7299 from BitGo/vechain-wrw
feat: recover function for vet recovery
2 parents 1280ae6 + de5f8bd commit 3902e57

File tree

9 files changed

+588
-5
lines changed

9 files changed

+588
-5
lines changed

modules/bitgo/test/v2/lib/recovery-nocks.ts

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,96 @@ module.exports.nockEthLikeRecovery = function (bitgo, nockData = nockEthData) {
416416
});
417417
};
418418

419+
module.exports.nockVetRecovery = function (bitgo, baseAddress) {
420+
// nock for account balance
421+
const url = Environments[bitgo.getEnv()].vetNodeUrl;
422+
nock(url).get(`/accounts/${baseAddress}`).reply(200, {
423+
balance: '0x8ac7230489e80000',
424+
energy: '0x5969b539627800',
425+
hasCode: false,
426+
});
427+
428+
nock(url).get('/blocks/best').reply(200, {
429+
number: 23107826,
430+
id: '0x016098f2a6779c3ad2bb52ef0a3f57c770af55a77bfa1b2837266f752118ad8d',
431+
size: 368,
432+
parentID: '0x016098f1acffb0125ffeca9b3e2491d31574d14b55a15e912e45e8081e063e0e',
433+
timestamp: 1761116630,
434+
gasLimit: 40000000,
435+
beneficiary: '0xae99cb89767a09d53e589a40cb4016974aba4b94',
436+
gasUsed: 0,
437+
totalScore: 218523577,
438+
txsRoot: '0x45b0cfc220ceec5b7c1c62c4d4193d38e4eba48e8815729ce75f9c0ab0e4c1c0',
439+
txsFeatures: 1,
440+
stateRoot: '0x7a5e7b3b8b89958e7fdd5e14acbc79dbc419672e84d02376a43b3beebe555e33',
441+
receiptsRoot: '0x45b0cfc220ceec5b7c1c62c4d4193d38e4eba48e8815729ce75f9c0ab0e4c1c0',
442+
com: true,
443+
signer: '0xae99cb89767a09d53e589a40cb4016974aba4b94',
444+
isTrunk: true,
445+
isFinalized: false,
446+
baseFeePerGas: '0x9184e72a000',
447+
transactions: [],
448+
});
449+
450+
nock(url)
451+
.post('/accounts/*', {
452+
clauses: [
453+
{
454+
to: '0xac05da78464520aa7c9d4c19bd7a440b111b3054',
455+
value: '10000000000000000000',
456+
data: '0x',
457+
},
458+
],
459+
caller: `${baseAddress}`,
460+
})
461+
.reply(200, [
462+
{
463+
data: '0x',
464+
events: [],
465+
transfers: [
466+
{
467+
sender: `${baseAddress}`,
468+
recipient: '0xac05da78464520aa7c9d4c19bd7a440b111b3054',
469+
amount: '0x8ac7230489e80000',
470+
},
471+
],
472+
gasUsed: 0,
473+
reverted: false,
474+
vmError: '',
475+
},
476+
]);
477+
// nock for vtho balance for gas
478+
nock(url)
479+
.post('/accounts/*', {
480+
clauses: [
481+
{
482+
to: '0x0000000000000000000000000000456E65726779',
483+
value: '0x0',
484+
data: `0x70a08231000000000000000000000000${baseAddress.slice(2)}`,
485+
},
486+
],
487+
})
488+
.reply(200, [
489+
{
490+
data: '0x000000000000000000000000000000000000000000000007e982789f8fe0cf0a',
491+
events: [],
492+
transfers: [],
493+
gasUsed: 870,
494+
reverted: false,
495+
vmError: '',
496+
},
497+
]);
498+
499+
nock(url)
500+
.post('/transactions', {
501+
raw: /^0x[0-9a-f]+$/i,
502+
})
503+
.reply(200, {
504+
id: '0x' + 'a'.repeat(64), // A fake transaction ID
505+
reverted: false,
506+
});
507+
};
508+
419509
module.exports.nockEtherscanRateLimitError = function () {
420510
const response = {
421511
status: '0',

modules/bitgo/test/v2/unit/recovery.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1457,4 +1457,48 @@ describe('Recovery:', function () {
14571457
(output.txRequests[0].transactions[0].unsignedTx.parsedTx as { outputs: any[] }).should.have.property('outputs');
14581458
});
14591459
});
1460+
1461+
describe('RecoverVet', function () {
1462+
beforeEach(() => {
1463+
nock.cleanAll();
1464+
});
1465+
let recoveryParams;
1466+
1467+
it('should construct a recovery tx with MPCv2 TSS', async function () {
1468+
const basecoin = bitgo.coin('tvet');
1469+
const baseAddress = ethLikeDKLSKeycard.senderAddress;
1470+
recoveryNocks.nockVetRecovery(bitgo, baseAddress);
1471+
recoveryParams = {
1472+
userKey: ethLikeDKLSKeycard.userKey,
1473+
backupKey: ethLikeDKLSKeycard.backupKey,
1474+
walletContractAddress: baseAddress,
1475+
recoveryDestination: ethLikeDKLSKeycard.destinationAddress,
1476+
walletPassphrase: ethLikeDKLSKeycard.walletPassphrase,
1477+
isTss: true,
1478+
};
1479+
1480+
const recovery = await basecoin.recover(recoveryParams);
1481+
1482+
should.exist(recovery);
1483+
recovery.should.have.property('id');
1484+
recovery.should.have.property('tx');
1485+
});
1486+
1487+
it('should construct an unsigned sweep tx with TSS', async function () {
1488+
recoveryNocks.nockVetRecovery(bitgo, '0xad848d2c97a08b2cd5e7f28f76ecd45dd0f82e0e');
1489+
const basecoin = bitgo.coin('tvet');
1490+
1491+
const unsignedSweepRecoveryParams = {
1492+
bitgoKey:
1493+
'03f54983c529802697d9a2320ded23eb7f15118fcba01156356c2264f04d32b4caa77fcf8cf3f73547078e984f28787c4c1e694586214b609e45b6de9cc32ad6e5',
1494+
recoveryDestination: ethLikeDKLSKeycard.destinationAddress,
1495+
};
1496+
1497+
const recovery = await basecoin.recover(unsignedSweepRecoveryParams);
1498+
should.exist(recovery);
1499+
recovery.should.have.property('txHex');
1500+
recovery.should.have.property('coin');
1501+
recovery.coin.should.equal('tvet');
1502+
});
1503+
});
14601504
});

modules/sdk-coin-vet/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
"@bitgo/sdk-core": "^36.15.0",
4646
"@bitgo/secp256k1": "^1.6.0",
4747
"@bitgo/statics": "^58.7.0",
48+
"@bitgo/sdk-lib-mpc": "^10.8.1",
4849
"@noble/curves": "1.8.1",
4950
"@vechain/sdk-core": "^1.2.0-rc.3",
5051
"bignumber.js": "^9.1.1",

modules/sdk-coin-vet/src/lib/constants.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,9 @@ export const STARGATE_DELEGATION_ADDRESS = '0x4cb1c9ef05b529c093371264fab2c93cc6
1515

1616
export const STARGATE_NFT_ADDRESS_TESTNET = '0x1ec1d168574603ec35b9d229843b7c2b44bcb770';
1717
export const STARGATE_DELEGATION_ADDRESS_TESTNET = '0x7240e3bc0d26431512d5b67dbd26d199205bffe8';
18+
19+
export const AVG_GAS_UNITS = '21000';
20+
export const EXPIRATION = 400;
21+
export const GAS_PRICE_COEF = '128';
22+
export const GAS_UNIT_PRICE = '10000000000000'; // vechain has fixed gas unit price of 10^13 wei
23+
export const COEF_DIVISOR = '255';

modules/sdk-coin-vet/src/lib/transaction/transaction.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export class Transaction extends BaseTransaction {
3232
private _senderSignature: Buffer | null;
3333
private _feePayerAddress: string;
3434
private _feePayerSignature: Buffer | null;
35+
private _isRecovery: boolean;
3536

3637
constructor(_coinConfig: Readonly<CoinConfig>) {
3738
super(_coinConfig);
@@ -47,6 +48,7 @@ export class Transaction extends BaseTransaction {
4748
this._recipients = [];
4849
this._senderSignature = null;
4950
this._feePayerSignature = null;
51+
this._isRecovery = false;
5052
}
5153

5254
public get id(): string {
@@ -198,6 +200,14 @@ export class Transaction extends BaseTransaction {
198200
this._transactionData = transactionData;
199201
}
200202

203+
get isRecovery(): boolean {
204+
return this._isRecovery;
205+
}
206+
207+
set isRecovery(isRecovery: boolean) {
208+
this._isRecovery = isRecovery;
209+
}
210+
201211
/**
202212
* Get all signatures associated with this transaction
203213
* Required by BaseTransaction
@@ -337,6 +347,9 @@ export class Transaction extends BaseTransaction {
337347
if (halfSignedTransaction.signature) {
338348
this._rawTransaction = halfSignedTransaction;
339349
this._sender = halfSignedTransaction.origin.toString().toLowerCase();
350+
if (this.isRecovery) {
351+
this._id = halfSignedTransaction.id.toString();
352+
}
340353
} else {
341354
return;
342355
}
@@ -372,7 +385,7 @@ export class Transaction extends BaseTransaction {
372385
};
373386

374387
if (
375-
this.type === TransactionType.Send ||
388+
(this.type === TransactionType.Send && !this.isRecovery) ||
376389
this.type === TransactionType.SendToken ||
377390
this.type === TransactionType.SendNFT ||
378391
this.type === TransactionType.ContractCall ||

modules/sdk-coin-vet/src/lib/transactionBuilder/transactionBuilder.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {
4545
return this;
4646
}
4747

48+
isRecovery(isRecovery: boolean): this {
49+
this._transaction.isRecovery = isRecovery;
50+
return this;
51+
}
52+
4853
/**
4954
* Sets the sender of this transaction.
5055
*

modules/sdk-coin-vet/src/lib/types.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,22 @@ export interface ClaimRewardsData {
1515
claimBaseRewards?: boolean;
1616
claimStakingRewards?: boolean;
1717
}
18+
19+
export type RecoverOptions = {
20+
userKey?: string;
21+
backupKey?: string;
22+
walletPassphrase?: string;
23+
recoveryDestination: string;
24+
isUnsignedSweep?: boolean; // specify if this is an unsigned recovery
25+
bitgoKey?: string;
26+
};
27+
28+
export interface RecoveryTransaction {
29+
id: string;
30+
tx: string;
31+
}
32+
33+
export interface UnsignedSweepRecoveryTransaction {
34+
txHex: string;
35+
coin: string;
36+
}

0 commit comments

Comments
 (0)