Skip to content

Commit 1072f3a

Browse files
committed
chore: fix types for sendmany
Ticket: WP-4634
1 parent f0b3c5e commit 1072f3a

2 files changed

Lines changed: 50 additions & 49 deletions

File tree

src/masterBitgoExpress/handleSendMany.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,22 @@ import { RequestTracer, PrebuildTransactionOptions, Memo } from '@bitgo/sdk-core
22
import { BitGoRequest } from '../types/request';
33
import { createEnclavedExpressClient } from './enclavedExpressClient';
44
import logger from '../logger';
5-
import { SendManyRequest } from './routers/masterApiSpec';
6-
import { TypeOf } from 'io-ts';
5+
import { MasterApiSpecRouteRequest } from './routers/masterApiSpec';
76

8-
export async function handleSendMany(req: BitGoRequest) {
7+
/**
8+
* Defines the structure for a single recipient in a send-many transaction.
9+
* This provides strong typing and autocompletion within the handler.
10+
*/
11+
interface Recipient {
12+
address: string;
13+
amount: string | number;
14+
feeLimit?: string;
15+
data?: string;
16+
tokenName?: string;
17+
tokenData?: any;
18+
}
19+
20+
export async function handleSendMany(req: MasterApiSpecRouteRequest<'v1.wallet.sendMany', 'post'>) {
921
const enclavedExpressClient = createEnclavedExpressClient(req.config, req.params.coin);
1022
if (!enclavedExpressClient) {
1123
throw new Error('Please configure enclaved express configs to sign the transactions.');
@@ -14,7 +26,9 @@ export async function handleSendMany(req: BitGoRequest) {
1426
const bitgo = req.bitgo;
1527
const baseCoin = bitgo.coin(req.params.coin);
1628

17-
const params = req.body as TypeOf<typeof SendManyRequest>;
29+
const params = req.decoded;
30+
params.recipients = params.recipients as Recipient[];
31+
1832
const walletId = req.params.walletId;
1933
const wallet = await baseCoin.wallets().get({ id: walletId, reqId });
2034
if (!wallet) {

src/masterBitgoExpress/routers/masterApiSpec.ts

Lines changed: 32 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -79,50 +79,37 @@ const GenerateWalletRequest = {
7979
isDistributedCustody: t.union([t.undefined, t.boolean]),
8080
};
8181

82-
export const SendManyRequest = t.intersection([
83-
t.type({
84-
pubkey: t.string,
85-
source: t.union([t.literal('user'), t.literal('backup')]),
86-
recipients: t.array(
87-
t.type({
88-
address: t.string,
89-
amount: t.union([t.string, t.number]),
90-
feeLimit: t.union([t.undefined, t.string]),
91-
data: t.union([t.undefined, t.string]),
92-
tokenName: t.union([t.undefined, t.string]),
93-
tokenData: t.union([t.undefined, t.any]),
94-
}),
95-
),
96-
}),
97-
t.partial({
98-
numBlocks: t.number,
99-
feeRate: t.number,
100-
feeMultiplier: t.number,
101-
maxFeeRate: t.number,
102-
minConfirms: t.number,
103-
enforceMinConfirmsForChange: t.boolean,
104-
targetWalletUnspents: t.number,
105-
message: t.string,
106-
minValue: t.union([t.number, t.string]),
107-
maxValue: t.union([t.number, t.string]),
108-
sequenceId: t.string,
109-
lastLedgerSequence: t.number,
110-
ledgerSequenceDelta: t.number,
111-
gasPrice: t.number,
112-
noSplitChange: t.boolean,
113-
unspents: t.array(t.string),
114-
comment: t.string,
115-
otp: t.string,
116-
changeAddress: t.string,
117-
allowExternalChangeAddress: t.boolean,
118-
instant: t.boolean,
119-
memo: t.string,
120-
transferId: t.number,
121-
eip1559: t.any,
122-
gasLimit: t.number,
123-
custodianTransactionId: t.string,
124-
}),
125-
]);
82+
export const SendManyRequest = {
83+
pubkey: t.string,
84+
source: t.union([t.literal('user'), t.literal('backup')]),
85+
recipients: t.array(t.any),
86+
numBlocks: t.union([t.undefined, t.number]),
87+
feeRate: t.union([t.undefined, t.number]),
88+
feeMultiplier: t.union([t.undefined, t.number]),
89+
maxFeeRate: t.union([t.undefined, t.number]),
90+
minConfirms: t.union([t.undefined, t.number]),
91+
enforceMinConfirmsForChange: t.union([t.undefined, t.boolean]),
92+
targetWalletUnspents: t.union([t.undefined, t.number]),
93+
message: t.union([t.undefined, t.string]),
94+
minValue: t.union([t.undefined, t.union([t.number, t.string])]),
95+
maxValue: t.union([t.undefined, t.union([t.number, t.string])]),
96+
sequenceId: t.union([t.undefined, t.string]),
97+
lastLedgerSequence: t.union([t.undefined, t.number]),
98+
ledgerSequenceDelta: t.union([t.undefined, t.number]),
99+
gasPrice: t.union([t.undefined, t.number]),
100+
noSplitChange: t.union([t.undefined, t.boolean]),
101+
unspents: t.union([t.undefined, t.array(t.string)]),
102+
comment: t.union([t.undefined, t.string]),
103+
otp: t.union([t.undefined, t.string]),
104+
changeAddress: t.union([t.undefined, t.string]),
105+
allowExternalChangeAddress: t.union([t.undefined, t.boolean]),
106+
instant: t.union([t.undefined, t.boolean]),
107+
memo: t.union([t.undefined, t.string]),
108+
transferId: t.union([t.undefined, t.number]),
109+
eip1559: t.union([t.undefined, t.any]),
110+
gasLimit: t.union([t.undefined, t.number]),
111+
custodianTransactionId: t.union([t.undefined, t.string]),
112+
};
126113

127114
export const SendManyResponse: HttpResponse = {
128115
// TODO: Get type from public types repo / Wallet Platform
@@ -137,7 +124,7 @@ export const SendManyResponse: HttpResponse = {
137124
export const MasterApiSpec = apiSpec({
138125
'v1.wallet.generate': {
139126
post: httpRoute({
140-
method: 'POST',
127+
method: 'POST' as const,
141128
path: '/{coin}/wallet/generate',
142129
request: httpRequest({
143130
params: {

0 commit comments

Comments
 (0)