tapimo 0.5.3 → 0.7.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 +15830 -7220
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js +9 -1
- package/dist/App.js.map +1 -1
- package/dist/Scope.d.ts +4 -0
- package/dist/Scope.d.ts.map +1 -1
- package/dist/Scope.js +5 -0
- package/dist/Scope.js.map +1 -1
- package/dist/admin/App.d.ts +1011 -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/api-keys.d.ts +2 -1
- package/dist/admin/apps/api-keys.d.ts.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/organizations.d.ts +124 -1
- package/dist/admin/apps/organizations.d.ts.map +1 -1
- package/dist/admin/apps/organizations.js +97 -6
- package/dist/admin/apps/organizations.js.map +1 -1
- 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 +95 -75
- package/dist/admin/ui.generated.js.map +1 -1
- package/dist/analytics/Analytics.d.ts.map +1 -1
- package/dist/analytics/Analytics.js +20 -0
- package/dist/analytics/Analytics.js.map +1 -1
- package/dist/analytics/tables/requestEvents.d.ts +18 -0
- package/dist/analytics/tables/requestEvents.d.ts.map +1 -1
- package/dist/analytics/tables/requestEvents.js +36 -7
- package/dist/analytics/tables/requestEvents.js.map +1 -1
- package/dist/apps/data/App.d.ts +6260 -4924
- 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 +194 -16
- 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 +3599 -1382
- package/dist/apps/data/routes/activities.d.ts.map +1 -1
- package/dist/apps/data/routes/activities.js +250 -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 +77 -26
- 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/blocks.d.ts +39 -39
- package/dist/apps/data/routes/coingecko.d.ts +54 -54
- package/dist/apps/data/routes/exchanges.d.ts +856 -105
- 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 +81 -67
- package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
- package/dist/apps/data/routes/fee-amm.js +76 -91
- package/dist/apps/data/routes/fee-amm.js.map +1 -1
- package/dist/apps/data/routes/funding.d.ts +80 -36
- package/dist/apps/data/routes/funding.d.ts.map +1 -1
- package/dist/apps/data/routes/funding.js +65 -31
- package/dist/apps/data/routes/funding.js.map +1 -1
- 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/tokens.d.ts +167 -174
- package/dist/apps/data/routes/tokens.d.ts.map +1 -1
- package/dist/apps/data/routes/tokens.js +15 -13
- 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 +157 -81
- package/dist/apps/data/routes/transfers.d.ts.map +1 -1
- package/dist/apps/data/routes/transfers.js +272 -130
- 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 +36 -36
- 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 +103 -123
- 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 +2 -1
- package/dist/apps/index.d.ts.map +1 -1
- package/dist/apps/index.js +2 -1
- package/dist/apps/index.js.map +1 -1
- package/dist/apps/management/App.d.ts +8554 -1692
- 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 +7 -0
- package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
- package/dist/apps/management/routes/api-keys.js +17 -3
- package/dist/apps/management/routes/api-keys.js.map +1 -1
- package/dist/apps/management/routes/billing.d.ts +157 -162
- package/dist/apps/management/routes/billing.d.ts.map +1 -1
- package/dist/apps/management/routes/billing.js +31 -23
- package/dist/apps/management/routes/billing.js.map +1 -1
- package/dist/apps/management/routes/faucet.d.ts +232 -0
- package/dist/apps/management/routes/faucet.d.ts.map +1 -0
- package/dist/apps/management/routes/faucet.js +154 -0
- package/dist/apps/management/routes/faucet.js.map +1 -0
- package/dist/apps/management/routes/invitations.d.ts +60 -60
- 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 +6 -6
- package/dist/apps/management/routes/members.d.ts +6 -6
- package/dist/apps/management/routes/orgs.d.ts +42 -42
- package/dist/apps/management/routes/orgs.d.ts.map +1 -1
- package/dist/apps/management/routes/orgs.js +5 -0
- package/dist/apps/management/routes/orgs.js.map +1 -1
- package/dist/apps/management/routes/projects.d.ts +44 -44
- package/dist/apps/management/routes/usage.d.ts +3 -0
- 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/apps/mpp/App.d.ts +363 -0
- package/dist/apps/mpp/App.d.ts.map +1 -0
- package/dist/apps/mpp/App.js +72 -0
- package/dist/apps/mpp/App.js.map +1 -0
- package/dist/apps/mpp/Mpp.d.ts +178 -0
- package/dist/apps/mpp/Mpp.d.ts.map +1 -0
- package/dist/apps/mpp/Mpp.js +183 -0
- package/dist/apps/mpp/Mpp.js.map +1 -0
- package/dist/apps/mpp/index.d.ts +3 -0
- package/dist/apps/mpp/index.d.ts.map +1 -0
- package/dist/apps/mpp/index.js +3 -0
- package/dist/apps/mpp/index.js.map +1 -0
- package/dist/apps/relay/App.d.ts.map +1 -1
- package/dist/apps/relay/App.js +56 -9
- package/dist/apps/relay/App.js.map +1 -1
- package/dist/db/Db.d.ts +6 -0
- package/dist/db/Db.d.ts.map +1 -1
- package/dist/db/Db.js +110 -0
- package/dist/db/Db.js.map +1 -1
- package/dist/db/Schema.d.ts +53 -0
- package/dist/db/Schema.d.ts.map +1 -1
- package/dist/db/Schema.js +56 -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/enabledBillingSources.d.ts +73 -0
- package/dist/db/tables/enabledBillingSources.d.ts.map +1 -0
- package/dist/db/tables/enabledBillingSources.js +69 -0
- package/dist/db/tables/enabledBillingSources.js.map +1 -0
- package/dist/db/tables/invitations.d.ts.map +1 -1
- package/dist/db/tables/invitations.js +3 -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/organizations.d.ts +5 -2
- package/dist/db/tables/organizations.d.ts.map +1 -1
- package/dist/db/tables/organizations.js +13 -2
- package/dist/db/tables/organizations.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/handlers/internal/utils.d.ts +1 -16
- package/dist/handlers/internal/utils.d.ts.map +1 -1
- package/dist/handlers/internal/utils.js +17 -6
- package/dist/handlers/internal/utils.js.map +1 -1
- package/dist/handlers/relay.d.ts.map +1 -1
- package/dist/handlers/relay.js +37 -5
- package/dist/handlers/relay.js.map +1 -1
- package/dist/internal/Auth.d.ts +11 -2
- package/dist/internal/Auth.d.ts.map +1 -1
- package/dist/internal/Auth.js +14 -47
- package/dist/internal/Auth.js.map +1 -1
- package/dist/internal/FundingQuotes.d.ts +147 -47
- package/dist/internal/FundingQuotes.d.ts.map +1 -1
- package/dist/internal/FundingQuotes.js +119 -33
- package/dist/internal/FundingQuotes.js.map +1 -1
- package/dist/internal/Log.d.ts +37 -5
- package/dist/internal/Log.d.ts.map +1 -1
- package/dist/internal/Log.js +52 -3
- package/dist/internal/Log.js.map +1 -1
- package/dist/internal/MetricSink.d.ts.map +1 -1
- package/dist/internal/MetricSink.js +24 -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/Response.d.ts +2 -2
- package/dist/internal/Response.d.ts.map +1 -1
- package/dist/internal/Response.js +12 -4
- package/dist/internal/Response.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/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 +7 -2
- package/src/App.test.ts +9 -4
- package/src/App.ts +23 -3
- package/src/Client.test-d.ts +733 -20
- package/src/Scope.ts +5 -0
- package/src/admin/App.test.ts +4 -0
- package/src/admin/App.ts +4 -0
- package/src/admin/apps/early-access.test.ts +125 -0
- package/src/admin/apps/early-access.ts +176 -0
- package/src/admin/apps/organizations.test.ts +86 -2
- package/src/admin/apps/organizations.ts +155 -31
- package/src/admin/apps/scopes.test.ts +5 -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/organizations.test.ts +81 -1
- package/src/admin/ui/src/lib/organizations.ts +92 -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/api-keys.tsx +1 -1
- package/src/admin/ui/src/routes/early-access.tsx +162 -0
- package/src/admin/ui/src/routes/organizations_.$orgId.tsx +103 -0
- package/src/admin/ui/src/routes/verified-tokens.tsx +230 -19
- package/src/admin/ui.generated.ts +95 -94
- package/src/analytics/Analytics.test.ts +83 -0
- package/src/analytics/Analytics.ts +20 -0
- package/src/analytics/tables/requestEvents.ts +60 -7
- package/src/apps/composition.test.ts +11 -2
- package/src/apps/data/App.test.ts +1 -1
- package/src/apps/data/App.ts +22 -14
- package/src/apps/data/FundingQuoteProviders.test.ts +297 -4
- package/src/apps/data/FundingQuoteProviders.ts +255 -29
- 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 +177 -3
- package/src/apps/data/routes/activities.ts +441 -132
- package/src/apps/data/routes/addresses.ts +19 -9
- package/src/apps/data/routes/balances.test.ts +148 -11
- package/src/apps/data/routes/balances.ts +140 -51
- package/src/apps/data/routes/exchanges.test.ts +544 -9
- package/src/apps/data/routes/exchanges.ts +690 -103
- package/src/apps/data/routes/fee-amm.test.ts +47 -23
- package/src/apps/data/routes/fee-amm.ts +98 -119
- package/src/apps/data/routes/funding.test.ts +113 -8
- package/src/apps/data/routes/funding.ts +77 -51
- package/src/apps/data/routes/receipts.test.ts +129 -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 +28 -13
- 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 +341 -31
- package/src/apps/data/routes/transfers.ts +358 -158
- package/src/apps/data/routes/valuation.test.ts +437 -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 +2 -1
- package/src/apps/management/App.ts +13 -0
- package/src/apps/management/routes/api-keys.test.ts +14 -0
- package/src/apps/management/routes/api-keys.ts +27 -3
- package/src/apps/management/routes/billing.test.ts +152 -20
- package/src/apps/management/routes/billing.ts +34 -18
- package/src/apps/management/routes/faucet.test.ts +87 -0
- package/src/apps/management/routes/faucet.ts +201 -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 +9 -99
- package/src/apps/management/routes/orgs.test.ts +45 -2
- package/src/apps/management/routes/orgs.ts +6 -0
- package/src/apps/management/routes/scopes.test.ts +1 -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/apps/mpp/App.ts +86 -0
- package/src/apps/mpp/Mpp.test.ts +193 -0
- package/src/apps/mpp/Mpp.ts +353 -0
- package/src/apps/mpp/index.ts +2 -0
- package/src/apps/mpp/internal/Adapter.ts +11 -0
- package/src/apps/mpp/internal/Error.ts +9 -0
- package/src/apps/mpp/internal/Idempotency.ts +7 -0
- package/src/apps/mpp/internal/Screening.ts +10 -0
- package/src/apps/relay/App.test.ts +88 -6
- package/src/apps/relay/App.ts +61 -9
- package/src/db/Db.test.ts +19 -0
- package/src/db/Db.ts +125 -0
- package/src/db/Schema.ts +68 -0
- package/src/db/tables/earlyAccess.ts +86 -0
- package/src/db/tables/enabledBillingSources.test.ts +303 -0
- package/src/db/tables/enabledBillingSources.ts +118 -0
- package/src/db/tables/invitations.ts +3 -0
- package/src/db/tables/inviteLinks.ts +22 -3
- package/src/db/tables/organizations.test.ts +103 -0
- package/src/db/tables/organizations.ts +18 -2
- 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/handlers/internal/utils.ts +22 -6
- package/src/handlers/relay.errors.test.ts +153 -0
- package/src/handlers/relay.ts +42 -7
- package/src/internal/Auth.test.ts +3 -3
- package/src/internal/Auth.ts +15 -47
- package/src/internal/FundingQuotes.test.ts +161 -6
- package/src/internal/FundingQuotes.ts +141 -39
- package/src/internal/Log.test-d.ts +21 -0
- package/src/internal/Log.test.ts +141 -0
- package/src/internal/Log.ts +93 -6
- package/src/internal/MetricSink.test.ts +215 -0
- package/src/internal/MetricSink.ts +24 -0
- package/src/internal/OpenApi.ts +3 -0
- package/src/internal/Response.test.ts +28 -0
- package/src/internal/Response.ts +12 -4
- 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
|
@@ -28,10 +28,16 @@ describe.skip('GET /fee-amm/pools', () => {
|
|
|
28
28
|
expect('nextCursor' in body).toBe(true)
|
|
29
29
|
expect('meta' in body).toBe(false)
|
|
30
30
|
|
|
31
|
-
// Stable
|
|
32
|
-
|
|
31
|
+
// Stable required shape; reserve amounts remain best-effort.
|
|
32
|
+
const {
|
|
33
|
+
userAmount: _userAmount,
|
|
34
|
+
validatorAmount: _validatorAmount,
|
|
35
|
+
...poolShape
|
|
36
|
+
} = body.data[0]!
|
|
37
|
+
expect(Object.keys(poolShape).sort()).toMatchInlineSnapshot(`
|
|
33
38
|
[
|
|
34
39
|
"createdAt",
|
|
40
|
+
"id",
|
|
35
41
|
"lastMintAt",
|
|
36
42
|
"mintCount",
|
|
37
43
|
"poolId",
|
|
@@ -40,13 +46,16 @@ describe.skip('GET /fee-amm/pools', () => {
|
|
|
40
46
|
]
|
|
41
47
|
`)
|
|
42
48
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
(/^\d+$/.test(
|
|
49
|
+
const validAmount = (
|
|
50
|
+
amount:
|
|
51
|
+
| { baseUnits: string; currency: string; decimals: number; formatted: string }
|
|
52
|
+
| undefined,
|
|
53
|
+
) =>
|
|
54
|
+
amount === undefined ||
|
|
55
|
+
(/^\d+$/.test(amount.baseUnits) &&
|
|
56
|
+
amount.currency.length > 0 &&
|
|
57
|
+
Number.isInteger(amount.decimals) &&
|
|
58
|
+
/^\d+(\.\d+)?$/.test(amount.formatted))
|
|
50
59
|
expect(
|
|
51
60
|
body.data.every(
|
|
52
61
|
(pool) =>
|
|
@@ -54,8 +63,12 @@ describe.skip('GET /fee-amm/pools', () => {
|
|
|
54
63
|
!Number.isNaN(Date.parse(pool.lastMintAt)) &&
|
|
55
64
|
Date.parse(pool.createdAt) <= Date.parse(pool.lastMintAt) &&
|
|
56
65
|
pool.mintCount > 0 &&
|
|
57
|
-
|
|
58
|
-
|
|
66
|
+
pool.userToken.currency.length > 0 &&
|
|
67
|
+
pool.userToken.symbol.length > 0 &&
|
|
68
|
+
pool.validatorToken.currency.length > 0 &&
|
|
69
|
+
pool.validatorToken.symbol.length > 0 &&
|
|
70
|
+
validAmount(pool.userAmount) &&
|
|
71
|
+
validAmount(pool.validatorAmount),
|
|
59
72
|
),
|
|
60
73
|
).toBe(true)
|
|
61
74
|
// Presentation order: most active first (by mint count).
|
|
@@ -130,7 +143,7 @@ describe.skip('GET /fee-amm/pools', () => {
|
|
|
130
143
|
expect(pageTwo.data[0]!.mintCount).toBeLessThanOrEqual(pageOne.data.at(-1)!.mintCount)
|
|
131
144
|
})
|
|
132
145
|
|
|
133
|
-
test('
|
|
146
|
+
test('returns core token metadata and opts into curated fields', async () => {
|
|
134
147
|
const client = TestApp.client()
|
|
135
148
|
const baseResponse = await client.v1['fee-amm'].pools.$get(
|
|
136
149
|
{ query: { limit: '5' } },
|
|
@@ -140,31 +153,33 @@ describe.skip('GET /fee-amm/pools', () => {
|
|
|
140
153
|
|
|
141
154
|
expect(baseResponse.status).toBe(200)
|
|
142
155
|
expect(base.data.length).toBeGreaterThan(0)
|
|
143
|
-
// The base page resolves no token metadata: each side carries just its
|
|
144
|
-
// `address` plus its (best-effort) reserve, never `symbol`/`decimals`/etc.
|
|
145
156
|
expect(
|
|
146
157
|
base.data.every(
|
|
147
158
|
(pool) =>
|
|
148
|
-
pool.userToken.symbol
|
|
149
|
-
pool.userToken.decimals
|
|
150
|
-
pool.
|
|
151
|
-
pool.
|
|
159
|
+
pool.userToken.symbol.length > 0 &&
|
|
160
|
+
Number.isInteger(pool.userToken.decimals) &&
|
|
161
|
+
pool.userToken.logoUri === undefined &&
|
|
162
|
+
pool.userToken.verified === undefined &&
|
|
163
|
+
pool.validatorToken.symbol.length > 0 &&
|
|
164
|
+
Number.isInteger(pool.validatorToken.decimals) &&
|
|
165
|
+
pool.validatorToken.logoUri === undefined &&
|
|
166
|
+
pool.validatorToken.verified === undefined,
|
|
152
167
|
),
|
|
153
168
|
).toBe(true)
|
|
154
169
|
|
|
155
170
|
const includeResponse = await client.v1['fee-amm'].pools.$get(
|
|
156
|
-
{ query: { include: 'token', limit: '5' } },
|
|
171
|
+
{ query: { include: 'token.logoUri,token.verified', limit: '5' } },
|
|
157
172
|
TestApp.auth,
|
|
158
173
|
)
|
|
159
174
|
const included = await TestApp.json(includeResponse, FeeAmm.schema.getFeeAmmPools.Response)
|
|
160
175
|
|
|
161
176
|
expect(includeResponse.status).toBe(200)
|
|
162
|
-
// The same pages line up, and `include=token` resolves metadata for at
|
|
163
|
-
// least one side (verified tokens always carry `symbol`/`decimals`).
|
|
164
177
|
expect(included.data.map((pool) => pool.poolId)).toEqual(base.data.map((pool) => pool.poolId))
|
|
165
178
|
expect(
|
|
166
|
-
included.data.
|
|
167
|
-
(pool) =>
|
|
179
|
+
included.data.every(
|
|
180
|
+
(pool) =>
|
|
181
|
+
typeof pool.userToken.verified === 'boolean' &&
|
|
182
|
+
typeof pool.validatorToken.verified === 'boolean',
|
|
168
183
|
),
|
|
169
184
|
).toBe(true)
|
|
170
185
|
})
|
|
@@ -187,6 +202,15 @@ describe.skip('GET /fee-amm/pools', () => {
|
|
|
187
202
|
})
|
|
188
203
|
})
|
|
189
204
|
|
|
205
|
+
describe('GET /fee-amm/pools query', () => {
|
|
206
|
+
test('rejects the legacy token include', async () => {
|
|
207
|
+
const response = await TestApp.create().request('/v1/fee-amm/pools?include=token', {
|
|
208
|
+
headers: TestApp.auth.headers,
|
|
209
|
+
})
|
|
210
|
+
expect(response.status).toBe(400)
|
|
211
|
+
})
|
|
212
|
+
})
|
|
213
|
+
|
|
190
214
|
describe('GET /fee-amm/mints', () => {
|
|
191
215
|
test('returns a decoded head page and walks the cursor to a disjoint page', async () => {
|
|
192
216
|
const client = TestApp.client()
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Hono, type Context } from 'hono'
|
|
2
|
-
import { AbiEvent, AbiParameters, Hash, type Hex
|
|
2
|
+
import { AbiEvent, AbiParameters, Hash, type Hex } from 'ox'
|
|
3
3
|
import { Abis, Addresses } from 'viem/tempo'
|
|
4
4
|
import * as z from 'zod/mini'
|
|
5
5
|
|
|
@@ -48,11 +48,8 @@ const legacyMintTopic = AbiEvent.getSelector(
|
|
|
48
48
|
export namespace schema {
|
|
49
49
|
/**
|
|
50
50
|
* A token referenced by a fee pool: its contract address plus best-effort
|
|
51
|
-
* metadata.
|
|
52
|
-
*
|
|
53
|
-
* succeeds, so a token whose metadata is unavailable keeps just the bare
|
|
54
|
-
* reference. The pools listing extends this shape with the side's reserve
|
|
55
|
-
* (`getFeeAmmPools.Token`).
|
|
51
|
+
* metadata. Fee AMM mints use this shape; pools require core metadata through
|
|
52
|
+
* `getFeeAmmPools.Token`.
|
|
56
53
|
*/
|
|
57
54
|
export const PoolToken = Schema.describe(
|
|
58
55
|
z.object({
|
|
@@ -94,21 +91,18 @@ export namespace schema {
|
|
|
94
91
|
|
|
95
92
|
/** Schemas for the getFeeAmmPools operation. */
|
|
96
93
|
export namespace getFeeAmmPools {
|
|
97
|
-
/** Optional
|
|
94
|
+
/** Optional curated token fields that callers opt into via `include`. */
|
|
98
95
|
export const Include = z
|
|
99
|
-
.enum(['token'])
|
|
100
|
-
.check(z.describe('
|
|
96
|
+
.enum(['token.logoUri', 'token.verified'])
|
|
97
|
+
.check(z.describe('Additional token fields to include in the pool response.'))
|
|
101
98
|
|
|
102
99
|
/**
|
|
103
|
-
* Parses
|
|
104
|
-
*
|
|
105
|
-
* `token.getMetadata` round trip, so it runs only when `include=token` is
|
|
106
|
-
* requested; the base page returns each side's bare `address` plus its
|
|
107
|
-
* reserve and skips the lookup entirely.
|
|
100
|
+
* Parses comma-separated curated token fields. Core token metadata is
|
|
101
|
+
* always present; callers opt into logo and verification fields.
|
|
108
102
|
*/
|
|
109
103
|
export const includeQuery = Schema.includeQuery(
|
|
110
104
|
Include,
|
|
111
|
-
'Comma-separated
|
|
105
|
+
'Comma-separated token fields to include, such as `token.logoUri,token.verified`.',
|
|
112
106
|
)
|
|
113
107
|
|
|
114
108
|
/** Query parameters for the fee pool list request. */
|
|
@@ -122,31 +116,10 @@ export namespace schema {
|
|
|
122
116
|
})
|
|
123
117
|
.check(...Schema.pageChecks(), z.describe('Query parameters for listing Fee AMM pools.'))
|
|
124
118
|
|
|
125
|
-
/**
|
|
126
|
-
* One side of a fee pool: the token reference carrying the side's current
|
|
127
|
-
* on-chain reserve. `amount`/`formatted` come from `FeeManager.getPool`
|
|
128
|
-
* and are absent when the read fails (best-effort, like the metadata
|
|
129
|
-
* fields).
|
|
130
|
-
*/
|
|
119
|
+
/** A fee-pool token with required RPC metadata and optional curated fields. */
|
|
131
120
|
export const Token = Schema.describe(
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
.optional(Schema.DecimalString)
|
|
135
|
-
.check(
|
|
136
|
-
z.describe(
|
|
137
|
-
'Current onchain reserve for this token, in base units, from `FeeManager.getPool`. Omitted if the read fails.',
|
|
138
|
-
),
|
|
139
|
-
),
|
|
140
|
-
formatted: z
|
|
141
|
-
.optional(z.string())
|
|
142
|
-
.check(
|
|
143
|
-
z.describe(
|
|
144
|
-
'Reserve as a human-readable decimal string using the token’s `decimals`. Omitted if the read fails.',
|
|
145
|
-
),
|
|
146
|
-
z.meta({ examples: ['1.5'] }),
|
|
147
|
-
),
|
|
148
|
-
}),
|
|
149
|
-
'One token side of a Fee AMM pool, including its current onchain reserve when available.',
|
|
121
|
+
Tokens.schema.TokenReference,
|
|
122
|
+
'A token referenced by one side of a Fee AMM pool.',
|
|
150
123
|
)
|
|
151
124
|
|
|
152
125
|
/** A fee AMM pool, aggregated from its `Mint` events. */
|
|
@@ -180,16 +153,16 @@ export namespace schema {
|
|
|
180
153
|
'Pool id computed as `keccak256(abi.encode(userToken, validatorToken))`, matching `FeeManager.getPoolId`.',
|
|
181
154
|
),
|
|
182
155
|
),
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
'
|
|
156
|
+
userAmount: z
|
|
157
|
+
.optional(Schema.TokenAmount)
|
|
158
|
+
.check(z.describe('Current user-token reserve. Omitted when the onchain read fails.')),
|
|
159
|
+
userToken: Token.check(z.describe('Token users pay fees with in this pool.')),
|
|
160
|
+
validatorAmount: z
|
|
161
|
+
.optional(Schema.TokenAmount)
|
|
162
|
+
.check(
|
|
163
|
+
z.describe('Current validator-token reserve. Omitted when the onchain read fails.'),
|
|
191
164
|
),
|
|
192
|
-
),
|
|
165
|
+
validatorToken: Token.check(z.describe('Token validators receive from this pool.')),
|
|
193
166
|
})
|
|
194
167
|
.check(z.describe('A Fee AMM pool discovered from its onchain `Mint` events.'))
|
|
195
168
|
|
|
@@ -319,7 +292,7 @@ export function feeAmm() {
|
|
|
319
292
|
'Lists Fee AMM pools, most active first, so you can see which stablecoin fee conversions have the most liquidity activity.',
|
|
320
293
|
operationId: 'getFeeAmmPools',
|
|
321
294
|
responses: OpenApi.responses({
|
|
322
|
-
errors: { 502: '
|
|
295
|
+
errors: { 502: 'Tempo RPC or the upstream indexer could not complete the request.' },
|
|
323
296
|
success: {
|
|
324
297
|
description: 'List of Fee AMM pools.',
|
|
325
298
|
schema: schema.getFeeAmmPools.Response,
|
|
@@ -330,7 +303,7 @@ export function feeAmm() {
|
|
|
330
303
|
}),
|
|
331
304
|
Cache.response<App.Environment>({
|
|
332
305
|
cacheControl: Cache.policies.state,
|
|
333
|
-
name: 'tempo-api:fee-amm:
|
|
306
|
+
name: 'tempo-api:fee-amm-pools:v2',
|
|
334
307
|
key: (c) => Cache.urlKey(c, schema.getFeeAmmPools.Query),
|
|
335
308
|
}),
|
|
336
309
|
async (c) => {
|
|
@@ -353,57 +326,63 @@ export function feeAmm() {
|
|
|
353
326
|
})
|
|
354
327
|
const pools = page.data
|
|
355
328
|
|
|
356
|
-
// Reserves
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
329
|
+
// Reserves and token metadata are independent batched RPC reads.
|
|
330
|
+
const [reserves, tokensByAddress] = await Promise.all([
|
|
331
|
+
Timing.time(c, 'fee_amm_reserves', () =>
|
|
332
|
+
Promise.all(
|
|
333
|
+
pools.map((pool) =>
|
|
334
|
+
getPoolReserves(c, {
|
|
335
|
+
chainId,
|
|
336
|
+
userToken: pool.userToken,
|
|
337
|
+
validatorToken: pool.validatorToken,
|
|
338
|
+
}),
|
|
339
|
+
),
|
|
367
340
|
),
|
|
368
341
|
),
|
|
369
|
-
|
|
342
|
+
resolveTokenMap(c, {
|
|
343
|
+
addresses: Array.from(
|
|
344
|
+
new Set(pools.flatMap((pool) => [pool.userToken, pool.validatorToken])),
|
|
345
|
+
),
|
|
346
|
+
chainId,
|
|
347
|
+
include: query.include,
|
|
348
|
+
}),
|
|
349
|
+
])
|
|
370
350
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
351
|
+
const token = (address: z.output<typeof Schema.Address>) => {
|
|
352
|
+
const metadata = tokensByAddress.get(address)
|
|
353
|
+
if (!metadata) throw new Error(`Token metadata unavailable for ${address}`)
|
|
354
|
+
return {
|
|
355
|
+
address,
|
|
356
|
+
currency: metadata.currency,
|
|
357
|
+
decimals: metadata.decimals,
|
|
358
|
+
...(query.include.includes('token.logoUri') && metadata.logoUri !== undefined
|
|
359
|
+
? { logoUri: metadata.logoUri }
|
|
360
|
+
: {}),
|
|
361
|
+
name: metadata.name,
|
|
362
|
+
symbol: metadata.symbol,
|
|
363
|
+
...(query.include.includes('token.verified') && metadata.verified !== undefined
|
|
364
|
+
? { verified: metadata.verified }
|
|
365
|
+
: {}),
|
|
366
|
+
}
|
|
367
|
+
}
|
|
383
368
|
|
|
384
369
|
const data = pools.map((pool, index) => {
|
|
385
370
|
const id = poolId(pool.userToken, pool.validatorToken)
|
|
386
|
-
const userToken =
|
|
387
|
-
const validatorToken =
|
|
388
|
-
address: pool.validatorToken,
|
|
389
|
-
...tokensByAddress?.get(pool.validatorToken),
|
|
390
|
-
}
|
|
391
|
-
// Each side's reserve rides on its token reference (like the
|
|
392
|
-
// metadata fields): absent when the `getPool` read failed.
|
|
371
|
+
const userToken = token(pool.userToken)
|
|
372
|
+
const validatorToken = token(pool.validatorToken)
|
|
393
373
|
return {
|
|
394
374
|
createdAt: pool.createdAt,
|
|
395
375
|
id,
|
|
396
376
|
lastMintAt: pool.lastMintAt,
|
|
397
377
|
mintCount: pool.mintCount,
|
|
398
378
|
poolId: id,
|
|
399
|
-
userToken:
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
},
|
|
379
|
+
userAmount: reserve({ amount: reserves[index]?.userToken, token: userToken }),
|
|
380
|
+
userToken,
|
|
381
|
+
validatorAmount: reserve({
|
|
382
|
+
amount: reserves[index]?.validatorToken,
|
|
383
|
+
token: validatorToken,
|
|
384
|
+
}),
|
|
385
|
+
validatorToken,
|
|
407
386
|
}
|
|
408
387
|
})
|
|
409
388
|
|
|
@@ -1030,38 +1009,31 @@ declare namespace decodeMint {
|
|
|
1030
1009
|
}
|
|
1031
1010
|
|
|
1032
1011
|
/**
|
|
1033
|
-
* Resolves
|
|
1034
|
-
* verified-token snapshot across the lookups. Mirrors the transfer feed's
|
|
1035
|
-
* `sourceToken` enrichment: a token whose metadata is unavailable maps to
|
|
1036
|
-
* undefined, so call sites spreading the result keep just the bare `address`
|
|
1037
|
-
* (the `PoolToken` shape).
|
|
1038
|
-
*
|
|
1039
|
-
* Unlike the full token resource, this resolves only the on-chain metadata
|
|
1040
|
-
* (one `token.getMetadata` read per token, auto-batched into a single
|
|
1041
|
-
* multicall) plus the in-memory verified snapshot. It deliberately skips the
|
|
1042
|
-
* curated R2 logo lookup (`getTokenLogo`), which is an un-batched storage read
|
|
1043
|
-
* per token and the dominant cost of the pools/mints listings; `logoUri`
|
|
1044
|
-
* therefore falls back to the verified entry's curated URL or the precompile's
|
|
1045
|
-
* on-chain `logoURI`, both already in hand.
|
|
1012
|
+
* Resolves RPC metadata and selected curated fields. Logo enrichment uses cached verification data or onchain metadata, avoiding one R2 read per token.
|
|
1046
1013
|
*/
|
|
1047
1014
|
async function resolveTokenMap(c: Context<App.Environment>, options: resolveTokenMap.Options) {
|
|
1048
1015
|
const { addresses, chainId } = options
|
|
1049
|
-
const
|
|
1016
|
+
const includeLogoUri = options.include?.includes('token.logoUri') ?? true
|
|
1017
|
+
const includeVerified = options.include?.includes('token.verified') ?? true
|
|
1018
|
+
const snapshot =
|
|
1019
|
+
includeLogoUri || includeVerified
|
|
1020
|
+
? await VerifiedTokens.snapshot(c, chainId).catch(() => undefined)
|
|
1021
|
+
: undefined
|
|
1050
1022
|
const resolved = await Timing.time(c, 'tokens', () =>
|
|
1051
1023
|
Promise.all(
|
|
1052
1024
|
addresses.map((token) =>
|
|
1053
1025
|
Tokens.getTokenMetadata(c, { address: token, chainId })
|
|
1054
1026
|
.then((metadata) => {
|
|
1055
|
-
const verified = snapshot
|
|
1027
|
+
const verified = snapshot?.byAddress.get(token)
|
|
1056
1028
|
return [
|
|
1057
1029
|
token,
|
|
1058
1030
|
{
|
|
1059
1031
|
currency: metadata.currency,
|
|
1060
1032
|
decimals: metadata.decimals,
|
|
1061
|
-
logoUri: verified?.logoUri ?? metadata.logoUri,
|
|
1033
|
+
logoUri: includeLogoUri ? (verified?.logoUri ?? metadata.logoUri) : undefined,
|
|
1062
1034
|
name: metadata.name,
|
|
1063
1035
|
symbol: metadata.symbol,
|
|
1064
|
-
verified: snapshot
|
|
1036
|
+
verified: includeVerified ? snapshot?.byAddress.has(token) : undefined,
|
|
1065
1037
|
},
|
|
1066
1038
|
] as const
|
|
1067
1039
|
})
|
|
@@ -1079,6 +1051,8 @@ declare namespace resolveTokenMap {
|
|
|
1079
1051
|
addresses: readonly z.output<typeof Schema.Address>[]
|
|
1080
1052
|
/** Tempo chain id. */
|
|
1081
1053
|
chainId: z.output<typeof Schema.ChainId>
|
|
1054
|
+
/** Curated token fields to return; omitted to preserve mint enrichment. */
|
|
1055
|
+
include?: readonly z.output<typeof schema.getFeeAmmPools.Include>[] | undefined
|
|
1082
1056
|
}
|
|
1083
1057
|
}
|
|
1084
1058
|
|
|
@@ -1095,19 +1069,24 @@ function poolId(
|
|
|
1095
1069
|
)
|
|
1096
1070
|
}
|
|
1097
1071
|
|
|
1098
|
-
/**
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1072
|
+
/** Builds a self-contained reserve amount after a successful onchain read. */
|
|
1073
|
+
function reserve(options: reserve.Options) {
|
|
1074
|
+
if (options.amount === undefined) return undefined
|
|
1075
|
+
return Value.tokenAmount({
|
|
1076
|
+
baseUnits: options.amount,
|
|
1077
|
+
currency: options.token.currency,
|
|
1078
|
+
decimals: options.token.decimals,
|
|
1079
|
+
})
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
declare namespace reserve {
|
|
1083
|
+
/** Inputs for formatting one side of a Fee AMM pool reserve. */
|
|
1084
|
+
type Options = {
|
|
1085
|
+
/** Base-unit reserve returned by `FeeManager.getPool`. */
|
|
1086
|
+
amount: string | undefined
|
|
1087
|
+
/** Token metadata used to describe and format the reserve. */
|
|
1088
|
+
token: Pick<z.output<typeof Tokens.schema.TokenReference>, 'currency' | 'decimals'>
|
|
1089
|
+
}
|
|
1111
1090
|
}
|
|
1112
1091
|
|
|
1113
1092
|
/** Left-pads a 20-byte address to its 32-byte log-topic form. */
|
|
@@ -6,6 +6,16 @@ import * as TestApp from '../../../../test/App.js'
|
|
|
6
6
|
import * as Funding from './funding.js'
|
|
7
7
|
|
|
8
8
|
describe('GET /funding/quotes', () => {
|
|
9
|
+
test('publishes alphabetically ordered quote example fields', async () => {
|
|
10
|
+
const app = TestApp.create({ auth: false })
|
|
11
|
+
const spec = await (await app.request('/openapi.json')).json()
|
|
12
|
+
const operation = spec.paths['/v1/funding/quotes'].get
|
|
13
|
+
const response = operation.responses['200'].content['application/json']
|
|
14
|
+
const fields = Object.keys(response.example.data[0])
|
|
15
|
+
|
|
16
|
+
expect(fields).toEqual([...fields].sort())
|
|
17
|
+
})
|
|
18
|
+
|
|
9
19
|
test('returns successful live quotes with output amounts', async () => {
|
|
10
20
|
const app = TestApp.create({ funding: { adapters: { relay: relayAdapter() } } })
|
|
11
21
|
const response = await app.request(quoteUrl(), { headers: TestApp.auth.headers })
|
|
@@ -15,16 +25,26 @@ describe('GET /funding/quotes', () => {
|
|
|
15
25
|
|
|
16
26
|
expect(body.data).toHaveLength(1)
|
|
17
27
|
expect(body.data[0]).toMatchObject({
|
|
28
|
+
destinationAmount: {
|
|
29
|
+
baseUnits: '990000',
|
|
30
|
+
currency: 'USD',
|
|
31
|
+
decimals: 6,
|
|
32
|
+
formatted: '0.99',
|
|
33
|
+
},
|
|
34
|
+
destinationAmountMin: {
|
|
35
|
+
baseUnits: '980000',
|
|
36
|
+
currency: 'USD',
|
|
37
|
+
decimals: 6,
|
|
38
|
+
formatted: '0.98',
|
|
39
|
+
},
|
|
18
40
|
id: 'base-usdc-tempo-usdce-relay',
|
|
19
41
|
provider: { id: 'relay' },
|
|
20
42
|
quality: { liquiditySource: 'providerQuote', tier: 'liquid' },
|
|
21
|
-
quote: {
|
|
22
|
-
|
|
23
|
-
outputAmount: '990000',
|
|
24
|
-
outputAmountFormatted: '0.99',
|
|
25
|
-
},
|
|
26
|
-
sourceAmount: { amount: '1000000', formatted: '1' },
|
|
43
|
+
quote: { sampledAt: '2026-01-01T00:00:00Z' },
|
|
44
|
+
sourceAmount: { baseUnits: '1000000', currency: 'USD', decimals: 6, formatted: '1' },
|
|
27
45
|
})
|
|
46
|
+
expect(body.data[0]?.sourceToken).not.toHaveProperty('amount')
|
|
47
|
+
expect(body.data[0]?.destinationToken).not.toHaveProperty('amount')
|
|
28
48
|
})
|
|
29
49
|
|
|
30
50
|
test('queries only the requested provider', async () => {
|
|
@@ -93,6 +113,7 @@ describe('GET /funding/quotes', () => {
|
|
|
93
113
|
})
|
|
94
114
|
|
|
95
115
|
test('returns an empty list when the provider reports no quote', async () => {
|
|
116
|
+
const entries: Log.Entry[] = []
|
|
96
117
|
const app = TestApp.create({
|
|
97
118
|
funding: {
|
|
98
119
|
adapters: {
|
|
@@ -103,11 +124,22 @@ describe('GET /funding/quotes', () => {
|
|
|
103
124
|
},
|
|
104
125
|
},
|
|
105
126
|
},
|
|
127
|
+
logger: (entry) => {
|
|
128
|
+
entries.push(entry)
|
|
129
|
+
},
|
|
106
130
|
})
|
|
107
131
|
const response = await app.request(quoteUrl(), { headers: TestApp.auth.headers })
|
|
108
132
|
expect(response.status).toBe(200)
|
|
109
133
|
const body = await TestApp.json(response, Funding.schema.quoteFunding.Response)
|
|
110
134
|
expect(body.data).toEqual([])
|
|
135
|
+
expect(entries[0]?.fundingProviderAttempts).toEqual([
|
|
136
|
+
{
|
|
137
|
+
durationMs: expect.any(Number),
|
|
138
|
+
id: 'relay',
|
|
139
|
+
operation: 'quote/v2',
|
|
140
|
+
outcome: 'unavailable',
|
|
141
|
+
},
|
|
142
|
+
])
|
|
111
143
|
})
|
|
112
144
|
|
|
113
145
|
test('returns 502 when every matching provider fails', async () => {
|
|
@@ -156,6 +188,15 @@ describe('GET /funding/quotes', () => {
|
|
|
156
188
|
id: 'across',
|
|
157
189
|
operation: 'swap/approval',
|
|
158
190
|
})
|
|
191
|
+
expect(entries[0]?.fundingProviderAttempts).toEqual([
|
|
192
|
+
{
|
|
193
|
+
durationMs: expect.any(Number),
|
|
194
|
+
failure: 'timeout',
|
|
195
|
+
id: 'across',
|
|
196
|
+
operation: 'swap/approval',
|
|
197
|
+
outcome: 'failed',
|
|
198
|
+
},
|
|
199
|
+
])
|
|
159
200
|
})
|
|
160
201
|
|
|
161
202
|
test('logs every failure when multiple providers fail', async () => {
|
|
@@ -192,6 +233,62 @@ describe('GET /funding/quotes', () => {
|
|
|
192
233
|
{ failure: 'network', id: 'across', operation: 'swap/approval' },
|
|
193
234
|
{ failure: 'unknown', id: 'relay', operation: 'quote/v2' },
|
|
194
235
|
])
|
|
236
|
+
expect(entries[0]?.fundingProviderAttempts).toEqual([
|
|
237
|
+
{
|
|
238
|
+
durationMs: expect.any(Number),
|
|
239
|
+
failure: 'network',
|
|
240
|
+
id: 'across',
|
|
241
|
+
operation: 'swap/approval',
|
|
242
|
+
outcome: 'failed',
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
durationMs: expect.any(Number),
|
|
246
|
+
failure: 'unknown',
|
|
247
|
+
id: 'relay',
|
|
248
|
+
operation: 'quote/v2',
|
|
249
|
+
outcome: 'failed',
|
|
250
|
+
},
|
|
251
|
+
])
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
test('logs failed providers when another provider returns a quote', async () => {
|
|
255
|
+
const entries: Log.Entry[] = []
|
|
256
|
+
const app = TestApp.create({
|
|
257
|
+
funding: {
|
|
258
|
+
adapters: {
|
|
259
|
+
across: {
|
|
260
|
+
async probeQuote() {
|
|
261
|
+
throw new TypeError(`wallet ${'0xaa'.repeat(20)} could not reach secret-provider`)
|
|
262
|
+
},
|
|
263
|
+
},
|
|
264
|
+
relay: relayAdapter(),
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
logger: (entry) => {
|
|
268
|
+
entries.push(entry)
|
|
269
|
+
},
|
|
270
|
+
})
|
|
271
|
+
|
|
272
|
+
const response = await app.request(quoteUrl(), { headers: TestApp.auth.headers })
|
|
273
|
+
|
|
274
|
+
expect(response.status).toBe(200)
|
|
275
|
+
expect(entries[0]?.fundingProviderAttempts).toEqual([
|
|
276
|
+
{
|
|
277
|
+
durationMs: expect.any(Number),
|
|
278
|
+
failure: 'network',
|
|
279
|
+
id: 'across',
|
|
280
|
+
operation: 'swap/approval',
|
|
281
|
+
outcome: 'failed',
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
durationMs: expect.any(Number),
|
|
285
|
+
id: 'relay',
|
|
286
|
+
operation: 'quote/v2',
|
|
287
|
+
outcome: 'available',
|
|
288
|
+
},
|
|
289
|
+
])
|
|
290
|
+
expect(JSON.stringify(entries[0])).not.toContain('secret-provider')
|
|
291
|
+
expect(JSON.stringify(entries[0])).not.toContain('0xaa')
|
|
195
292
|
})
|
|
196
293
|
|
|
197
294
|
test('rejects successful provider results without output amounts', async () => {
|
|
@@ -265,6 +362,9 @@ describe('GET /funding/chains', () => {
|
|
|
265
362
|
expect(body.data.flatMap((chain) => chain.tokens.map((token) => token.symbol))).toEqual(
|
|
266
363
|
expect.arrayContaining(['USDC', 'USDT']),
|
|
267
364
|
)
|
|
365
|
+
expect(
|
|
366
|
+
body.data.flatMap((chain) => chain.tokens).every((token) => token.currency === 'USD'),
|
|
367
|
+
).toBe(true)
|
|
268
368
|
})
|
|
269
369
|
})
|
|
270
370
|
|
|
@@ -306,6 +406,13 @@ describe('GET /funding/providers', () => {
|
|
|
306
406
|
requiresApiKey: true,
|
|
307
407
|
status: 'unconfigured',
|
|
308
408
|
},
|
|
409
|
+
{
|
|
410
|
+
id: 'symbiosis',
|
|
411
|
+
kind: 'crossChainDex',
|
|
412
|
+
name: 'Symbiosis',
|
|
413
|
+
requiresApiKey: false,
|
|
414
|
+
status: 'unconfigured',
|
|
415
|
+
},
|
|
309
416
|
])
|
|
310
417
|
})
|
|
311
418
|
|
|
@@ -340,7 +447,6 @@ function relayAdapter(onProbe: () => void = () => {}): FundingQuotes.ProviderAda
|
|
|
340
447
|
return {
|
|
341
448
|
minimumOutputAmount: '980000',
|
|
342
449
|
outputAmount: '990000',
|
|
343
|
-
outputAmountFormatted: '0.99',
|
|
344
450
|
quality: {
|
|
345
451
|
estimatedSeconds: 4,
|
|
346
452
|
liquiditySource: 'providerQuote',
|
|
@@ -364,7 +470,6 @@ function acrossAdapter(onProbe: () => void = () => {}): FundingQuotes.ProviderAd
|
|
|
364
470
|
expiresAt: '2026-01-01T00:01:00Z',
|
|
365
471
|
minimumOutputAmount: '988000',
|
|
366
472
|
outputAmount: '990000',
|
|
367
|
-
outputAmountFormatted: '0.99',
|
|
368
473
|
quality: {
|
|
369
474
|
estimatedSeconds: 2,
|
|
370
475
|
liquiditySource: 'providerQuote',
|