tapimo 0.4.3 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/dist/App.d.ts +2491 -2861
  2. package/dist/App.d.ts.map +1 -1
  3. package/dist/admin/apps/verified-tokens.d.ts +57 -57
  4. package/dist/apps/data/App.d.ts +2354 -2724
  5. package/dist/apps/data/App.d.ts.map +1 -1
  6. package/dist/apps/data/FundingRouteProviders.d.ts +3 -110
  7. package/dist/apps/data/FundingRouteProviders.d.ts.map +1 -1
  8. package/dist/apps/data/FundingRouteProviders.js +1 -302
  9. package/dist/apps/data/FundingRouteProviders.js.map +1 -1
  10. package/dist/apps/data/routes/exchanges.d.ts +455 -455
  11. package/dist/apps/data/routes/fee-amm.d.ts +92 -92
  12. package/dist/apps/data/routes/funding.d.ts +138 -730
  13. package/dist/apps/data/routes/funding.d.ts.map +1 -1
  14. package/dist/apps/data/routes/funding.js +7 -241
  15. package/dist/apps/data/routes/funding.js.map +1 -1
  16. package/dist/apps/data/routes/tokenlist.d.ts +12 -12
  17. package/dist/apps/data/routes/transactions.d.ts +281 -281
  18. package/dist/apps/data/routes/transfers.d.ts +58 -58
  19. package/dist/apps/data/routes/verified-tokens.d.ts +86 -86
  20. package/dist/apps/management/App.d.ts +855 -855
  21. package/dist/apps/management/routes/api-keys.d.ts +40 -40
  22. package/dist/apps/management/routes/billing.d.ts +207 -207
  23. package/dist/apps/management/routes/me.d.ts +6 -6
  24. package/dist/apps/management/routes/members.d.ts +30 -30
  25. package/dist/apps/management/routes/orgs.d.ts +92 -92
  26. package/dist/apps/management/routes/projects.d.ts +28 -28
  27. package/dist/apps/management/routes/usage.d.ts +24 -24
  28. package/dist/apps/mcp.d.ts.map +1 -1
  29. package/dist/apps/mcp.js +3 -1
  30. package/dist/apps/mcp.js.map +1 -1
  31. package/dist/cloudflare.d.ts +2 -0
  32. package/dist/cloudflare.d.ts.map +1 -1
  33. package/dist/cloudflare.js +4 -0
  34. package/dist/cloudflare.js.map +1 -1
  35. package/dist/internal/Auth.d.ts +33 -22
  36. package/dist/internal/Auth.d.ts.map +1 -1
  37. package/dist/internal/Auth.js +40 -11
  38. package/dist/internal/Auth.js.map +1 -1
  39. package/dist/internal/Errors.d.ts +6 -0
  40. package/dist/internal/Errors.d.ts.map +1 -0
  41. package/dist/internal/Errors.js +16 -0
  42. package/dist/internal/Errors.js.map +1 -0
  43. package/dist/internal/FundingRoutes.d.ts +15 -213
  44. package/dist/internal/FundingRoutes.d.ts.map +1 -1
  45. package/dist/internal/FundingRoutes.js +1 -72
  46. package/dist/internal/FundingRoutes.js.map +1 -1
  47. package/dist/internal/Store.d.ts +61 -16
  48. package/dist/internal/Store.d.ts.map +1 -1
  49. package/dist/internal/Store.js +72 -17
  50. package/dist/internal/Store.js.map +1 -1
  51. package/dist/internal/Viem.d.ts +1 -1
  52. package/dist/internal/index.d.ts +27 -0
  53. package/dist/internal/index.d.ts.map +1 -0
  54. package/dist/internal/index.js +27 -0
  55. package/dist/internal/index.js.map +1 -0
  56. package/package.json +8 -3
  57. package/src/App.test.ts +60 -4
  58. package/src/Client.test-d.ts +0 -47
  59. package/src/apps/data/FundingRouteProviders.test.ts +37 -297
  60. package/src/apps/data/FundingRouteProviders.ts +3 -435
  61. package/src/apps/data/routes/funding.test.ts +7 -109
  62. package/src/apps/data/routes/funding.ts +8 -323
  63. package/src/apps/data/routes/indexer.test.ts +2 -2
  64. package/src/apps/data/routes/webhooks.test.ts +2 -2
  65. package/src/apps/mcp.test.ts +55 -14
  66. package/src/apps/mcp.ts +3 -1
  67. package/src/cloudflare.ts +5 -0
  68. package/src/internal/Auth.test.ts +397 -16
  69. package/src/internal/Auth.ts +76 -32
  70. package/src/internal/FundingRoutes.test.ts +8 -34
  71. package/src/internal/FundingRoutes.ts +1 -174
  72. package/src/internal/Log.test.ts +4 -4
  73. package/src/internal/Store.test-d.ts +15 -0
  74. package/src/internal/Store.test.ts +153 -2
  75. package/src/internal/Store.ts +157 -41
  76. package/src/internal/index.test.ts +34 -0
  77. package/src/internal/index.ts +26 -0
