Skip to content

Commit 2e80147

Browse files
authored
fix(express): pendingApprovalV1 type codec
2 parents 0e2428f + 00e4c72 commit 2e80147

File tree

2 files changed

+76
-2
lines changed

2 files changed

+76
-2
lines changed

modules/express/src/typedRoutes/api/v1/pendingApproval.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ export const pendingApprovalRequestParams = {
88
};
99

1010
export const pendingApprovalRequestBody = {
11+
/** State of the approval: 'approved' to approve, omit or 'rejected' to reject (defaults to rejection) */
12+
state: optional(t.string),
1113
/** Wallet passphrase for decrypting user keys (required for transaction signing) */
1214
walletPassphrase: optional(t.string),
1315
/** One-time password for 2FA verification */

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

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ describe('PendingApproval codec tests', function () {
4949
describe('pendingApprovalRequestBody', function () {
5050
it('should validate body with all fields', function () {
5151
const validBody = {
52+
state: 'approved',
5253
walletPassphrase: 'mySecurePassword',
5354
otp: '123456',
5455
tx: 'transactionHexString',
@@ -58,6 +59,7 @@ describe('PendingApproval codec tests', function () {
5859
};
5960

6061
const decoded = assertDecode(t.type(pendingApprovalRequestBody), validBody);
62+
assert.strictEqual(decoded.state, validBody.state);
6163
assert.strictEqual(decoded.walletPassphrase, validBody.walletPassphrase);
6264
assert.strictEqual(decoded.otp, validBody.otp);
6365
assert.strictEqual(decoded.tx, validBody.tx);
@@ -66,10 +68,13 @@ describe('PendingApproval codec tests', function () {
6668
assert.strictEqual(decoded.pendingApprovalId, validBody.pendingApprovalId);
6769
});
6870

69-
it('should validate body with no fields (all optional)', function () {
70-
const validBody = {};
71+
it('should validate body with only state field', function () {
72+
const validBody = {
73+
state: 'approved',
74+
};
7175

7276
const decoded = assertDecode(t.type(pendingApprovalRequestBody), validBody);
77+
assert.strictEqual(decoded.state, validBody.state);
7378
assert.strictEqual(decoded.walletPassphrase, undefined);
7479
assert.strictEqual(decoded.otp, undefined);
7580
assert.strictEqual(decoded.tx, undefined);
@@ -80,11 +85,13 @@ describe('PendingApproval codec tests', function () {
8085

8186
it('should validate body with some fields', function () {
8287
const validBody = {
88+
state: 'rejected',
8389
walletPassphrase: 'mySecurePassword',
8490
otp: '123456',
8591
};
8692

8793
const decoded = assertDecode(t.type(pendingApprovalRequestBody), validBody);
94+
assert.strictEqual(decoded.state, validBody.state);
8895
assert.strictEqual(decoded.walletPassphrase, validBody.walletPassphrase);
8996
assert.strictEqual(decoded.otp, validBody.otp);
9097
assert.strictEqual(decoded.tx, undefined);
@@ -93,8 +100,60 @@ describe('PendingApproval codec tests', function () {
93100
assert.strictEqual(decoded.pendingApprovalId, undefined);
94101
});
95102

103+
it('should validate body with missing state field (defaults to rejection)', function () {
104+
const validBody = {
105+
walletPassphrase: 'mySecurePassword',
106+
};
107+
108+
const decoded = assertDecode(t.type(pendingApprovalRequestBody), validBody);
109+
assert.strictEqual(decoded.state, undefined);
110+
assert.strictEqual(decoded.walletPassphrase, validBody.walletPassphrase);
111+
});
112+
113+
it('should validate empty body (defaults to rejection)', function () {
114+
const validBody = {};
115+
116+
const decoded = assertDecode(t.type(pendingApprovalRequestBody), validBody);
117+
assert.strictEqual(decoded.state, undefined);
118+
assert.strictEqual(decoded.walletPassphrase, undefined);
119+
assert.strictEqual(decoded.otp, undefined);
120+
assert.strictEqual(decoded.tx, undefined);
121+
assert.strictEqual(decoded.xprv, undefined);
122+
assert.strictEqual(decoded.previewPendingTxs, undefined);
123+
assert.strictEqual(decoded.pendingApprovalId, undefined);
124+
});
125+
126+
it('should reject body with non-string state', function () {
127+
const invalidBody = {
128+
state: 12345, // number instead of string
129+
};
130+
131+
assert.throws(() => {
132+
assertDecode(t.type(pendingApprovalRequestBody), invalidBody);
133+
});
134+
});
135+
136+
it('should validate body with state "approved"', function () {
137+
const validBody = {
138+
state: 'approved',
139+
};
140+
141+
const decoded = assertDecode(t.type(pendingApprovalRequestBody), validBody);
142+
assert.strictEqual(decoded.state, 'approved');
143+
});
144+
145+
it('should validate body with state "rejected"', function () {
146+
const validBody = {
147+
state: 'rejected',
148+
};
149+
150+
const decoded = assertDecode(t.type(pendingApprovalRequestBody), validBody);
151+
assert.strictEqual(decoded.state, 'rejected');
152+
});
153+
96154
it('should reject body with non-string walletPassphrase', function () {
97155
const invalidBody = {
156+
state: 'approved',
98157
walletPassphrase: 12345, // number instead of string
99158
};
100159

@@ -105,6 +164,7 @@ describe('PendingApproval codec tests', function () {
105164

106165
it('should reject body with non-string otp', function () {
107166
const invalidBody = {
167+
state: 'approved',
108168
otp: 123456, // number instead of string
109169
};
110170

@@ -115,6 +175,7 @@ describe('PendingApproval codec tests', function () {
115175

116176
it('should reject body with non-string tx', function () {
117177
const invalidBody = {
178+
state: 'approved',
118179
tx: 12345, // number instead of string
119180
};
120181

@@ -125,6 +186,7 @@ describe('PendingApproval codec tests', function () {
125186

126187
it('should reject body with non-string xprv', function () {
127188
const invalidBody = {
189+
state: 'approved',
128190
xprv: 12345, // number instead of string
129191
};
130192

@@ -135,6 +197,7 @@ describe('PendingApproval codec tests', function () {
135197

136198
it('should reject body with non-boolean previewPendingTxs', function () {
137199
const invalidBody = {
200+
state: 'approved',
138201
previewPendingTxs: 'true', // string instead of boolean
139202
};
140203

@@ -145,6 +208,7 @@ describe('PendingApproval codec tests', function () {
145208

146209
it('should reject body with non-string pendingApprovalId', function () {
147210
const invalidBody = {
211+
state: 'approved',
148212
pendingApprovalId: 12345, // number instead of string
149213
};
150214

@@ -157,6 +221,7 @@ describe('PendingApproval codec tests', function () {
157221
describe('Edge cases', function () {
158222
it('should handle empty strings for string fields', function () {
159223
const body = {
224+
state: '',
160225
walletPassphrase: '',
161226
otp: '',
162227
tx: '',
@@ -165,6 +230,7 @@ describe('PendingApproval codec tests', function () {
165230
};
166231

167232
const decoded = assertDecode(t.type(pendingApprovalRequestBody), body);
233+
assert.strictEqual(decoded.state, '');
168234
assert.strictEqual(decoded.walletPassphrase, '');
169235
assert.strictEqual(decoded.otp, '');
170236
assert.strictEqual(decoded.tx, '');
@@ -174,12 +240,14 @@ describe('PendingApproval codec tests', function () {
174240

175241
it('should handle additional unknown properties', function () {
176242
const body = {
243+
state: 'approved',
177244
walletPassphrase: 'mySecurePassword',
178245
unknownProperty: 'some value',
179246
};
180247

181248
// io-ts with t.exact() strips out additional properties
182249
const decoded = assertDecode(t.exact(t.type(pendingApprovalRequestBody)), body);
250+
assert.strictEqual(decoded.state, 'approved');
183251
assert.strictEqual(decoded.walletPassphrase, 'mySecurePassword');
184252
// @ts-expect-error - unknownProperty doesn't exist on the type
185253
assert.strictEqual(decoded.unknownProperty, undefined);
@@ -352,6 +420,7 @@ describe('PendingApproval codec tests', function () {
352420
it('should successfully preview pending transactions', async function () {
353421
const approvalId = '123456789abcdef';
354422
const requestBody = {
423+
state: 'approved',
355424
previewPendingTxs: true,
356425
};
357426

@@ -417,6 +486,7 @@ describe('PendingApproval codec tests', function () {
417486
it('should handle SDK method failure', async function () {
418487
const approvalId = '123456789abcdef';
419488
const requestBody = {
489+
state: 'approved',
420490
walletPassphrase: 'mySecurePassword',
421491
};
422492

@@ -442,6 +512,7 @@ describe('PendingApproval codec tests', function () {
442512
it('should handle invalid type in request field', async function () {
443513
const approvalId = '123456789abcdef';
444514
const requestBody = {
515+
state: 'approved',
445516
walletPassphrase: 12345, // number instead of string
446517
};
447518

@@ -457,6 +528,7 @@ describe('PendingApproval codec tests', function () {
457528
it('should handle invalid previewPendingTxs type', async function () {
458529
const approvalId = '123456789abcdef';
459530
const requestBody = {
531+
state: 'approved',
460532
previewPendingTxs: 'true', // string instead of boolean
461533
};
462534

0 commit comments

Comments
 (0)