Skip to content

Commit 7fafd77

Browse files
committed
chore(advanced-wallets): improve error handling
Ticket: WP-5260
1 parent 15c27bd commit 7fafd77

File tree

11 files changed

+189
-44
lines changed

11 files changed

+189
-44
lines changed

src/__tests__/api/enclaved/signMpcTransaction.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ describe('signMpcTransaction', () => {
269269
.set('Authorization', `Bearer ${accessToken}`)
270270
.send(input);
271271

272-
response.status.should.equal(500);
272+
response.status.should.equal(404);
273273
response.body.should.have.property('error');
274274
kmsNock.done();
275275
});

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,10 @@ describe('POST /api/:coin/wallet/:walletId/accelerate', () => {
157157
cpfpTxIds: ['b8a828b98dbf32d9fd1875cbace9640ceb8c82626716b4a64203fdc79bb46d26'],
158158
});
159159

160-
response.status.should.equal(500);
160+
response.status.should.equal(404);
161161
response.body.should.have.property('error');
162+
response.body.error.should.equal('ApiResponseError');
163+
response.body.details.should.deepEqual({ error: 'Wallet not found' });
162164

163165
walletGetNock.done();
164166
});
@@ -190,8 +192,10 @@ describe('POST /api/:coin/wallet/:walletId/accelerate', () => {
190192
cpfpTxIds: ['b8a828b98dbf32d9fd1875cbace9640ceb8c82626716b4a64203fdc79bb46d26'],
191193
});
192194

193-
response.status.should.equal(500);
195+
response.status.should.equal(404);
194196
response.body.should.have.property('error');
197+
response.body.error.should.equal('ApiResponseError');
198+
response.body.details.should.deepEqual({ error: 'Keychain not found' });
195199

196200
walletGetNock.done();
197201
keychainGetNock.done();

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

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -145,11 +145,21 @@ describe('POST /api/:coin/wallet/:walletId/consolidate', () => {
145145
consolidateAddresses: ['0x1234567890abcdef', '0xfedcba0987654321'],
146146
});
147147

148-
response.status.should.equal(500);
149-
response.body.should.have.property('error', 'Internal Server Error');
150-
response.body.should.have
151-
.property('details')
152-
.which.match(/Consolidations failed: 1 and succeeded: 1/);
148+
response.status.should.equal(202);
149+
response.body.should.deepEqual({
150+
success: [
151+
{
152+
txid: 'consolidation-tx-1',
153+
status: 'signed',
154+
},
155+
],
156+
failure: [
157+
{
158+
error: 'Insufficient funds',
159+
address: '0xfedcba0987654321',
160+
},
161+
],
162+
});
153163

154164
walletGetNock.done();
155165
keychainGetNock.done();

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

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,6 @@ describe('POST /api/:coin/wallet/:walletId/consolidateunspents', () => {
128128

129129
const mockError = {
130130
error: 'Internal Server Error',
131-
name: 'ApiResponseError',
132131
details:
133132
'There are too few unspents that meet the given parameters to consolidate (1 available).',
134133
};
@@ -147,9 +146,6 @@ describe('POST /api/:coin/wallet/:walletId/consolidateunspents', () => {
147146
});
148147

149148
response.status.should.equal(500);
150-
response.body.should.have.property('error', mockError.error);
151-
response.body.should.have.property('name', mockError.name);
152-
response.body.should.have.property('details', mockError.details);
153149

154150
walletGetNock.done();
155151
keychainGetNock.done();

src/api/master/clients/enclavedExpressClient.ts

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import {
3030
MpcV2RoundResponseType,
3131
} from '../../../enclavedBitgoExpress/routers/enclavedApiSpec';
3232
import { FormattedOfflineVaultTxInfo } from '@bitgo/abstract-utxo';
33+
import { EnclavedError } from '../../../errors';
3334

3435
const debugLogger = debug('bitgo:express:enclavedExpressClient');
3536

@@ -242,7 +243,7 @@ export class EnclavedExpressClient {
242243
} catch (error) {
243244
const err = error as Error;
244245
debugLogger('Failed to create independent keychain: %s', err.message);
245-
throw err;
246+
throw new EnclavedError(`Failed to create independent keychain: ${err.message}`, 500);
246247
}
247248
}
248249

@@ -272,7 +273,7 @@ export class EnclavedExpressClient {
272273
} catch (error) {
273274
const err = error as Error;
274275
debugLogger('Failed to sign multisig: %s', err.message);
275-
throw err;
276+
throw new EnclavedError(`Failed to sign multisig transaction: ${err.message}`, 500);
276277
}
277278
}
278279

@@ -296,7 +297,7 @@ export class EnclavedExpressClient {
296297
} catch (error) {
297298
const err = error as Error;
298299
debugLogger('Enclaved express service ping failed: %s', err.message);
299-
throw err;
300+
throw new EnclavedError(`Failed to ping enclaved express service: ${err.message}`, 500);
300301
}
301302
}
302303

