diff --git a/modules/sdk-coin-vet/src/vet.ts b/modules/sdk-coin-vet/src/vet.ts index 2c57c644a2..814e7edfb6 100644 --- a/modules/sdk-coin-vet/src/vet.ts +++ b/modules/sdk-coin-vet/src/vet.ts @@ -20,7 +20,7 @@ import { SignedTransaction, SignTransactionOptions, TokenTransferRecipientParams, - VerifyAddressOptions, + TssVerifyAddressOptions, VerifyTransactionOptions, TokenType, Ecdsa, @@ -28,6 +28,7 @@ import { Environments, BaseBroadcastTransactionOptions, BaseBroadcastTransactionResult, + verifyMPCWalletAddress, } from '@bitgo/sdk-core'; import * as mpc from '@bitgo/sdk-lib-mpc'; import { BaseCoin as StaticsBaseCoin, coins } from '@bitgo/statics'; @@ -53,6 +54,12 @@ interface FeeEstimateData { coefDivisor: string; } +export interface TssVerifyVetAddressOptions extends TssVerifyAddressOptions { + address: string; + baseAddress?: string; + walletVersion?: number; +} + /** * Full Name: Vechain * Docs: https://docs.vechain.org/ @@ -153,12 +160,46 @@ export class Vet extends BaseCoin { return true; } - async isWalletAddress(params: VerifyAddressOptions): Promise { - const { address: newAddress } = params; + /** + * Verify that an address belongs to this wallet. + * + * @param {TssVerifyVetAddressOptions} params - Verification parameters + * @returns {Promise} True if address belongs to wallet + * @throws {InvalidAddressError} If address format is invalid + * @throws {Error} If invalid wallet version or missing parameters + */ + async isWalletAddress(params: TssVerifyVetAddressOptions): Promise { + const { address, baseAddress, walletVersion } = params; + + if (address && !this.isValidAddress(address)) { + throw new InvalidAddressError(`invalid address: ${address}`); + } + + if (walletVersion !== 6) { + throw new Error(`VET only supports wallet version 6, but got version ${walletVersion}`); + } + + const isVerifyingBaseAddress = baseAddress && address.toLowerCase() === baseAddress.toLowerCase(); + if (isVerifyingBaseAddress) { + const index = typeof params.index === 'string' ? parseInt(params.index, 10) : params.index; + if (index !== 0) { + throw new Error(`Base address verification requires index 0, but got index ${params.index}.`); + } + } - if (!this.isValidAddress(newAddress)) { - throw new InvalidAddressError(`invalid address: ${newAddress}`); + const result = await verifyMPCWalletAddress( + { ...params, keyCurve: 'secp256k1' }, + this.isValidAddress.bind(this), + (pubKey) => { + const keyPair = new EthKeyPair({ pub: pubKey }); + return keyPair.getAddress(); + } + ); + + if (!result) { + throw new InvalidAddressError(`invalid address: ${address}`); } + return true; } diff --git a/modules/sdk-coin-vet/test/unit/vet.ts b/modules/sdk-coin-vet/test/unit/vet.ts index 9385d7f449..6b804cb3f7 100644 --- a/modules/sdk-coin-vet/test/unit/vet.ts +++ b/modules/sdk-coin-vet/test/unit/vet.ts @@ -238,4 +238,99 @@ describe('Vechain', function () { basecoin.isValidAddress(address).should.equal(false); }); }); + + describe('address verification', () => { + const testData = { + walletVersion: 6, + commonKeychain: + '02fad451e7d1a536897ded5f803a73cc7309a403cf43bb25bda494b9800efe32999b6b71b6159eccf1244492556b733f68733a23c184bf40bc37c52da5ad29e575', + baseAddress: '0x8420429aa50b7f6ab196c4ce0dcf629fdbb821a1', + feeAddress: '0x33f9d3172de8a88e47b399562e51fa9cde0f2511', + depositAddress: '0x26b88c0a103d185792a9597580c2c5170d93f410', + depositIndex: 3, + forwarderVersion: 5, + }; + + it('should verify a valid TSS base address (wallet version 6)', async function () { + const params = { + address: testData.baseAddress, + baseAddress: testData.baseAddress, + keychains: [ + { commonKeychain: testData.commonKeychain }, + { commonKeychain: testData.commonKeychain }, + { commonKeychain: testData.commonKeychain }, + ], + index: 0, + walletVersion: testData.walletVersion, + coinSpecific: { + feeAddress: testData.feeAddress, + forwarderVersion: testData.forwarderVersion, + }, + }; + + const result = await basecoin.isWalletAddress(params); + result.should.equal(true); + }); + + it('should fail to verify a invalid TSS base address (wallet version 6)', async function () { + const params = { + address: '0x8420429aa50b7f6ab196c4ce0dcf629fdbb821a0', + baseAddress: testData.baseAddress, + keychains: [ + { commonKeychain: testData.commonKeychain }, + { commonKeychain: testData.commonKeychain }, + { commonKeychain: testData.commonKeychain }, + ], + index: 0, + walletVersion: testData.walletVersion, + coinSpecific: { + feeAddress: testData.feeAddress, + forwarderVersion: testData.forwarderVersion, + }, + }; + + await basecoin.isWalletAddress(params).should.be.rejected(); + }); + + it('should verify a valid TSS deposit address (wallet version 6)', async function () { + const params = { + address: testData.depositAddress, + baseAddress: testData.baseAddress, + keychains: [ + { commonKeychain: testData.commonKeychain }, + { commonKeychain: testData.commonKeychain }, + { commonKeychain: testData.commonKeychain }, + ], + index: testData.depositIndex, + walletVersion: testData.walletVersion, + coinSpecific: { + feeAddress: testData.feeAddress, + forwarderVersion: testData.forwarderVersion, + }, + }; + + const result = await basecoin.isWalletAddress(params); + result.should.equal(true); + }); + + it('should fail to verify a invalid TSS deposit address (wallet version 6)', async function () { + const params = { + address: '0x26b88c0a103d185792a9597580c2c5170d93f411', + baseAddress: testData.baseAddress, + keychains: [ + { commonKeychain: testData.commonKeychain }, + { commonKeychain: testData.commonKeychain }, + { commonKeychain: testData.commonKeychain }, + ], + index: testData.depositIndex, + walletVersion: testData.walletVersion, + coinSpecific: { + feeAddress: testData.feeAddress, + forwarderVersion: testData.forwarderVersion, + }, + }; + + await basecoin.isWalletAddress(params).should.be.rejected(); + }); + }); });