From be4a440cbc37bc28d2550158021ea9a18e1e9e6f Mon Sep 17 00:00:00 2001 From: nvjsr Date: Wed, 3 Sep 2025 23:53:02 +0530 Subject: [PATCH] Revert "feat(sdk-core): EVM keyring wallet and address creation changes" TICKET: COIN-5193 --- .../sdk-core/src/bitgo/baseCoin/iBaseCoin.ts | 1 - modules/sdk-core/src/bitgo/wallet/iWallet.ts | 2 - modules/sdk-core/src/bitgo/wallet/iWallets.ts | 2 - modules/sdk-core/src/bitgo/wallet/wallet.ts | 26 -- modules/sdk-core/src/bitgo/wallet/wallets.ts | 69 +---- .../bitgo/wallet/walletEvmAddressCreation.ts | 254 ------------------ .../unit/bitgo/wallet/walletsEvmKeyring.ts | 203 -------------- 7 files changed, 3 insertions(+), 554 deletions(-) delete mode 100644 modules/sdk-core/test/unit/bitgo/wallet/walletEvmAddressCreation.ts delete mode 100644 modules/sdk-core/test/unit/bitgo/wallet/walletsEvmKeyring.ts diff --git a/modules/sdk-core/src/bitgo/baseCoin/iBaseCoin.ts b/modules/sdk-core/src/bitgo/baseCoin/iBaseCoin.ts index 6b6fcfcbea..203e85b89b 100644 --- a/modules/sdk-core/src/bitgo/baseCoin/iBaseCoin.ts +++ b/modules/sdk-core/src/bitgo/baseCoin/iBaseCoin.ts @@ -208,7 +208,6 @@ export interface SupplementGenerateWalletOptions { type: 'hot' | 'cold' | 'custodial'; subType?: 'lightningCustody' | 'lightningSelfCustody' | 'onPrem'; coinSpecific?: { [coinName: string]: unknown }; - referenceWalletId?: string; } export interface FeeEstimateOptions { diff --git a/modules/sdk-core/src/bitgo/wallet/iWallet.ts b/modules/sdk-core/src/bitgo/wallet/iWallet.ts index fbc74eeb91..c6d0c4af8c 100644 --- a/modules/sdk-core/src/bitgo/wallet/iWallet.ts +++ b/modules/sdk-core/src/bitgo/wallet/iWallet.ts @@ -500,8 +500,6 @@ export interface CreateAddressOptions { derivedAddress?: string; index?: number; onToken?: string; - referenceCoin?: string; - referenceAddress?: string; } export interface UpdateAddressOptions { diff --git a/modules/sdk-core/src/bitgo/wallet/iWallets.ts b/modules/sdk-core/src/bitgo/wallet/iWallets.ts index d5442828c6..a6ca7e1311 100644 --- a/modules/sdk-core/src/bitgo/wallet/iWallets.ts +++ b/modules/sdk-core/src/bitgo/wallet/iWallets.ts @@ -70,7 +70,6 @@ export interface GenerateWalletOptions { commonKeychain?: string; type?: 'hot' | 'cold' | 'custodial'; subType?: 'lightningCustody' | 'lightningSelfCustody'; - referenceWalletId?: string; } export const GenerateLightningWalletOptionsCodec = t.strict( @@ -171,7 +170,6 @@ export interface AddWalletOptions { initializationTxs?: any; disableTransactionNotifications?: boolean; gasPrice?: number; - referenceWalletId?: string; } type KeySignatures = { diff --git a/modules/sdk-core/src/bitgo/wallet/wallet.ts b/modules/sdk-core/src/bitgo/wallet/wallet.ts index a0472136ea..8c96410124 100644 --- a/modules/sdk-core/src/bitgo/wallet/wallet.ts +++ b/modules/sdk-core/src/bitgo/wallet/wallet.ts @@ -1251,8 +1251,6 @@ export class Wallet implements IWallet { baseAddress, allowSkipVerifyAddress = true, onToken, - referenceCoin, - referenceAddress, } = params; if (!_.isUndefined(chain)) { @@ -1327,30 +1325,6 @@ export class Wallet implements IWallet { } } - // Validate EVM keyring params, referenceAddress is required and referenceCoin is optional for EVM keyring - if (!_.isUndefined(referenceAddress)) { - if (!_.isString(referenceAddress)) { - throw new Error('referenceAddress has to be a string'); - } - if (!this.baseCoin.isEVM()) { - throw new Error('referenceAddress is only supported for EVM chains'); - } - if (!this.baseCoin.isValidAddress(referenceAddress)) { - throw new Error('referenceAddress must be a valid address'); - } - addressParams.referenceAddress = referenceAddress; - - if (!_.isUndefined(referenceCoin)) { - if (!_.isString(referenceCoin)) { - throw new Error('referenceCoin has to be a string'); - } - addressParams.referenceCoin = referenceCoin; - } - } else if (!_.isUndefined(referenceCoin)) { - // referenceCoin cannot be used without referenceAddress - throw new Error('referenceAddress is required when using referenceCoin for EVM keyring'); - } - // get keychains for address verification const keychains = await Promise.all(this._wallet.keys.map((k) => this.baseCoin.keychains().get({ id: k, reqId }))); const rootAddress = _.get(this._wallet, 'receiveAddress.address'); diff --git a/modules/sdk-core/src/bitgo/wallet/wallets.ts b/modules/sdk-core/src/bitgo/wallet/wallets.ts index 8c19a07dad..1cfaba3e43 100644 --- a/modules/sdk-core/src/bitgo/wallet/wallets.ts +++ b/modules/sdk-core/src/bitgo/wallet/wallets.ts @@ -101,21 +101,8 @@ export class Wallets implements IWallets { throw new Error('missing required string parameter label'); } - // Validate referenceWalletId parameter - if (params.referenceWalletId) { - if (!_.isString(params.referenceWalletId)) { - throw new Error('invalid referenceWalletId argument, expecting string'); - } - if (!this.baseCoin.isEVM()) { - throw new Error('referenceWalletId is only supported for EVM chains'); - } - } - - // For wallets with referenceWalletId, skip multisig validation as configuration is inherited - if (params.referenceWalletId) { - // Skip all multisig validation - configuration will be inherited from reference wallet - } else if (params.type !== 'custodial') { - // Standard validation for non-custodial wallets without referenceWalletId + // no need to pass keys for (single) custodial wallets + if (params.type !== 'custodial') { if (Array.isArray(params.keys) === false || !_.isNumber(params.m) || !_.isNumber(params.n)) { throw new Error('invalid argument'); } @@ -285,10 +272,9 @@ export class Wallets implements IWallets { throw new Error('missing required string parameter label'); } - const { type = 'hot', label, passphrase, enterprise, isDistributedCustody, referenceWalletId } = params; + const { type = 'hot', label, passphrase, enterprise, isDistributedCustody } = params; const isTss = params.multisigType === 'tss' && this.baseCoin.supportsTss(); const canEncrypt = !!passphrase && typeof passphrase === 'string'; - const isEVMWithReference = this.baseCoin.isEVM() && referenceWalletId; const walletParams: SupplementGenerateWalletOptions = { label: label, @@ -298,11 +284,6 @@ export class Wallets implements IWallets { type: !!params.userKey && params.multisigType !== 'onchain' ? 'cold' : type, }; - // Add referenceWalletId to walletParams if provided for EVM chains - if (isEVMWithReference) { - walletParams.referenceWalletId = referenceWalletId; - } - if (!_.isUndefined(params.passcodeEncryptionCode)) { if (!_.isString(params.passcodeEncryptionCode)) { throw new Error('passcodeEncryptionCode must be a string'); @@ -316,59 +297,15 @@ export class Wallets implements IWallets { walletParams.enterprise = enterprise; } - // Validate referenceWalletId for EVM keyring - if (!_.isUndefined(referenceWalletId)) { - if (!_.isString(referenceWalletId)) { - throw new Error('invalid referenceWalletId argument, expecting string'); - } - if (!this.baseCoin.isEVM()) { - throw new Error('referenceWalletId is only supported for EVM chains'); - } - } - // EVM TSS wallets must use wallet version 3, 5 and 6 - // Skip this validation for EVM keyring wallets as they inherit version from reference wallet if ( isTss && this.baseCoin.isEVM() && - !referenceWalletId && !(params.walletVersion === 3 || params.walletVersion === 5 || params.walletVersion === 6) ) { throw new Error('EVM TSS wallets are only supported for wallet version 3, 5 and 6'); } - // Handle EVM keyring wallet creation with referenceWalletId - if (isEVMWithReference) { - // For EVM keyring wallets, multisigType will be inferred from the reference wallet - // No need to explicitly validate TSS requirement here as it will be handled by bgms - - // For EVM keyring wallets, we use the add method directly with referenceWalletId - // This bypasses the normal key generation process since keys are shared via keyring - const addWalletParams = { - label, - referenceWalletId, - }; - - const newWallet = await this.bitgo.post(this.baseCoin.url('/wallet/add')).send(addWalletParams).result(); - - // For EVM keyring wallets, we need to get the keychains from the reference wallet - const userKeychain = this.baseCoin.keychains().get({ id: newWallet.keys[KeyIndices.USER] }); - const backupKeychain = this.baseCoin.keychains().get({ id: newWallet.keys[KeyIndices.BACKUP] }); - const bitgoKeychain = this.baseCoin.keychains().get({ id: newWallet.keys[KeyIndices.BITGO] }); - - const [userKey, backupKey, bitgoKey] = await Promise.all([userKeychain, backupKeychain, bitgoKeychain]); - - const result: WalletWithKeychains = { - wallet: new Wallet(this.bitgo, this.baseCoin, newWallet), - userKeychain: userKey, - backupKeychain: backupKey, - bitgoKeychain: bitgoKey, - responseType: 'WalletWithKeychains', - }; - - return result; - } - if (isTss) { if (!this.baseCoin.supportsTss()) { throw new Error(`coin ${this.baseCoin.getFamily()} does not support TSS at this time`); diff --git a/modules/sdk-core/test/unit/bitgo/wallet/walletEvmAddressCreation.ts b/modules/sdk-core/test/unit/bitgo/wallet/walletEvmAddressCreation.ts deleted file mode 100644 index fe4390a3d7..0000000000 --- a/modules/sdk-core/test/unit/bitgo/wallet/walletEvmAddressCreation.ts +++ /dev/null @@ -1,254 +0,0 @@ -import * as assert from 'assert'; -import * as sinon from 'sinon'; -import 'should'; -import { Wallet } from '../../../../src/bitgo/wallet/wallet'; - -describe('Wallet - EVM Keyring Address Creation', function () { - let wallet: Wallet; - let mockBitGo: any; - let mockBaseCoin: any; - let mockWalletData: any; - - beforeEach(function () { - mockBitGo = { - post: sinon.stub(), - setRequestTracer: sinon.stub(), - }; - - mockBaseCoin = { - isEVM: sinon.stub(), - supportsTss: sinon.stub().returns(true), - getFamily: sinon.stub().returns('eth'), - isValidAddress: sinon.stub(), - keychains: sinon.stub(), - url: sinon.stub().returns('/test/wallet/address'), - }; - - mockWalletData = { - id: 'test-wallet-id', - keys: ['user-key', 'backup-key', 'bitgo-key'], - }; - - wallet = new Wallet(mockBitGo, mockBaseCoin, mockWalletData); - }); - - afterEach(function () { - sinon.restore(); - }); - - describe('createAddress with EVM keyring parameters', function () { - beforeEach(function () { - mockBaseCoin.isEVM.returns(true); - mockBaseCoin.isValidAddress.returns(true); - mockBaseCoin.keychains.returns({ - get: sinon.stub().resolves({ id: 'keychain-id', pub: 'public-key' }), - }); - }); - - it('should create address with referenceCoin and referenceAddress', async function () { - const mockAddressResponse = { - id: '507f1f77bcf86cd799439012', - address: '0x1234567890123456789012345678901234567890', - }; - - mockBitGo.post.returns({ - send: sinon.stub().returns({ - result: sinon.stub().resolves(mockAddressResponse), - }), - }); - - const result = await wallet.createAddress({ - chain: 0, - label: 'Test EVM Address', - referenceCoin: 'hteth', - referenceAddress: '0x742d35Cc6634C0532925a3b8D404fddF4f780EAD', - }); - - result.should.have.property('id', '507f1f77bcf86cd799439012'); - result.should.have.property('address', '0x1234567890123456789012345678901234567890'); - mockBitGo.post.should.have.been.calledOnce; - }); - - it('should throw error if only referenceCoin provided without referenceAddress', async function () { - try { - await wallet.createAddress({ - chain: 0, - label: 'Test Address', - referenceCoin: 'hteth', - // Missing referenceAddress - }); - assert.fail('Should have thrown error'); - } catch (error) { - error.message.should.equal('referenceAddress is required when using referenceCoin for EVM keyring'); - } - }); - - it('should create address with only referenceAddress (referenceCoin is optional)', async function () { - const mockAddressResponse = { - id: '507f1f77bcf86cd799439012', - address: '0x1234567890123456789012345678901234567890', - }; - - mockBitGo.post.returns({ - send: sinon.stub().returns({ - result: sinon.stub().resolves(mockAddressResponse), - }), - } as any); - - const result = await wallet.createAddress({ - chain: 0, - label: 'Test Address', - referenceAddress: '0x742d35Cc6634C0532925a3b8D404fddF4f780EAD', - // referenceCoin is optional - }); - - result.should.have.property('id', '507f1f77bcf86cd799439012'); - result.should.have.property('address', '0x1234567890123456789012345678901234567890'); - }); - - it('should throw error if referenceCoin is not a string', async function () { - try { - await wallet.createAddress({ - chain: 0, - label: 'Test Address', - referenceCoin: 123 as any, - referenceAddress: '0x742d35Cc6634C0532925a3b8D404fddF4f780EAD', - }); - assert.fail('Should have thrown error'); - } catch (error) { - error.message.should.equal('referenceCoin has to be a string'); - } - }); - - it('should throw error if referenceAddress is not a string', async function () { - try { - await wallet.createAddress({ - chain: 0, - label: 'Test Address', - referenceCoin: 'hteth', - referenceAddress: 123 as any, - }); - assert.fail('Should have thrown error'); - } catch (error) { - error.message.should.equal('referenceAddress has to be a string'); - } - }); - - it('should throw error if referenceAddress is not a valid address', async function () { - mockBaseCoin.isValidAddress.returns(false); - - try { - await wallet.createAddress({ - chain: 0, - label: 'Test Address', - referenceCoin: 'hteth', - referenceAddress: 'invalid-address', - }); - assert.fail('Should have thrown error'); - } catch (error) { - error.message.should.equal('referenceAddress must be a valid address'); - } - }); - - it('should throw error for non-EVM chains with referenceCoin', async function () { - mockBaseCoin.isEVM.returns(false); - - try { - await wallet.createAddress({ - chain: 0, - label: 'Test Address', - referenceCoin: 'btc', - referenceAddress: '1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2', - }); - assert.fail('Should have thrown error'); - } catch (error) { - error.message.should.equal('referenceAddress is only supported for EVM chains'); - } - }); - - it('should throw error for non-EVM chains with referenceAddress', async function () { - mockBaseCoin.isEVM.returns(false); - - try { - await wallet.createAddress({ - chain: 0, - label: 'Test Address', - referenceCoin: 'btc', - referenceAddress: '1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2', - }); - assert.fail('Should have thrown error'); - } catch (error) { - error.message.should.equal('referenceAddress is only supported for EVM chains'); - } - }); - - it('should create address without reference parameters for regular addresses', async function () { - const mockAddressResponse = { - id: 'regular-address-id', - address: '0x9876543210987654321098765432109876543210', - }; - - mockBitGo.post.returns({ - send: sinon.stub().returns({ - result: sinon.stub().resolves(mockAddressResponse), - }), - }); - - const result = await wallet.createAddress({ - chain: 0, - label: 'Regular Address', - // No reference parameters - }); - - result.should.have.property('id', 'regular-address-id'); - result.should.have.property('address', '0x9876543210987654321098765432109876543210'); - mockBitGo.post.should.have.been.calledOnce; - }); - }); - - describe('Non-EVM chains', function () { - beforeEach(function () { - mockBaseCoin.isEVM.returns(false); - }); - - it('should not allow referenceCoin for non-EVM chains', async function () { - try { - await wallet.createAddress({ - chain: 0, - label: 'Test Address', - referenceCoin: 'btc', - referenceAddress: '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa', - }); - assert.fail('Should have thrown error'); - } catch (error) { - error.message.should.equal('referenceAddress is only supported for EVM chains'); - } - }); - - it('should create regular addresses for non-EVM chains', async function () { - const mockAddressResponse = { - id: 'btc-address-id', - address: '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa', - }; - - mockBitGo.post.returns({ - send: sinon.stub().returns({ - result: sinon.stub().resolves(mockAddressResponse), - }), - }); - - mockBaseCoin.keychains.returns({ - get: sinon.stub().resolves({ id: 'keychain-id', pub: 'public-key' }), - }); - - const result = await wallet.createAddress({ - chain: 0, - label: 'BTC Address', - }); - - result.should.have.property('id', 'btc-address-id'); - result.should.have.property('address', '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa'); - mockBitGo.post.should.have.been.calledOnce; - }); - }); -}); diff --git a/modules/sdk-core/test/unit/bitgo/wallet/walletsEvmKeyring.ts b/modules/sdk-core/test/unit/bitgo/wallet/walletsEvmKeyring.ts deleted file mode 100644 index e9828a13f0..0000000000 --- a/modules/sdk-core/test/unit/bitgo/wallet/walletsEvmKeyring.ts +++ /dev/null @@ -1,203 +0,0 @@ -import * as assert from 'assert'; -import * as sinon from 'sinon'; -import 'should'; -import { Wallets } from '../../../../src/bitgo/wallet/wallets'; - -describe('Wallets', function () { - let wallets: Wallets; - let mockBitGo: any; - let mockBaseCoin: any; - - beforeEach(function () { - mockBitGo = { - post: sinon.stub(), - encrypt: sinon.stub(), - setRequestTracer: sinon.stub(), - }; - - mockBaseCoin = { - isEVM: sinon.stub(), - supportsTss: sinon.stub().returns(true), - getFamily: sinon.stub().returns('eth'), - getDefaultMultisigType: sinon.stub(), - keychains: sinon.stub(), - url: sinon.stub().returns('/test/url'), - isValidMofNSetup: sinon.stub(), - }; - - wallets = new Wallets(mockBitGo, mockBaseCoin); - }); - - afterEach(function () { - sinon.restore(); - }); - - describe('EVM Keyring - generateWallet', function () { - beforeEach(function () { - mockBaseCoin.isEVM.returns(true); - mockBaseCoin.supportsTss.returns(true); - mockBaseCoin.getDefaultMultisigType.returns('tss'); - }); - - it('should create EVM wallet with referenceWalletId', async function () { - const mockWalletResponse = { - id: '597f1f77bcf86cd799439011', - keys: ['user-key', 'backup-key', 'bitgo-key'], - }; - - mockBitGo.post.returns({ - send: sinon.stub().returns({ - result: sinon.stub().resolves(mockWalletResponse), - }), - } as any); - - mockBaseCoin.keychains.returns({ - get: sinon.stub().resolves({ id: 'keychain-id', pub: 'public-key' }), - } as any); - - const result = await wallets.generateWallet({ - label: 'Test EVM Wallet', - referenceWalletId: '507f1f77bcf86cd799439011', - }); - - result.should.have.property('wallet'); - result.should.have.property('userKeychain'); - result.should.have.property('backupKeychain'); - result.should.have.property('bitgoKeychain'); - }); - - it('should throw error if referenceWalletId provided for non-EVM chain', async function () { - mockBaseCoin.isEVM.returns(false); - - try { - await wallets.generateWallet({ - label: 'Test Wallet', - referenceWalletId: '507f1f77bcf86cd799439011', - }); - assert.fail('Should have thrown error'); - } catch (error) { - error.message.should.equal('referenceWalletId is only supported for EVM chains'); - } - }); - - it('should throw error if referenceWalletId is not a string', async function () { - try { - await wallets.generateWallet({ - label: 'Test Wallet', - referenceWalletId: 123 as any, - }); - assert.fail('Should have thrown error'); - } catch (error) { - error.message.should.equal('invalid referenceWalletId argument, expecting string'); - } - }); - }); - - describe('EVM Keyring - add method', function () { - beforeEach(function () { - mockBaseCoin.isEVM.returns(true); - }); - - it('should add EVM wallet with referenceWalletId without multisig validation', async function () { - const mockWalletResponse = { - id: 'new-wallet-id', - keys: ['user-key', 'backup-key', 'bitgo-key'], - }; - - mockBitGo.post.returns({ - send: sinon.stub().returns({ - result: sinon.stub().resolves(mockWalletResponse), - }), - } as any); - - const result = await wallets.add({ - label: 'Test EVM Wallet', - referenceWalletId: 'reference-wallet-id', - }); - - result.should.have.property('wallet'); - mockBitGo.post.should.have.been.calledOnce; - }); - - it('should skip multisig validation for EVM wallets with referenceWalletId', async function () { - const mockWalletResponse = { - id: 'new-wallet-id', - keys: ['user-key', 'backup-key', 'bitgo-key'], - }; - - mockBitGo.post.returns({ - send: sinon.stub().returns({ - result: sinon.stub().resolves(mockWalletResponse), - }), - } as any); - - // This should not throw error even without keys, m, n parameters - const result = await wallets.add({ - label: 'Test EVM Wallet', - referenceWalletId: '507f1f77bcf86cd799439011', - // No keys, m, n provided - should be fine for EVM keyring - }); - - result.should.have.property('wallet'); - }); - - it('should throw error for non-EVM chains with referenceWalletId', async function () { - mockBaseCoin.isEVM.returns(false); - - try { - await wallets.add({ - label: 'Test Wallet', - referenceWalletId: '507f1f77bcf86cd799439011', - }); - assert.fail('Should have thrown error'); - } catch (error) { - error.message.should.equal('referenceWalletId is only supported for EVM chains'); - } - }); - - it('should still validate multisig for regular wallets', async function () { - mockBaseCoin.isEVM.returns(true); - - try { - await wallets.add({ - label: 'Test Wallet', - type: 'hot', - // No referenceWalletId, so should require keys, m, n - }); - assert.fail('Should have thrown error'); - } catch (error) { - error.message.should.equal('invalid argument'); - } - }); - }); - - describe('Non-EVM chains', function () { - beforeEach(function () { - mockBaseCoin.isEVM.returns(false); - }); - - it('should not allow referenceWalletId for non-EVM chains in generateWallet', async function () { - try { - await wallets.generateWallet({ - label: 'Test Wallet', - referenceWalletId: 'reference-wallet-id', - }); - assert.fail('Should have thrown error'); - } catch (error) { - error.message.should.equal('referenceWalletId is only supported for EVM chains'); - } - }); - - it('should not allow referenceWalletId for non-EVM chains in add', async function () { - try { - await wallets.add({ - label: 'Test Wallet', - referenceWalletId: 'reference-wallet-id', - }); - assert.fail('Should have thrown error'); - } catch (error) { - error.message.should.equal('referenceWalletId is only supported for EVM chains'); - } - }); - }); -});