@@ -319,7 +320,7 @@ export class EnclavedExpressClient {
319320
} catch (error) {
320321
const err = error as Error;
321322
debugLogger('Failed to get version information: %s', err.message);
322-
throw err;
323+
throw new EnclavedError(`Failed to get version information: ${err.message}`, 500);
323324
}
324325
}
325326

@@ -344,7 +345,7 @@ export class EnclavedExpressClient {
344345
} catch (error) {
345346
const err = error as Error;
346347
debugLogger('Failed to recover multisig: %s', err.message);
347-
throw err;
348+
throw new EnclavedError(`Failed to recover multisig transaction: ${err.message}`, 500);
348349
}
349350
}
350351

@@ -376,7 +377,7 @@ export class EnclavedExpressClient {
376377
} catch (error) {
377378
const err = error as Error;
378379
debugLogger('Failed to initialize MPC key generation: %s', err.message);
379-
throw err;
380+
throw new EnclavedError(`Failed to initialize MPC key generation: ${err.message}`, 500);
380381
}
381382
}
382383

@@ -422,7 +423,7 @@ export class EnclavedExpressClient {
422423
} catch (error) {
423424
const err = error as Error;
424425
debugLogger('Failed to finalize MPC key generation: %s', err.message);
425-
throw err;
426+
throw new EnclavedError(`Failed to finalize MPC key generation: ${err.message}`, 500);
426427
}
427428
}
428429

@@ -446,7 +447,7 @@ export class EnclavedExpressClient {
446447
} catch (error) {
447448
const err = error as Error;
448449
debugLogger('Failed to sign mpc commitment: %s', err.message);
449-
throw err;
450+
throw new EnclavedError(`Failed to sign MPC commitment: ${err.message}`, 500);
450451
}
451452
}
452453

@@ -470,7 +471,7 @@ export class EnclavedExpressClient {
470471
} catch (error) {
471472
const err = error as Error;
472473
debugLogger('Failed to sign mpc r-share: %s', err.message);
473-
throw err;
474+
throw new EnclavedError(`Failed to sign MPC R-share: ${err.message}`, 500);
474475
}
475476
}
476477

@@ -494,7 +495,7 @@ export class EnclavedExpressClient {
494495
} catch (error) {
495496
const err = error as Error;
496497
debugLogger('Failed to sign mpc g-share: %s', err.message);
497-
throw err;
498+
throw new EnclavedError(`Failed to sign MPC G-share: ${err.message}`, 500);
498499
}
499500
}
500501

@@ -524,7 +525,7 @@ export class EnclavedExpressClient {
524525
} catch (error) {
525526
const err = error as Error;
526527
debugLogger('Failed to initialize MPCv2 key generation: %s', err.message);
527-
throw err;
528+
throw new EnclavedError(`Failed to initialize MPCv2 key generation: ${err.message}`, 500);
528529
}
529530
}
530531

@@ -561,7 +562,7 @@ export class EnclavedExpressClient {
561562
} catch (error) {
562563
const err = error as Error;
563564
debugLogger('Failed to execute MPCv2 round: %s', err.message);
564-
throw err;
565+
throw new EnclavedError(`Failed to execute MPCv2 round: ${err.message}`, 500);
565566
}
566567
}
567568

@@ -595,7 +596,7 @@ export class EnclavedExpressClient {
595596
} catch (error) {
596597
const err = error as Error;
597598
debugLogger('Failed to finalize MPCv2 key generation: %s', err.message);
598-
throw err;
599+
throw new EnclavedError(`Failed to finalize MPCv2 key generation: ${err.message}`, 500);
599600
}
600601
}
601602

@@ -628,7 +629,7 @@ export class EnclavedExpressClient {
628629
} catch (error) {
629630
const err = error as Error;
630631
debugLogger('Failed to sign mpcv2 round 1: %s', err.message);
631-
throw err;
632+
throw new EnclavedError(`Failed to sign MPCv2 Round 1: ${err.message}`, 500);
632633
}
633634
}
634635

@@ -661,7 +662,7 @@ export class EnclavedExpressClient {
661662
} catch (error) {
662663
const err = error as Error;
663664
debugLogger('Failed to sign mpcv2 round 2: %s', err.message);
664-
throw err;
665+
throw new EnclavedError(`Failed to sign MPCv2 Round 2: ${err.message}`, 500);
665666
}
666667
}
667668

@@ -694,7 +695,7 @@ export class EnclavedExpressClient {
694695
} catch (error) {
695696
const err = error as Error;
696697
debugLogger('Failed to sign mpcv2 round 3: %s', err.message);
697-
throw err;
698+
throw new EnclavedError(`Failed to sign MPCv2 Round 3: ${err.message}`, 500);
698699
}
699700
}
700701
}

src/api/master/handlers/handleConsolidate.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ export async function handleConsolidate(
6161
msg = `Consolidations failed: ${result.failure.length} and succeeded: ${result.success.length}`;
6262
} else {
6363
// All failed
64-
status = 400;
64+
status = 500;
6565
msg = 'All consolidations failed';
6666
}
6767

