tapimo 0.5.3 → 0.6.0
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.
- package/dist/App.d.ts +13987 -5755
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js.map +1 -1
- package/dist/admin/App.d.ts +910 -412
- package/dist/admin/App.d.ts.map +1 -1
- package/dist/admin/App.js +4 -0
- package/dist/admin/App.js.map +1 -1
- package/dist/admin/apps/early-access.d.ts +148 -0
- package/dist/admin/apps/early-access.d.ts.map +1 -0
- package/dist/admin/apps/early-access.js +133 -0
- package/dist/admin/apps/early-access.js.map +1 -0
- package/dist/admin/apps/verified-tokens.d.ts +526 -1
- package/dist/admin/apps/verified-tokens.d.ts.map +1 -1
- package/dist/admin/apps/verified-tokens.js +214 -1
- package/dist/admin/apps/verified-tokens.js.map +1 -1
- package/dist/admin/ui.generated.d.ts +1 -1
- package/dist/admin/ui.generated.d.ts.map +1 -1
- package/dist/admin/ui.generated.js +45 -33
- package/dist/admin/ui.generated.js.map +1 -1
- package/dist/apps/data/App.d.ts +3733 -2428
- package/dist/apps/data/App.d.ts.map +1 -1
- package/dist/apps/data/App.js +11 -6
- package/dist/apps/data/App.js.map +1 -1
- package/dist/apps/data/FundingQuoteProviders.d.ts +34 -1
- package/dist/apps/data/FundingQuoteProviders.d.ts.map +1 -1
- package/dist/apps/data/FundingQuoteProviders.js +193 -2
- package/dist/apps/data/FundingQuoteProviders.js.map +1 -1
- package/dist/apps/data/FxOracle.d.ts +71 -0
- package/dist/apps/data/FxOracle.d.ts.map +1 -0
- package/dist/apps/data/FxOracle.js +97 -0
- package/dist/apps/data/FxOracle.js.map +1 -0
- package/dist/apps/data/index.d.ts +1 -0
- package/dist/apps/data/index.d.ts.map +1 -1
- package/dist/apps/data/index.js +1 -0
- package/dist/apps/data/index.js.map +1 -1
- package/dist/apps/data/routes/activities.d.ts +3575 -1358
- package/dist/apps/data/routes/activities.d.ts.map +1 -1
- package/dist/apps/data/routes/activities.js +230 -88
- package/dist/apps/data/routes/activities.js.map +1 -1
- package/dist/apps/data/routes/addresses.d.ts +872 -251
- package/dist/apps/data/routes/addresses.d.ts.map +1 -1
- package/dist/apps/data/routes/addresses.js +11 -9
- package/dist/apps/data/routes/addresses.js.map +1 -1
- package/dist/apps/data/routes/balances.d.ts +108 -57
- package/dist/apps/data/routes/balances.d.ts.map +1 -1
- package/dist/apps/data/routes/balances.js +88 -45
- package/dist/apps/data/routes/balances.js.map +1 -1
- package/dist/apps/data/routes/coingecko.d.ts +169 -169
- package/dist/apps/data/routes/exchanges.d.ts +952 -201
- package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
- package/dist/apps/data/routes/exchanges.js +518 -76
- package/dist/apps/data/routes/exchanges.js.map +1 -1
- package/dist/apps/data/routes/fee-amm.d.ts +24 -24
- package/dist/apps/data/routes/funding.d.ts +8 -2
- package/dist/apps/data/routes/funding.d.ts.map +1 -1
- package/dist/apps/data/routes/funding.js +32 -6
- package/dist/apps/data/routes/funding.js.map +1 -1
- package/dist/apps/data/routes/indexer.d.ts +5 -5
- package/dist/apps/data/routes/receipts.d.ts +392 -315
- package/dist/apps/data/routes/receipts.d.ts.map +1 -1
- package/dist/apps/data/routes/receipts.js +152 -77
- package/dist/apps/data/routes/receipts.js.map +1 -1
- package/dist/apps/data/routes/rpc.d.ts +31 -31
- package/dist/apps/data/routes/tokens.d.ts +166 -173
- package/dist/apps/data/routes/tokens.d.ts.map +1 -1
- package/dist/apps/data/routes/tokens.js +14 -12
- package/dist/apps/data/routes/tokens.js.map +1 -1
- package/dist/apps/data/routes/transactions.d.ts +277 -536
- package/dist/apps/data/routes/transactions.d.ts.map +1 -1
- package/dist/apps/data/routes/transactions.js +96 -77
- package/dist/apps/data/routes/transactions.js.map +1 -1
- package/dist/apps/data/routes/transfers.d.ts +82 -17
- package/dist/apps/data/routes/transfers.d.ts.map +1 -1
- package/dist/apps/data/routes/transfers.js +70 -13
- package/dist/apps/data/routes/transfers.js.map +1 -1
- package/dist/apps/data/routes/valuation.d.ts +307 -0
- package/dist/apps/data/routes/valuation.d.ts.map +1 -0
- package/dist/apps/data/routes/valuation.js +292 -0
- package/dist/apps/data/routes/valuation.js.map +1 -0
- package/dist/apps/data/routes/verified-tokens.d.ts.map +1 -1
- package/dist/apps/data/routes/verified-tokens.js +7 -5
- package/dist/apps/data/routes/verified-tokens.js.map +1 -1
- package/dist/apps/data/routes/webhooks.d.ts +459 -479
- package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
- package/dist/apps/data/routes/webhooks.js +124 -25
- package/dist/apps/data/routes/webhooks.js.map +1 -1
- package/dist/apps/index.d.ts +1 -1
- package/dist/apps/index.d.ts.map +1 -1
- package/dist/apps/index.js +1 -1
- package/dist/apps/index.js.map +1 -1
- package/dist/apps/management/App.d.ts +8606 -1681
- package/dist/apps/management/App.d.ts.map +1 -1
- package/dist/apps/management/App.js +12 -1
- package/dist/apps/management/App.js.map +1 -1
- package/dist/apps/management/routes/api-keys.d.ts +23 -0
- package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
- package/dist/apps/management/routes/api-keys.js +5 -3
- package/dist/apps/management/routes/api-keys.js.map +1 -1
- package/dist/apps/management/routes/billing.d.ts +88 -48
- package/dist/apps/management/routes/billing.d.ts.map +1 -1
- package/dist/apps/management/routes/billing.js +10 -2
- package/dist/apps/management/routes/billing.js.map +1 -1
- package/dist/apps/management/routes/faucet.d.ts +218 -0
- package/dist/apps/management/routes/faucet.d.ts.map +1 -0
- package/dist/apps/management/routes/faucet.js +139 -0
- package/dist/apps/management/routes/faucet.js.map +1 -0
- package/dist/apps/management/routes/invitations.d.ts +121 -121
- package/dist/apps/management/routes/invitations.d.ts.map +1 -1
- package/dist/apps/management/routes/invitations.js +3 -0
- package/dist/apps/management/routes/invitations.js.map +1 -1
- package/dist/apps/management/routes/invite-links.d.ts +49 -20
- package/dist/apps/management/routes/invite-links.d.ts.map +1 -1
- package/dist/apps/management/routes/invite-links.js +26 -1
- package/dist/apps/management/routes/invite-links.js.map +1 -1
- package/dist/apps/management/routes/me.d.ts +2 -0
- package/dist/apps/management/routes/me.d.ts.map +1 -1
- package/dist/apps/management/routes/me.js +4 -0
- package/dist/apps/management/routes/me.js.map +1 -1
- package/dist/apps/management/routes/members.d.ts +49 -49
- package/dist/apps/management/routes/orgs.d.ts +91 -91
- package/dist/apps/management/routes/projects.d.ts +44 -44
- package/dist/apps/management/routes/usage.d.ts +35 -32
- package/dist/apps/management/routes/usage.d.ts.map +1 -1
- package/dist/apps/management/routes/usage.js +4 -0
- package/dist/apps/management/routes/usage.js.map +1 -1
- package/dist/apps/management/routes/verified-token-requests.d.ts +697 -0
- package/dist/apps/management/routes/verified-token-requests.d.ts.map +1 -0
- package/dist/apps/management/routes/verified-token-requests.js +271 -0
- package/dist/apps/management/routes/verified-token-requests.js.map +1 -0
- package/dist/apps/management/routes/webhooks.d.ts +6977 -0
- package/dist/apps/management/routes/webhooks.d.ts.map +1 -0
- package/dist/apps/management/routes/webhooks.js +573 -0
- package/dist/apps/management/routes/webhooks.js.map +1 -0
- package/dist/db/Db.d.ts +4 -0
- package/dist/db/Db.d.ts.map +1 -1
- package/dist/db/Db.js +83 -0
- package/dist/db/Db.js.map +1 -1
- package/dist/db/Schema.d.ts +41 -0
- package/dist/db/Schema.d.ts.map +1 -1
- package/dist/db/Schema.js +45 -0
- package/dist/db/Schema.js.map +1 -1
- package/dist/db/tables/earlyAccess.d.ts +50 -0
- package/dist/db/tables/earlyAccess.d.ts.map +1 -0
- package/dist/db/tables/earlyAccess.js +63 -0
- package/dist/db/tables/earlyAccess.js.map +1 -0
- package/dist/db/tables/invitations.d.ts +12 -1
- package/dist/db/tables/invitations.d.ts.map +1 -1
- package/dist/db/tables/invitations.js +23 -0
- package/dist/db/tables/invitations.js.map +1 -1
- package/dist/db/tables/inviteLinks.d.ts +10 -2
- package/dist/db/tables/inviteLinks.d.ts.map +1 -1
- package/dist/db/tables/inviteLinks.js +10 -1
- package/dist/db/tables/inviteLinks.js.map +1 -1
- package/dist/db/tables/sponsoredTransactions.d.ts +2 -0
- package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
- package/dist/db/tables/sponsoredTransactions.js +2 -0
- package/dist/db/tables/sponsoredTransactions.js.map +1 -1
- package/dist/db/tables/verifiedTokenRequests.d.ts +94 -0
- package/dist/db/tables/verifiedTokenRequests.d.ts.map +1 -0
- package/dist/db/tables/verifiedTokenRequests.js +120 -0
- package/dist/db/tables/verifiedTokenRequests.js.map +1 -0
- package/dist/db/tables/webhookSubscriptions.d.ts +14 -0
- package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
- package/dist/db/tables/webhookSubscriptions.js +16 -0
- package/dist/db/tables/webhookSubscriptions.js.map +1 -1
- package/dist/internal/Auth.d.ts +43 -2
- package/dist/internal/Auth.d.ts.map +1 -1
- package/dist/internal/Auth.js +60 -45
- package/dist/internal/Auth.js.map +1 -1
- package/dist/internal/FundingQuotes.d.ts +69 -15
- package/dist/internal/FundingQuotes.d.ts.map +1 -1
- package/dist/internal/FundingQuotes.js +74 -25
- package/dist/internal/FundingQuotes.js.map +1 -1
- package/dist/internal/Log.d.ts +19 -1
- package/dist/internal/Log.d.ts.map +1 -1
- package/dist/internal/Log.js +2 -0
- package/dist/internal/Log.js.map +1 -1
- package/dist/internal/MetricSink.d.ts.map +1 -1
- package/dist/internal/MetricSink.js +9 -0
- package/dist/internal/MetricSink.js.map +1 -1
- package/dist/internal/OpenApi.d.ts +2 -2
- package/dist/internal/OpenApi.d.ts.map +1 -1
- package/dist/internal/OpenApi.js +3 -0
- package/dist/internal/OpenApi.js.map +1 -1
- package/dist/internal/Schema.d.ts +14 -5
- package/dist/internal/Schema.d.ts.map +1 -1
- package/dist/internal/Schema.js +23 -5
- package/dist/internal/Schema.js.map +1 -1
- package/dist/internal/Value.d.ts +18 -0
- package/dist/internal/Value.d.ts.map +1 -1
- package/dist/internal/Value.js +11 -1
- package/dist/internal/Value.js.map +1 -1
- package/dist/internal/VerifiedTokens.d.ts.map +1 -1
- package/dist/internal/VerifiedTokens.js +10 -1
- package/dist/internal/VerifiedTokens.js.map +1 -1
- package/dist/internal/Viem.d.ts +1 -1
- package/dist/internal/Webhooks.d.ts +24 -3
- package/dist/internal/Webhooks.d.ts.map +1 -1
- package/dist/internal/Webhooks.js +34 -8
- package/dist/internal/Webhooks.js.map +1 -1
- package/package.json +1 -1
- package/src/App.ts +9 -1
- package/src/Client.test-d.ts +638 -6
- package/src/admin/App.ts +4 -0
- package/src/admin/apps/early-access.test.ts +125 -0
- package/src/admin/apps/early-access.ts +175 -0
- package/src/admin/apps/verified-tokens.test.ts +201 -0
- package/src/admin/apps/verified-tokens.ts +532 -286
- package/src/admin/ui/plugin.ts +2 -1
- package/src/admin/ui/src/lib/early-access.ts +63 -0
- package/src/admin/ui/src/lib/verified-tokens.ts +79 -0
- package/src/admin/ui/src/routeTree.gen.ts +33 -2
- package/src/admin/ui/src/routes/__root.tsx +2 -1
- package/src/admin/ui/src/routes/early-access.tsx +157 -0
- package/src/admin/ui/src/routes/verified-tokens.tsx +230 -19
- package/src/admin/ui.generated.ts +48 -33
- package/src/apps/data/App.ts +22 -14
- package/src/apps/data/FundingQuoteProviders.test.ts +298 -0
- package/src/apps/data/FundingQuoteProviders.ts +257 -4
- package/src/apps/data/FxOracle.test.ts +118 -0
- package/src/apps/data/FxOracle.ts +153 -0
- package/src/apps/data/index.ts +1 -0
- package/src/apps/data/routes/activities.test.ts +173 -3
- package/src/apps/data/routes/activities.ts +403 -132
- package/src/apps/data/routes/addresses.ts +19 -9
- package/src/apps/data/routes/balances.test.ts +144 -11
- package/src/apps/data/routes/balances.ts +140 -51
- package/src/apps/data/routes/exchanges.test.ts +540 -9
- package/src/apps/data/routes/exchanges.ts +690 -103
- package/src/apps/data/routes/funding.test.ts +84 -0
- package/src/apps/data/routes/funding.ts +38 -6
- package/src/apps/data/routes/receipts.test.ts +125 -23
- package/src/apps/data/routes/receipts.ts +205 -100
- package/src/apps/data/routes/tokens.test.ts +43 -0
- package/src/apps/data/routes/tokens.ts +27 -12
- package/src/apps/data/routes/transactions.test.ts +72 -19
- package/src/apps/data/routes/transactions.ts +162 -92
- package/src/apps/data/routes/transfers.test.ts +146 -4
- package/src/apps/data/routes/transfers.ts +91 -13
- package/src/apps/data/routes/valuation.test.ts +422 -0
- package/src/apps/data/routes/valuation.ts +423 -0
- package/src/apps/data/routes/verified-tokens.ts +14 -2
- package/src/apps/data/routes/webhooks.test.ts +56 -8
- package/src/apps/data/routes/webhooks.ts +144 -27
- package/src/apps/index.ts +1 -1
- package/src/apps/management/App.ts +13 -0
- package/src/apps/management/routes/api-keys.test.ts +87 -0
- package/src/apps/management/routes/api-keys.ts +4 -3
- package/src/apps/management/routes/billing.test.ts +112 -1
- package/src/apps/management/routes/billing.ts +7 -2
- package/src/apps/management/routes/faucet.test.ts +79 -0
- package/src/apps/management/routes/faucet.ts +185 -0
- package/src/apps/management/routes/invitations.test.ts +172 -0
- package/src/apps/management/routes/invitations.ts +3 -0
- package/src/apps/management/routes/invite-links.test.ts +117 -0
- package/src/apps/management/routes/invite-links.ts +43 -1
- package/src/apps/management/routes/me.test.ts +140 -88
- package/src/apps/management/routes/me.ts +6 -0
- package/src/apps/management/routes/usage.test.ts +6 -0
- package/src/apps/management/routes/usage.ts +7 -0
- package/src/apps/management/routes/verified-token-requests.test.ts +377 -0
- package/src/apps/management/routes/verified-token-requests.ts +397 -0
- package/src/apps/management/routes/webhooks.test.ts +426 -0
- package/src/apps/management/routes/webhooks.ts +672 -0
- package/src/db/Db.test.ts +19 -0
- package/src/db/Db.ts +95 -0
- package/src/db/Schema.ts +53 -0
- package/src/db/tables/earlyAccess.ts +86 -0
- package/src/db/tables/invitations.ts +26 -1
- package/src/db/tables/inviteLinks.ts +22 -3
- package/src/db/tables/sponsoredTransactions.ts +4 -0
- package/src/db/tables/verifiedTokenRequests.test.ts +200 -0
- package/src/db/tables/verifiedTokenRequests.ts +182 -0
- package/src/db/tables/webhookSubscriptions.ts +31 -0
- package/src/internal/Auth.ts +73 -45
- package/src/internal/FundingQuotes.test.ts +143 -1
- package/src/internal/FundingQuotes.ts +95 -28
- package/src/internal/Log.test-d.ts +21 -0
- package/src/internal/Log.test.ts +50 -0
- package/src/internal/Log.ts +24 -1
- package/src/internal/MetricSink.test.ts +160 -0
- package/src/internal/MetricSink.ts +10 -0
- package/src/internal/OpenApi.ts +3 -0
- package/src/internal/Schema.ts +50 -5
- package/src/internal/Value.test.ts +20 -0
- package/src/internal/Value.ts +24 -1
- package/src/internal/VerifiedTokens.ts +9 -1
- package/src/internal/Webhooks.test.ts +140 -0
- package/src/internal/Webhooks.ts +53 -9
|
@@ -93,6 +93,7 @@ describe('GET /funding/quotes', () => {
|
|
|
93
93
|
})
|
|
94
94
|
|
|
95
95
|
test('returns an empty list when the provider reports no quote', async () => {
|
|
96
|
+
const entries: Log.Entry[] = []
|
|
96
97
|
const app = TestApp.create({
|
|
97
98
|
funding: {
|
|
98
99
|
adapters: {
|
|
@@ -103,11 +104,22 @@ describe('GET /funding/quotes', () => {
|
|
|
103
104
|
},
|
|
104
105
|
},
|
|
105
106
|
},
|
|
107
|
+
logger: (entry) => {
|
|
108
|
+
entries.push(entry)
|
|
109
|
+
},
|
|
106
110
|
})
|
|
107
111
|
const response = await app.request(quoteUrl(), { headers: TestApp.auth.headers })
|
|
108
112
|
expect(response.status).toBe(200)
|
|
109
113
|
const body = await TestApp.json(response, Funding.schema.quoteFunding.Response)
|
|
110
114
|
expect(body.data).toEqual([])
|
|
115
|
+
expect(entries[0]?.fundingProviderAttempts).toEqual([
|
|
116
|
+
{
|
|
117
|
+
durationMs: expect.any(Number),
|
|
118
|
+
id: 'relay',
|
|
119
|
+
operation: 'quote/v2',
|
|
120
|
+
outcome: 'unavailable',
|
|
121
|
+
},
|
|
122
|
+
])
|
|
111
123
|
})
|
|
112
124
|
|
|
113
125
|
test('returns 502 when every matching provider fails', async () => {
|
|
@@ -156,6 +168,15 @@ describe('GET /funding/quotes', () => {
|
|
|
156
168
|
id: 'across',
|
|
157
169
|
operation: 'swap/approval',
|
|
158
170
|
})
|
|
171
|
+
expect(entries[0]?.fundingProviderAttempts).toEqual([
|
|
172
|
+
{
|
|
173
|
+
durationMs: expect.any(Number),
|
|
174
|
+
failure: 'timeout',
|
|
175
|
+
id: 'across',
|
|
176
|
+
operation: 'swap/approval',
|
|
177
|
+
outcome: 'failed',
|
|
178
|
+
},
|
|
179
|
+
])
|
|
159
180
|
})
|
|
160
181
|
|
|
161
182
|
test('logs every failure when multiple providers fail', async () => {
|
|
@@ -192,6 +213,62 @@ describe('GET /funding/quotes', () => {
|
|
|
192
213
|
{ failure: 'network', id: 'across', operation: 'swap/approval' },
|
|
193
214
|
{ failure: 'unknown', id: 'relay', operation: 'quote/v2' },
|
|
194
215
|
])
|
|
216
|
+
expect(entries[0]?.fundingProviderAttempts).toEqual([
|
|
217
|
+
{
|
|
218
|
+
durationMs: expect.any(Number),
|
|
219
|
+
failure: 'network',
|
|
220
|
+
id: 'across',
|
|
221
|
+
operation: 'swap/approval',
|
|
222
|
+
outcome: 'failed',
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
durationMs: expect.any(Number),
|
|
226
|
+
failure: 'unknown',
|
|
227
|
+
id: 'relay',
|
|
228
|
+
operation: 'quote/v2',
|
|
229
|
+
outcome: 'failed',
|
|
230
|
+
},
|
|
231
|
+
])
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
test('logs failed providers when another provider returns a quote', async () => {
|
|
235
|
+
const entries: Log.Entry[] = []
|
|
236
|
+
const app = TestApp.create({
|
|
237
|
+
funding: {
|
|
238
|
+
adapters: {
|
|
239
|
+
across: {
|
|
240
|
+
async probeQuote() {
|
|
241
|
+
throw new TypeError(`wallet ${'0xaa'.repeat(20)} could not reach secret-provider`)
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
relay: relayAdapter(),
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
logger: (entry) => {
|
|
248
|
+
entries.push(entry)
|
|
249
|
+
},
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
const response = await app.request(quoteUrl(), { headers: TestApp.auth.headers })
|
|
253
|
+
|
|
254
|
+
expect(response.status).toBe(200)
|
|
255
|
+
expect(entries[0]?.fundingProviderAttempts).toEqual([
|
|
256
|
+
{
|
|
257
|
+
durationMs: expect.any(Number),
|
|
258
|
+
failure: 'network',
|
|
259
|
+
id: 'across',
|
|
260
|
+
operation: 'swap/approval',
|
|
261
|
+
outcome: 'failed',
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
durationMs: expect.any(Number),
|
|
265
|
+
id: 'relay',
|
|
266
|
+
operation: 'quote/v2',
|
|
267
|
+
outcome: 'available',
|
|
268
|
+
},
|
|
269
|
+
])
|
|
270
|
+
expect(JSON.stringify(entries[0])).not.toContain('secret-provider')
|
|
271
|
+
expect(JSON.stringify(entries[0])).not.toContain('0xaa')
|
|
195
272
|
})
|
|
196
273
|
|
|
197
274
|
test('rejects successful provider results without output amounts', async () => {
|
|
@@ -306,6 +383,13 @@ describe('GET /funding/providers', () => {
|
|
|
306
383
|
requiresApiKey: true,
|
|
307
384
|
status: 'unconfigured',
|
|
308
385
|
},
|
|
386
|
+
{
|
|
387
|
+
id: 'symbiosis',
|
|
388
|
+
kind: 'crossChainDex',
|
|
389
|
+
name: 'Symbiosis',
|
|
390
|
+
requiresApiKey: false,
|
|
391
|
+
status: 'unconfigured',
|
|
392
|
+
},
|
|
309
393
|
])
|
|
310
394
|
})
|
|
311
395
|
|
|
@@ -5,6 +5,7 @@ import type * as App from '../../../App.js'
|
|
|
5
5
|
import * as Auth from '../../../internal/Auth.js'
|
|
6
6
|
import * as Cache from '../../../internal/Cache.js'
|
|
7
7
|
import * as FundingQuotes from '../../../internal/FundingQuotes.js'
|
|
8
|
+
import type * as Log from '../../../internal/Log.js'
|
|
8
9
|
import * as OpenApi from '../../../internal/OpenApi.js'
|
|
9
10
|
import * as Response from '../../../internal/Response.js'
|
|
10
11
|
import * as Schema from '../../../internal/Schema.js'
|
|
@@ -118,7 +119,7 @@ export namespace schema {
|
|
|
118
119
|
export const ProviderRef = Schema.describe(
|
|
119
120
|
z.object({
|
|
120
121
|
id: z
|
|
121
|
-
.enum(['across', 'relay', 'rhino', 'squid'])
|
|
122
|
+
.enum(['across', 'relay', 'rhino', 'squid', 'symbiosis'])
|
|
122
123
|
.check(z.describe('Stable provider id.'), z.meta({ examples: ['relay'] })),
|
|
123
124
|
kind: z
|
|
124
125
|
.string()
|
|
@@ -186,7 +187,9 @@ export namespace schema {
|
|
|
186
187
|
minimumOutputAmount: z
|
|
187
188
|
.optional(Schema.DecimalString)
|
|
188
189
|
.check(
|
|
189
|
-
z.describe(
|
|
190
|
+
z.describe(
|
|
191
|
+
'Provider-derived minimum destination amount in base units. Symbiosis and Squid quotes use a fixed 1% slippage tolerance.',
|
|
192
|
+
),
|
|
190
193
|
z.meta({ examples: ['988000'] }),
|
|
191
194
|
),
|
|
192
195
|
outputAmount: z
|
|
@@ -237,7 +240,7 @@ export namespace schema {
|
|
|
237
240
|
export const Provider = Schema.describe(
|
|
238
241
|
z.object({
|
|
239
242
|
id: z
|
|
240
|
-
.enum(['across', 'relay', 'rhino', 'squid'])
|
|
243
|
+
.enum(['across', 'relay', 'rhino', 'squid', 'symbiosis'])
|
|
241
244
|
.check(z.describe('Stable provider id.'), z.meta({ examples: ['relay'] })),
|
|
242
245
|
kind: z
|
|
243
246
|
.string()
|
|
@@ -285,10 +288,10 @@ export namespace schema {
|
|
|
285
288
|
z.meta({ examples: ['USDC.e'] }),
|
|
286
289
|
),
|
|
287
290
|
provider: z
|
|
288
|
-
.optional(z.enum(['across', 'relay', 'rhino', 'squid']))
|
|
291
|
+
.optional(z.enum(['across', 'relay', 'rhino', 'squid', 'symbiosis']))
|
|
289
292
|
.check(
|
|
290
293
|
z.describe(
|
|
291
|
-
'Only request a quote from this provider. Supported ids are `across`, `relay`, `rhino`, and `
|
|
294
|
+
'Only request a quote from this provider. Supported ids are `across`, `relay`, `rhino`, `squid`, and `symbiosis`; omit it to query every configured provider.',
|
|
292
295
|
),
|
|
293
296
|
z.meta({ examples: ['relay'] }),
|
|
294
297
|
),
|
|
@@ -416,7 +419,7 @@ export function funding(options: funding.Options = {}) {
|
|
|
416
419
|
}),
|
|
417
420
|
OpenApi.describeRoute({
|
|
418
421
|
description:
|
|
419
|
-
'Returns live quotes for funding Tempo with a stablecoin. Omit `provider` to query all configured providers. This endpoint does not execute a transfer.',
|
|
422
|
+
'Returns live quotes for funding Tempo with a stablecoin. Omit `provider` to query all configured providers. Provider minimums can use provider-specific slippage policies; Symbiosis and Squid use 1%. This endpoint does not execute a transfer.',
|
|
420
423
|
operationId: 'quoteFunding',
|
|
421
424
|
responses: OpenApi.responses({
|
|
422
425
|
errors: {
|
|
@@ -445,6 +448,7 @@ export function funding(options: funding.Options = {}) {
|
|
|
445
448
|
})
|
|
446
449
|
|
|
447
450
|
const query = c.req.valid('query')
|
|
451
|
+
const attempts: FundingQuotes.ProviderAttempt[] = []
|
|
448
452
|
try {
|
|
449
453
|
c.header('Cache-Control', 'no-store')
|
|
450
454
|
return c.json(
|
|
@@ -454,6 +458,7 @@ export function funding(options: funding.Options = {}) {
|
|
|
454
458
|
adapterTimeoutMs: options.adapterTimeoutMs,
|
|
455
459
|
cache: { bypass: cacheBypass(c.req.raw) },
|
|
456
460
|
destinationToken: query.destinationToken,
|
|
461
|
+
onAttempt: (attempt) => attempts.push(attempt),
|
|
457
462
|
provider: query.provider,
|
|
458
463
|
sourceAmount: query.sourceAmount,
|
|
459
464
|
sourceAmountUnits: query.sourceAmountUnits,
|
|
@@ -478,6 +483,9 @@ export function funding(options: funding.Options = {}) {
|
|
|
478
483
|
})
|
|
479
484
|
}
|
|
480
485
|
throw cause
|
|
486
|
+
} finally {
|
|
487
|
+
if (attempts.length > 0)
|
|
488
|
+
c.set('fundingProviderAttempts', attempts.map(fundingProviderAttempt))
|
|
481
489
|
}
|
|
482
490
|
},
|
|
483
491
|
)
|
|
@@ -557,6 +565,30 @@ export declare namespace funding {
|
|
|
557
565
|
}
|
|
558
566
|
}
|
|
559
567
|
|
|
568
|
+
function fundingProviderAttempt(
|
|
569
|
+
attempt: FundingQuotes.ProviderAttempt,
|
|
570
|
+
): Log.FundingProviderAttempt {
|
|
571
|
+
const operation = FundingQuoteProviders.providerOperation(attempt.provider)
|
|
572
|
+
if (attempt.outcome !== 'failed')
|
|
573
|
+
return {
|
|
574
|
+
durationMs: attempt.durationMs,
|
|
575
|
+
id: attempt.provider,
|
|
576
|
+
operation,
|
|
577
|
+
outcome: attempt.outcome,
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
return {
|
|
581
|
+
durationMs: attempt.durationMs,
|
|
582
|
+
failure: FundingQuoteProviders.providerFailure({
|
|
583
|
+
cause: attempt.cause,
|
|
584
|
+
provider: attempt.provider,
|
|
585
|
+
}).failure,
|
|
586
|
+
id: attempt.provider,
|
|
587
|
+
operation,
|
|
588
|
+
outcome: attempt.outcome,
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
560
592
|
// Maps caller-input errors to a specific 400 message; anything else rethrows.
|
|
561
593
|
function requestErrorMessage(cause: unknown) {
|
|
562
594
|
if (cause instanceof FundingQuotes.InvalidAmountError) return 'Invalid `sourceAmount`.'
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Schema } from 'tapimo'
|
|
2
|
-
import {
|
|
2
|
+
import { FxOracle } from 'tapimo/apps'
|
|
3
|
+
import { Hex, Value as core_Value } from 'ox'
|
|
3
4
|
import { zeroHash } from 'viem'
|
|
4
5
|
|
|
5
6
|
import * as TestApp from '../../../../test/App.js'
|
|
@@ -7,6 +8,12 @@ import * as Runtime from '../../../../test/runtime.js'
|
|
|
7
8
|
import * as Viem from '../../../../test/Viem.js'
|
|
8
9
|
import * as Receipts from './receipts.js'
|
|
9
10
|
|
|
11
|
+
// Deterministic EUR-based rate set so conversion math is exact in assertions.
|
|
12
|
+
const fixed = FxOracle.from({
|
|
13
|
+
name: 'fixed',
|
|
14
|
+
rates: async () => ({ asOf: '2026-01-01', base: 'EUR', rates: { AUD: '1.6', USD: '1.0' } }),
|
|
15
|
+
})
|
|
16
|
+
|
|
10
17
|
/** The decoded `type` names a humanized receipt may report. */
|
|
11
18
|
const transactionTypes = ['legacy', 'eip2930', 'eip1559', 'eip4844', 'eip7702', 'tempo', 'unknown']
|
|
12
19
|
|
|
@@ -40,28 +47,44 @@ describe('GET /transactions/:transactionHash/receipt', () => {
|
|
|
40
47
|
expect(typeof body.gasUsed).toBe('number')
|
|
41
48
|
expect(Array.isArray(body.logs)).toBe(true)
|
|
42
49
|
// `feeAmount` is the fee charged to the fee payer, derived as
|
|
43
|
-
// ceil(gasUsed * effectiveGasPrice / 1e12), in
|
|
44
|
-
expect(body.feeAmount).toMatch(/^\d+$/)
|
|
50
|
+
// ceil(gasUsed * effectiveGasPrice / 1e12), in USD base units.
|
|
45
51
|
const expectedFee =
|
|
46
52
|
(BigInt(body.gasUsed) * BigInt(body.effectiveGasPrice) + 10n ** 12n - 1n) / 10n ** 12n
|
|
47
|
-
expect(body.feeAmount).toBe(expectedFee.toString())
|
|
48
|
-
|
|
49
|
-
expect(body.
|
|
53
|
+
expect(body.feeAmount.baseUnits).toBe(expectedFee.toString())
|
|
54
|
+
expect(body.feeAmount.currency).toBe('USD')
|
|
55
|
+
expect(body.feeAmount.decimals).toBe(6)
|
|
56
|
+
expect(body.feeAmount.formatted).toMatch(/^\d+(\.\d+)?$/)
|
|
57
|
+
// Core fee-token metadata is present by default while the raw address stays
|
|
58
|
+
// under `meta.rpc`. Curated fields remain opt-in.
|
|
59
|
+
if (body.meta.rpc.feeToken) {
|
|
60
|
+
expect(body.feeToken?.address).toBe(body.meta.rpc.feeToken)
|
|
61
|
+
expect(typeof body.feeToken?.currency).toBe('string')
|
|
62
|
+
expect(typeof body.feeToken?.decimals).toBe('number')
|
|
63
|
+
expect(typeof body.feeToken?.name).toBe('string')
|
|
64
|
+
expect(typeof body.feeToken?.symbol).toBe('string')
|
|
65
|
+
expect(body.feeToken?.logoUri).toBeUndefined()
|
|
66
|
+
expect(body.feeToken?.verified).toBeUndefined()
|
|
67
|
+
} else expect(body.feeToken).toBeUndefined()
|
|
68
|
+
expect(body.meta).not.toHaveProperty('feeToken')
|
|
50
69
|
// The verbatim JSON-RPC receipt is always available under `meta.rpc`, where
|
|
51
70
|
// `status` is the raw `0x1`/`0x0` flag and gas values stay hex-encoded.
|
|
52
71
|
expect(['0x0', '0x1']).toContain(body.meta.rpc.status)
|
|
53
72
|
expect(body.meta.rpc.gasUsed).toMatch(/^0x[0-9a-f]+$/)
|
|
54
73
|
|
|
55
|
-
//
|
|
74
|
+
// Curated fee-token fields are opt-in on the top-level reference.
|
|
56
75
|
const includedResponse = await client.v1.transactions[':transactionHash'].receipt.$get(
|
|
57
|
-
{
|
|
76
|
+
{
|
|
77
|
+
param: { transactionHash: transactionHash! },
|
|
78
|
+
query: { include: 'feeToken.logoUri,feeToken.verified' },
|
|
79
|
+
},
|
|
58
80
|
TestApp.auth,
|
|
59
81
|
)
|
|
60
82
|
const includedBody = await TestApp.json(includedResponse, Receipts.schema.getReceipt.Response)
|
|
61
83
|
expect(includedResponse.status).toBe(200)
|
|
62
|
-
if (includedBody.feeToken
|
|
63
|
-
expect(includedBody.
|
|
64
|
-
expect(typeof includedBody.
|
|
84
|
+
if (includedBody.feeToken) {
|
|
85
|
+
expect(includedBody.feeToken.address).toBe(includedBody.meta.rpc.feeToken)
|
|
86
|
+
expect(typeof includedBody.feeToken.verified).toBe('boolean')
|
|
87
|
+
if (includedBody.feeToken.logoUri) expect(typeof includedBody.feeToken.logoUri).toBe('string')
|
|
65
88
|
}
|
|
66
89
|
})
|
|
67
90
|
|
|
@@ -90,7 +113,7 @@ describe('GET /transactions/:transactionHash/receipt', () => {
|
|
|
90
113
|
})
|
|
91
114
|
|
|
92
115
|
describe('GET /transactions/receipts', () => {
|
|
93
|
-
test('returns a humanized receipt page
|
|
116
|
+
test('returns a humanized receipt page with fee-token references', async () => {
|
|
94
117
|
const client = TestApp.client()
|
|
95
118
|
const response = await client.v1.transactions.receipts.$get(
|
|
96
119
|
{ query: { limit: '5' } },
|
|
@@ -105,6 +128,17 @@ describe('GET /transactions/receipts', () => {
|
|
|
105
128
|
expect(body.nextCursor === null || typeof body.nextCursor === 'string').toBe(true)
|
|
106
129
|
expect(body.data.length).toBeLessThanOrEqual(5)
|
|
107
130
|
|
|
131
|
+
if (body.nextCursor) {
|
|
132
|
+
const cursorResponse = await client.v1.transactions.receipts.$get(
|
|
133
|
+
{ query: { cursor: body.nextCursor, limit: '5' } },
|
|
134
|
+
TestApp.auth,
|
|
135
|
+
)
|
|
136
|
+
expect(cursorResponse.status).toBe(200)
|
|
137
|
+
expect(cursorResponse.headers.get('cache-control')).toMatchInlineSnapshot(
|
|
138
|
+
`"private, max-age=60, stale-while-revalidate=300"`,
|
|
139
|
+
)
|
|
140
|
+
}
|
|
141
|
+
|
|
108
142
|
if (body.data.length > 0) {
|
|
109
143
|
const [receipt] = body.data
|
|
110
144
|
// List rows reuse the detail endpoint's humanized shape: decoded
|
|
@@ -115,23 +149,35 @@ describe('GET /transactions/receipts', () => {
|
|
|
115
149
|
expect(['success', 'reverted']).toContain(receipt!.status)
|
|
116
150
|
expect(transactionTypes).toContain(receipt!.type)
|
|
117
151
|
expect(typeof receipt!.gasUsed).toBe('number')
|
|
118
|
-
expect(receipt!.feeAmount).toMatch(/^\d+$/)
|
|
152
|
+
expect(receipt!.feeAmount.baseUnits).toMatch(/^\d+$/)
|
|
153
|
+
expect(receipt!.feeAmount.currency).toBe('USD')
|
|
154
|
+
expect(receipt!.feeAmount.decimals).toBe(6)
|
|
155
|
+
expect(receipt!.feeAmount.formatted).toMatch(/^\d+(\.\d+)?$/)
|
|
119
156
|
expect(receipt!.meta.rpc.status).toMatch(/^0x[0-9a-f]+$/)
|
|
120
|
-
|
|
121
|
-
|
|
157
|
+
if (receipt!.meta.rpc.feeToken) {
|
|
158
|
+
expect(receipt!.feeToken?.address).toBe(receipt!.meta.rpc.feeToken)
|
|
159
|
+
expect(typeof receipt!.feeToken?.currency).toBe('string')
|
|
160
|
+
expect(typeof receipt!.feeToken?.decimals).toBe('number')
|
|
161
|
+
expect(typeof receipt!.feeToken?.name).toBe('string')
|
|
162
|
+
expect(typeof receipt!.feeToken?.symbol).toBe('string')
|
|
163
|
+
expect(receipt!.feeToken?.logoUri).toBeUndefined()
|
|
164
|
+
expect(receipt!.feeToken?.verified).toBeUndefined()
|
|
165
|
+
} else expect(receipt!.feeToken).toBeUndefined()
|
|
166
|
+
expect(receipt!.meta).not.toHaveProperty('feeToken')
|
|
122
167
|
}
|
|
123
168
|
|
|
124
169
|
const includedResponse = await client.v1.transactions.receipts.$get(
|
|
125
|
-
{ query: { limit: '5', include: 'feeToken' } },
|
|
170
|
+
{ query: { limit: '5', include: 'feeToken.logoUri,feeToken.verified' } },
|
|
126
171
|
TestApp.auth,
|
|
127
172
|
)
|
|
128
173
|
const includedBody = await TestApp.json(includedResponse, Receipts.schema.getReceipts.Response)
|
|
129
174
|
expect(includedResponse.status).toBe(200)
|
|
130
|
-
const withFeeToken = includedBody.data.find((receipt) => receipt.
|
|
175
|
+
const withFeeToken = includedBody.data.find((receipt) => receipt.feeToken)
|
|
131
176
|
if (withFeeToken) {
|
|
132
|
-
|
|
133
|
-
expect(withFeeToken.
|
|
134
|
-
|
|
177
|
+
expect(withFeeToken.feeToken!.address).toBe(withFeeToken.meta.rpc.feeToken)
|
|
178
|
+
expect(typeof withFeeToken.feeToken!.verified).toBe('boolean')
|
|
179
|
+
if (withFeeToken.feeToken!.logoUri)
|
|
180
|
+
expect(typeof withFeeToken.feeToken!.logoUri).toBe('string')
|
|
135
181
|
}
|
|
136
182
|
})
|
|
137
183
|
|
|
@@ -149,10 +195,39 @@ describe('GET /transactions/receipts', () => {
|
|
|
149
195
|
expect(body.error.code).toBe('query_invalid')
|
|
150
196
|
})
|
|
151
197
|
|
|
198
|
+
test('values the fee in a requested denomination', async () => {
|
|
199
|
+
expect(transactionHash).toBeDefined()
|
|
200
|
+
const client = TestApp.client({ fx: { oracle: fixed } })
|
|
201
|
+
|
|
202
|
+
// Denominations are case-insensitive.
|
|
203
|
+
const response = await client.v1.transactions[':transactionHash'].receipt.$get(
|
|
204
|
+
{ param: { transactionHash: transactionHash! }, query: { denomination: 'aud' } },
|
|
205
|
+
TestApp.auth,
|
|
206
|
+
)
|
|
207
|
+
const body = await TestApp.json(response, Receipts.schema.getReceipt.Response)
|
|
208
|
+
|
|
209
|
+
expect(response.status).toBe(200)
|
|
210
|
+
expect(response.headers.get('cache-control')).toMatchInlineSnapshot(
|
|
211
|
+
`"private, max-age=60, stale-while-revalidate=300"`,
|
|
212
|
+
)
|
|
213
|
+
// USD -> AUD at the fixed 1.6 cross rate, floored to 6 dp.
|
|
214
|
+
expect(body.feeAmount.valuation).toEqual({
|
|
215
|
+
amount: core_Value.format((BigInt(body.feeAmount.baseUnits) * 16n) / 10n, 6),
|
|
216
|
+
currency: 'AUD',
|
|
217
|
+
})
|
|
218
|
+
expect(body.meta.pricing).toMatchInlineSnapshot(`
|
|
219
|
+
{
|
|
220
|
+
"asOf": "2026-01-01",
|
|
221
|
+
"basis": "nominal",
|
|
222
|
+
"source": "fixed",
|
|
223
|
+
}
|
|
224
|
+
`)
|
|
225
|
+
})
|
|
226
|
+
|
|
152
227
|
test('rejects the transactions-only include=receipt member', async () => {
|
|
153
228
|
// `receipt` is a transactions-list embed; the receipts endpoints own their
|
|
154
|
-
// own
|
|
155
|
-
//
|
|
229
|
+
// own include enum and must reject it. The typed client would refuse the
|
|
230
|
+
// literal, so exercise the validator via `app.request`.
|
|
156
231
|
const response = await TestApp.create().request('/v1/transactions/receipts?include=receipt', {
|
|
157
232
|
headers: { authorization: `Bearer ${TestApp.key.token}` },
|
|
158
233
|
})
|
|
@@ -161,6 +236,25 @@ describe('GET /transactions/receipts', () => {
|
|
|
161
236
|
expect(body.error.code).toBe('query_invalid')
|
|
162
237
|
})
|
|
163
238
|
|
|
239
|
+
test('rejects the legacy include=feeToken member', async () => {
|
|
240
|
+
const response = await TestApp.create().request('/v1/transactions/receipts?include=feeToken', {
|
|
241
|
+
headers: { authorization: `Bearer ${TestApp.key.token}` },
|
|
242
|
+
})
|
|
243
|
+
const body = await TestApp.json(response, Schema.ErrorResponse)
|
|
244
|
+
expect(response.status).toBe(400)
|
|
245
|
+
expect(body.error.code).toBe('query_invalid')
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
test('rejects generic token fields', async () => {
|
|
249
|
+
const response = await TestApp.create().request(
|
|
250
|
+
'/v1/transactions/receipts?include=token.logoUri',
|
|
251
|
+
{ headers: { authorization: `Bearer ${TestApp.key.token}` } },
|
|
252
|
+
)
|
|
253
|
+
const body = await TestApp.json(response, Schema.ErrorResponse)
|
|
254
|
+
expect(response.status).toBe(400)
|
|
255
|
+
expect(body.error.code).toBe('query_invalid')
|
|
256
|
+
})
|
|
257
|
+
|
|
164
258
|
test('narrows receipts by execution status', async () => {
|
|
165
259
|
const client = TestApp.client()
|
|
166
260
|
const response = await client.v1.transactions.receipts.$get(
|
|
@@ -193,7 +287,15 @@ describe('GET /transactions/receipts', () => {
|
|
|
193
287
|
expect(Number.isInteger(body.meta?.totalCount)).toBe(true)
|
|
194
288
|
expect(body.meta!.totalCount).toBeGreaterThanOrEqual(body.data.length)
|
|
195
289
|
expect(body.meta!.totalCount).toBeLessThanOrEqual(Schema.countCap)
|
|
196
|
-
expect(body.meta!.totalCountCapped).toBe(body.meta!.totalCount >= Schema.countCap)
|
|
290
|
+
expect(body.meta!.totalCountCapped).toBe(body.meta!.totalCount! >= Schema.countCap)
|
|
291
|
+
// Fees are USD, so the default denomination values them at identity with
|
|
292
|
+
// no rate provenance.
|
|
293
|
+
for (const receipt of body.data)
|
|
294
|
+
expect(receipt.feeAmount.valuation).toEqual({
|
|
295
|
+
amount: receipt.feeAmount.formatted,
|
|
296
|
+
currency: 'USD',
|
|
297
|
+
})
|
|
298
|
+
expect(body.meta!.pricing).toBeUndefined()
|
|
197
299
|
|
|
198
300
|
// Without `include=totalCount`, the same page omits `meta` and the count.
|
|
199
301
|
const bare = await client.v1.transactions.receipts.$get(
|