Skip to content

Commit fe96f7f

Browse files
authored
Merge pull request #7317 from BitGo/vet-wrw-token
feat: add logic for vechain token recoveries
2 parents 2712283 + aaaf29b commit fe96f7f

File tree

6 files changed

+340
-17
lines changed

6 files changed

+340
-17
lines changed

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

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,115 @@ module.exports.nockVetRecovery = function (bitgo, baseAddress) {
506506
});
507507
};
508508

509+
module.exports.nockVetTokenRecovery = function (bitgo, baseAddress) {
510+
// nock for account balance
511+
const url = Environments[bitgo.getEnv()].vetNodeUrl;
512+
nock(url)
513+
.post('/accounts/*', {
514+
clauses: [
515+
{
516+
to: '0x0000000000000000000000000000456E65726779',
517+
value: '0x0',
518+
data: `0x70a08231000000000000000000000000${baseAddress.slice(2)}`,
519+
},
520+
],
521+
})
522+
.reply(200, [
523+
{
524+
data: '0x000000000000000000000000000000000000000000000000416003863bd917f8',
525+
events: [],
526+
transfers: [],
527+
gasUsed: 870,
528+
reverted: false,
529+
vmError: '',
530+
},
531+
]);
532+
533+
nock(url).get('/blocks/best').reply(200, {
534+
number: 23107826,
535+
id: '0x016098f2a6779c3ad2bb52ef0a3f57c770af55a77bfa1b2837266f752118ad8d',
536+
size: 368,
537+
parentID: '0x016098f1acffb0125ffeca9b3e2491d31574d14b55a15e912e45e8081e063e0e',
538+
timestamp: 1761116630,
539+
gasLimit: 40000000,
540+
beneficiary: '0xae99cb89767a09d53e589a40cb4016974aba4b94',
541+
gasUsed: 0,
542+
totalScore: 218523577,
543+
txsRoot: '0x45b0cfc220ceec5b7c1c62c4d4193d38e4eba48e8815729ce75f9c0ab0e4c1c0',
544+
txsFeatures: 1,
545+
stateRoot: '0x7a5e7b3b8b89958e7fdd5e14acbc79dbc419672e84d02376a43b3beebe555e33',
546+
receiptsRoot: '0x45b0cfc220ceec5b7c1c62c4d4193d38e4eba48e8815729ce75f9c0ab0e4c1c0',
547+
com: true,
548+
signer: '0xae99cb89767a09d53e589a40cb4016974aba4b94',
549+
isTrunk: true,
550+
isFinalized: false,
551+
baseFeePerGas: '0x9184e72a000',
552+
transactions: [],
553+
});
554+
555+
nock(url)
556+
.post('/accounts/*', {
557+
clauses: [
558+
{
559+
to: '0x0000000000000000000000000000456E65726779',
560+
value: '0x0',
561+
data: '0xa9059cbb000000000000000000000000ac05da78464520aa7c9d4c19bd7a440b111b305400000000000000000000000000000000000000000000000036a9d31575bcee8e',
562+
},
563+
],
564+
caller: `${baseAddress}`,
565+
})
566+
.reply(200, [
567+
{
568+
data: '0x0000000000000000000000000000000000000000000000000000000000000001',
569+
events: [
570+
{
571+
address: '0x0000000000000000000000000000456e65726779',
572+
topics: [
573+
'0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
574+
'0x000000000000000000000000880ff4718587d678e78fc7803b3634bd12ecf019',
575+
'0x000000000000000000000000ac05da78464520aa7c9d4c19bd7a440b111b3054',
576+
],
577+
data: '0x00000000000000000000000000000000000000000000000036a9d31575bcee8e',
578+
},
579+
],
580+
transfers: [],
581+
gasUsed: 13326,
582+
reverted: false,
583+
vmError: '',
584+
},
585+
]);
586+
// nock for vtho balance for gas
587+
nock(url)
588+
.post('/accounts/*', {
589+
clauses: [
590+
{
591+
to: '0x0000000000000000000000000000456E65726779',
592+
value: '0x0',
593+
data: `0x70a08231000000000000000000000000${baseAddress.slice(2)}`,
594+
},
595+
],
596+
})
597+
.reply(200, [
598+
{
599+
data: '0x000000000000000000000000000000000000000000000000416003863bd917f8',
600+
events: [],
601+
transfers: [],
602+
gasUsed: 870,
603+
reverted: false,
604+
vmError: '',
605+
},
606+
]);
607+
608+
nock(url)
609+
.post('/transactions', {
610+
raw: /^0x[0-9a-f]+$/i,
611+
})
612+
.reply(200, {
613+
id: '0x' + 'a'.repeat(64), // A fake transaction ID
614+
reverted: false,
615+
});
616+
};
617+
509618
module.exports.nockEtherscanRateLimitError = function () {
510619
const response = {
511620
status: '0',

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

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1500,5 +1500,43 @@ describe('Recovery:', function () {
15001500
recovery.should.have.property('coin');
15011501
recovery.coin.should.equal('tvet');
15021502
});
1503+
1504+
it('should construct a token(vtho) recovery tx with MPCv2 TSS', async function () {
1505+
const basecoin = bitgo.coin('tvet:vtho');
1506+
const baseAddress = ethLikeDKLSKeycard.senderAddress;
1507+
recoveryNocks.nockVetTokenRecovery(bitgo, baseAddress);
1508+
recoveryParams = {
1509+
userKey: ethLikeDKLSKeycard.userKey,
1510+
backupKey: ethLikeDKLSKeycard.backupKey,
1511+
walletContractAddress: baseAddress,
1512+
recoveryDestination: ethLikeDKLSKeycard.destinationAddress,
1513+
walletPassphrase: ethLikeDKLSKeycard.walletPassphrase,
1514+
tokenContractAddress: '0x0000000000000000000000000000456E65726779',
1515+
};
1516+
1517+
const recovery = await basecoin.recover(recoveryParams);
1518+
1519+
should.exist(recovery);
1520+
recovery.should.have.property('id');
1521+
recovery.should.have.property('tx');
1522+
});
1523+
1524+
it('should construct an unsigned sweep token tx(vtho) with TSS', async function () {
1525+
recoveryNocks.nockVetTokenRecovery(bitgo, '0xad848d2c97a08b2cd5e7f28f76ecd45dd0f82e0e');
1526+
const basecoin = bitgo.coin('tvet:vtho');
1527+
1528+
const unsignedSweepRecoveryParams = {
1529+
bitgoKey:
1530+
'03f54983c529802697d9a2320ded23eb7f15118fcba01156356c2264f04d32b4caa77fcf8cf3f73547078e984f28787c4c1e694586214b609e45b6de9cc32ad6e5',
1531+
recoveryDestination: ethLikeDKLSKeycard.destinationAddress,
1532+
tokenContractAddress: '0x0000000000000000000000000000456E65726779',
1533+
};
1534+
1535+
const recovery = await basecoin.recover(unsignedSweepRecoveryParams);
1536+
should.exist(recovery);
1537+
recovery.should.have.property('txHex');
1538+
recovery.should.have.property('coin');
1539+
recovery.coin.should.equal('tvet:vtho');
1540+
});
15031541
});
15041542
});

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,10 @@ export const EXPIRATION = 400;
2121
export const GAS_PRICE_COEF = '128';
2222
export const GAS_UNIT_PRICE = '10000000000000'; // vechain has fixed gas unit price of 10^13 wei
2323
export const COEF_DIVISOR = '255';
24+
25+
export const feeEstimateData = {
26+
gas: AVG_GAS_UNITS,
27+
gasUnitPrice: GAS_UNIT_PRICE,
28+
gasPriceCoef: GAS_PRICE_COEF,
29+
coefDivisor: COEF_DIVISOR,
30+
};

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export type RecoverOptions = {
2323
recoveryDestination: string;
2424
isUnsignedSweep?: boolean; // specify if this is an unsigned recovery
2525
bitgoKey?: string;
26+
tokenContractAddress?: string;
2627
};
2728