package/src/App.test.ts CHANGED
@@ -1,10 +1,12 @@
1
1
  import * as http from 'node:http'
2
+ import { Challenge } from 'mppx'
2
3
  import { ApiKeys, App, Metrics, RateLimit, Store } from 'tapimo'
3
4
  import * as Docs from 'tapimo/docs'
4
5
  import * as Tokens from './apps/data/routes/tokens.js'
5
6
  import type * as Log from './internal/Log.js'
6
7
  import * as TestApp from '../test/App.js'
7
8
  import * as Runtime from '../test/runtime.js'
9
+ import * as Tempo from '../test/Tempo.js'
8
10
 
9
11
  describe('create', () => {
10
12
  test('composes default dependencies', async () => {
@@ -208,6 +210,53 @@ describe('create', () => {
208
210
  `)
209
211
  })
210
212
 
213
+ test('applies the configured global MPP rate limit', async () => {
214
+ const store = Store.memory()
215
+ const limit = { perMinute: 2 }
216
+ const app = TestApp.create({
217
+ mpp: { rateLimit: limit },
218
+ rateLimit: { store },
219
+ })
220
+ await exhaustQuota(RateLimit.memory({ store }), 'mpp:public:203.0.113.10', limit)
221
+
222
+ const response = await app.request(`/v1/tokens/${TestApp.token}`, {
223
+ headers: {
224
+ authorization: 'Payment malformed',
225
+ 'x-forwarded-for': '203.0.113.10',
226
+ },
227
+ })
228
+
229
+ expect(response.status).toBe(429)
230
+ expect(response.headers.get('RateLimit-Limit')).toBe('2')
231
+ expect(response.headers.get('RateLimit-Scope')).toBe('mpp')
232
+ })
233
+
234
+ test('endpoint MPP rate limit overrides the global limit', async () => {
235
+ const store = Store.memory()
236
+ const routeLimit = { perMinute: 1 }
237
+ const app = TestApp.create({
238
+ auth: {
239
+ overrides: {
240
+ 'GET /v1/tokens/:token': { mpp: { rateLimit: routeLimit } },
241
+ },
242
+ },
243
+ mpp: { rateLimit: { perMinute: 2 } },
244
+ rateLimit: { store },
245
+ })
246
+ await exhaustQuota(RateLimit.memory({ store }), 'mpp:public:203.0.113.10', routeLimit)
247
+
248
+ const response = await app.request(`/v1/tokens/${TestApp.token}`, {
249
+ headers: {
250
+ authorization: 'Payment malformed',
251
+ 'x-forwarded-for': '203.0.113.10',
252
+ },
253
+ })
254
+
255
+ expect(response.status).toBe(429)
256
+ expect(response.headers.get('RateLimit-Limit')).toBe('1')
257
+ expect(response.headers.get('RateLimit-Scope')).toBe('mpp')
258
+ })
259
+
211
260
  test('serves Vocs API reference', async () => {
212
261
  const app = TestApp.create({ docs: Docs.docs() })
213
262
  const response = await app.request('/')
@@ -602,11 +651,13 @@ describe('create', () => {
602
651
  auth,
603
652
  cache: { store },
604
653
  mpp: {
605
- charge: {
606
- currency: 'USD',
607
- decimals: 2,
608
- },
609
654
  secretKey: 'secret_test_key_0123456789abcdef',
655
+ session: {
656
+ chainId: Tempo.chain.id,
657
+ decimals: 6,
658
+ getClient: () => Tempo.client,
659
+ recipient: Tempo.accounts[2].address,
660
+ },
610
661
  },
611
662
  rateLimit: {
612
663
  now,
@@ -627,6 +678,11 @@ describe('create', () => {
627
678
  })
628
679
  const overQuota = await app.request('/v1/tokens/not-an-address')
629
680
  expect(overQuota.status).toMatchInlineSnapshot(`402`)
681
+ expect(Challenge.fromHeaders(overQuota.headers).request['currency']).toBe(Tempo.currency)
682
+
683
+ const head = await app.request('/v1/tokens/not-an-address', { method: 'HEAD' })
684
+ expect(head.status).toMatchInlineSnapshot(`402`)
685
+ expect(Challenge.fromHeaders(head.headers).intent).toBe('session')
630
686
  })
631
687
 
632
688
  test('supports bearer API-key fallback', async () => {
@@ -1221,53 +1221,6 @@ describe('narrows responses by status', () => {
1221
1221
  }
1222
1222
  })
1223
1223
 
1224
- test('POST /v1/funding/routes/quote', async () => {
1225
- const client = Client.create()
1226
- const res = await client.v1.funding.routes.quote.$post({
1227
- json: {
1228
- depositor: '0x1111111111111111111111111111111111111111',
1229
- provider: 'across',
1230
- sourceAmount: '1000000',
1231
- sourceChain: 'base',
1232
- sourceToken: 'USDC',
1233
- },
1234
- })
1235
-
1236
- expectTypeOf(res.status).toEqualTypeOf<200 | 400 | 404 | 501 | 502 | PaidAccessStatus>()
1237
-
1238
- switch (res.status) {
1239
- case 200: {
1240
- const json = await res.json()
1241
- expectTypeOf(json).toEqualTypeOf<
1242
- z.output<typeof Funding.schema.quoteFundingRoute.Response>
1243
- >()
1244
- return
1245
- }
1246
- case 400: {
1247
- const json = await res.json()
1248
- expectTypeOf(json.error.code).toEqualTypeOf<Access400<'body_invalid'>>()
1249
- return
1250
- }
1251
- case 404: {
1252
- const json = await res.json()
1253
- expectTypeOf(json.error.code).toEqualTypeOf<'quote_unavailable' | 'route_not_found'>()
1254
- return
1255
- }
1256
- case 501: {
1257
- const json = await res.json()
1258
- expectTypeOf(json.error.code).toEqualTypeOf<'provider_unconfigured'>()
1259
- return
1260
- }
1261
- case 502: {
1262
- const json = await res.json()
1263
- expectTypeOf(json.error.code).toEqualTypeOf<
1264
- 'provider_error' | 'provider_rate_limited' | 'provider_timeout'
1265
- >()
1266
- return
1267
- }
1268
- }
1269
- })
1270
-
1271
1224
  test('GET /v1/funding/chains', async () => {
1272
1225
  const client = Client.create()
1273
1226
  const res = await client.v1.funding.chains.$get()
@@ -4,249 +4,6 @@ import * as FundingRouteProviders from './FundingRouteProviders.js'
4
4
  const now = () => new Date('2026-01-01T00:00:00.000Z')
5
5
 
6
6
  describe('FundingRouteProviders', () => {
7
- test('maps Across suggested-fees responses into quote probes', async () => {
8
- const requests: RecordedRequest[] = []
9
- const fetch = recordingFetch(requests, async () =>
10
- jsonResponse({
11
- estimatedFillTimeSec: 2,
12
- limits: {
13
- maxDeposit: '2000000',
14
- maxDepositInstant: '1500000',
15
- minDeposit: '500000',
16
- },
17
- outputAmount: '990000',
18
- relayFeePct: '1200000000000000',
19
- timestamp: '1767225600',
20
- }),
21
- )
22
- const adapter = FundingRouteProviders.across({
23
- apiKey: 'across-api-key',
24
- baseUrl: 'https://across.test/api/',
25
- fetch,
26
- integratorId: 'tempo',
27
- now,
28
- })
29
-
30
- const result = await adapter.probeQuote(
31
- await probeInput('across'),
32
- new AbortController().signal,
33
- )
34
-
35
- expect(requests).toHaveLength(1)
36
- expect(requests[0]?.url.pathname).toBe('/api/suggested-fees')
37
- expect(requests[0]?.url.searchParams.get('originChainId')).toBe('8453')
38
- expect(requests[0]?.url.searchParams.get('destinationChainId')).toBe('4217')
39
- expect(requests[0]?.url.searchParams.get('amount')).toBe('1000000')
40
- expect(requests[0]?.url.searchParams.get('integratorId')).toBe('tempo')
41
- expect(requests[0]?.url.searchParams.get('allowUnmatchedDecimals')).toBe('true')
42
- expect(new Headers(requests[0]?.init?.headers).get('authorization')).toBe(
43
- 'Bearer across-api-key',
44
- )
45
- expect(result).toMatchObject({
46
- expiresAt: '2026-01-01T00:10:00.000Z',
47
- limits: {
48
- instantSourceAmount: '1500000',
49
- maxSourceAmount: '2000000',
50
- minSourceAmount: '500000',
51
- },
52
- outputAmount: '990000',
53
- outputAmountFormatted: '0.99',
54
- quality: {
55
- availableVolumeUsd: '2',
56
- estimatedSeconds: 2,
57
- feeBps: 12,
58
- instantVolumeUsd: '1.5',
59
- liquiditySource: 'providerLimit',
60
- sourceDetail: 'across:suggested-fees',
61
- tier: 'liquid',
62
- },
63
- sampledAt: '2026-01-01T00:00:00.000Z',
64
- status: 'available',
65
- })
66
- })
67
-
68
- test('maps recognized Across quote errors to unavailable probes', async () => {
69
- const fetch = recordingFetch([], async () =>
70
- jsonResponse({ code: 'AMOUNT_TOO_HIGH', message: 'Amount exceeds max deposit' }, 400),
71
- )
72
- const adapter = FundingRouteProviders.across({
73
- apiKey: 'across-api-key',
74
- fetch,
75
- integratorId: 'tempo',
76
- now,
77
- })
78
-
79
- const result = await adapter.probeQuote(
80
- await probeInput('across'),
81
- new AbortController().signal,
82
- )
83
-
84
- expect(result).toMatchObject({
85
- quality: {
86
- liquiditySource: 'providerLimit',
87
- score: 0,
88
- sourceDetail: 'across:suggested-fees:AMOUNT_TOO_HIGH',
89
- tier: 'unavailable',
90
- },
91
- sampledAt: '2026-01-01T00:00:00.000Z',
92
- status: 'unavailable',
93
- })
94
- })
95
-
96
- test('builds an authenticated exact-input Across quote request', async () => {
97
- const route = await staticRoute('across')
98
- const request = FundingRouteProviders.createAcrossQuoteRequest({
99
- apiKey: 'across-api-key',
100
- baseUrl: 'https://across.test/api/',
101
- depositor: '0x1111111111111111111111111111111111111111',
102
- integratorId: '0xdead',
103
- recipient: '0x2222222222222222222222222222222222222222',
104
- route,
105
- })
106
-
107
- expect(request.url.pathname).toBe('/api/swap/approval')
108
- expect(request.url.searchParams.get('originChainId')).toBe('8453')
109
- expect(request.url.searchParams.get('destinationChainId')).toBe('4217')
110
- expect(request.url.searchParams.get('amount')).toBe('1000000')
111
- expect(request.url.searchParams.get('integratorId')).toBe('0xdead')
112
- expect(request.url.searchParams.get('tradeType')).toBe('exactInput')
113
- expect(request.url.searchParams.get('skipOriginTxEstimation')).toBe('true')
114
- expect(request.url.searchParams.get('strictTradeType')).toBe('true')
115
- expect(request.url.searchParams.get('depositor')).toBe(
116
- '0x1111111111111111111111111111111111111111',
117
- )
118
- expect(request.url.searchParams.get('recipient')).toBe(
119
- '0x2222222222222222222222222222222222222222',
120
- )
121
- expect(new Headers(request.headers).get('authorization')).toBe('Bearer across-api-key')
122
- })
123
-
124
- test('calls the runtime fetch method with its global receiver', async () => {
125
- const route = await staticRoute('across')
126
- vi.useFakeTimers()
127
- vi.setSystemTime(now())
128
- const fetch = vi.fn(function (this: unknown) {
129
- expect(this).toBe(globalThis)
130
- return Promise.resolve(jsonResponse(acrossQuoteResponse(route)))
131
- })
132
- vi.stubGlobal('fetch', fetch)
133
-
134
- try {
135
- const quote = FundingRouteProviders.acrossQuote({
136
- apiKey: 'across-api-key',
137
- integratorId: '0xdead',
138
- })
139
- const result = await quote(
140
- { depositor: '0x1111111111111111111111111111111111111111', route },
141
- new AbortController().signal,
142
- )
143
-
144
- expect(result.outputAmount).toBe('990000')
145
- expect(fetch).toHaveBeenCalledOnce()
146
- } finally {
147
- vi.unstubAllGlobals()
148
- vi.useRealTimers()
149
- }
150
- })
151
-
152
- test('normalizes an Across quote payload', async () => {
153
- const route = await staticRoute('across')
154
- const result = FundingRouteProviders.parseAcrossQuote({
155
- body: acrossQuoteResponse(route),
156
- now: now(),
157
- route,
158
- })
159
-
160
- expect(result).toMatchObject({
161
- estimatedSeconds: 2,
162
- expiresAt: '2026-01-01T00:01:00.000Z',
163
- fees: {
164
- total: {
165
- amount: '1200',
166
- amountUsd: '0.0012',
167
- bps: 12,
168
- token: { chainId: 'eip155:8453', symbol: 'USDC' },
169
- },
170
- totalMax: {
171
- amount: '1800',
172
- amountUsd: '0.0018',
173
- bps: 18,
174
- token: { chainId: 'eip155:8453', symbol: 'USDC' },
175
- },
176
- },
177
- minimumOutputAmount: '988000',
178
- outputAmount: '990000',
179
- sampledAt: '2026-01-01T00:00:00.000Z',
180
- })
181
- })
182
-
183
- test('maps Across HTTP errors into stable provider errors', () => {
184
- expect(
185
- FundingRouteProviders.mapAcrossQuoteError({ body: { code: 'RATE_LIMITED' }, status: 429 }),
186
- ).toBeInstanceOf(FundingRoutes.ProviderRateLimitError)
187
- expect(
188
- FundingRouteProviders.mapAcrossQuoteError({ body: { code: 'NO_ROUTE' }, status: 400 }),
189
- ).toBeInstanceOf(FundingRoutes.ProviderQuoteUnavailableError)
190
- const error = FundingRouteProviders.mapAcrossQuoteError({
191
- body: { code: 'NOT_FOUND' },
192
- status: 404,
193
- })
194
- expect(error).toMatchObject({ name: 'FundingRouteProviders.ProviderResponseError' })
195
- expect(FundingRouteProviders.acrossQuoteFailure({ cause: error })).toEqual({
196
- code: 'NOT_FOUND',
197
- failure: 'http',
198
- id: 'across',
199
- operation: 'swap/approval',
200
- status: 404,
201
- })
202
- })
203
-
204
- test('rejects invalid Across configuration during adapter construction', () => {
205
- expect(() =>
206
- FundingRouteProviders.acrossQuote({ apiKey: 'across-api-key', integratorId: 'tempo' }),
207
- ).toThrowErrorMatchingInlineSnapshot(`[FundingRouteProviders.ProviderConfigurationError]`)
208
- })
209
-
210
- test('rejects malformed Across quote payloads', async () => {
211
- const route = await staticRoute('across')
212
- const failure = (() => {
213
- try {
214
- FundingRouteProviders.parseAcrossQuote({
215
- body: { expectedOutputAmount: '990000' },
216
- now: now(),
217
- route,
218
- })
219
- throw new Error('Expected malformed payload to fail')
220
- } catch (cause) {
221
- return cause
222
- }
223
- })()
224
- expect(failure).toMatchObject({ name: 'FundingRouteProviders.ProviderPayloadError' })
225
- expect(FundingRouteProviders.acrossQuoteFailure({ cause: failure })).toEqual({
226
- failure: 'payload',
227
- id: 'across',
228
- operation: 'swap/approval',
229
- })
230
- })
231
-
232
- test('rejects inconsistent Across fee summaries', async () => {
233
- const route = await staticRoute('across')
234
- const body = acrossQuoteResponse(route)
235
- body.fees.totalMax.amount = '1000'
236
- expect(() => FundingRouteProviders.parseAcrossQuote({ body, now: now(), route })).toThrow(
237
- expect.objectContaining({ name: 'FundingRouteProviders.ProviderPayloadError' }),
238
- )
239
- })
240
-
241
- test('rejects mismatched Across fee tokens', async () => {
242
- const route = await staticRoute('across')
243
- const body = acrossQuoteResponse(route)
244
- body.fees.total.token.address = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
245
- expect(() => FundingRouteProviders.parseAcrossQuote({ body, now: now(), route })).toThrow(
246
- expect.objectContaining({ name: 'FundingRouteProviders.ProviderPayloadError' }),
247
- )
248
- })
249
-
250
7
  test('maps Relay liquidity and quote responses into quote probes', async () => {
251
8
  const requests: RecordedRequest[] = []
252
9
  const route = await staticRoute('relay')
@@ -319,6 +76,43 @@ describe('FundingRouteProviders', () => {
319
76
  })
320
77
  })
321
78
 
79
+ test('calls the runtime fetch method with its global receiver', async () => {
80
+ const route = await staticRoute('relay')
81
+ const fetch = vi.fn(function (this: unknown, input: Parameters<typeof globalThis.fetch>[0]) {
82
+ expect(this).toBe(globalThis)
83
+ const url = toUrl(input)
84
+ return Promise.resolve(
85
+ jsonResponse(
86
+ url.pathname === '/quote/v2'
87
+ ? {
88
+ details: {
89
+ currencyOut: { amount: '990000', minimumAmount: '980000' },
90
+ timeEstimate: 15,
91
+ },
92
+ }
93
+ : { liquidity: [] },
94
+ ),
95
+ )
96
+ })
97
+ vi.stubGlobal('fetch', fetch)
98
+
99
+ try {
100
+ const adapter = FundingRouteProviders.relay({
101
+ now,
102
+ userAddress: '0x1111111111111111111111111111111111111111',
103
+ })
104
+ const result = await adapter.probeQuote(
105
+ probeInputFromRoute(route),
106
+ new AbortController().signal,
107
+ )
108
+
109
+ expect(result.outputAmount).toBe('990000')
110
+ expect(fetch).toHaveBeenCalledTimes(2)
111
+ } finally {
112
+ vi.unstubAllGlobals()
113
+ }
114
+ })
115
+
322
116
  test('keeps Relay quotes when the liquidity probe fails', async () => {
323
117
  const route = await staticRoute('relay')
324
118
  const fetch = recordingFetch([], async (request) => {
@@ -378,10 +172,6 @@ async function staticRoute(
378
172
  return route as FundingRoutes.QuoteProbeInput['route']
379
173
  }
380
174
 
381
- async function probeInput(provider: FundingRoutes.ProviderId) {
382
- return probeInputFromRoute(await staticRoute(provider))
383
- }
384
-
385
175
  function probeInputFromRoute(
386
176
  route: FundingRoutes.QuoteProbeInput['route'],
387
177
  ): FundingRoutes.QuoteProbeInput {
@@ -406,56 +196,6 @@ function probeInputFromRoute(
406
196
  }
407
197
  }
408
198
 
409
- function acrossQuoteResponse(route: FundingRoutes.QuoteProbeInput['route']) {
410
- return {
411
- amountType: 'exactInput',
412
- approvalTxns: [{ data: '0x1234', to: '0x2222222222222222222222222222222222222222' }],
413
- checks: { balance: { actual: '1000000', expected: '1000000' } },
414
- expectedFillTime: 2,
415
- expectedOutputAmount: '990000',
416
- fees: {
417
- total: {
418
- amount: '1200',
419
- amountUsd: '0.0012',
420
- pct: '1200000000000000',
421
- token: {
422
- address: route.sourceToken.address,
423
- chainId: 8453,
424
- decimals: 6,
425
- symbol: 'USDC',
426
- },
427
- },
428
- totalMax: {
429
- amount: '1800',
430
- amountUsd: '0.0018',
431
- pct: '1800000000000000',
432
- token: {
433
- address: route.sourceToken.address,
434
- chainId: 8453,
435
- decimals: 6,
436
- symbol: 'USDC',
437
- },
438
- },
439
- },
440
- inputAmount: '1000000',
441
- inputToken: {
442
- address: route.sourceToken.address,
443
- chainId: 8453,
444
- decimals: 6,
445
- symbol: 'USDC',
446
- },
447
- minOutputAmount: '988000',
448
- outputToken: {
449
- address: route.destinationToken.address,
450
- chainId: 4217,
451
- decimals: 6,
452
- symbol: 'USDC.e',
453
- },
454
- quoteExpiryTimestamp: 1767225660,
455
- swapTx: { data: '0xabcd', to: '0x3333333333333333333333333333333333333333' },
456
- }
457
- }
458
-
459
199
  function recordingFetch(
460
200
  requests: RecordedRequest[],
461
201
  respond: (request: RecordedRequest) => Response | Promise<Response>,