Skip to content

Commit be6980a

Browse files
feat(express): migrate verifycoinaddress to typed routes
2 parents 04a805f + 0491a83 commit be6980a

File tree

4 files changed

+85
-12
lines changed

4 files changed

+85
-12
lines changed

modules/express/src/clientRoutes.ts

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -356,26 +356,18 @@ function handleV2UserREST(req: express.Request, res: express.Response, next: exp
356356
* handle v2 address validation
357357
* @param req
358358
*/
359-
function handleV2VerifyAddress(req: express.Request): { isValid: boolean } {
360-
if (!_.isString(req.body.address)) {
361-
throw new Error('Expected address to be a string');
362-
}
363-
364-
if (req.body.supportOldScriptHashVersion !== undefined && !_.isBoolean(req.body.supportOldScriptHashVersion)) {
365-
throw new Error('Expected supportOldScriptHashVersion to be a boolean.');
366-
}
367-
359+
function handleV2VerifyAddress(req: ExpressApiRouteRequest<'express.verifycoinaddress', 'post'>): { isValid: boolean } {
368360
const bitgo = req.bitgo;
369361
const coin = bitgo.coin(req.params.coin);
370362

371363
if (coin instanceof Coin.AbstractUtxoCoin) {
372364
return {
373-
isValid: coin.isValidAddress(req.body.address, !!req.body.supportOldScriptHashVersion),
365+
isValid: coin.isValidAddress(req.decoded.address, req.decoded.supportOldScriptHashVersion),
374366
};
375367
}
376368

377369
return {
378-
isValid: coin.isValidAddress(req.body.address),
370+
isValid: coin.isValidAddress(req.decoded.address),
379371
};
380372
}
381373

@@ -1720,7 +1712,7 @@ export function setupAPIRoutes(app: express.Application, config: Config): void {
17201712

17211713
// Miscellaneous
17221714
app.post('/api/v2/:coin/canonicaladdress', parseBody, prepareBitGo(config), promiseWrapper(handleCanonicalAddress));
1723-
app.post('/api/v2/:coin/verifyaddress', parseBody, prepareBitGo(config), promiseWrapper(handleV2VerifyAddress));
1715+
router.post('express.verifycoinaddress', [prepareBitGo(config), typedPromiseWrapper(handleV2VerifyAddress)]);
17241716
app.put(
17251717
'/api/v2/:coin/pendingapprovals/:id',
17261718
parseBody,

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { PostAcceptShare } from './v1/acceptShare';
1212
import { PostSimpleCreate } from './v1/simpleCreate';
1313
import { PutPendingApproval } from './v1/pendingApproval';
1414
import { PostSignTransaction } from './v1/signTransaction';
15+
import { PostVerifyCoinAddress } from './v2/verifyAddress';
1516

1617
export const ExpressApi = apiSpec({
1718
'express.ping': {
@@ -44,6 +45,9 @@ export const ExpressApi = apiSpec({
4445
'express.v1.wallet.signTransaction': {
4546
post: PostSignTransaction,
4647
},
48+
'express.verifycoinaddress': {
49+
post: PostVerifyCoinAddress,
50+
},
4751
});
4852

4953
export type ExpressApi = typeof ExpressApi;
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
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+
/**
6+
* Path parameters for coin-specific address verification.
7+
* @property coin - Ticker or identifier of the coin (e.g. 'btc', 'eth').
8+
*/
9+
export const VerifyAddressV2Params = {
10+
/** Coin ticker / chain identifier */
11+
coin: t.string,
12+
};
13+
14+
/**
15+
* Request body for coin-specific address verification.
16+
*
17+
* @property address - The address string to validate.
18+
* @property supportOldScriptHashVersion - (UTXO only) When true, treat legacy script hash version as acceptable.
19+
*/
20+
export const VerifyAddressV2Body = {
21+
/** Address which should be verified for correct format */
22+
address: t.string,
23+
/** Accept legacy script hash version for applicable UTXO coins (optional). */
24+
supportOldScriptHashVersion: optional(t.boolean),
25+
};
26+
27+
/**
28+
* Verify address for a given coin.
29+
*
30+
* Returns whether the address is valid for the specified coin.
31+
* For UTXO coins, an optional legacy script hash flag can be provided to allow previous script hash versions.
32+
*
33+
* @operationId express.verifycoinaddress
34+
*/
35+
export const PostVerifyCoinAddress = httpRoute({
36+
path: '/api/v2/{coin}/verifyaddress',
37+
method: 'POST',
38+
request: httpRequest({
39+
params: VerifyAddressV2Params,
40+
body: VerifyAddressV2Body,
41+
}),
42+
response: {
43+
200: t.type({
44+
isValid: t.boolean,
45+
}),
46+
404: BitgoExpressError,
47+
},
48+
});

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { DecryptRequestBody } from '../../../src/typedRoutes/api/common/decrypt'
44
import { EncryptRequestBody } from '../../../src/typedRoutes/api/common/encrypt';
55
import { LoginRequest } from '../../../src/typedRoutes/api/common/login';
66
import { VerifyAddressBody } from '../../../src/typedRoutes/api/common/verifyAddress';
7+
import { VerifyAddressV2Body, VerifyAddressV2Params } from '../../../src/typedRoutes/api/v2/verifyAddress';
78
import { SimpleCreateRequestBody } from '../../../src/typedRoutes/api/v1/simpleCreate';
89

910
export function assertDecode<T>(codec: t.Type<T, unknown>, input: unknown): T {
@@ -92,6 +93,34 @@ describe('io-ts decode tests', function () {
9293
address: 'some-address',
9394
});
9495
});
96+
it('express.verifycoinaddress', function () {
97+
// invalid coin param type
98+
assert.throws(() =>
99+
assertDecode(t.type(VerifyAddressV2Params), {
100+
coin: 123,
101+
})
102+
);
103+
// valid coin param
104+
assertDecode(t.type(VerifyAddressV2Params), {
105+
coin: 'btc',
106+
});
107+
108+
// invalid address type in body
109+
assert.throws(() =>
110+
assertDecode(t.type(VerifyAddressV2Body), {
111+
address: 123,
112+
})
113+
);
114+
// valid body without optional flag
115+
assertDecode(t.type(VerifyAddressV2Body), {
116+
address: 'some-address',
117+
});
118+
// valid body with optional flag
119+
assertDecode(t.type(VerifyAddressV2Body), {
120+
address: 'some-address',
121+
supportOldScriptHashVersion: true,
122+
});
123+
});
95124
it('express.v1.wallet.simplecreate', function () {
96125
// passphrase is required
97126
assert.throws(() => assertDecode(t.type(SimpleCreateRequestBody), {}));

0 commit comments

Comments
 (0)