Skip to content

Commit c74f277

Browse files
committed
refactor: wallet generation handler to use new sdk callback
Ticket: WCN-684
1 parent 59c3c4f commit c74f277

6 files changed

Lines changed: 319 additions & 255 deletions

File tree

package-lock.json

Lines changed: 263 additions & 141 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"@bitgo-beta/abstract-cosmos": "1.0.1-beta.1741",
3434
"@bitgo-beta/abstract-eth": "1.0.2-beta.2004",
3535
"@bitgo-beta/abstract-utxo": "1.1.1-beta.2007",
36-
"@bitgo-beta/sdk-api": "1.10.1-beta.1773",
36+
"@bitgo-beta/sdk-api": "1.10.1-beta.1812",
3737
"@bitgo-beta/sdk-coin-ada": "2.3.14-beta.1758",
3838
"@bitgo-beta/sdk-coin-algo": "2.8.9-beta.238",
3939
"@bitgo-beta/sdk-coin-apt": "1.0.1-beta.1200",
@@ -101,7 +101,7 @@
101101
"@bitgo-beta/sdk-coin-zec": "1.1.1-beta.1984",
102102
"@bitgo-beta/sdk-coin-zeta": "1.0.1-beta.1675",
103103
"@bitgo-beta/sdk-coin-zketh": "1.0.1-beta.1540",
104-
"@bitgo-beta/sdk-core": "8.2.1-beta.1775",
104+
"@bitgo-beta/sdk-core": "8.2.1-beta.1815",
105105
"@bitgo-beta/sdk-lib-mpc": "8.2.0-beta.1770",
106106
"@bitgo-beta/statics": "15.1.1-beta.1782",
107107
"@bitgo/wasm-miniscript": "2.0.0-beta.7",
@@ -122,7 +122,7 @@
122122
"zod": "^3.25.48"
123123
},
124124
"overrides": {
125-
"@bitgo-beta/sdk-core": "8.2.1-beta.1775",
125+
"@bitgo-beta/sdk-core": "8.2.1-beta.1815",
126126
"@bitgo-beta/statics": "15.1.1-beta.1782",
127127
"elliptic": "^6.6.1",
128128
"expo": "^48.0.0",

src/__tests__/api/master/generateWallet.test.ts

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ describe('POST /api/v1/:coin/advancedwallet/generate', () => {
6464
const ecdsaCoin = 'hteth';
6565
const accessToken = 'test-token';
6666

67+
// Valid BIP32 extended public keys required by the SDK's isValidPub check
68+
const validUserPub =
69+
'xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8';
70+
const validBackupPub =
71+
'xpub661MyMwAqRbcGczjuMoRm6dXaLDEhW1u34gKenbeYqAix21mdUKJyuyu5F1rzYGVxyL6tmgBUAEPrEz92mBXjByMRiJdba9wpnN37RLLAXa';
72+
6773
let bitgo: BitGoAPI;
6874

6975
function makeConfig(overrides: Partial<MasterExpressConfig> = {}): MasterExpressConfig {
@@ -132,7 +138,7 @@ describe('POST /api/v1/:coin/advancedwallet/generate', () => {
132138
source: 'user',
133139
})
134140
.reply(200, {
135-
pub: 'xpub_user',
141+
pub: validUserPub,
136142
source: 'user',
137143
type: 'independent',
138144
});
@@ -143,33 +149,37 @@ describe('POST /api/v1/:coin/advancedwallet/generate', () => {
143149
source: 'backup',
144150
})
145151
.reply(200, {
146-
pub: 'xpub_backup',
152+
pub: validBackupPub,
147153
source: 'backup',
148154
type: 'independent',
149155
});
150156

151157
const bitgoAddUserKeyNock = nock(bitgoApiUrl)
152158
.post(`/api/v2/${coin}/key`, {
153-
pub: 'xpub_user',
159+
pub: validUserPub,
154160
keyType: 'independent',
155161
source: 'user',
156162
})
157163
.matchHeader('any', () => true)
158-
.reply(200, { id: 'user-key-id', pub: 'xpub_user' });
164+
.reply(200, { id: 'user-key-id', pub: validUserPub, source: 'user', type: 'independent' });
159165

160166
const bitgoAddBackupKeyNock = nock(bitgoApiUrl)
161167
.post(`/api/v2/${coin}/key`, {
162-
pub: 'xpub_backup',
168+
pub: validBackupPub,
163169
keyType: 'independent',
164170
source: 'backup',
165171
})
166172
.matchHeader('any', () => true)
167-
.reply(200, { id: 'backup-key-id', pub: 'xpub_backup' });
173+
.reply(200, {
174+
id: 'backup-key-id',
175+
pub: validBackupPub,
176+
source: 'backup',
177+
type: 'independent',
178+
});
168179

169180
const bitgoAddBitGoKeyNock = nock(bitgoApiUrl)
170181
.post(`/api/v2/${coin}/key`, {
171182
source: 'bitgo',
172-
keyType: 'independent',
173183
enterprise: 'test_enterprise',
174184
})
175185
.reply(200, {
@@ -223,7 +233,7 @@ describe('POST /api/v1/:coin/advancedwallet/generate', () => {
223233
source: 'user',
224234
})
225235
.reply(200, {
226-
pub: 'xpub_user',
236+
pub: validUserPub,
227237
source: 'user',
228238
type: 'independent',
229239
});
@@ -233,33 +243,37 @@ describe('POST /api/v1/:coin/advancedwallet/generate', () => {
233243
source: 'backup',
234244
})
235245
.reply(200, {
236-
pub: 'xpub_backup',
246+
pub: validBackupPub,
237247
source: 'backup',
238248
type: 'independent',
239249
});
240250

241251
const bitgoAddUserKeyNock = nock(bitgoApiUrl)
242252
.post(`/api/v2/${coin}/key`, {
243-
pub: 'xpub_user',
253+
pub: validUserPub,
244254
keyType: 'independent',
245255
source: 'user',
246256
})
247257
.matchHeader('any', () => true)
248-
.reply(200, { id: 'user-key-id', pub: 'xpub_user' });
258+
.reply(200, { id: 'user-key-id', pub: validUserPub, source: 'user', type: 'independent' });
249259

250260
const bitgoAddBackupKeyNock = nock(bitgoApiUrl)
251261
.post(`/api/v2/${coin}/key`, {
252-
pub: 'xpub_backup',
262+
pub: validBackupPub,
253263
keyType: 'independent',
254264
source: 'backup',
255265
})
256266
.matchHeader('any', () => true)
257-
.reply(200, { id: 'backup-key-id', pub: 'xpub_backup' });
267+
.reply(200, {
268+
id: 'backup-key-id',
269+
pub: validBackupPub,
270+
source: 'backup',
271+
type: 'independent',
272+
});
258273

259274
const bitgoAddBitGoKeyNock = nock(bitgoApiUrl)
260275
.post(`/api/v2/${coin}/key`, {
261276
source: 'bitgo',
262-
keyType: 'independent',
263277
enterprise: 'test_enterprise',
264278
})
265279
.reply(200, {
@@ -276,8 +290,6 @@ describe('POST /api/v1/:coin/advancedwallet/generate', () => {
276290
.post(`/api/v2/${coin}/wallet/add`, {
277291
label: 'test_wallet',
278292
enterprise: 'test_enterprise',
279-
multisigType: 'onchain',
280-
coin: coin,
281293
m: 2,
282294
n: 3,
283295
keys: ['user-key-id', 'backup-key-id', 'bitgo-key-id'],
@@ -319,8 +331,8 @@ describe('POST /api/v1/:coin/advancedwallet/generate', () => {
319331
multisigType: 'onchain',
320332
type: 'advanced',
321333
});
322-
response.body.should.have.propertyByPath('userKeychain', 'pub').eql('xpub_user');
323-
response.body.should.have.propertyByPath('backupKeychain', 'pub').eql('xpub_backup');
334+
response.body.should.have.propertyByPath('userKeychain', 'pub').eql(validUserPub);
335+
response.body.should.have.propertyByPath('backupKeychain', 'pub').eql(validBackupPub);
324336
response.body.should.have.propertyByPath('bitgoKeychain', 'pub').eql('xpub_bitgo');
325337

326338
userKeychainNock.done();

src/advancedWalletManager/keyProviderClient/keyProviderClient.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,8 @@ export class KeyProviderClient extends BaseHttpClient {
7777
);
7878
}
7979

80-
const { pub, coin, source } = response.body;
81-
return { pub, coin, source } as PostKeyResponse;
80+
const { pub, coin, source, type } = response.body;
81+
return { pub, coin, source, type } as PostKeyResponse;
8282
}
8383

8484
async getKey(params: GetKeyParams): Promise<GetKeyResponse> {

src/masterBitgoExpress/handlers/handleGenerateWallet.ts

Lines changed: 8 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
11
import {
2-
AddKeychainOptions,
3-
Keychain,
4-
KeychainsTriplet,
5-
promiseProps,
62
RequestTracer,
73
SupplementGenerateWalletOptions,
84
Wallet,
@@ -16,6 +12,7 @@ import coinFactory from '../../shared/coinFactory';
1612
import { BadRequestError } from '../../shared/errors';
1713
import { KeySource } from '../../shared/types';
1814
import { submitJobViaBridgeClient } from './utils/asyncUtils';
15+
import { createOnchainKeyGenCallback } from './walletGenerationCallbacks';
1916

2017
/**
2118
* Request handler for generating an advanced wallet.
@@ -55,98 +52,18 @@ async function handleGenerateOnChainWallet(
5552
const bitgo = req.bitgo;
5653
const baseCoin = await coinFactory.getCoin(req.params.coin, bitgo);
5754

58-
// The awmClient is now available from the request
59-
const awmClient = req.awmUserClient;
60-
const awmBackupClient = req.awmBackupClient;
55+
const createKeychainCallback = createOnchainKeyGenCallback(
56+
req.awmUserClient,
57+
req.awmBackupClient,
58+
);
6159

62-
const reqId = new RequestTracer();
63-
64-
const { label, enterprise } = req.decoded;
65-
66-
// Create wallet parameters
67-
const walletParams = {
60+
const result = await baseCoin.wallets().generateWallet({
6861
...req.decoded,
69-
label: label,
70-
m: 2,
71-
n: 3,
72-
keys: [],
73-
type: 'advanced',
62+
type: 'advanced' as 'cold',
7463
multisigType: 'onchain',
75-
} as SupplementGenerateWalletOptions;
76-
77-
if (!_.isUndefined(enterprise)) {
78-
if (!_.isString(enterprise)) {
79-
throw new Error('invalid enterprise argument, expecting string');
80-
}
81-
walletParams.enterprise = enterprise;
82-
}
83-
84-
const userKeychainPromise = async (): Promise<Keychain> => {
85-
const userKeychain = await awmClient.createIndependentKeychain({
86-
source: 'user',
87-
coin: req.params.coin,
88-
type: 'independent',
89-
});
90-
const userKeychainParams: AddKeychainOptions = {
91-
pub: userKeychain.pub,
92-
keyType: userKeychain.type,
93-
source: userKeychain.source,
94-
reqId,
95-
};
96-
97-
const newUserKeychain = await baseCoin.keychains().add(userKeychainParams);
98-
return _.extend({}, newUserKeychain, userKeychain);
99-
};
100-
101-
const backupKeychainPromise = async (): Promise<Keychain> => {
102-
const backupKeychain = await awmBackupClient.createIndependentKeychain({
103-
source: 'backup',
104-
coin: req.params.coin,
105-
type: 'independent',
106-
});
107-
const backupKeychainParams: AddKeychainOptions = {
108-
pub: backupKeychain.pub,
109-
keyType: backupKeychain.type,
110-
source: backupKeychain.source,
111-
reqId,
112-
};
113-
114-
const newBackupKeychain = await baseCoin.keychains().add(backupKeychainParams);
115-
return _.extend({}, newBackupKeychain, backupKeychain);
116-
};
117-
118-
const { userKeychain, backupKeychain, bitgoKeychain }: KeychainsTriplet = await promiseProps({
119-
userKeychain: userKeychainPromise(),
120-
backupKeychain: backupKeychainPromise(),
121-
bitgoKeychain: baseCoin.keychains().createBitGo({
122-
enterprise: req.decoded.enterprise,
123-
keyType: 'independent',
124-
reqId,
125-
isDistributedCustody: req.decoded.isDistributedCustody,
126-
}),
64+
createKeychainCallback,
12765
});
12866

129-
walletParams.keys = [userKeychain.id, backupKeychain.id, bitgoKeychain.id];
130-
131-
const keychains = {
132-
userKeychain,
133-
backupKeychain,
134-
bitgoKeychain,
135-
};
136-
137-
const finalWalletParams = await baseCoin.supplementGenerateWallet(walletParams, keychains);
138-
139-
bitgo.setRequestTracer(reqId);
140-
const newWallet = await bitgo.post(baseCoin.url('/wallet/add')).send(finalWalletParams).result();
141-
142-
const result: WalletWithKeychains = {
143-
wallet: new Wallet(bitgo, baseCoin, newWallet),
144-
userKeychain: userKeychain,
145-
backupKeychain: backupKeychain,
146-
bitgoKeychain: bitgoKeychain,
147-
responseType: 'WalletWithKeychains',
148-
};
149-
15067
return { ...result, wallet: result.wallet.toJSON() };
15168
}
15269

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { CreateKeychainCallback } from '@bitgo-beta/sdk-core';
2+
import { AdvancedWalletManagerClient } from '../clients/advancedWalletManagerClient';
3+
4+
export function createOnchainKeyGenCallback(
5+
awmUserClient: AdvancedWalletManagerClient,
6+
awmBackupClient: AdvancedWalletManagerClient,
7+
): CreateKeychainCallback {
8+
return async ({ source, coin }) => {
9+
const client = source === 'user' ? awmUserClient : awmBackupClient;
10+
const keychain = await client.createIndependentKeychain({ source, coin, type: 'independent' });
11+
return keychain as { pub: string; type: 'independent'; source: typeof source };
12+
};
13+
}

0 commit comments

Comments
 (0)