Skip to content

Commit 93d9cfd

Browse files
committed
fix(passport): undefined fee options, post to relayer error
1 parent 805c24c commit 93d9cfd

File tree

4 files changed

+72
-6
lines changed

4 files changed

+72
-6
lines changed

packages/passport/sdk/src/zkEvm/relayerClient.test.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ describe('relayerClient', () => {
7272
});
7373
});
7474

75-
it('throws HTTP error for non-ok response', async () => {
75+
it('throws error from JSON response when response contains error field', async () => {
7676
const to = '0xd64b0d2d72bb1b3f18046b8a7fc6c9ee6bccd287';
7777
const data = '0x123';
7878

@@ -84,7 +84,23 @@ describe('relayerClient', () => {
8484
});
8585

8686
await expect(relayerClient.ethSendTransaction(to, data)).rejects.toThrow(
87-
'Relayer HTTP error: 401. Content: "{"error":"invalid_token"}"',
87+
'invalid_token',
88+
);
89+
});
90+
91+
it('throws HTTP error for non-ok response without error field', async () => {
92+
const to = '0xd64b0d2d72bb1b3f18046b8a7fc6c9ee6bccd287';
93+
const data = '0x123';
94+
95+
(global.fetch as jest.Mock).mockResolvedValue({
96+
ok: false,
97+
status: 500,
98+
statusText: 'Internal Server Error',
99+
text: () => Promise.resolve('{"result":"some_result"}'),
100+
});
101+
102+
await expect(relayerClient.ethSendTransaction(to, data)).rejects.toThrow(
103+
'Relayer HTTP error: 500. Content: "{"result":"some_result"}"',
88104
);
89105
});
90106

packages/passport/sdk/src/zkEvm/relayerClient.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ type ImGetFeeOptionsRequest = {
5151
};
5252

5353
type ImGetFeeOptionsResponse = JsonRpc & {
54-
result: FeeOption[]
54+
result: FeeOption[] | undefined
5555
};
5656

5757
// ImSign types
@@ -126,13 +126,13 @@ export class RelayerClient {
126126
body: JSON.stringify(body),
127127
});
128128

129+
const responseText = await response.text();
130+
129131
if (!response.ok) {
130-
const responseText = await response.text();
131132
const preview = RelayerClient.getResponsePreview(responseText);
132133
throw new Error(`Relayer HTTP error: ${response.status}. Content: "${preview}"`);
133134
}
134135

135-
const responseText = await response.text();
136136
let jsonResponse;
137137
try {
138138
jsonResponse = JSON.parse(responseText);
@@ -141,6 +141,10 @@ export class RelayerClient {
141141
throw new Error(`Relayer JSON parse error: ${parseError instanceof Error ? parseError.message : 'Unknown error'}. Content: "${preview}"`);
142142
}
143143

144+
if (jsonResponse.error) {
145+
throw new Error(jsonResponse.error);
146+
}
147+
144148
return jsonResponse;
145149
}
146150

@@ -167,7 +171,7 @@ export class RelayerClient {
167171
return result;
168172
}
169173

170-
public async imGetFeeOptions(userAddress: string, data: BytesLike): Promise<FeeOption[]> {
174+
public async imGetFeeOptions(userAddress: string, data: BytesLike): Promise<FeeOption[] | undefined> {
171175
const { chainId } = await this.rpcProvider.getNetwork();
172176
const payload: ImGetFeeOptionsRequest = {
173177
method: 'im_getFeeOptions',

packages/passport/sdk/src/zkEvm/transactionHelpers.test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,48 @@ describe('transactionHelpers', () => {
306306
flow,
307307
})).rejects.toThrow('Transaction send failed');
308308
});
309+
310+
it('throws an error when imGetFeeOptions returns undefined', async () => {
311+
(relayerClient.imGetFeeOptions as jest.Mock).mockResolvedValue(undefined);
312+
313+
await expect(prepareAndSignTransaction({
314+
transactionRequest,
315+
ethSigner,
316+
rpcProvider,
317+
guardianClient,
318+
relayerClient,
319+
zkEvmAddress,
320+
flow,
321+
})).rejects.toThrow('Invalid fee options received from relayer');
322+
});
323+
324+
it('throws an error when imGetFeeOptions returns null', async () => {
325+
(relayerClient.imGetFeeOptions as jest.Mock).mockResolvedValue(null);
326+
327+
await expect(prepareAndSignTransaction({
328+
transactionRequest,
329+
ethSigner,
330+
rpcProvider,
331+
guardianClient,
332+
relayerClient,
333+
zkEvmAddress,
334+
flow,
335+
})).rejects.toThrow('Invalid fee options received from relayer');
336+
});
337+
338+
it('throws an error when imGetFeeOptions returns a non-array', async () => {
339+
(relayerClient.imGetFeeOptions as jest.Mock).mockResolvedValue({ invalid: 'response' });
340+
341+
await expect(prepareAndSignTransaction({
342+
transactionRequest,
343+
ethSigner,
344+
rpcProvider,
345+
guardianClient,
346+
relayerClient,
347+
zkEvmAddress,
348+
flow,
349+
})).rejects.toThrow('Invalid fee options received from relayer');
350+
});
309351
});
310352

311353
describe('prepareAndSignEjectionTransaction', () => {

packages/passport/sdk/src/zkEvm/transactionHelpers.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ const getFeeOption = async (
5555
transactions,
5656
);
5757

58+
if (!feeOptions || !Array.isArray(feeOptions)) {
59+
throw new Error('Invalid fee options received from relayer');
60+
}
61+
5862
const imxFeeOption = feeOptions.find(
5963
(feeOption) => feeOption.tokenSymbol === 'IMX',
6064
);

0 commit comments

Comments
 (0)