2829
export interface RecoveryTransaction {

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

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ import {
4343
VetParseTransactionOptions,
4444
} from './lib/types';
4545
import { VetTransactionExplanation } from './lib/iface';
46-
import { AVG_GAS_UNITS, COEF_DIVISOR, EXPIRATION, GAS_PRICE_COEF, GAS_UNIT_PRICE } from './lib/constants';
46+
import { AVG_GAS_UNITS, EXPIRATION, GAS_PRICE_COEF, feeEstimateData } from './lib/constants';
4747

4848
interface FeeEstimateData {
4949
gas: string;
@@ -52,13 +52,6 @@ interface FeeEstimateData {
5252
coefDivisor: string;
5353
}
5454

55-
const feeEstimateData: FeeEstimateData = {
56-
gas: AVG_GAS_UNITS,
57-
gasUnitPrice: GAS_UNIT_PRICE,
58-
gasPriceCoef: GAS_PRICE_COEF,
59-
coefDivisor: COEF_DIVISOR,
60-
};
61-
6255
/**
6356
* Full Name: Vechain
6457
* Docs: https://docs.vechain.org/
@@ -419,11 +412,6 @@ export class Vet extends BaseCoin {
419412

420413
const signedTx = await txBuilder.build();
421414

422-
// broadcast this transaction
423-
await this.broadcastTransaction({
424-
serializedSignedTransaction: signedTx.toBroadcastFormat(),
425-
});
426-
427415
return {
428416
id: signedTx.id,
429417
tx: signedTx.toBroadcastFormat(),
@@ -447,7 +435,7 @@ export class Vet extends BaseCoin {
447435
* @param {BigNumber} estimatedGasLimit - The estimated gas limit for the transaction.
448436
* @returns {BigNumber} The calculated transaction fee.
449437
*/
450-
private calculateFee(feeEstimateData: FeeEstimateData, estimatedGasLimit: BigNumber): BigNumber {
438+
protected calculateFee(feeEstimateData: FeeEstimateData, estimatedGasLimit: BigNumber): BigNumber {
451439
const gasLimit = estimatedGasLimit;
452440
const adjustmentFactor = new BigNumber(1).plus(
453441
new BigNumber(feeEstimateData.gasPriceCoef)
@@ -630,7 +618,7 @@ export class Vet extends BaseCoin {
630618
* @returns {Promise<Transaction>} A promise that resolves to the built recovery transaction.
631619
* @throws {Error} If there's no VET balance to recover or if there's an error building the transaction.
632620
*/
633-
private async buildRecoveryTransaction(buildParams: {
621+
protected async buildRecoveryTransaction(buildParams: {
634622
baseAddress: string;
635623
params: RecoverOptions;
636624
}): Promise<Transaction> {

0 commit comments

Comments
 (0)