Skip to content

Commit 13a6024

Browse files
feat(express): migrate v1 wallet create to typed routes
2 parents 4e2f89e + 8968cb8 commit 13a6024

File tree

4 files changed

+70
-6
lines changed

4 files changed

+70
-6
lines changed

modules/express/src/clientRoutes.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ function handleDeriveLocalKeyChain(req: express.Request) {
132132
* @deprecated
133133
* @param req
134134
*/
135-
function handleCreateWalletWithKeychains(req: express.Request) {
135+
function handleCreateWalletWithKeychains(req: ExpressApiRouteRequest<'express.v1.wallet.simplecreate', 'post'>) {
136136
return req.bitgo.wallets().createWalletWithKeychains(req.body);
137137
}
138138

@@ -1575,12 +1575,10 @@ export function setupAPIRoutes(app: express.Application, config: Config): void {
15751575

15761576
app.post('/api/v1/keychain/local', parseBody, prepareBitGo(config), promiseWrapper(handleCreateLocalKeyChain));
15771577
app.post('/api/v1/keychain/derive', parseBody, prepareBitGo(config), promiseWrapper(handleDeriveLocalKeyChain));
1578-
app.post(
1579-
'/api/v1/wallets/simplecreate',
1580-
parseBody,
1578+
router.post('express.v1.wallet.simplecreate', [
15811579
prepareBitGo(config),
1582-
promiseWrapper(handleCreateWalletWithKeychains)
1583-
);
1580+
typedPromiseWrapper(handleCreateWalletWithKeychains),
1581+
]);
15841582

15851583
app.post('/api/v1/wallet/:id/sendcoins', parseBody, prepareBitGo(config), promiseWrapper(handleSendCoins));
15861584
app.post('/api/v1/wallet/:id/sendmany', parseBody, prepareBitGo(config), promiseWrapper(handleSendMany));

modules/express/src/typedRoutes/api/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { PostLogin } from './common/login';
88
import { PostDecrypt } from './common/decrypt';
99
import { PostVerifyAddress } from './common/verifyAddress';
1010
import { PostAcceptShare } from './common/acceptShare';
11+
import { PostSimpleCreate } from './v1/simpleCreate';
1112

1213
export const ExpressApi = apiSpec({
1314
'express.ping': {
@@ -28,6 +29,9 @@ export const ExpressApi = apiSpec({
2829
'express.v1.wallet.acceptShare': {
2930
post: PostAcceptShare,
3031
},
32+
'express.v1.wallet.simplecreate': {
33+
post: PostSimpleCreate,
34+
},
3135
});
3236

3337
export type ExpressApi = typeof ExpressApi;
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import * as t from 'io-ts';
2+
import { httpRoute, httpRequest, optional } from '@api-ts/io-ts-http';
3+
import { BitgoExpressError } from '../../schemas/error';
4+
5+
export const SimpleCreateRequestBody = {
6+
/** wallet passphrase to encrypt user and backup keys with */
7+
passphrase: t.string,
8+
/** wallet label, is shown in BitGo UI */
9+
label: optional(t.string),
10+
/** backup keychain xpub, it is HIGHLY RECOMMENDED you generate this on a separate machine!
11+
* BITGO DOES NOT GUARANTEE SAFETY OF WALLETS WITH MULTIPLE KEYS CREATED ON THE SAME MACHINE */
12+
backupXpub: optional(t.string),
13+
/* Provision backup key from this provider (KRS), e.g. "keyternal". Setting this value will create an instant-capable wallet. */
14+
backupXpubProvider: optional(t.string),
15+
enterprise: optional(t.string),
16+
/** the code used to encrypt the wallet passcode used in the recovery process */
17+
passcodeEncryptionCode: optional(t.string),
18+
disableTransactionNotifications: optional(t.boolean),
19+
disableKRSEmail: optional(t.boolean),
20+
};
21+
22+
/**
23+
* Create Wallet with Keychain
24+
* Create a new 2-of-3 wallet and it's associated keychains.
25+
* Returns the locally created keys with their encrypted xprvs.
26+
* **WARNING: BE SURE TO BACKUP! NOT DOING SO CAN RESULT IN LOSS OF FUNDS!**
27+
*
28+
* 1. Creates the user keychain locally on the client, and encrypts it with the provided passphrase
29+
* 2. If no xpub was provided, creates the backup keychain locally on the client, and encrypts it with the provided passphrase
30+
* 3. Uploads the encrypted user and backup keychains to BitGo
31+
* 4. Creates the BitGo key on the service
32+
* 5. Creates the wallet on BitGo with the 3 public keys above
33+
*
34+
* @operationId express.v1.wallet.simplecreate
35+
*/
36+
export const PostSimpleCreate = httpRoute({
37+
path: '/api/v1/wallets/simplecreate',
38+
method: 'POST',
39+
request: httpRequest({
40+
body: SimpleCreateRequestBody,
41+
}),
42+
response: {
43+
200: t.type({
44+
/** newly created wallet model object */
45+
wallet: t.string,
46+
/** the newly created user keychain, which has an encrypted xprv stored on BitGo */
47+
userKeychain: t.string,
48+
/** the newly created backup keychain */
49+
backupKeychain: t.string,
50+
}),
51+
400: BitgoExpressError,
52+
},
53+
});

modules/express/test/unit/typedRoutes/decode.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as t from 'io-ts';
33
import { DecryptRequestBody } from '../../../src/typedRoutes/api/common/decrypt';
44
import { LoginRequest } from '../../../src/typedRoutes/api/common/login';
55
import { VerifyAddressBody } from '../../../src/typedRoutes/api/common/verifyAddress';
6+
import { SimpleCreateRequestBody } from '../../../src/typedRoutes/api/v1/simpleCreate';
67

78
export function assertDecode<T>(codec: t.Type<T, unknown>, input: unknown): T {
89
const result = codec.decode(input);
@@ -50,4 +51,12 @@ describe('io-ts decode tests', function () {
5051
address: 'some-address',
5152
});
5253
});
54+
it('express.v1.wallet.simplecreate', function () {
55+
// passphrase is required
56+
assert.throws(() => assertDecode(t.type(SimpleCreateRequestBody), {}));
57+
58+
assertDecode(t.type(SimpleCreateRequestBody), {
59+
passphrase: 'pass',
60+
});
61+
});
5362
});

0 commit comments

Comments
 (0)