src/api/master/routers/enclavedExpressHealth.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ const PingEnclavedResponse: HttpResponse = {
1414
status: t.string,
1515
enclavedResponse: PingResponseType,
1616
}),
17+
404: t.type({
18+
error: t.string,
19+
details: t.string,
20+
}),
1721
500: t.type({
1822
error: t.string,
1923
details: t.string,
@@ -22,6 +26,10 @@ const PingEnclavedResponse: HttpResponse = {
2226

2327
const VersionEnclavedResponse: HttpResponse = {
2428
200: VersionResponseType,
29+
404: t.type({
30+
error: t.string,
31+
details: t.string,
32+
}),
2533
500: t.type({
2634
error: t.string,
2735
details: t.string,

src/api/master/routers/healthCheck.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,23 @@ import { Response } from '@api-ts/response';
44
import pjson from '../../../../package.json';
55
import { responseHandler } from '../../../shared/middleware';
66
import { PingResponseType, VersionResponseType } from '../../../types/health';
7+
import * as t from 'io-ts';
78

89
// API Response types
910
const PingResponse: HttpResponse = {
1011
200: PingResponseType,
12+
404: t.type({
13+
error: t.string,
14+
details: t.string,
15+
}),
1116
};
1217

1318
const VersionResponse: HttpResponse = {
1419
200: VersionResponseType,
20+
404: t.type({
21+
error: t.string,
22+
details: t.string,
23+
}),
1524
};
1625

1726
// API Specification

src/api/master/routers/masterApiSpec.ts

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ export function parseBody(req: express.Request, res: express.Response, next: exp
3535
const GenerateWalletResponse: HttpResponse = {
3636
// TODO: Get type from public types repo
3737
200: t.any,
38+
400: t.type({
39+
error: t.string,
40+
details: t.string,
41+
}),
42+
404: t.type({
43+
error: t.string,
44+
details: t.string,
45+
}),
3846
500: t.type({
3947
error: t.string,
4048
details: t.string,
@@ -57,6 +65,7 @@ export const SendManyRequest = {
5765
t.undefined,
5866
t.literal('transfer'),
5967
t.literal('acceleration'),
68+
t.literal('fillNonce'),
6069
t.literal('accountSet'),
6170
t.literal('enabletoken'),
6271
t.literal('stakingLock'),
@@ -66,7 +75,7 @@ export const SendManyRequest = {
6675
]),
6776
commonKeychain: t.union([t.undefined, t.string]),
6877
source: t.union([t.literal('user'), t.literal('backup')]),
69-
recipients: t.array(t.any),
78+
recipients: t.union([t.undefined, t.array(t.any)]),
7079
numBlocks: t.union([t.undefined, t.number]),
7180
feeRate: t.union([t.undefined, t.number]),
7281
feeMultiplier: t.union([t.undefined, t.number]),
@@ -98,6 +107,11 @@ export const SendManyRequest = {
98107
export const SendManyResponse: HttpResponse = {
99108
// TODO: Get type from public types repo / Wallet Platform
100109
200: t.any,
110+
400: t.any,
111+
404: t.type({
112+
error: t.string,
113+
details: t.string,
114+
}),
101115
500: t.type({
102116
error: t.string,
103117
details: t.string,
@@ -115,7 +129,12 @@ export const ConsolidateRequest = {
115129
// Response type for /consolidate endpoint
116130
const ConsolidateResponse: HttpResponse = {
117131
200: t.any,
132+
202: t.any,
118133
400: t.any, // All failed
134+
404: t.type({
135+
error: t.string,
136+
details: t.string,
137+
}),
119138
500: t.type({
120139
error: t.string,
121140
details: t.string,
@@ -140,6 +159,14 @@ const AccelerateResponse: HttpResponse = {
140159
txid: t.string,
141160
tx: t.string,
142161
}),
162+
400: t.type({
163+
error: t.string,
164+
details: t.string,
165+
}),
166+
404: t.type({
167+
error: t.string,
168+
details: t.any,
169+
}),
143170
500: t.type({
144171
error: t.string,
145172
details: t.string,
@@ -152,6 +179,14 @@ const RecoveryWalletResponse: HttpResponse = {
152179
200: t.type({
153180
txHex: t.string, // the full signed transaction hex
154181
}),
182+
400: t.type({
183+
error: t.string,
184+
details: t.string,
185+
}),
186+
404: t.type({
187+
error: t.string,
188+
details: t.string,
189+
}),
155190
500: t.type({
156191
error: t.string,
157192
details: t.string,
@@ -212,6 +247,10 @@ const ConsolidateUnspentsResponse: HttpResponse = {
212247
txid: t.string,
213248
}),
214249
400: t.any,
250+
404: t.type({
251+
error: t.string,
252+
details: t.string,
253+
}),
215254
500: t.type({
216255
error: t.string,
217256
details: t.string,

0 commit comments

Comments
 (0)