tapimo 0.7.1 → 0.7.2
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/ApiKeys.d.ts +24 -7
- package/dist/ApiKeys.d.ts.map +1 -1
- package/dist/ApiKeys.js +17 -5
- package/dist/ApiKeys.js.map +1 -1
- package/dist/App.d.ts +12104 -7861
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js +191 -128
- package/dist/App.js.map +1 -1
- package/dist/Assets.d.ts +10 -0
- package/dist/Assets.d.ts.map +1 -1
- package/dist/Assets.js +17 -4
- package/dist/Assets.js.map +1 -1
- package/dist/Scope.d.ts +19 -8
- package/dist/Scope.d.ts.map +1 -1
- package/dist/Scope.js +25 -9
- package/dist/Scope.js.map +1 -1
- package/dist/Webhooks.d.ts +1 -1
- package/dist/admin/App.d.ts +601 -20
- package/dist/admin/App.d.ts.map +1 -1
- package/dist/admin/App.js +12 -2
- package/dist/admin/App.js.map +1 -1
- package/dist/admin/apps/api-keys.d.ts +94 -11
- package/dist/admin/apps/api-keys.d.ts.map +1 -1
- package/dist/admin/apps/api-keys.js +141 -32
- package/dist/admin/apps/api-keys.js.map +1 -1
- package/dist/admin/apps/earn-vaults.d.ts +1069 -0
- package/dist/admin/apps/earn-vaults.d.ts.map +1 -0
- package/dist/admin/apps/earn-vaults.js +409 -0
- package/dist/admin/apps/earn-vaults.js.map +1 -0
- package/dist/admin/apps/verified-tokens.d.ts +166 -166
- 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 +99 -43
- package/dist/admin/ui.generated.js.map +1 -1
- package/dist/analytics/Analytics.d.ts +2 -0
- package/dist/analytics/Analytics.d.ts.map +1 -1
- package/dist/analytics/Analytics.js +18 -2
- package/dist/analytics/Analytics.js.map +1 -1
- package/dist/analytics/tables/requestEvents.d.ts +22 -1
- package/dist/analytics/tables/requestEvents.d.ts.map +1 -1
- package/dist/analytics/tables/requestEvents.js +59 -39
- package/dist/analytics/tables/requestEvents.js.map +1 -1
- package/dist/apps/Zones.d.ts +8335 -0
- package/dist/apps/Zones.d.ts.map +1 -0
- package/dist/apps/Zones.js +38 -0
- package/dist/apps/Zones.js.map +1 -0
- package/dist/apps/data/App.d.ts +12125 -7913
- package/dist/apps/data/App.d.ts.map +1 -1
- package/dist/apps/data/App.js +91 -19
- package/dist/apps/data/App.js.map +1 -1
- package/dist/apps/data/FxOracle.d.ts +1 -1
- package/dist/apps/data/FxOracle.d.ts.map +1 -1
- package/dist/apps/data/index.d.ts +0 -1
- package/dist/apps/data/index.d.ts.map +1 -1
- package/dist/apps/data/index.js +0 -1
- package/dist/apps/data/index.js.map +1 -1
- package/dist/apps/data/routes/activities.d.ts +32 -32
- package/dist/apps/data/routes/activities.d.ts.map +1 -1
- package/dist/apps/data/routes/activities.js +130 -65
- package/dist/apps/data/routes/activities.js.map +1 -1
- package/dist/apps/data/routes/addresses.d.ts +312 -312
- package/dist/apps/data/routes/balances.d.ts +18 -18
- package/dist/apps/data/routes/balances.js +5 -5
- package/dist/apps/data/routes/balances.js.map +1 -1
- package/dist/apps/data/routes/coingecko.d.ts +176 -176
- package/dist/apps/data/routes/coingecko.d.ts.map +1 -1
- package/dist/apps/data/routes/coingecko.js +62 -35
- package/dist/apps/data/routes/coingecko.js.map +1 -1
- package/dist/apps/data/routes/earn.d.ts +2144 -0
- package/dist/apps/data/routes/earn.d.ts.map +1 -0
- package/dist/apps/data/routes/earn.js +947 -0
- package/dist/apps/data/routes/earn.js.map +1 -0
- package/dist/apps/data/routes/exchanges.d.ts +1625 -718
- package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
- package/dist/apps/data/routes/exchanges.js +656 -193
- package/dist/apps/data/routes/exchanges.js.map +1 -1
- package/dist/apps/data/routes/fee-amm.d.ts +108 -108
- package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
- package/dist/apps/data/routes/fee-amm.js +59 -8
- package/dist/apps/data/routes/fee-amm.js.map +1 -1
- package/dist/apps/data/routes/funding.d.ts +4092 -387
- package/dist/apps/data/routes/funding.d.ts.map +1 -1
- package/dist/apps/data/routes/funding.js +1403 -256
- package/dist/apps/data/routes/funding.js.map +1 -1
- package/dist/apps/data/routes/indexer.d.ts +30 -30
- package/dist/apps/data/routes/indexer.d.ts.map +1 -1
- package/dist/apps/data/routes/indexer.js +19 -2
- package/dist/apps/data/routes/indexer.js.map +1 -1
- package/dist/apps/data/routes/receipts.d.ts +263 -263
- package/dist/apps/data/routes/receipts.d.ts.map +1 -1
- package/dist/apps/data/routes/receipts.js +11 -11
- package/dist/apps/data/routes/receipts.js.map +1 -1
- package/dist/apps/data/routes/rpc.d.ts +5 -5
- package/dist/apps/data/routes/rpc.d.ts.map +1 -1
- package/dist/apps/data/routes/rpc.js +211 -22
- package/dist/apps/data/routes/rpc.js.map +1 -1
- package/dist/apps/data/routes/tokenlist.d.ts +36 -36
- package/dist/apps/data/routes/tokenlist.d.ts.map +1 -1
- package/dist/apps/data/routes/tokenlist.js +39 -8
- package/dist/apps/data/routes/tokenlist.js.map +1 -1
- package/dist/apps/data/routes/tokens.d.ts +114 -86
- package/dist/apps/data/routes/tokens.d.ts.map +1 -1
- package/dist/apps/data/routes/tokens.js +194 -91
- package/dist/apps/data/routes/tokens.js.map +1 -1
- package/dist/apps/data/routes/transactions.d.ts +53 -53
- package/dist/apps/data/routes/transactions.d.ts.map +1 -1
- package/dist/apps/data/routes/transactions.js +78 -39
- package/dist/apps/data/routes/transactions.js.map +1 -1
- package/dist/apps/data/routes/transfers.d.ts +76 -27
- package/dist/apps/data/routes/transfers.d.ts.map +1 -1
- package/dist/apps/data/routes/transfers.js +165 -67
- package/dist/apps/data/routes/transfers.js.map +1 -1
- package/dist/apps/data/routes/valuation.d.ts +42 -42
- package/dist/apps/data/routes/valuation.js +2 -2
- package/dist/apps/data/routes/valuation.js.map +1 -1
- package/dist/apps/data/routes/webhooks.d.ts +369 -367
- package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
- package/dist/apps/data/routes/webhooks.js +161 -59
- package/dist/apps/data/routes/webhooks.js.map +1 -1
- package/dist/apps/data/routes/zones.d.ts +281 -0
- package/dist/apps/data/routes/zones.d.ts.map +1 -0
- package/dist/apps/data/routes/zones.js +252 -0
- package/dist/apps/data/routes/zones.js.map +1 -0
- package/dist/apps/docs/reference.js +6 -5
- package/dist/apps/docs/reference.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 +670 -670
- package/dist/apps/management/Billing.d.ts +8 -0
- package/dist/apps/management/Billing.d.ts.map +1 -1
- package/dist/apps/management/Billing.js +12 -0
- package/dist/apps/management/Billing.js.map +1 -1
- package/dist/apps/management/Error.d.ts +12 -0
- package/dist/apps/management/Error.d.ts.map +1 -0
- package/dist/apps/management/Error.js +10 -0
- package/dist/apps/management/Error.js.map +1 -0
- package/dist/apps/management/routes/api-keys.d.ts +5 -5
- package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
- package/dist/apps/management/routes/api-keys.js +2 -8
- package/dist/apps/management/routes/api-keys.js.map +1 -1
- package/dist/apps/management/routes/billing.d.ts +119 -119
- package/dist/apps/management/routes/faucet.d.ts +2 -2
- package/dist/apps/management/routes/invitations.d.ts +62 -62
- package/dist/apps/management/routes/invitations.d.ts.map +1 -1
- package/dist/apps/management/routes/invitations.js +4 -10
- package/dist/apps/management/routes/invitations.js.map +1 -1
- package/dist/apps/management/routes/invite-links.d.ts +30 -30
- package/dist/apps/management/routes/me.d.ts +6 -6
- package/dist/apps/management/routes/members.d.ts +2 -2
- package/dist/apps/management/routes/orgs.d.ts +48 -48
- package/dist/apps/management/routes/orgs.d.ts.map +1 -1
- package/dist/apps/management/routes/orgs.js +2 -8
- package/dist/apps/management/routes/orgs.js.map +1 -1
- package/dist/apps/management/routes/projects.d.ts +9 -9
- package/dist/apps/management/routes/scopes.js +2 -2
- package/dist/apps/management/routes/scopes.js.map +1 -1
- package/dist/apps/management/routes/verified-token-requests.d.ts +36 -36
- package/dist/apps/management/routes/webhooks.d.ts +50 -50
- package/dist/apps/management/routes/webhooks.d.ts.map +1 -1
- package/dist/apps/management/routes/webhooks.js +15 -3
- package/dist/apps/management/routes/webhooks.js.map +1 -1
- package/dist/apps/mpp/App.d.ts +55 -56
- package/dist/apps/mpp/App.d.ts.map +1 -1
- package/dist/apps/mpp/App.js +192 -27
- package/dist/apps/mpp/App.js.map +1 -1
- package/dist/apps/mpp/Mpp.d.ts +0 -20
- package/dist/apps/mpp/Mpp.d.ts.map +1 -1
- package/dist/apps/mpp/Mpp.js +0 -24
- package/dist/apps/mpp/Mpp.js.map +1 -1
- package/dist/apps/mpp/internal/Adapter.d.ts +40 -0
- package/dist/apps/mpp/internal/Adapter.d.ts.map +1 -0
- package/dist/apps/mpp/internal/Adapter.js +66 -0
- package/dist/apps/mpp/internal/Adapter.js.map +1 -0
- package/dist/apps/mpp/internal/Error.d.ts +4 -0
- package/dist/apps/mpp/internal/Error.d.ts.map +1 -0
- package/dist/apps/mpp/internal/Error.js +41 -0
- package/dist/apps/mpp/internal/Error.js.map +1 -0
- package/dist/apps/mpp/internal/Idempotency.d.ts +33 -0
- package/dist/apps/mpp/internal/Idempotency.d.ts.map +1 -0
- package/dist/apps/mpp/internal/Idempotency.js +28 -0
- package/dist/apps/mpp/internal/Idempotency.js.map +1 -0
- package/dist/apps/mpp/internal/Policy.d.ts +46 -0
- package/dist/apps/mpp/internal/Policy.d.ts.map +1 -0
- package/dist/apps/mpp/internal/Policy.js +57 -0
- package/dist/apps/mpp/internal/Policy.js.map +1 -0
- package/dist/apps/mpp/internal/ScreenManager.d.ts +27 -0
- package/dist/apps/mpp/internal/ScreenManager.d.ts.map +1 -0
- package/dist/apps/mpp/internal/ScreenManager.js +18 -0
- package/dist/apps/mpp/internal/ScreenManager.js.map +1 -0
- package/dist/apps/mpp/internal/Screening.d.ts +35 -0
- package/dist/apps/mpp/internal/Screening.d.ts.map +1 -0
- package/dist/apps/mpp/internal/Screening.js +20 -0
- package/dist/apps/mpp/internal/Screening.js.map +1 -0
- package/dist/apps/mpp/internal/Sponsorship.d.ts +36 -0
- package/dist/apps/mpp/internal/Sponsorship.d.ts.map +1 -0
- package/dist/apps/mpp/internal/Sponsorship.js +103 -0
- package/dist/apps/mpp/internal/Sponsorship.js.map +1 -0
- package/dist/apps/mpp/internal/Utils.d.ts +7 -0
- package/dist/apps/mpp/internal/Utils.d.ts.map +1 -0
- package/dist/apps/mpp/internal/Utils.js +24 -0
- package/dist/apps/mpp/internal/Utils.js.map +1 -0
- package/dist/apps/relay/App.js +183 -23
- package/dist/apps/relay/App.js.map +1 -1
- package/dist/apps/relay/Sponsorships.d.ts +4 -0
- package/dist/apps/relay/Sponsorships.d.ts.map +1 -1
- package/dist/apps/relay/Sponsorships.js +15 -6
- package/dist/apps/relay/Sponsorships.js.map +1 -1
- package/dist/db/Db.d.ts +20 -0
- package/dist/db/Db.d.ts.map +1 -1
- package/dist/db/Db.js +342 -0
- package/dist/db/Db.js.map +1 -1
- package/dist/db/Schema.d.ts +921 -1
- package/dist/db/Schema.d.ts.map +1 -1
- package/dist/db/Schema.js +269 -1
- package/dist/db/Schema.js.map +1 -1
- package/dist/db/tables/earnVaults.d.ts +68 -0
- package/dist/db/tables/earnVaults.d.ts.map +1 -0
- package/dist/db/tables/earnVaults.js +72 -0
- package/dist/db/tables/earnVaults.js.map +1 -0
- package/dist/db/tables/fundingCatalog.d.ts +56 -0
- package/dist/db/tables/fundingCatalog.d.ts.map +1 -0
- package/dist/db/tables/fundingCatalog.js +85 -0
- package/dist/db/tables/fundingCatalog.js.map +1 -0
- package/dist/db/tables/fundingDepositAddresses.d.ts +159 -0
- package/dist/db/tables/fundingDepositAddresses.d.ts.map +1 -0
- package/dist/db/tables/fundingDepositAddresses.js +206 -0
- package/dist/db/tables/fundingDepositAddresses.js.map +1 -0
- package/dist/db/tables/fundingDeposits.d.ts +115 -0
- package/dist/db/tables/fundingDeposits.d.ts.map +1 -0
- package/dist/db/tables/fundingDeposits.js +100 -0
- package/dist/db/tables/fundingDeposits.js.map +1 -0
- package/dist/db/tables/fundingIdempotency.d.ts +91 -0
- package/dist/db/tables/fundingIdempotency.d.ts.map +1 -0
- package/dist/db/tables/fundingIdempotency.js +103 -0
- package/dist/db/tables/fundingIdempotency.js.map +1 -0
- package/dist/db/tables/fundingTransferEvents.d.ts +12 -0
- package/dist/db/tables/fundingTransferEvents.d.ts.map +1 -0
- package/dist/db/tables/fundingTransferEvents.js +18 -0
- package/dist/db/tables/fundingTransferEvents.js.map +1 -0
- package/dist/db/tables/fundingTransferTransactions.d.ts +15 -0
- package/dist/db/tables/fundingTransferTransactions.d.ts.map +1 -0
- package/dist/db/tables/fundingTransferTransactions.js +27 -0
- package/dist/db/tables/fundingTransferTransactions.js.map +1 -0
- package/dist/db/tables/fundingTransfers.d.ts +82 -0
- package/dist/db/tables/fundingTransfers.d.ts.map +1 -0
- package/dist/db/tables/fundingTransfers.js +89 -0
- package/dist/db/tables/fundingTransfers.js.map +1 -0
- package/dist/db/tables/organizations.d.ts +8 -0
- package/dist/db/tables/organizations.d.ts.map +1 -1
- package/dist/db/tables/organizations.js +16 -0
- package/dist/db/tables/organizations.js.map +1 -1
- package/dist/db/tables/projects.d.ts +8 -0
- package/dist/db/tables/projects.d.ts.map +1 -1
- package/dist/db/tables/projects.js +16 -0
- package/dist/db/tables/projects.js.map +1 -1
- package/dist/db/tables/requestUsage.d.ts +13 -0
- package/dist/db/tables/requestUsage.d.ts.map +1 -1
- package/dist/db/tables/requestUsage.js +16 -0
- package/dist/db/tables/requestUsage.js.map +1 -1
- package/dist/db/tables/sponsoredTransactions.d.ts +2 -2
- package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
- package/dist/db/tables/sponsoredTransactions.js +1 -1
- package/dist/db/tables/sponsoredTransactions.js.map +1 -1
- package/dist/db/tables/users.d.ts +8 -0
- package/dist/db/tables/users.d.ts.map +1 -1
- package/dist/db/tables/users.js +16 -0
- package/dist/db/tables/users.js.map +1 -1
- package/dist/db/tables/verifiedTokens.d.ts +14 -7
- package/dist/db/tables/verifiedTokens.d.ts.map +1 -1
- package/dist/db/tables/verifiedTokens.js +9 -7
- package/dist/db/tables/verifiedTokens.js.map +1 -1
- package/dist/db/tables/webhookSubscriptions.d.ts +31 -1
- package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
- package/dist/db/tables/webhookSubscriptions.js +24 -3
- package/dist/db/tables/webhookSubscriptions.js.map +1 -1
- package/dist/handlers/relay.js +108 -108
- package/dist/handlers/relay.js.map +1 -1
- package/dist/internal/Auth.d.ts +26 -0
- package/dist/internal/Auth.d.ts.map +1 -1
- package/dist/internal/Auth.js +35 -2
- package/dist/internal/Auth.js.map +1 -1
- package/dist/internal/Cache.d.ts.map +1 -1
- package/dist/internal/Cache.js +16 -10
- package/dist/internal/Cache.js.map +1 -1
- package/dist/internal/Cursor.js +1 -1
- package/dist/internal/Cursor.js.map +1 -1
- package/dist/internal/EarnRates.d.ts +89 -0
- package/dist/internal/EarnRates.d.ts.map +1 -0
- package/dist/internal/EarnRates.js +266 -0
- package/dist/internal/EarnRates.js.map +1 -0
- package/dist/internal/EarnVaults.d.ts +171 -0
- package/dist/internal/EarnVaults.d.ts.map +1 -0
- package/dist/internal/EarnVaults.js +547 -0
- package/dist/internal/EarnVaults.js.map +1 -0
- package/dist/internal/EdgeCache.d.ts +8 -1
- package/dist/internal/EdgeCache.d.ts.map +1 -1
- package/dist/internal/EdgeCache.js +33 -7
- package/dist/internal/EdgeCache.js.map +1 -1
- package/dist/internal/Id.d.ts +11 -0
- package/dist/internal/Id.d.ts.map +1 -1
- package/dist/internal/Id.js +13 -0
- package/dist/internal/Id.js.map +1 -1
- package/dist/internal/Idempotency.d.ts +83 -0
- package/dist/internal/Idempotency.d.ts.map +1 -0
- package/dist/internal/Idempotency.js +113 -0
- package/dist/internal/Idempotency.js.map +1 -0
- package/dist/internal/Log.d.ts +64 -9
- package/dist/internal/Log.d.ts.map +1 -1
- package/dist/internal/Log.js +29 -7
- package/dist/internal/Log.js.map +1 -1
- package/dist/internal/MetricSink.d.ts.map +1 -1
- package/dist/internal/MetricSink.js +47 -1
- package/dist/internal/MetricSink.js.map +1 -1
- package/dist/internal/OpenApi.d.ts +1 -1
- 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/Provider.d.ts +14 -0
- package/dist/internal/Provider.d.ts.map +1 -0
- package/dist/internal/Provider.js +5 -0
- package/dist/internal/Provider.js.map +1 -0
- package/dist/internal/Schema.d.ts +6 -1
- package/dist/internal/Schema.d.ts.map +1 -1
- package/dist/internal/Schema.js +20 -11
- package/dist/internal/Schema.js.map +1 -1
- package/dist/internal/Store.d.ts +6 -0
- package/dist/internal/Store.d.ts.map +1 -1
- package/dist/internal/Store.js +35 -0
- package/dist/internal/Store.js.map +1 -1
- package/dist/internal/Tidx.d.ts +43 -24
- package/dist/internal/Tidx.d.ts.map +1 -1
- package/dist/internal/Tidx.js +79 -11
- package/dist/internal/Tidx.js.map +1 -1
- package/dist/internal/Viem.d.ts +82 -65
- package/dist/internal/Viem.d.ts.map +1 -1
- package/dist/internal/Viem.js +83 -12
- package/dist/internal/Viem.js.map +1 -1
- package/dist/internal/WebhookDestination.d.ts.map +1 -1
- package/dist/internal/WebhookDestination.js +34 -28
- package/dist/internal/WebhookDestination.js.map +1 -1
- package/dist/internal/Webhooks.d.ts +9 -0
- package/dist/internal/Webhooks.d.ts.map +1 -1
- package/dist/internal/Webhooks.js +15 -10
- package/dist/internal/Webhooks.js.map +1 -1
- package/dist/internal/exchange/Provider.d.ts +219 -0
- package/dist/internal/exchange/Provider.d.ts.map +1 -0
- package/dist/internal/exchange/Provider.js +117 -0
- package/dist/internal/exchange/Provider.js.map +1 -0
- package/dist/internal/exchange/index.d.ts +2 -0
- package/dist/internal/exchange/index.d.ts.map +1 -0
- package/dist/internal/exchange/index.js +2 -0
- package/dist/internal/exchange/index.js.map +1 -0
- package/dist/internal/exchange/providers/uniswap.d.ts +57 -0
- package/dist/internal/exchange/providers/uniswap.d.ts.map +1 -0
- package/dist/internal/exchange/providers/uniswap.js +553 -0
- package/dist/internal/exchange/providers/uniswap.js.map +1 -0
- package/dist/internal/funding/Action.d.ts +55 -0
- package/dist/internal/funding/Action.d.ts.map +1 -0
- package/dist/internal/funding/Action.js +74 -0
- package/dist/internal/funding/Action.js.map +1 -0
- package/dist/internal/funding/Catalog.d.ts +107 -0
- package/dist/internal/funding/Catalog.d.ts.map +1 -0
- package/dist/internal/funding/Catalog.js +270 -0
- package/dist/internal/funding/Catalog.js.map +1 -0
- package/dist/internal/funding/Chain.d.ts +76 -0
- package/dist/internal/funding/Chain.d.ts.map +1 -0
- package/dist/internal/funding/Chain.js +38 -0
- package/dist/internal/funding/Chain.js.map +1 -0
- package/dist/internal/funding/Deposit.d.ts +366 -0
- package/dist/internal/funding/Deposit.d.ts.map +1 -0
- package/dist/internal/funding/Deposit.js +286 -0
- package/dist/internal/funding/Deposit.js.map +1 -0
- package/dist/internal/funding/DepositAddress.d.ts +345 -0
- package/dist/internal/funding/DepositAddress.d.ts.map +1 -0
- package/dist/internal/funding/DepositAddress.js +189 -0
- package/dist/internal/funding/DepositAddress.js.map +1 -0
- package/dist/internal/funding/Evidence.d.ts +52 -0
- package/dist/internal/funding/Evidence.d.ts.map +1 -0
- package/dist/internal/funding/Evidence.js +314 -0
- package/dist/internal/funding/Evidence.js.map +1 -0
- package/dist/internal/funding/Provider.d.ts +1186 -0
- package/dist/internal/funding/Provider.d.ts.map +1 -0
- package/dist/internal/funding/Provider.js +1081 -0
- package/dist/internal/funding/Provider.js.map +1 -0
- package/dist/internal/funding/Reconciliation.d.ts +113 -0
- package/dist/internal/funding/Reconciliation.d.ts.map +1 -0
- package/dist/internal/funding/Reconciliation.js +676 -0
- package/dist/internal/funding/Reconciliation.js.map +1 -0
- package/dist/internal/funding/Route.d.ts +21 -0
- package/dist/internal/funding/Route.d.ts.map +1 -0
- package/dist/internal/funding/Route.js +5 -0
- package/dist/internal/funding/Route.js.map +1 -0
- package/dist/internal/funding/Subsidy.d.ts +113 -0
- package/dist/internal/funding/Subsidy.d.ts.map +1 -0
- package/dist/internal/funding/Subsidy.js +138 -0
- package/dist/internal/funding/Subsidy.js.map +1 -0
- package/dist/internal/funding/Token.d.ts +41 -0
- package/dist/internal/funding/Token.d.ts.map +1 -0
- package/dist/internal/funding/Token.js +22 -0
- package/dist/internal/funding/Token.js.map +1 -0
- package/dist/internal/funding/Transfer.d.ts +643 -0
- package/dist/internal/funding/Transfer.d.ts.map +1 -0
- package/dist/internal/funding/Transfer.js +332 -0
- package/dist/internal/funding/Transfer.js.map +1 -0
- package/dist/internal/funding/index.d.ts +13 -0
- package/dist/internal/funding/index.d.ts.map +1 -0
- package/dist/internal/funding/index.js +13 -0
- package/dist/internal/funding/index.js.map +1 -0
- package/dist/internal/funding/providers/across.d.ts +21 -0
- package/dist/internal/funding/providers/across.d.ts.map +1 -0
- package/dist/internal/funding/providers/across.js +117 -0
- package/dist/internal/funding/providers/across.js.map +1 -0
- package/dist/internal/funding/providers/relay.d.ts +46 -0
- package/dist/internal/funding/providers/relay.d.ts.map +1 -0
- package/dist/internal/funding/providers/relay.js +464 -0
- package/dist/internal/funding/providers/relay.js.map +1 -0
- package/dist/internal/funding/providers/rhino.d.ts +15 -0
- package/dist/internal/funding/providers/rhino.d.ts.map +1 -0
- package/dist/internal/funding/providers/rhino.js +116 -0
- package/dist/internal/funding/providers/rhino.js.map +1 -0
- package/dist/internal/funding/providers/squid.d.ts +19 -0
- package/dist/internal/funding/providers/squid.d.ts.map +1 -0
- package/dist/internal/funding/providers/squid.js +120 -0
- package/dist/internal/funding/providers/squid.js.map +1 -0
- package/dist/internal/funding/providers/symbiosis.d.ts +20 -0
- package/dist/internal/funding/providers/symbiosis.d.ts.map +1 -0
- package/dist/internal/funding/providers/symbiosis.js +176 -0
- package/dist/internal/funding/providers/symbiosis.js.map +1 -0
- package/dist/internal/index.d.ts +5 -1
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +5 -1
- package/dist/internal/index.js.map +1 -1
- package/dist/internal/webhookDestinations/url.js +61 -57
- package/dist/internal/webhookDestinations/url.js.map +1 -1
- package/dist/providers/index.d.ts +43 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +19 -0
- package/dist/providers/index.js.map +1 -0
- package/package.json +9 -4
- package/src/ApiKeys.test.ts +11 -7
- package/src/ApiKeys.ts +37 -9
- package/src/App.test.ts +85 -10
- package/src/App.ts +224 -137
- package/src/Assets.ts +29 -4
- package/src/Client.test-d.ts +650 -30
- package/src/Scope.test.ts +19 -0
- package/src/Scope.ts +28 -11
- package/src/Webhooks.test.ts +25 -0
- package/src/Webhooks.ts +1 -1
- package/src/admin/App.test.ts +9 -2
- package/src/admin/App.ts +32 -9
- package/src/admin/apps/api-keys.test.ts +167 -23
- package/src/admin/apps/api-keys.ts +166 -28
- package/src/admin/apps/earn-vaults.test.ts +338 -0
- package/src/admin/apps/earn-vaults.ts +572 -0
- package/src/admin/apps/scopes.test.ts +16 -1
- package/src/admin/ui/plugin.ts +2 -2
- package/src/admin/ui/src/components/EarnVaultForm.tsx +137 -0
- package/src/admin/ui/src/components/MobileProfile.tsx +2 -2
- package/src/admin/ui/src/components/Page.tsx +1 -1
- package/src/admin/ui/src/components/ThemeToggle.tsx +1 -1
- package/src/admin/ui/src/lib/api-keys.ts +37 -7
- package/src/admin/ui/src/lib/client.ts +1 -1
- package/src/admin/ui/src/lib/config.ts +1 -1
- package/src/admin/ui/src/lib/early-access.ts +8 -9
- package/src/admin/ui/src/lib/earn-vaults.ts +207 -0
- package/src/admin/ui/src/lib/format.ts +13 -0
- package/src/admin/ui/src/lib/organizations.test.ts +14 -4
- package/src/admin/ui/src/lib/organizations.ts +7 -1
- package/src/admin/ui/src/lib/response.ts +22 -0
- package/src/admin/ui/src/lib/scopes.test.ts +19 -11
- package/src/admin/ui/src/lib/scopes.ts +28 -7
- package/src/admin/ui/src/lib/verified-tokens.ts +10 -9
- package/src/admin/ui/src/routeTree.gen.ts +70 -7
- package/src/admin/ui/src/router.tsx +2 -2
- package/src/admin/ui/src/routes/__root.tsx +9 -8
- package/src/admin/ui/src/routes/api-keys.tsx +475 -64
- package/src/admin/ui/src/routes/early-access.tsx +5 -12
- package/src/admin/ui/src/routes/earn.vaults.tsx +348 -0
- package/src/admin/ui/src/routes/earn.vaults_.$vaultId.edit.tsx +154 -0
- package/src/admin/ui/src/routes/earn.vaults_.new.tsx +190 -0
- package/src/admin/ui/src/routes/organizations.tsx +4 -7
- package/src/admin/ui/src/routes/organizations_.$orgId.tsx +56 -54
- package/src/admin/ui/src/routes/verified-tokens.tsx +4 -4
- package/src/admin/ui/vite.config.ts +4 -1
- package/src/admin/ui.generated.ts +113 -43
- package/src/analytics/Analytics.test.ts +69 -10
- package/src/analytics/Analytics.ts +20 -1
- package/src/analytics/tables/requestEvents.ts +79 -37
- package/src/apps/Zones.test.ts +33 -0
- package/src/apps/Zones.ts +40 -0
- package/src/apps/composition.test.ts +84 -1
- package/src/apps/data/App.test.ts +28 -11
- package/src/apps/data/App.ts +96 -33
- package/src/apps/data/FxOracle.ts +1 -1
- package/src/apps/data/index.ts +0 -1
- package/src/apps/data/routes/activities.test.ts +82 -6
- package/src/apps/data/routes/activities.ts +131 -71
- package/src/apps/data/routes/balances.test.ts +50 -37
- package/src/apps/data/routes/balances.ts +5 -5
- package/src/apps/data/routes/blocks.test.ts +2 -0
- package/src/apps/data/routes/coingecko.test.ts +22 -0
- package/src/apps/data/routes/coingecko.ts +84 -48
- package/src/apps/data/routes/earn.test.ts +1108 -0
- package/src/apps/data/routes/earn.ts +1391 -0
- package/src/apps/data/routes/exchanges.test.ts +82 -33
- package/src/apps/data/routes/exchanges.ts +842 -227
- package/src/apps/data/routes/fee-amm.test.ts +4 -6
- package/src/apps/data/routes/fee-amm.ts +69 -12
- package/src/apps/data/routes/funding.test.ts +2712 -221
- package/src/apps/data/routes/funding.ts +1604 -387
- package/src/apps/data/routes/indexer.test.ts +43 -34
- package/src/apps/data/routes/indexer.ts +19 -2
- package/src/apps/data/routes/receipts.test.ts +5 -3
- package/src/apps/data/routes/receipts.ts +13 -11
- package/src/apps/data/routes/rpc.test.ts +446 -28
- package/src/apps/data/routes/rpc.ts +243 -25
- package/src/apps/data/routes/tokenlist.ts +72 -19
- package/src/apps/data/routes/tokens.ts +258 -86
- package/src/apps/data/routes/transactions.test.ts +2 -0
- package/src/apps/data/routes/transactions.ts +77 -42
- package/src/apps/data/routes/transfers.test.ts +166 -4
- package/src/apps/data/routes/transfers.ts +216 -78
- package/src/apps/data/routes/valuation.test.ts +62 -9
- package/src/apps/data/routes/valuation.ts +2 -2
- package/src/apps/data/routes/webhooks.test.ts +386 -43
- package/src/apps/data/routes/webhooks.ts +172 -71
- package/src/apps/data/routes/zones.test.ts +473 -0
- package/src/apps/data/routes/zones.ts +338 -0
- package/src/apps/docs/reference.ts +8 -6
- package/src/apps/index.ts +2 -1
- package/src/apps/management/Billing.test.ts +29 -0
- package/src/apps/management/Billing.ts +23 -0
- package/src/apps/management/Error.ts +12 -0
- package/src/apps/management/routes/api-keys.test.ts +5 -3
- package/src/apps/management/routes/api-keys.ts +2 -9
- package/src/apps/management/routes/invitations.ts +4 -11
- package/src/apps/management/routes/orgs.ts +2 -9
- package/src/apps/management/routes/scopes.test.ts +7 -2
- package/src/apps/management/routes/scopes.ts +2 -2
- package/src/apps/management/routes/webhooks.test.ts +6 -1
- package/src/apps/management/routes/webhooks.ts +15 -3
- package/src/apps/mpp/App.ts +276 -29
- package/src/apps/mpp/Mpp.test.ts +631 -26
- package/src/apps/mpp/Mpp.ts +0 -42
- package/src/apps/mpp/internal/Adapter.ts +108 -3
- package/src/apps/mpp/internal/Error.test.ts +33 -0
- package/src/apps/mpp/internal/Error.ts +44 -6
- package/src/apps/mpp/internal/Idempotency.test.ts +213 -0
- package/src/apps/mpp/internal/Idempotency.ts +59 -5
- package/src/apps/mpp/internal/Policy.test.ts +122 -0
- package/src/apps/mpp/internal/Policy.ts +98 -0
- package/src/apps/mpp/internal/ScreenManager.test.ts +68 -0
- package/src/apps/mpp/internal/ScreenManager.ts +41 -0
- package/src/apps/mpp/internal/Screening.ts +40 -3
- package/src/apps/mpp/internal/Sponsorship.ts +144 -0
- package/src/apps/mpp/internal/Utils.ts +30 -0
- package/src/apps/relay/App.test.ts +493 -62
- package/src/apps/relay/App.ts +233 -23
- package/src/apps/relay/Sponsorships.test.ts +49 -0
- package/src/apps/relay/Sponsorships.ts +18 -6
- package/src/db/Db.ts +439 -0
- package/src/db/Schema.ts +325 -2
- package/src/db/tables/earnVaults.test.ts +185 -0
- package/src/db/tables/earnVaults.ts +151 -0
- package/src/db/tables/fundingCatalog.test.ts +108 -0
- package/src/db/tables/fundingCatalog.ts +157 -0
- package/src/db/tables/fundingDepositAddresses.test.ts +580 -0
- package/src/db/tables/fundingDepositAddresses.ts +376 -0
- package/src/db/tables/fundingDeposits.test.ts +261 -0
- package/src/db/tables/fundingDeposits.ts +229 -0
- package/src/db/tables/fundingIdempotency.test.ts +182 -0
- package/src/db/tables/fundingIdempotency.ts +180 -0
- package/src/db/tables/fundingTransferEvents.ts +28 -0
- package/src/db/tables/fundingTransferTransactions.test.ts +69 -0
- package/src/db/tables/fundingTransferTransactions.ts +37 -0
- package/src/db/tables/fundingTransfers.test.ts +89 -0
- package/src/db/tables/fundingTransfers.ts +153 -0
- package/src/db/tables/organizations.ts +16 -0
- package/src/db/tables/projects.ts +16 -0
- package/src/db/tables/requestUsage.ts +23 -0
- package/src/db/tables/sponsoredTransactions.test.ts +11 -0
- package/src/db/tables/sponsoredTransactions.ts +3 -3
- package/src/db/tables/users.ts +16 -0
- package/src/db/tables/verifiedTokens.ts +19 -14
- package/src/db/tables/webhookSubscriptions.ts +58 -3
- package/src/handlers/relay.test.ts +2 -0
- package/src/handlers/relay.ts +95 -99
- package/src/internal/Auth.test.ts +48 -0
- package/src/internal/Auth.ts +61 -2
- package/src/internal/Cache.ts +13 -9
- package/src/internal/Cursor.test.ts +2 -2
- package/src/internal/Cursor.ts +1 -1
- package/src/internal/EarnRates.test.ts +125 -0
- package/src/internal/EarnRates.ts +409 -0
- package/src/internal/EarnVaults.test.ts +195 -0
- package/src/internal/EarnVaults.ts +876 -0
- package/src/internal/EdgeCache.test.ts +19 -0
- package/src/internal/EdgeCache.ts +35 -5
- package/src/internal/Id.ts +14 -0
- package/src/internal/Idempotency.test.ts +109 -0
- package/src/internal/Idempotency.ts +237 -0
- package/src/internal/Log.test-d.ts +41 -8
- package/src/internal/Log.test.ts +189 -8
- package/src/internal/Log.ts +124 -17
- package/src/internal/MetricSink.test.ts +244 -4
- package/src/internal/MetricSink.ts +51 -1
- package/src/internal/OpenApi.ts +3 -0
- package/src/internal/Provider.test.ts +17 -0
- package/src/internal/Provider.ts +17 -0
- package/src/internal/Schema.ts +27 -17
- package/src/internal/Store.test.ts +25 -0
- package/src/internal/Store.ts +46 -0
- package/src/internal/Tidx.local.test.ts +78 -3
- package/src/internal/Tidx.test.ts +212 -18
- package/src/internal/Tidx.ts +112 -32
- package/src/internal/VerifiedTokens.test.ts +15 -0
- package/src/internal/Viem.test.ts +170 -17
- package/src/internal/Viem.ts +111 -28
- package/src/internal/WebhookDestination.ts +25 -23
- package/src/internal/Webhooks.test.ts +59 -0
- package/src/internal/Webhooks.ts +34 -10
- package/src/internal/exchange/Provider.test.ts +216 -0
- package/src/internal/exchange/Provider.ts +326 -0
- package/src/internal/exchange/index.test.ts +6 -0
- package/src/internal/exchange/index.ts +1 -0
- package/src/internal/exchange/providers/uniswap.test.ts +122 -0
- package/src/internal/exchange/providers/uniswap.ts +682 -0
- package/src/internal/funding/Action.test.ts +138 -0
- package/src/internal/funding/Action.ts +117 -0
- package/src/internal/funding/Catalog.test.ts +311 -0
- package/src/internal/funding/Catalog.ts +347 -0
- package/src/internal/funding/Chain.test.ts +79 -0
- package/src/internal/funding/Chain.ts +120 -0
- package/src/internal/funding/Deposit.test.ts +26 -0
- package/src/internal/funding/Deposit.ts +453 -0
- package/src/internal/funding/DepositAddress.test.ts +18 -0
- package/src/internal/funding/DepositAddress.ts +312 -0
- package/src/internal/funding/Evidence.test.ts +297 -0
- package/src/internal/funding/Evidence.ts +430 -0
- package/src/internal/funding/Provider.test.ts +1328 -0
- package/src/internal/funding/Provider.ts +1796 -0
- package/src/internal/funding/Reconciliation.local.test.ts +504 -0
- package/src/internal/funding/Reconciliation.test.ts +2020 -0
- package/src/internal/funding/Reconciliation.ts +930 -0
- package/src/internal/funding/Route.test.ts +66 -0
- package/src/internal/funding/Route.ts +29 -0
- package/src/internal/funding/Subsidy.local.test.ts +152 -0
- package/src/internal/funding/Subsidy.test.ts +75 -0
- package/src/internal/funding/Subsidy.ts +260 -0
- package/src/internal/funding/Token.test.ts +47 -0
- package/src/internal/funding/Token.ts +59 -0
- package/src/internal/funding/Transfer.test.ts +369 -0
- package/src/internal/funding/Transfer.ts +522 -0
- package/src/internal/funding/index.test.ts +20 -0
- package/src/internal/funding/index.ts +12 -0
- package/src/internal/funding/providers/across.ts +149 -0
- package/src/{apps/data/FundingQuoteProviders.test.ts → internal/funding/providers/index.test.ts} +178 -157
- package/src/internal/funding/providers/relay.test.ts +474 -0
- package/src/internal/funding/providers/relay.ts +559 -0
- package/src/internal/funding/providers/rhino.ts +139 -0
- package/src/internal/funding/providers/squid.ts +151 -0
- package/src/internal/funding/providers/symbiosis.ts +221 -0
- package/src/internal/index.test.ts +5 -1
- package/src/internal/index.ts +5 -1
- package/src/internal/webhookDestinations/url.ts +49 -45
- package/src/providers/index.test.ts +14 -0
- package/src/providers/index.ts +54 -0
- package/dist/apps/data/FundingQuoteProviders.d.ts +0 -174
- package/dist/apps/data/FundingQuoteProviders.d.ts.map +0 -1
- package/dist/apps/data/FundingQuoteProviders.js +0 -775
- package/dist/apps/data/FundingQuoteProviders.js.map +0 -1
- package/dist/internal/FundingQuotes.d.ts +0 -864
- package/dist/internal/FundingQuotes.d.ts.map +0 -1
- package/dist/internal/FundingQuotes.js +0 -672
- package/dist/internal/FundingQuotes.js.map +0 -1
- package/src/apps/data/FundingQuoteProviders.ts +0 -1043
- package/src/internal/FundingQuotes.test.ts +0 -456
- package/src/internal/FundingQuotes.ts +0 -944
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { Hono } from 'hono';
|
|
2
2
|
import { AbiError, AbiEvent } from 'ox';
|
|
3
|
-
import { BaseError, ContractFunctionRevertedError, decodeFunctionData, parseAbi, } from 'viem';
|
|
3
|
+
import { BaseError, ContractFunctionRevertedError, decodeFunctionData, parseAbi, parseEventLogs, } from 'viem';
|
|
4
4
|
import { Abis, Actions, Addresses, Tick } from 'viem/tempo';
|
|
5
5
|
import * as z from 'zod/mini';
|
|
6
6
|
import * as Auth from '../../../internal/Auth.js';
|
|
7
7
|
import * as Cache from '../../../internal/Cache.js';
|
|
8
8
|
import * as Cursor from '../../../internal/Cursor.js';
|
|
9
|
+
import * as ExchangeProvider from '../../../internal/exchange/Provider.js';
|
|
9
10
|
import * as OpenApi from '../../../internal/OpenApi.js';
|
|
10
11
|
import * as Response from '../../../internal/Response.js';
|
|
11
12
|
import * as Schema from '../../../internal/Schema.js';
|
|
@@ -21,6 +22,8 @@ import * as Valuation from './valuation.js';
|
|
|
21
22
|
// this address; the indexer pre-decodes those into the `dex_pairs` table.
|
|
22
23
|
const stablecoinDex = Addresses.stablecoinDex.toLowerCase();
|
|
23
24
|
const contractPausedSelector = AbiError.getSelector(AbiError.fromAbi(Abis.tip20, 'ContractPaused'));
|
|
25
|
+
/** Largest amount accepted by TIP-20 and external uint256 provider contracts. */
|
|
26
|
+
const maxProviderAmount = 2n ** 256n - 1n;
|
|
24
27
|
// `OrderCancelled(uint128 orderId)` — emitted when a maker cancels a resting
|
|
25
28
|
// order. Used by the orders endpoint to exclude cancelled orders from the
|
|
26
29
|
// resting set.
|
|
@@ -181,19 +184,19 @@ export var schema;
|
|
|
181
184
|
const ValuedAmount = z.extend(Schema.TokenAmount, {
|
|
182
185
|
valuation: z
|
|
183
186
|
.optional(z.nullable(Valuation.schema.Value))
|
|
184
|
-
.check(z.describe('The amount’s nominal value in the requested `
|
|
187
|
+
.check(z.describe('The amount’s nominal value in the requested `valuation.currency`. `null` when the token is ' +
|
|
185
188
|
'unverified, its display currency has no rate, or rates were unavailable.')),
|
|
186
189
|
});
|
|
187
|
-
/** Schemas for creating an executable
|
|
190
|
+
/** Schemas for creating an executable exchange quote. */
|
|
188
191
|
let createQuote;
|
|
189
192
|
(function (createQuote) {
|
|
190
193
|
const DestinationTokenAddress = Schema.tokenAddress(exampleBase);
|
|
191
194
|
const SourceTokenAddress = Schema.tokenAddress(exampleSourceToken);
|
|
192
|
-
/** Positive token amount accepted by
|
|
195
|
+
/** Positive token amount accepted by exchange providers. */
|
|
193
196
|
createQuote.Amount = Schema.DecimalString.check(z.refine((value) => {
|
|
194
197
|
const amount = BigInt(value);
|
|
195
|
-
return amount > 0n && amount <=
|
|
196
|
-
}, { error: 'Amount must be
|
|
198
|
+
return amount > 0n && amount <= maxProviderAmount;
|
|
199
|
+
}, { error: 'Amount must be a positive uint256.' }), z.describe('Positive token amount in the token’s smallest unit, encoded as a decimal string.'), z.meta({ examples: ['1000000'] }));
|
|
197
200
|
/** Optional token fields that require sources beyond RPC metadata. */
|
|
198
201
|
createQuote.Include = z
|
|
199
202
|
.enum(tokenFields)
|
|
@@ -204,13 +207,16 @@ export var schema;
|
|
|
204
207
|
createQuote.Query = z
|
|
205
208
|
.strictObject({
|
|
206
209
|
chainId: Schema.ChainIdQuery,
|
|
207
|
-
denomination: Schema.Denomination,
|
|
208
210
|
include: createQuote.includeQuery,
|
|
211
|
+
'valuation.currency': Schema.Denomination,
|
|
209
212
|
})
|
|
210
|
-
.check(z.describe('Query parameters for creating
|
|
213
|
+
.check(z.describe('Query parameters for creating an exchange quote.'));
|
|
211
214
|
/** Quote request with one pinned side and caller-selected slippage. */
|
|
212
215
|
createQuote.Request = z
|
|
213
216
|
.strictObject({
|
|
217
|
+
account: z
|
|
218
|
+
.optional(Schema.Address)
|
|
219
|
+
.check(z.describe('Wallet that will sign and execute the swap.'), z.meta({ examples: ['0x1111111111111111111111111111111111111111'] })),
|
|
214
220
|
amount: createQuote.Amount.check(z.describe('Pinned amount in base units: source amount for `exactSource`, destination amount for `exactDestination`.')),
|
|
215
221
|
destinationToken: DestinationTokenAddress.check(z.describe('TIP-20 token the swap receives.')),
|
|
216
222
|
mode: z
|
|
@@ -223,13 +229,13 @@ export var schema;
|
|
|
223
229
|
})
|
|
224
230
|
.check(z.refine((request) => request.sourceToken !== request.destinationToken, {
|
|
225
231
|
error: 'Source and destination tokens must differ.',
|
|
226
|
-
}), z.describe('Request for an executable quote
|
|
232
|
+
}), z.describe('Request for an executable quote from the configured exchange providers.'));
|
|
227
233
|
/** One call in the unsigned Tempo transaction plan. */
|
|
228
234
|
createQuote.Call = z
|
|
229
235
|
.object({
|
|
230
|
-
data: Schema.Hex.check(z.describe('ABI-encoded call data.')),
|
|
231
|
-
to: Schema.Address.check(z.describe('Contract or precompile that receives the call.')),
|
|
232
|
-
value: Schema.Quantity.check(z.describe('Native token value sent with the call
|
|
236
|
+
data: Schema.Hex.check(z.describe('ABI-encoded call data.'), z.meta({ examples: ['0x095ea7b3'] })),
|
|
237
|
+
to: Schema.Address.check(z.describe('Contract or precompile that receives the call.'), z.meta({ examples: [Addresses.stablecoinDex] })),
|
|
238
|
+
value: Schema.Quantity.check(z.describe('Native token value sent with the call.'), z.meta({ examples: ['0x0'] })),
|
|
233
239
|
})
|
|
234
240
|
.check(z.describe('One unsigned call in the Tempo transaction plan.'));
|
|
235
241
|
const QuoteToken = Schema.describe(z.partial(z.omit(Tokens.schema.Token, { id: true }), {
|
|
@@ -242,9 +248,9 @@ export var schema;
|
|
|
242
248
|
const SourceToken = z.extend(QuoteToken, {
|
|
243
249
|
address: SourceTokenAddress.check(z.describe('TIP-20 token the swap spends.')),
|
|
244
250
|
});
|
|
245
|
-
|
|
251
|
+
createQuote.Transaction = z
|
|
246
252
|
.object({
|
|
247
|
-
calls: z.array(createQuote.Call).check(z.
|
|
253
|
+
calls: z.array(createQuote.Call).check(z.minLength(1), z.describe('Calls to execute in order.'), z.meta({
|
|
248
254
|
examples: [
|
|
249
255
|
[
|
|
250
256
|
{
|
|
@@ -262,41 +268,161 @@ export var schema;
|
|
|
262
268
|
/** Response-level valuation rate provenance. */
|
|
263
269
|
createQuote.Meta = z
|
|
264
270
|
.object({
|
|
265
|
-
|
|
271
|
+
valuation: z
|
|
266
272
|
.optional(Valuation.schema.Pricing)
|
|
267
273
|
.check(z.describe('Rate provenance for amount valuations. Present when conversion rates were consulted.')),
|
|
268
274
|
})
|
|
269
275
|
.check(z.describe('Response-level resources attached to this quote.'));
|
|
270
|
-
/**
|
|
271
|
-
createQuote.
|
|
272
|
-
.
|
|
273
|
-
z.
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
276
|
+
/** Provider-neutral EIP-712 payload to sign before finalizing a quote. */
|
|
277
|
+
createQuote.TypedData = z
|
|
278
|
+
.object({
|
|
279
|
+
domain: z.record(z.string(), z.unknown()).check(z.describe('EIP-712 signing domain.'), z.meta({
|
|
280
|
+
examples: [
|
|
281
|
+
{
|
|
282
|
+
chainId: 4217,
|
|
283
|
+
name: 'Permit2',
|
|
284
|
+
verifyingContract: '0x000000000022d473030f116ddee9f6b43ac78ba3',
|
|
285
|
+
},
|
|
286
|
+
],
|
|
287
|
+
})),
|
|
288
|
+
message: z.record(z.string(), z.unknown()).check(z.describe('Values encoded by the primary EIP-712 type.'), z.meta({
|
|
289
|
+
examples: [
|
|
290
|
+
{
|
|
291
|
+
details: {
|
|
292
|
+
amount: '1000000',
|
|
293
|
+
expiration: '4102444800',
|
|
294
|
+
nonce: '0',
|
|
295
|
+
token: exampleSourceToken,
|
|
296
|
+
},
|
|
297
|
+
sigDeadline: '4102444800',
|
|
298
|
+
spender: '0x1febb76be10aaf3a1402f04e8e835f2c382f7914',
|
|
299
|
+
},
|
|
300
|
+
],
|
|
301
|
+
})),
|
|
302
|
+
primaryType: z
|
|
303
|
+
.string()
|
|
304
|
+
.check(z.minLength(1))
|
|
305
|
+
.check(z.describe('Root EIP-712 type.'), z.meta({ examples: ['PermitSingle'] })),
|
|
306
|
+
types: z
|
|
307
|
+
.record(z.string(), z.array(z.strictObject({
|
|
308
|
+
name: z.string(),
|
|
309
|
+
type: z.string(),
|
|
310
|
+
})))
|
|
311
|
+
.check(z.describe('EIP-712 type definitions keyed by type name.'), z.meta({
|
|
312
|
+
examples: [
|
|
313
|
+
{
|
|
314
|
+
PermitDetails: [
|
|
315
|
+
{ name: 'token', type: 'address' },
|
|
316
|
+
{ name: 'amount', type: 'uint160' },
|
|
317
|
+
{ name: 'expiration', type: 'uint48' },
|
|
318
|
+
{ name: 'nonce', type: 'uint48' },
|
|
319
|
+
],
|
|
320
|
+
PermitSingle: [
|
|
321
|
+
{ name: 'details', type: 'PermitDetails' },
|
|
322
|
+
{ name: 'spender', type: 'address' },
|
|
323
|
+
{ name: 'sigDeadline', type: 'uint256' },
|
|
324
|
+
],
|
|
325
|
+
},
|
|
326
|
+
],
|
|
327
|
+
})),
|
|
328
|
+
})
|
|
329
|
+
.check(z.describe('EIP-712 payload the wallet must sign before execution can continue.'));
|
|
330
|
+
const Provider = z
|
|
331
|
+
.string()
|
|
332
|
+
.check(z.describe('Provider selected for this route.'), z.meta({ examples: ['nativeDex'] }));
|
|
333
|
+
const Quote = {
|
|
334
|
+
gasEstimate: Schema.DecimalString.check(z.describe('Estimated network fee in the chain native token’s base unit.'), z.meta({ examples: ['150000000000000'] })),
|
|
335
|
+
provider: Provider,
|
|
336
|
+
};
|
|
337
|
+
const ApprovalRequired = {
|
|
338
|
+
approval: z.object({
|
|
339
|
+
calls: z.array(createQuote.Call).check(z.minLength(1), z.describe('Approval calls to confirm before requesting a fresh quote.'), z.meta({
|
|
340
|
+
examples: [
|
|
341
|
+
[
|
|
342
|
+
{
|
|
343
|
+
data: exampleApprovalCall.data,
|
|
344
|
+
to: exampleApprovalCall.to,
|
|
345
|
+
value: '0x0',
|
|
346
|
+
},
|
|
347
|
+
],
|
|
348
|
+
],
|
|
349
|
+
})),
|
|
296
350
|
}),
|
|
351
|
+
status: z
|
|
352
|
+
.literal('approvalRequired')
|
|
353
|
+
.check(z.describe('Confirm the approvals, then request a fresh quote.'), z.meta({ examples: ['approvalRequired'] })),
|
|
354
|
+
};
|
|
355
|
+
const Ready = {
|
|
356
|
+
status: z
|
|
357
|
+
.literal('ready')
|
|
358
|
+
.check(z.describe('The returned calls can be executed now.'), z.meta({ examples: ['ready'] })),
|
|
359
|
+
transaction: createQuote.Transaction,
|
|
360
|
+
};
|
|
361
|
+
const SignatureRequired = {
|
|
362
|
+
continuation: z
|
|
363
|
+
.string()
|
|
364
|
+
.check(z.minLength(1), z.describe('Opaque state supplied to the finalization endpoint within 30 seconds.'), z.meta({ examples: ['eyJwcm92aWRlciI6InVuaXN3YXAifQ'] })),
|
|
365
|
+
status: z
|
|
366
|
+
.literal('signatureRequired')
|
|
367
|
+
.check(z.describe('Sign the typed data before final calldata can be built.'), z.meta({ examples: ['signatureRequired'] })),
|
|
368
|
+
typedData: createQuote.TypedData,
|
|
369
|
+
};
|
|
370
|
+
const ExactSource = {
|
|
371
|
+
destinationAmount: ValuedAmount.check(z.describe('Quoted destination amount.')),
|
|
372
|
+
destinationAmountMin: ValuedAmount.check(z.describe('Minimum destination amount after slippage.')),
|
|
373
|
+
destinationToken: DestinationToken,
|
|
374
|
+
meta: z.optional(createQuote.Meta).check(z.describe('Valuation rate provenance for this quote.')),
|
|
375
|
+
mode: z
|
|
376
|
+
.literal('exactSource')
|
|
377
|
+
.check(z.describe('The source amount is fixed and the destination has a minimum.'), z.meta({ examples: ['exactSource'] })),
|
|
378
|
+
sourceAmount: ValuedAmount.check(z.describe('Exact source amount.')),
|
|
379
|
+
sourceToken: SourceToken.check(z.describe('Token spent by the swap.')),
|
|
380
|
+
};
|
|
381
|
+
const ExactDestination = {
|
|
382
|
+
destinationAmount: ValuedAmount.check(z.describe('Exact destination amount.')),
|
|
383
|
+
destinationToken: DestinationToken.check(z.describe('Token received by the swap.')),
|
|
384
|
+
meta: z.optional(createQuote.Meta).check(z.describe('Valuation rate provenance for this quote.')),
|
|
385
|
+
mode: z
|
|
386
|
+
.literal('exactDestination')
|
|
387
|
+
.check(z.describe('The destination amount is fixed and the source has a maximum.'), z.meta({ examples: ['exactDestination'] })),
|
|
388
|
+
sourceAmount: ValuedAmount.check(z.describe('Quoted source amount.')),
|
|
389
|
+
sourceAmountMax: ValuedAmount.check(z.describe('Maximum source amount after slippage.')),
|
|
390
|
+
sourceToken: SourceToken,
|
|
391
|
+
};
|
|
392
|
+
/** Provider-neutral quote and the action needed to execute it. */
|
|
393
|
+
createQuote.Response = z
|
|
394
|
+
.union([
|
|
395
|
+
z.object({ ...ApprovalRequired, ...ExactSource, ...Quote }),
|
|
396
|
+
z.object({ ...ExactSource, ...Quote, ...Ready }),
|
|
397
|
+
z.object({ ...ExactSource, ...Quote, ...SignatureRequired }),
|
|
398
|
+
z.object({ ...ApprovalRequired, ...ExactDestination, ...Quote }),
|
|
399
|
+
z.object({ ...ExactDestination, ...Quote, ...Ready }),
|
|
400
|
+
z.object({ ...ExactDestination, ...Quote, ...SignatureRequired }),
|
|
297
401
|
])
|
|
298
|
-
.check(z.describe('
|
|
402
|
+
.check(z.describe('Provider-neutral exchange quote with its next execution action.'));
|
|
299
403
|
})(createQuote = schema.createQuote || (schema.createQuote = {}));
|
|
404
|
+
/** Schemas for finishing a quote after a provider-requested signature. */
|
|
405
|
+
let executeQuote;
|
|
406
|
+
(function (executeQuote) {
|
|
407
|
+
/** Signed continuation request. */
|
|
408
|
+
executeQuote.Request = z.strictObject({
|
|
409
|
+
account: Schema.Address.check(z.describe('Wallet that signed and will execute the swap.'), z.meta({ examples: ['0x1111111111111111111111111111111111111111'] })),
|
|
410
|
+
continuation: z
|
|
411
|
+
.string()
|
|
412
|
+
.check(z.minLength(1), z.maxLength(100_000), z.describe('Opaque state returned by the quote request.'), z.meta({ examples: ['eyJwcm92aWRlciI6InVuaXN3YXAifQ'] })),
|
|
413
|
+
provider: z
|
|
414
|
+
.string()
|
|
415
|
+
.check(z.minLength(1), z.describe('Provider that issued the continuation.'), z.meta({ examples: ['uniswap'] })),
|
|
416
|
+
signature: Schema.Hex.check(z.refine((value) => value.length === 132, { error: 'Signature must be 65 bytes.' }), z.describe('65-byte EIP-712 signature requested by the quote.'), z.meta({ examples: [`0x${'11'.repeat(65)}`] })),
|
|
417
|
+
});
|
|
418
|
+
/** Final transaction plan. */
|
|
419
|
+
executeQuote.Response = z.object({
|
|
420
|
+
provider: z
|
|
421
|
+
.string()
|
|
422
|
+
.check(z.describe('Provider that built the transaction.'), z.meta({ examples: ['uniswap'] })),
|
|
423
|
+
transaction: createQuote.Transaction,
|
|
424
|
+
});
|
|
425
|
+
})(executeQuote = schema.executeQuote || (schema.executeQuote = {}));
|
|
300
426
|
/** Schemas for the getPairs operation. */
|
|
301
427
|
let getPairs;
|
|
302
428
|
(function (getPairs) {
|
|
@@ -408,7 +534,6 @@ export var schema;
|
|
|
408
534
|
'blockNumber.to': Schema.blockNumberBound('swaps', 'to'),
|
|
409
535
|
chainId: Schema.ChainIdQuery,
|
|
410
536
|
cursor: Schema.Cursor,
|
|
411
|
-
denomination: Schema.Denomination,
|
|
412
537
|
include: getSwaps.includeQuery,
|
|
413
538
|
limit: Schema.Limit,
|
|
414
539
|
maker: z
|
|
@@ -426,6 +551,7 @@ export var schema;
|
|
|
426
551
|
transactionHash: z
|
|
427
552
|
.optional(Schema.Hash)
|
|
428
553
|
.check(z.describe('Only include swaps included in this transaction hash.')),
|
|
554
|
+
'valuation.currency': Schema.Denomination,
|
|
429
555
|
})
|
|
430
556
|
.check(z.describe('Query parameters for swap feed requests. Cursor-paginated only — a batched ' +
|
|
431
557
|
'transaction expands one fill group into a variable number of swap rows, so a ' +
|
|
@@ -503,7 +629,7 @@ export var schema;
|
|
|
503
629
|
/** Page-level resources: valuation rate provenance. */
|
|
504
630
|
getSwaps.Meta = z
|
|
505
631
|
.object({
|
|
506
|
-
|
|
632
|
+
valuation: z
|
|
507
633
|
.optional(Valuation.schema.Pricing)
|
|
508
634
|
.check(z.describe('Rate provenance for amount valuations. Present when conversion rates were ' +
|
|
509
635
|
'consulted; absent when every value was identity-valued or rates were unavailable.')),
|
|
@@ -953,19 +1079,19 @@ export function exchanges(options = {}) {
|
|
|
953
1079
|
code: 'body_invalid',
|
|
954
1080
|
message: 'Invalid request body',
|
|
955
1081
|
}), OpenApi.describeRoute({
|
|
956
|
-
description: '
|
|
1082
|
+
description: 'Attempts exchange providers in priority order and returns the first executable quote. This endpoint does not submit a transaction.',
|
|
957
1083
|
operationId: 'createExchangeQuote',
|
|
958
1084
|
responses: OpenApi.responses({
|
|
959
1085
|
errors: {
|
|
960
1086
|
400: { codes: ['body_invalid', 'query_invalid', 'quote_amount_out_of_range'] },
|
|
961
1087
|
404: {
|
|
962
1088
|
codes: ['quote_not_available'],
|
|
963
|
-
description: '
|
|
1089
|
+
description: 'No configured provider can price an executable exchange for these terms.',
|
|
964
1090
|
},
|
|
965
1091
|
502: 'The Tempo RPC could not quote the swap or resolve token metadata.',
|
|
966
1092
|
},
|
|
967
1093
|
success: {
|
|
968
|
-
description: 'A
|
|
1094
|
+
description: 'A provider-neutral quote and its next execution action.',
|
|
969
1095
|
schema: schema.createQuote.Response,
|
|
970
1096
|
},
|
|
971
1097
|
}),
|
|
@@ -985,8 +1111,8 @@ export function exchanges(options = {}) {
|
|
|
985
1111
|
message: 'Invalid request body',
|
|
986
1112
|
});
|
|
987
1113
|
const request = c.req.valid('json');
|
|
988
|
-
const
|
|
989
|
-
const chainId =
|
|
1114
|
+
const query = c.req.valid('query');
|
|
1115
|
+
const chainId = query.chainId ?? c.get('chainId');
|
|
990
1116
|
const client = c.get('getClient')(chainId);
|
|
991
1117
|
const amount = BigInt(request.amount);
|
|
992
1118
|
const slippageBps = BigInt(request.slippageBps);
|
|
@@ -994,7 +1120,7 @@ export function exchanges(options = {}) {
|
|
|
994
1120
|
try {
|
|
995
1121
|
// Value quoted amounts via their curated display currency; snapshot
|
|
996
1122
|
// or rate failures degrade the values to `null`, never the quote.
|
|
997
|
-
const denomination =
|
|
1123
|
+
const denomination = query['valuation.currency'] ?? 'USD';
|
|
998
1124
|
const snapshot = await VerifiedTokens.snapshot(c, chainId).catch(() => undefined);
|
|
999
1125
|
const rates = await Valuation.ratesFor(c, {
|
|
1000
1126
|
currencies: snapshot
|
|
@@ -1019,6 +1145,8 @@ export function exchanges(options = {}) {
|
|
|
1019
1145
|
token: snapshot?.byAddress.get(address.toLowerCase()),
|
|
1020
1146
|
}),
|
|
1021
1147
|
});
|
|
1148
|
+
if (options.nativeDex === false || amount > maxSwapAmount)
|
|
1149
|
+
throw new ExchangeProvider.RouteUnavailableError();
|
|
1022
1150
|
if (request.mode === 'exactSource') {
|
|
1023
1151
|
const destinationAmount = await Actions.dex.getSellQuote(client, {
|
|
1024
1152
|
amountIn: amount,
|
|
@@ -1026,7 +1154,7 @@ export function exchanges(options = {}) {
|
|
|
1026
1154
|
tokenOut: request.destinationToken,
|
|
1027
1155
|
});
|
|
1028
1156
|
if (destinationAmount === 0n)
|
|
1029
|
-
|
|
1157
|
+
throw new ExchangeProvider.RouteUnavailableError();
|
|
1030
1158
|
const minimumAmount = (destinationAmount * (slippageDenominator - slippageBps) + slippageDenominator - 1n) /
|
|
1031
1159
|
slippageDenominator;
|
|
1032
1160
|
const approve = Actions.token.approve.call(client, {
|
|
@@ -1040,10 +1168,19 @@ export function exchanges(options = {}) {
|
|
|
1040
1168
|
tokenIn: request.sourceToken,
|
|
1041
1169
|
tokenOut: request.destinationToken,
|
|
1042
1170
|
});
|
|
1043
|
-
const
|
|
1171
|
+
const calls = [
|
|
1172
|
+
{ data: approve.data, to: approve.to, value: 0n },
|
|
1173
|
+
{ data: swap.data, to: swap.to, value: 0n },
|
|
1174
|
+
];
|
|
1175
|
+
const gasUnits = await client.estimateGas({
|
|
1176
|
+
...(request.account ? { account: request.account } : {}),
|
|
1177
|
+
calls,
|
|
1178
|
+
});
|
|
1179
|
+
const gasPrice = await client.getGasPrice();
|
|
1180
|
+
const tokensByAddress = await Tokens.resolveTokens(c, {
|
|
1044
1181
|
addresses: [request.destinationToken, request.sourceToken],
|
|
1045
1182
|
chainId,
|
|
1046
|
-
include:
|
|
1183
|
+
include: query.include,
|
|
1047
1184
|
});
|
|
1048
1185
|
const destinationToken = tokensByAddress.get(request.destinationToken);
|
|
1049
1186
|
const sourceToken = tokensByAddress.get(request.sourceToken);
|
|
@@ -1056,18 +1193,18 @@ export function exchanges(options = {}) {
|
|
|
1056
1193
|
...destinationToken,
|
|
1057
1194
|
address: request.destinationToken,
|
|
1058
1195
|
},
|
|
1059
|
-
...(rates ? { meta: {
|
|
1196
|
+
...(rates ? { meta: { valuation: Valuation.pricing(rates, oracle) } } : {}),
|
|
1197
|
+
gasEstimate: gasCost({ gasPrice, gasUnits }),
|
|
1060
1198
|
mode: request.mode,
|
|
1199
|
+
provider: 'nativeDex',
|
|
1061
1200
|
sourceAmount: valued(request.amount, request.sourceToken, sourceToken),
|
|
1062
1201
|
sourceToken: {
|
|
1063
1202
|
...sourceToken,
|
|
1064
1203
|
address: request.sourceToken,
|
|
1065
1204
|
},
|
|
1205
|
+
status: 'ready',
|
|
1066
1206
|
transaction: {
|
|
1067
|
-
calls:
|
|
1068
|
-
{ data: approve.data, to: approve.to, value: '0x0' },
|
|
1069
|
-
{ data: swap.data, to: swap.to, value: '0x0' },
|
|
1070
|
-
],
|
|
1207
|
+
calls: calls.map((call) => ({ ...call, value: '0x0' })),
|
|
1071
1208
|
chainId,
|
|
1072
1209
|
},
|
|
1073
1210
|
}), 200);
|
|
@@ -1078,14 +1215,11 @@ export function exchanges(options = {}) {
|
|
|
1078
1215
|
tokenOut: request.destinationToken,
|
|
1079
1216
|
});
|
|
1080
1217
|
if (sourceAmount === 0n)
|
|
1081
|
-
|
|
1082
|
-
const maximumAmount = (sourceAmount * (slippageDenominator + slippageBps)) /
|
|
1218
|
+
throw new ExchangeProvider.RouteUnavailableError();
|
|
1219
|
+
const maximumAmount = (sourceAmount * (slippageDenominator + slippageBps) + slippageDenominator - 1n) /
|
|
1220
|
+
slippageDenominator;
|
|
1083
1221
|
if (maximumAmount > maxSwapAmount)
|
|
1084
|
-
|
|
1085
|
-
code: 'quote_amount_out_of_range',
|
|
1086
|
-
message: 'Slippage-adjusted source amount exceeds the native DEX limit',
|
|
1087
|
-
status: 400,
|
|
1088
|
-
});
|
|
1222
|
+
throw new NativeDexAmountOutOfRangeError();
|
|
1089
1223
|
const approve = Actions.token.approve.call(client, {
|
|
1090
1224
|
amount: maximumAmount,
|
|
1091
1225
|
spender: Addresses.stablecoinDex,
|
|
@@ -1097,10 +1231,19 @@ export function exchanges(options = {}) {
|
|
|
1097
1231
|
tokenIn: request.sourceToken,
|
|
1098
1232
|
tokenOut: request.destinationToken,
|
|
1099
1233
|
});
|
|
1100
|
-
const
|
|
1234
|
+
const calls = [
|
|
1235
|
+
{ data: approve.data, to: approve.to, value: 0n },
|
|
1236
|
+
{ data: swap.data, to: swap.to, value: 0n },
|
|
1237
|
+
];
|
|
1238
|
+
const gasUnits = await client.estimateGas({
|
|
1239
|
+
...(request.account ? { account: request.account } : {}),
|
|
1240
|
+
calls,
|
|
1241
|
+
});
|
|
1242
|
+
const gasPrice = await client.getGasPrice();
|
|
1243
|
+
const tokensByAddress = await Tokens.resolveTokens(c, {
|
|
1101
1244
|
addresses: [request.destinationToken, request.sourceToken],
|
|
1102
1245
|
chainId,
|
|
1103
|
-
include:
|
|
1246
|
+
include: query.include,
|
|
1104
1247
|
});
|
|
1105
1248
|
const destinationToken = tokensByAddress.get(request.destinationToken);
|
|
1106
1249
|
const sourceToken = tokensByAddress.get(request.sourceToken);
|
|
@@ -1112,34 +1255,184 @@ export function exchanges(options = {}) {
|
|
|
1112
1255
|
...destinationToken,
|
|
1113
1256
|
address: request.destinationToken,
|
|
1114
1257
|
},
|
|
1115
|
-
...(rates ? { meta: {
|
|
1258
|
+
...(rates ? { meta: { valuation: Valuation.pricing(rates, oracle) } } : {}),
|
|
1259
|
+
gasEstimate: gasCost({ gasPrice, gasUnits }),
|
|
1116
1260
|
mode: request.mode,
|
|
1261
|
+
provider: 'nativeDex',
|
|
1117
1262
|
sourceAmount: valued(sourceAmount, request.sourceToken, sourceToken),
|
|
1118
1263
|
sourceAmountMax: valued(maximumAmount, request.sourceToken, sourceToken),
|
|
1119
1264
|
sourceToken: {
|
|
1120
1265
|
...sourceToken,
|
|
1121
1266
|
address: request.sourceToken,
|
|
1122
1267
|
},
|
|
1268
|
+
status: 'ready',
|
|
1123
1269
|
transaction: {
|
|
1124
|
-
calls:
|
|
1125
|
-
{ data: approve.data, to: approve.to, value: '0x0' },
|
|
1126
|
-
{ data: swap.data, to: swap.to, value: '0x0' },
|
|
1127
|
-
],
|
|
1270
|
+
calls: calls.map((call) => ({ ...call, value: '0x0' })),
|
|
1128
1271
|
chainId,
|
|
1129
1272
|
},
|
|
1130
1273
|
}), 200);
|
|
1131
1274
|
}
|
|
1132
1275
|
catch (cause) {
|
|
1133
|
-
if (
|
|
1276
|
+
if (cause instanceof Valuation.UnsupportedDenominationError)
|
|
1277
|
+
return Response.error(c, { code: 'query_invalid', message: cause.message, status: 400 });
|
|
1278
|
+
const amountOutOfRange = cause instanceof NativeDexAmountOutOfRangeError ||
|
|
1279
|
+
(request.mode === 'exactSource' && isQuoteAmountOutOfRange(cause));
|
|
1280
|
+
const providers = c.get('providers').filter(ExchangeProvider.is);
|
|
1281
|
+
if (amountOutOfRange && providers.length === 0)
|
|
1134
1282
|
return Response.error(c, {
|
|
1135
1283
|
code: 'quote_amount_out_of_range',
|
|
1136
1284
|
message: 'Quote amount exceeds the native DEX limit',
|
|
1137
1285
|
status: 400,
|
|
1138
1286
|
});
|
|
1139
|
-
if (
|
|
1287
|
+
if (!(cause instanceof ExchangeProvider.RouteUnavailableError) &&
|
|
1288
|
+
!isQuoteUnavailable(cause) &&
|
|
1289
|
+
!amountOutOfRange)
|
|
1290
|
+
return Response.upstream(c, cause);
|
|
1291
|
+
if (!request.account)
|
|
1140
1292
|
return quoteNotAvailable(c);
|
|
1141
|
-
|
|
1142
|
-
|
|
1293
|
+
for (const provider of providers)
|
|
1294
|
+
try {
|
|
1295
|
+
const quote = await provider.quote({
|
|
1296
|
+
account: request.account,
|
|
1297
|
+
amount: request.amount,
|
|
1298
|
+
chainId,
|
|
1299
|
+
destinationToken: request.destinationToken,
|
|
1300
|
+
mode: request.mode,
|
|
1301
|
+
slippageBps: request.slippageBps,
|
|
1302
|
+
sourceToken: request.sourceToken,
|
|
1303
|
+
}, c.req.raw.signal);
|
|
1304
|
+
if (quote.status === 'ready')
|
|
1305
|
+
await validateProviderCalls(client, {
|
|
1306
|
+
account: request.account,
|
|
1307
|
+
calls: quote.transaction.calls,
|
|
1308
|
+
execution: providerExecution({ quote, request }),
|
|
1309
|
+
});
|
|
1310
|
+
const [gasPrice, gasUnits] = await Promise.all([
|
|
1311
|
+
client.getGasPrice(),
|
|
1312
|
+
quote.status === 'approvalRequired'
|
|
1313
|
+
? client.estimateGas({
|
|
1314
|
+
account: request.account,
|
|
1315
|
+
calls: quote.approval.calls.map((call) => ({
|
|
1316
|
+
data: call.data,
|
|
1317
|
+
to: call.to,
|
|
1318
|
+
value: BigInt(call.value),
|
|
1319
|
+
})),
|
|
1320
|
+
})
|
|
1321
|
+
: Promise.resolve(BigInt(quote.gasUnits)),
|
|
1322
|
+
]);
|
|
1323
|
+
return c.json(Response.validated(schema.createQuote.Response, await providerQuoteResponse(c, {
|
|
1324
|
+
chainId,
|
|
1325
|
+
gasPrice,
|
|
1326
|
+
gasUnits,
|
|
1327
|
+
include: query.include,
|
|
1328
|
+
oracle,
|
|
1329
|
+
query,
|
|
1330
|
+
quote,
|
|
1331
|
+
request,
|
|
1332
|
+
provider,
|
|
1333
|
+
})), 200);
|
|
1334
|
+
}
|
|
1335
|
+
catch (error) {
|
|
1336
|
+
if (error instanceof ExchangeProvider.RouteUnavailableError)
|
|
1337
|
+
continue;
|
|
1338
|
+
const failure = ExchangeProvider.failure(error, {
|
|
1339
|
+
chainId,
|
|
1340
|
+
operation: 'quote',
|
|
1341
|
+
provider,
|
|
1342
|
+
});
|
|
1343
|
+
if (failure)
|
|
1344
|
+
c.set('providerFailure', failure);
|
|
1345
|
+
return Response.upstream(c, error);
|
|
1346
|
+
}
|
|
1347
|
+
return quoteNotAvailable(c);
|
|
1348
|
+
}
|
|
1349
|
+
})
|
|
1350
|
+
.post('/v1/exchange/quotes/execute', Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }), OpenApi.validate('query', schema.createQuote.Query, {
|
|
1351
|
+
code: 'query_invalid',
|
|
1352
|
+
message: 'Invalid query parameters',
|
|
1353
|
+
}), OpenApi.validate('json', schema.executeQuote.Request, {
|
|
1354
|
+
code: 'body_invalid',
|
|
1355
|
+
message: 'Invalid request body',
|
|
1356
|
+
}), OpenApi.describeRoute({
|
|
1357
|
+
description: 'Finishes a provider quote after the wallet supplies the requested typed-data signature. This endpoint does not submit a transaction.',
|
|
1358
|
+
operationId: 'finalizeExchangeQuote',
|
|
1359
|
+
responses: OpenApi.responses({
|
|
1360
|
+
errors: {
|
|
1361
|
+
400: {
|
|
1362
|
+
codes: [
|
|
1363
|
+
'body_invalid',
|
|
1364
|
+
'query_invalid',
|
|
1365
|
+
'swap_continuation_invalid',
|
|
1366
|
+
'swap_provider_invalid',
|
|
1367
|
+
],
|
|
1368
|
+
},
|
|
1369
|
+
502: 'The selected provider could not build the swap right now.',
|
|
1370
|
+
},
|
|
1371
|
+
success: {
|
|
1372
|
+
description: 'The final unsigned calls needed to execute the swap.',
|
|
1373
|
+
schema: schema.executeQuote.Response,
|
|
1374
|
+
},
|
|
1375
|
+
}),
|
|
1376
|
+
summary: 'Finalize quote',
|
|
1377
|
+
tags: ['Exchange'],
|
|
1378
|
+
}), async (c) => {
|
|
1379
|
+
if (Auth.narrowAccess)
|
|
1380
|
+
return Auth.paidAccessError(c);
|
|
1381
|
+
if (OpenApi.narrowValidation)
|
|
1382
|
+
return OpenApi.validationError(c, {
|
|
1383
|
+
code: 'query_invalid',
|
|
1384
|
+
message: 'Invalid query parameters',
|
|
1385
|
+
});
|
|
1386
|
+
if (OpenApi.narrowValidation)
|
|
1387
|
+
return OpenApi.validationError(c, {
|
|
1388
|
+
code: 'body_invalid',
|
|
1389
|
+
message: 'Invalid request body',
|
|
1390
|
+
});
|
|
1391
|
+
const request = c.req.valid('json');
|
|
1392
|
+
const chainId = c.req.valid('query').chainId ?? c.get('chainId');
|
|
1393
|
+
const provider = c
|
|
1394
|
+
.get('providers')
|
|
1395
|
+
.filter(ExchangeProvider.is)
|
|
1396
|
+
.find((candidate) => candidate.id === request.provider && candidate.finalizeQuote);
|
|
1397
|
+
if (!provider?.finalizeQuote)
|
|
1398
|
+
return Response.error(c, {
|
|
1399
|
+
code: 'swap_provider_invalid',
|
|
1400
|
+
message: 'The selected swap provider is not configured',
|
|
1401
|
+
status: 400,
|
|
1402
|
+
});
|
|
1403
|
+
c.header('Cache-Control', 'no-store');
|
|
1404
|
+
try {
|
|
1405
|
+
const client = c.get('getClient')(chainId);
|
|
1406
|
+
const result = await provider.finalizeQuote({
|
|
1407
|
+
account: request.account,
|
|
1408
|
+
chainId,
|
|
1409
|
+
continuation: request.continuation,
|
|
1410
|
+
signature: request.signature,
|
|
1411
|
+
}, c.req.raw.signal);
|
|
1412
|
+
await validateProviderCalls(client, {
|
|
1413
|
+
account: request.account,
|
|
1414
|
+
calls: result.calls,
|
|
1415
|
+
execution: result.execution,
|
|
1416
|
+
});
|
|
1417
|
+
return c.json(Response.validated(schema.executeQuote.Response, {
|
|
1418
|
+
provider: provider.id,
|
|
1419
|
+
transaction: { calls: result.calls, chainId },
|
|
1420
|
+
}), 200);
|
|
1421
|
+
}
|
|
1422
|
+
catch (cause) {
|
|
1423
|
+
if (cause instanceof ExchangeProvider.ProviderContinuationError)
|
|
1424
|
+
return Response.error(c, {
|
|
1425
|
+
code: 'swap_continuation_invalid',
|
|
1426
|
+
message: 'Invalid swap continuation',
|
|
1427
|
+
status: 400,
|
|
1428
|
+
});
|
|
1429
|
+
const failure = ExchangeProvider.failure(cause, {
|
|
1430
|
+
chainId,
|
|
1431
|
+
operation: 'finalize',
|
|
1432
|
+
provider,
|
|
1433
|
+
});
|
|
1434
|
+
if (failure)
|
|
1435
|
+
c.set('providerFailure', failure);
|
|
1143
1436
|
return Response.upstream(c, cause);
|
|
1144
1437
|
}
|
|
1145
1438
|
})
|
|
@@ -1180,10 +1473,6 @@ export function exchanges(options = {}) {
|
|
|
1180
1473
|
if (options.cursor !== undefined)
|
|
1181
1474
|
Cache.setPolicy(c, Cache.policies.metadata);
|
|
1182
1475
|
try {
|
|
1183
|
-
// The pair index (base address → pair) resolves each fill's book
|
|
1184
|
-
// orientation (the order events only carry the base-side `token`;
|
|
1185
|
-
// the quote is intrinsic to it).
|
|
1186
|
-
const pairIndex = await getPairIndex(c, { chainId });
|
|
1187
1476
|
const page = await getSwaps(c, {
|
|
1188
1477
|
chainId,
|
|
1189
1478
|
cursor: options.cursor,
|
|
@@ -1192,7 +1481,6 @@ export function exchanges(options = {}) {
|
|
|
1192
1481
|
limit: options.limit,
|
|
1193
1482
|
maker: options.maker,
|
|
1194
1483
|
order: options.order,
|
|
1195
|
-
pairIndex,
|
|
1196
1484
|
participant: options.participant,
|
|
1197
1485
|
taker: options.taker,
|
|
1198
1486
|
toBlock: options['blockNumber.to'],
|
|
@@ -1201,14 +1489,14 @@ export function exchanges(options = {}) {
|
|
|
1201
1489
|
});
|
|
1202
1490
|
// `route` spans every swap and fill side, so one lookup resolves each
|
|
1203
1491
|
// token once for required RPC metadata and requested curated fields.
|
|
1204
|
-
const tokensByAddress = await
|
|
1492
|
+
const tokensByAddress = await Tokens.resolveTokens(c, {
|
|
1205
1493
|
addresses: page.data.flatMap((swap) => swap.route),
|
|
1206
1494
|
chainId,
|
|
1207
1495
|
include: options.include,
|
|
1208
1496
|
});
|
|
1209
1497
|
// Value amounts via their curated display currency; snapshot or rate
|
|
1210
1498
|
// failures degrade the values to `null`, never the feed.
|
|
1211
|
-
const denomination = options.
|
|
1499
|
+
const denomination = options['valuation.currency'] ?? 'USD';
|
|
1212
1500
|
const snapshot = page.data.length > 0
|
|
1213
1501
|
? await VerifiedTokens.snapshot(c, chainId).catch(() => undefined)
|
|
1214
1502
|
: undefined;
|
|
@@ -1275,7 +1563,7 @@ export function exchanges(options = {}) {
|
|
|
1275
1563
|
});
|
|
1276
1564
|
return c.json(Response.validated(schema.getSwaps.Response, {
|
|
1277
1565
|
data,
|
|
1278
|
-
...(rates ? { meta: {
|
|
1566
|
+
...(rates ? { meta: { valuation: Valuation.pricing(rates, oracle) } } : {}),
|
|
1279
1567
|
nextCursor: page.nextCursor,
|
|
1280
1568
|
}), 200);
|
|
1281
1569
|
}
|
|
@@ -1352,7 +1640,7 @@ export function exchanges(options = {}) {
|
|
|
1352
1640
|
transactionHash: pair.transactionHash,
|
|
1353
1641
|
}));
|
|
1354
1642
|
if (options.include.includes('tokens') && data.length > 0) {
|
|
1355
|
-
const tokensByAddress = await
|
|
1643
|
+
const tokensByAddress = await Tokens.resolveTokens(c, {
|
|
1356
1644
|
addresses: data.flatMap((pair) => [pair.base.address, pair.quote.address]),
|
|
1357
1645
|
chainId,
|
|
1358
1646
|
include: tokenFields,
|
|
@@ -1437,7 +1725,7 @@ export function exchanges(options = {}) {
|
|
|
1437
1725
|
let baseToken = { address: target.base };
|
|
1438
1726
|
let quoteToken = { address: target.quote };
|
|
1439
1727
|
if (options.include.includes('tokens')) {
|
|
1440
|
-
const tokensByAddress = await
|
|
1728
|
+
const tokensByAddress = await Tokens.resolveTokens(c, {
|
|
1441
1729
|
addresses: [target.base, target.quote],
|
|
1442
1730
|
chainId,
|
|
1443
1731
|
include: tokenFields,
|
|
@@ -1503,18 +1791,19 @@ export function exchanges(options = {}) {
|
|
|
1503
1791
|
const options = c.req.valid('query');
|
|
1504
1792
|
const chainId = options.chainId ?? c.get('chainId');
|
|
1505
1793
|
try {
|
|
1506
|
-
// The pair index (base address → pair) resolves the `base` selector
|
|
1507
|
-
// and each order's pair; the OrderPlaced scan only carries the
|
|
1508
|
-
// base-side `token`.
|
|
1509
|
-
const pairIndex = await getPairIndex(c, { chainId });
|
|
1510
1794
|
// `base` selects the single pair it identifies — a pair's quote is
|
|
1511
1795
|
// intrinsic to its base token on-chain, so the base address alone
|
|
1512
1796
|
// is a complete selector.
|
|
1513
1797
|
let pair;
|
|
1514
1798
|
if (options.base !== undefined) {
|
|
1515
|
-
const target =
|
|
1799
|
+
const target = (await getPairsByBase(c, { bases: [options.base], chainId })).get(options.base);
|
|
1800
|
+
// The 404's quote-token hint scans the full pair index; fetch it
|
|
1801
|
+
// only on this miss path so page requests never pay for it.
|
|
1516
1802
|
if (!target)
|
|
1517
|
-
return pairNotFoundError(c, {
|
|
1803
|
+
return pairNotFoundError(c, {
|
|
1804
|
+
base: options.base,
|
|
1805
|
+
pairIndex: await getPairIndex(c, { chainId }),
|
|
1806
|
+
});
|
|
1518
1807
|
pair = target;
|
|
1519
1808
|
}
|
|
1520
1809
|
const page = await getOrders(c, {
|
|
@@ -1525,7 +1814,6 @@ export function exchanges(options = {}) {
|
|
|
1525
1814
|
order: options.order,
|
|
1526
1815
|
page: options.page,
|
|
1527
1816
|
pair,
|
|
1528
|
-
pairIndex,
|
|
1529
1817
|
side: options.side,
|
|
1530
1818
|
sort: options.sort,
|
|
1531
1819
|
});
|
|
@@ -1535,7 +1823,7 @@ export function exchanges(options = {}) {
|
|
|
1535
1823
|
// unavailable keeps just `address`.
|
|
1536
1824
|
let data = page.data;
|
|
1537
1825
|
if (options.include.includes('tokens') && data.length > 0) {
|
|
1538
|
-
const tokensByAddress = await
|
|
1826
|
+
const tokensByAddress = await Tokens.resolveTokens(c, {
|
|
1539
1827
|
addresses: data.flatMap((o) => [o.pair.base.address, o.pair.quote.address]),
|
|
1540
1828
|
chainId,
|
|
1541
1829
|
include: tokenFields,
|
|
@@ -1815,7 +2103,7 @@ export function exchanges(options = {}) {
|
|
|
1815
2103
|
let base = { address: target.base };
|
|
1816
2104
|
let quote = { address: target.quote };
|
|
1817
2105
|
if (options.include.includes('tokens')) {
|
|
1818
|
-
const tokensByAddress = await
|
|
2106
|
+
const tokensByAddress = await Tokens.resolveTokens(c, {
|
|
1819
2107
|
addresses: [target.base, target.quote],
|
|
1820
2108
|
chainId,
|
|
1821
2109
|
include: tokenFields,
|
|
@@ -1906,7 +2194,7 @@ export function exchanges(options = {}) {
|
|
|
1906
2194
|
let base = { address: target.base };
|
|
1907
2195
|
let quote = { address: target.quote };
|
|
1908
2196
|
if (options.include.includes('tokens')) {
|
|
1909
|
-
const tokensByAddress = await
|
|
2197
|
+
const tokensByAddress = await Tokens.resolveTokens(c, {
|
|
1910
2198
|
addresses: [target.base, target.quote],
|
|
1911
2199
|
chainId,
|
|
1912
2200
|
include: tokenFields,
|
|
@@ -1943,51 +2231,6 @@ function pairNotFoundError(c, options) {
|
|
|
1943
2231
|
: 'Pair not found';
|
|
1944
2232
|
return Response.error(c, { code: 'pair_not_found', message, status: 404 });
|
|
1945
2233
|
}
|
|
1946
|
-
/** Resolves RPC token metadata and explicitly requested enrichments. Unresolvable addresses are omitted. */
|
|
1947
|
-
async function resolveTokensByAddress(c, options) {
|
|
1948
|
-
const { addresses, chainId, include } = options;
|
|
1949
|
-
const includeLogoUri = include.includes('token.logoUri');
|
|
1950
|
-
const includeVerified = include.includes('token.verified');
|
|
1951
|
-
const tokensByAddress = new Map();
|
|
1952
|
-
const uniqueTokens = [...new Set(addresses)];
|
|
1953
|
-
if (uniqueTokens.length === 0)
|
|
1954
|
-
return tokensByAddress;
|
|
1955
|
-
const snapshot = includeLogoUri || includeVerified
|
|
1956
|
-
? await VerifiedTokens.snapshot(c, chainId).catch(() => undefined)
|
|
1957
|
-
: undefined;
|
|
1958
|
-
const resolved = await Timing.time(c, 'tokens', () => Promise.all(uniqueTokens.map(async (token) => {
|
|
1959
|
-
try {
|
|
1960
|
-
const [logoUri, metadata] = await Promise.all([
|
|
1961
|
-
includeLogoUri
|
|
1962
|
-
? Timing.time(c, 'token_logo', () => Tokens.getTokenLogo(c, { address: token, chainId })).catch(() => undefined)
|
|
1963
|
-
: undefined,
|
|
1964
|
-
Timing.time(c, 'token_metadata', () => Tokens.getTokenMetadata(c, { address: token, chainId })),
|
|
1965
|
-
]);
|
|
1966
|
-
return [
|
|
1967
|
-
token,
|
|
1968
|
-
{
|
|
1969
|
-
address: token,
|
|
1970
|
-
currency: metadata.currency,
|
|
1971
|
-
decimals: metadata.decimals,
|
|
1972
|
-
id: token,
|
|
1973
|
-
logoUri: includeLogoUri
|
|
1974
|
-
? (logoUri ?? snapshot?.byAddress.get(token)?.logoUri ?? metadata.logoUri)
|
|
1975
|
-
: undefined,
|
|
1976
|
-
name: metadata.name,
|
|
1977
|
-
symbol: metadata.symbol,
|
|
1978
|
-
verified: includeVerified ? snapshot?.byAddress.has(token) : undefined,
|
|
1979
|
-
},
|
|
1980
|
-
];
|
|
1981
|
-
}
|
|
1982
|
-
catch {
|
|
1983
|
-
return [token, undefined];
|
|
1984
|
-
}
|
|
1985
|
-
})));
|
|
1986
|
-
for (const [token, metadata] of resolved)
|
|
1987
|
-
if (metadata)
|
|
1988
|
-
tokensByAddress.set(token, metadata);
|
|
1989
|
-
return tokensByAddress;
|
|
1990
|
-
}
|
|
1991
2234
|
async function getPairs(c, options) {
|
|
1992
2235
|
if (options.sort === 'liquidity')
|
|
1993
2236
|
return getPairsByLiquidity(c, options);
|
|
@@ -2187,6 +2430,86 @@ async function getPairIndex(c, options) {
|
|
|
2187
2430
|
ttl: Ttl.minutes(5),
|
|
2188
2431
|
})).then((entries) => new Map(entries));
|
|
2189
2432
|
}
|
|
2433
|
+
/**
|
|
2434
|
+
* Base-address chunk size for {@link getPairsByBase}. `tidx.fetch` transmits
|
|
2435
|
+
* queries as GET, so an unbounded `IN (...)` could overflow the request URI.
|
|
2436
|
+
*/
|
|
2437
|
+
const pairLookupBatchSize = 200;
|
|
2438
|
+
/**
|
|
2439
|
+
* Resolves the pairs for a set of book base addresses with one targeted
|
|
2440
|
+
* `dex_pairs` lookup, avoiding the full pair-index fetch (1MB+ on large
|
|
2441
|
+
* chains).
|
|
2442
|
+
*/
|
|
2443
|
+
async function getPairsByBase(c, options) {
|
|
2444
|
+
const { bases, chainId } = options;
|
|
2445
|
+
const pairs = new Map();
|
|
2446
|
+
if (bases.length === 0)
|
|
2447
|
+
return pairs;
|
|
2448
|
+
const tidx = c.get('getTidx')(chainId);
|
|
2449
|
+
return Timing.time(c, 'pair_lookup', async () => {
|
|
2450
|
+
for (let i = 0; i < bases.length; i += pairLookupBatchSize) {
|
|
2451
|
+
const list = bases
|
|
2452
|
+
.slice(i, i + pairLookupBatchSize)
|
|
2453
|
+
.map((base) => `'${base}'`)
|
|
2454
|
+
.join(', ');
|
|
2455
|
+
// `LIMIT 1 BY base` with the ascending sort picks each base's oldest
|
|
2456
|
+
// row, the row the pair index's last-entry-wins `Map` build selects.
|
|
2457
|
+
const result = await tidx.fetch({
|
|
2458
|
+
chainId,
|
|
2459
|
+
engine: 'clickhouse',
|
|
2460
|
+
query: `
|
|
2461
|
+
SELECT key, base, quote
|
|
2462
|
+
FROM dex_pairs
|
|
2463
|
+
WHERE address = '${stablecoinDex}' AND base IN (${list})
|
|
2464
|
+
ORDER BY block_num ASC, log_idx ASC
|
|
2465
|
+
LIMIT 1 BY base
|
|
2466
|
+
`,
|
|
2467
|
+
});
|
|
2468
|
+
// Drop malformed rows, mirroring `parsePairRow`.
|
|
2469
|
+
for (const row of result.rows) {
|
|
2470
|
+
const key = Schema.Hash.safeParse(row['key']);
|
|
2471
|
+
const base = Schema.TokenAddress.safeParse(row['base']);
|
|
2472
|
+
const quote = Schema.TokenAddress.safeParse(row['quote']);
|
|
2473
|
+
if (key.success && base.success && quote.success)
|
|
2474
|
+
pairs.set(base.data, { base: base.data, key: key.data, quote: quote.data });
|
|
2475
|
+
}
|
|
2476
|
+
}
|
|
2477
|
+
return pairs;
|
|
2478
|
+
});
|
|
2479
|
+
}
|
|
2480
|
+
/**
|
|
2481
|
+
* Resolves one pair by its book key with a targeted `dex_pairs` lookup,
|
|
2482
|
+
* covering books the bounded pair index ages out of its newest window.
|
|
2483
|
+
*/
|
|
2484
|
+
async function getPairByKey(c, options) {
|
|
2485
|
+
const { chainId, key } = options;
|
|
2486
|
+
const tidx = c.get('getTidx')(chainId);
|
|
2487
|
+
return Timing.time(c, 'pair_lookup', async () => {
|
|
2488
|
+
// The ascending sort picks the key's oldest row, matching the pair
|
|
2489
|
+
// index's last-entry-wins `Map` build.
|
|
2490
|
+
const result = await tidx.fetch({
|
|
2491
|
+
chainId,
|
|
2492
|
+
engine: 'clickhouse',
|
|
2493
|
+
query: `
|
|
2494
|
+
SELECT key, base, quote
|
|
2495
|
+
FROM dex_pairs
|
|
2496
|
+
WHERE address = '${stablecoinDex}' AND key = '${key}'
|
|
2497
|
+
ORDER BY block_num ASC, log_idx ASC
|
|
2498
|
+
LIMIT 1
|
|
2499
|
+
`,
|
|
2500
|
+
});
|
|
2501
|
+
const row = result.rows[0];
|
|
2502
|
+
if (!row)
|
|
2503
|
+
return undefined;
|
|
2504
|
+
// Drop malformed rows, mirroring `parsePairRow`.
|
|
2505
|
+
const parsedKey = Schema.Hash.safeParse(row['key']);
|
|
2506
|
+
const base = Schema.TokenAddress.safeParse(row['base']);
|
|
2507
|
+
const quote = Schema.TokenAddress.safeParse(row['quote']);
|
|
2508
|
+
if (!parsedKey.success || !base.success || !quote.success)
|
|
2509
|
+
return undefined;
|
|
2510
|
+
return { base: base.data, key: parsedKey.data, quote: quote.data };
|
|
2511
|
+
});
|
|
2512
|
+
}
|
|
2190
2513
|
/**
|
|
2191
2514
|
* Validates and shapes one `PairCreated` row into the internal pair shape.
|
|
2192
2515
|
* Returns `undefined` for malformed rows so the caller can drop them without
|
|
@@ -2248,7 +2571,7 @@ function parsePairRow(row) {
|
|
|
2248
2571
|
* no candidate is discarded after the query runs.
|
|
2249
2572
|
*/
|
|
2250
2573
|
async function getSwaps(c, options) {
|
|
2251
|
-
const { chainId, cursor: cursorToken, fromBlock, fromTimestamp, limit, maker, order,
|
|
2574
|
+
const { chainId, cursor: cursorToken, fromBlock, fromTimestamp, limit, maker, order, participant, taker, toBlock, toTimestamp, transactionHash, } = options;
|
|
2252
2575
|
const tidx = c.get('getTidx')(chainId);
|
|
2253
2576
|
const direction = order === 'asc' ? 'ASC' : 'DESC';
|
|
2254
2577
|
// Keyset cursor on `(block_num, group first_idx, row first log_idx)`: the
|
|
@@ -2370,16 +2693,17 @@ async function getSwaps(c, options) {
|
|
|
2370
2693
|
...new Set(groups.flatMap((group) => group.fills.map((fill) => fill.orderId))),
|
|
2371
2694
|
],
|
|
2372
2695
|
}));
|
|
2373
|
-
// Each fill's book quote: from
|
|
2374
|
-
// the base token's on-chain
|
|
2375
|
-
//
|
|
2376
|
-
// `dex_pairs` row.
|
|
2696
|
+
// Each fill's book quote: from a targeted `dex_pairs` lookup of this
|
|
2697
|
+
// batch's bases when indexed, else the base token's on-chain
|
|
2698
|
+
// `quoteToken()` — some books predate the indexer's `PairCreated`
|
|
2699
|
+
// decode (genesis system books) and have no `dex_pairs` row.
|
|
2377
2700
|
const bases = [
|
|
2378
2701
|
...new Set([...states.values()].flatMap((events) => events.map((event) => event.token))),
|
|
2379
2702
|
];
|
|
2703
|
+
const pairs = await getPairsByBase(c, { bases, chainId });
|
|
2380
2704
|
const quoteByBase = new Map();
|
|
2381
2705
|
for (const bookBase of bases) {
|
|
2382
|
-
const indexed =
|
|
2706
|
+
const indexed = pairs.get(bookBase);
|
|
2383
2707
|
if (indexed)
|
|
2384
2708
|
quoteByBase.set(bookBase, indexed.quote);
|
|
2385
2709
|
}
|
|
@@ -3212,11 +3536,11 @@ const orderCursorTickBias = 32768;
|
|
|
3212
3536
|
* `remaining = OrderPlaced.amount - sum(OrderFilled.amountFilled)`; orders
|
|
3213
3537
|
* with an `OrderCancelled` event are excluded outright. Each row is annotated
|
|
3214
3538
|
* with its pair: the scoped feed reuses the resolved `pair`, the unscoped
|
|
3215
|
-
* feed resolves
|
|
3216
|
-
* unknown are dropped).
|
|
3539
|
+
* feed resolves the page's base tokens with one targeted `dex_pairs` lookup
|
|
3540
|
+
* (rows whose pair is unknown are dropped).
|
|
3217
3541
|
*/
|
|
3218
3542
|
async function getOrders(c, options) {
|
|
3219
|
-
const { chainId, cursor, limit, maker, order, page, pair,
|
|
3543
|
+
const { chainId, cursor, limit, maker, order, page, pair, side, sort } = options;
|
|
3220
3544
|
const store = c.get('store');
|
|
3221
3545
|
return Timing.time(c, 'orders', async () => {
|
|
3222
3546
|
// Snapshot is invariant in `(chainId, base?, maker?)`; sort/side/order are
|
|
@@ -3238,9 +3562,11 @@ async function getOrders(c, options) {
|
|
|
3238
3562
|
side,
|
|
3239
3563
|
sort,
|
|
3240
3564
|
});
|
|
3565
|
+
const bases = pair ? [] : [...new Set(pageRows.map((row) => row.token))];
|
|
3566
|
+
const pairsByBase = await getPairsByBase(c, { bases, chainId });
|
|
3241
3567
|
const data = [];
|
|
3242
3568
|
for (const row of pageRows) {
|
|
3243
|
-
const rowPair = pair ??
|
|
3569
|
+
const rowPair = pair ?? pairsByBase.get(row.token);
|
|
3244
3570
|
if (!rowPair)
|
|
3245
3571
|
continue;
|
|
3246
3572
|
const shaped = shapeRestingOrder(row);
|
|
@@ -3470,11 +3796,17 @@ async function loadRestingOrders(c, options) {
|
|
|
3470
3796
|
});
|
|
3471
3797
|
const truncated = result.rows.length > scanCap;
|
|
3472
3798
|
const placedRows = result.rows.slice(0, scanCap);
|
|
3799
|
+
// `dex_orders` can carry duplicate rows per placement; keep the first
|
|
3800
|
+
// (newest) copy so pages emit each order once and a duplicate straddling an
|
|
3801
|
+
// IN-batch boundary can't double-count fills.
|
|
3473
3802
|
const placed = [];
|
|
3803
|
+
const seen = new Set();
|
|
3474
3804
|
for (const row of placedRows) {
|
|
3475
3805
|
const parsed = parsePlacedRow(row);
|
|
3476
|
-
if (parsed)
|
|
3477
|
-
|
|
3806
|
+
if (!parsed || seen.has(parsed.orderId))
|
|
3807
|
+
continue;
|
|
3808
|
+
seen.add(parsed.orderId);
|
|
3809
|
+
placed.push(parsed);
|
|
3478
3810
|
}
|
|
3479
3811
|
if (placed.length === 0)
|
|
3480
3812
|
return { orders: [], truncated };
|
|
@@ -3534,12 +3866,14 @@ export async function resolveBookReserves(c, options) {
|
|
|
3534
3866
|
return { reserves, truncated: false };
|
|
3535
3867
|
const tidx = c.get('getTidx')(chainId);
|
|
3536
3868
|
// Scan the newest `scanCap` `OrderPlaced` rows per base. `LIMIT ... BY token`
|
|
3537
|
-
// is the ClickHouse fair cap
|
|
3538
|
-
//
|
|
3539
|
-
//
|
|
3869
|
+
// is the ClickHouse fair cap over raw rows; `rawPerToken` flips `truncated`
|
|
3870
|
+
// when a token's window overflows, since unfetched older rows may hold unique
|
|
3871
|
+
// placements even when duplicates keep the unique count under the cap.
|
|
3540
3872
|
let truncated = false;
|
|
3541
3873
|
const placed = [];
|
|
3542
3874
|
const perToken = new Map();
|
|
3875
|
+
const rawPerToken = new Map();
|
|
3876
|
+
const seen = new Set();
|
|
3543
3877
|
for (let i = 0; i < unique.length; i += reserveBaseInBatchSize) {
|
|
3544
3878
|
const group = unique.slice(i, i + reserveBaseInBatchSize);
|
|
3545
3879
|
const list = group.map((base) => `'${base}'`).join(', ');
|
|
@@ -3558,11 +3892,18 @@ export async function resolveBookReserves(c, options) {
|
|
|
3558
3892
|
const parsed = parsePlacedRow(row);
|
|
3559
3893
|
if (!parsed)
|
|
3560
3894
|
continue;
|
|
3561
|
-
const
|
|
3562
|
-
|
|
3895
|
+
const raw = (rawPerToken.get(parsed.token) ?? 0) + 1;
|
|
3896
|
+
rawPerToken.set(parsed.token, raw);
|
|
3897
|
+
if (raw > scanCap)
|
|
3563
3898
|
truncated = true;
|
|
3899
|
+
// Duplicate placement rows (see `loadRestingOrders`) can't add the same
|
|
3900
|
+
// order's remaining liquidity twice; the raw probe above still counts them.
|
|
3901
|
+
if (seen.has(parsed.orderId))
|
|
3564
3902
|
continue;
|
|
3565
|
-
|
|
3903
|
+
const count = perToken.get(parsed.token) ?? 0;
|
|
3904
|
+
if (count >= scanCap)
|
|
3905
|
+
continue;
|
|
3906
|
+
seen.add(parsed.orderId);
|
|
3566
3907
|
perToken.set(parsed.token, count + 1);
|
|
3567
3908
|
placed.push(parsed);
|
|
3568
3909
|
}
|
|
@@ -3649,6 +3990,9 @@ async function fetchCancelledByIds(c, options) {
|
|
|
3649
3990
|
if (orderIds.length === 0)
|
|
3650
3991
|
return cancelled;
|
|
3651
3992
|
const tidx = c.get('getTidx')(chainId);
|
|
3993
|
+
// Chunks resolve serially: the managed indexer rejects bursts of concurrent
|
|
3994
|
+
// chunk queries (~2-3 in flight), and the cancel/fill helpers already
|
|
3995
|
+
// overlap via `Promise.all`.
|
|
3652
3996
|
for (let i = 0; i < orderIds.length; i += orderInBatchSize) {
|
|
3653
3997
|
const batch = orderIds.slice(i, i + orderInBatchSize);
|
|
3654
3998
|
const result = await tidx.fetch({
|
|
@@ -3681,6 +4025,9 @@ async function fetchFillSumsByIds(c, options) {
|
|
|
3681
4025
|
if (orderIds.length === 0)
|
|
3682
4026
|
return sums;
|
|
3683
4027
|
const tidx = c.get('getTidx')(chainId);
|
|
4028
|
+
// Chunks resolve serially: the managed indexer rejects bursts of concurrent
|
|
4029
|
+
// chunk queries (~2-3 in flight), and the cancel/fill helpers already
|
|
4030
|
+
// overlap via `Promise.all`.
|
|
3684
4031
|
for (let i = 0; i < orderIds.length; i += orderInBatchSize) {
|
|
3685
4032
|
const batch = orderIds.slice(i, i + orderInBatchSize);
|
|
3686
4033
|
const result = await tidx.fetch({
|
|
@@ -3773,30 +4120,27 @@ async function getOrder(c, options) {
|
|
|
3773
4120
|
const client = c.get('getClient')(chainId);
|
|
3774
4121
|
return Timing.time(c, 'order', () => Store.memoize(async () => {
|
|
3775
4122
|
// The on-chain DEX exposes the full order struct (placement params
|
|
3776
|
-
// plus current `remaining`) in one view call.
|
|
3777
|
-
|
|
3778
|
-
//
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
return undefined;
|
|
3788
|
-
throw cause;
|
|
3789
|
-
})),
|
|
3790
|
-
getPairIndexByKey(c, { chainId }),
|
|
3791
|
-
]);
|
|
4123
|
+
// plus current `remaining`) in one view call.
|
|
4124
|
+
const chainOrder = await Timing.time(c, 'order_dex_get', () =>
|
|
4125
|
+
// The DEX reverts with `OrderDoesNotExist()` for ids it no longer
|
|
4126
|
+
// holds (never placed, or filled/cancelled and cleared), rather
|
|
4127
|
+
// than returning the zero struct. Map that revert to not-found so
|
|
4128
|
+
// the route answers 404 instead of bubbling up as a 502.
|
|
4129
|
+
client.dex.getOrder({ orderId: BigInt(orderId) }).catch((cause) => {
|
|
4130
|
+
if (isOrderDoesNotExist(cause))
|
|
4131
|
+
return undefined;
|
|
4132
|
+
throw cause;
|
|
4133
|
+
}));
|
|
3792
4134
|
// The DEX returns the zero struct (or reverts, handled above) when an
|
|
3793
4135
|
// order id is unknown.
|
|
3794
4136
|
if (!chainOrder || chainOrder.orderId === 0n)
|
|
3795
4137
|
return undefined;
|
|
3796
|
-
//
|
|
3797
|
-
//
|
|
3798
|
-
|
|
3799
|
-
|
|
4138
|
+
// Targeted lookup off the returned `bookKey`; the bounded pair index
|
|
4139
|
+
// misses books outside its newest window, 404ing live orders.
|
|
4140
|
+
const pair = await getPairByKey(c, {
|
|
4141
|
+
chainId,
|
|
4142
|
+
key: chainOrder.bookKey.toLowerCase(),
|
|
4143
|
+
});
|
|
3800
4144
|
if (!pair)
|
|
3801
4145
|
return undefined;
|
|
3802
4146
|
const tick = chainOrder.tick;
|
|
@@ -3852,11 +4196,139 @@ function isOrderDoesNotExist(error) {
|
|
|
3852
4196
|
return (revert instanceof ContractFunctionRevertedError &&
|
|
3853
4197
|
revert.data?.errorName === 'OrderDoesNotExist');
|
|
3854
4198
|
}
|
|
3855
|
-
|
|
4199
|
+
async function providerQuoteResponse(c, options) {
|
|
4200
|
+
const { chainId, gasPrice, gasUnits, oracle, provider, query, quote, request } = options;
|
|
4201
|
+
const tokensByAddress = await Tokens.resolveTokens(c, {
|
|
4202
|
+
addresses: [request.destinationToken, request.sourceToken],
|
|
4203
|
+
chainId,
|
|
4204
|
+
include: options.include,
|
|
4205
|
+
});
|
|
4206
|
+
const destinationToken = tokensByAddress.get(request.destinationToken);
|
|
4207
|
+
const sourceToken = tokensByAddress.get(request.sourceToken);
|
|
4208
|
+
if (!destinationToken || !sourceToken)
|
|
4209
|
+
throw new Error('Unable to resolve exchange quote token metadata');
|
|
4210
|
+
const denomination = query['valuation.currency'] ?? 'USD';
|
|
4211
|
+
const snapshot = await VerifiedTokens.snapshot(c, chainId).catch(() => undefined);
|
|
4212
|
+
const rates = await Valuation.ratesFor(c, {
|
|
4213
|
+
currencies: snapshot
|
|
4214
|
+
? [request.destinationToken, request.sourceToken].flatMap((address) => {
|
|
4215
|
+
const held = snapshot.byAddress.get(address.toLowerCase())?.currency;
|
|
4216
|
+
return held === undefined ? [] : [held];
|
|
4217
|
+
})
|
|
4218
|
+
: [],
|
|
4219
|
+
denomination,
|
|
4220
|
+
oracle,
|
|
4221
|
+
});
|
|
4222
|
+
const valued = (baseUnits, address, token) => ({
|
|
4223
|
+
...Value.tokenAmount({ baseUnits, currency: token.currency, decimals: token.decimals }),
|
|
4224
|
+
valuation: Valuation.valuationFor({
|
|
4225
|
+
amount: BigInt(baseUnits),
|
|
4226
|
+
denomination,
|
|
4227
|
+
rates,
|
|
4228
|
+
token: snapshot?.byAddress.get(address.toLowerCase()),
|
|
4229
|
+
}),
|
|
4230
|
+
});
|
|
4231
|
+
const execution = quote.status === 'ready'
|
|
4232
|
+
? {
|
|
4233
|
+
status: quote.status,
|
|
4234
|
+
transaction: { calls: [...quote.transaction.calls], chainId },
|
|
4235
|
+
}
|
|
4236
|
+
: quote.status === 'approvalRequired'
|
|
4237
|
+
? { approval: { calls: [...quote.approval.calls] }, status: quote.status }
|
|
4238
|
+
: {
|
|
4239
|
+
continuation: quote.continuation,
|
|
4240
|
+
status: quote.status,
|
|
4241
|
+
typedData: quote.typedData,
|
|
4242
|
+
};
|
|
4243
|
+
const common = {
|
|
4244
|
+
destinationToken: { ...destinationToken, address: request.destinationToken },
|
|
4245
|
+
...execution,
|
|
4246
|
+
...(rates ? { meta: { valuation: Valuation.pricing(rates, oracle) } } : {}),
|
|
4247
|
+
gasEstimate: gasCost({ gasPrice, gasUnits }),
|
|
4248
|
+
provider: provider.id,
|
|
4249
|
+
sourceToken: { ...sourceToken, address: request.sourceToken },
|
|
4250
|
+
};
|
|
4251
|
+
if (request.mode === 'exactSource') {
|
|
4252
|
+
if (!quote.minimumDestinationAmount)
|
|
4253
|
+
throw new ExchangeProvider.ProviderPayloadError();
|
|
4254
|
+
return {
|
|
4255
|
+
...common,
|
|
4256
|
+
destinationAmount: valued(quote.destinationAmount, request.destinationToken, destinationToken),
|
|
4257
|
+
destinationAmountMin: valued(quote.minimumDestinationAmount, request.destinationToken, destinationToken),
|
|
4258
|
+
mode: request.mode,
|
|
4259
|
+
sourceAmount: valued(quote.sourceAmount, request.sourceToken, sourceToken),
|
|
4260
|
+
};
|
|
4261
|
+
}
|
|
4262
|
+
if (!quote.maximumSourceAmount)
|
|
4263
|
+
throw new ExchangeProvider.ProviderPayloadError();
|
|
4264
|
+
return {
|
|
4265
|
+
...common,
|
|
4266
|
+
destinationAmount: valued(quote.destinationAmount, request.destinationToken, destinationToken),
|
|
4267
|
+
mode: request.mode,
|
|
4268
|
+
sourceAmount: valued(quote.sourceAmount, request.sourceToken, sourceToken),
|
|
4269
|
+
sourceAmountMax: valued(quote.maximumSourceAmount, request.sourceToken, sourceToken),
|
|
4270
|
+
};
|
|
4271
|
+
}
|
|
4272
|
+
function providerExecution(options) {
|
|
4273
|
+
const { quote, request } = options;
|
|
4274
|
+
return {
|
|
4275
|
+
destinationAmount: quote.destinationAmount,
|
|
4276
|
+
destinationToken: request.destinationToken,
|
|
4277
|
+
gasUnits: quote.gasUnits,
|
|
4278
|
+
...(quote.maximumSourceAmount ? { maximumSourceAmount: quote.maximumSourceAmount } : {}),
|
|
4279
|
+
...(quote.minimumDestinationAmount
|
|
4280
|
+
? { minimumDestinationAmount: quote.minimumDestinationAmount }
|
|
4281
|
+
: {}),
|
|
4282
|
+
mode: request.mode,
|
|
4283
|
+
sourceAmount: quote.sourceAmount,
|
|
4284
|
+
sourceToken: request.sourceToken,
|
|
4285
|
+
};
|
|
4286
|
+
}
|
|
4287
|
+
async function validateProviderCalls(client, options) {
|
|
4288
|
+
try {
|
|
4289
|
+
const { results } = await Actions.simulate.simulateCalls(client, {
|
|
4290
|
+
account: options.account,
|
|
4291
|
+
calls: options.calls.map((call) => ({
|
|
4292
|
+
data: call.data,
|
|
4293
|
+
to: call.to,
|
|
4294
|
+
value: BigInt(call.value),
|
|
4295
|
+
})),
|
|
4296
|
+
traceTransfers: true,
|
|
4297
|
+
});
|
|
4298
|
+
if (results.some((result) => result.status !== 'success'))
|
|
4299
|
+
throw new ExchangeProvider.ProviderPayloadError();
|
|
4300
|
+
const logs = results.flatMap((result) => result.logs ?? []);
|
|
4301
|
+
const transfers = parseEventLogs({
|
|
4302
|
+
abi: [AbiEvent.fromAbi(Abis.tip20, 'Transfer')],
|
|
4303
|
+
eventName: 'Transfer',
|
|
4304
|
+
logs,
|
|
4305
|
+
}).map((log) => ({
|
|
4306
|
+
amount: log.args.amount,
|
|
4307
|
+
from: log.args.from,
|
|
4308
|
+
to: log.args.to,
|
|
4309
|
+
token: log.address,
|
|
4310
|
+
}));
|
|
4311
|
+
ExchangeProvider.validateExecution({
|
|
4312
|
+
account: options.account,
|
|
4313
|
+
execution: options.execution,
|
|
4314
|
+
transfers,
|
|
4315
|
+
});
|
|
4316
|
+
}
|
|
4317
|
+
catch (cause) {
|
|
4318
|
+
if (cause instanceof ExchangeProvider.ProviderPayloadError)
|
|
4319
|
+
throw cause;
|
|
4320
|
+
throw new ExchangeProvider.ProviderPayloadError();
|
|
4321
|
+
}
|
|
4322
|
+
}
|
|
4323
|
+
/** Converts estimated gas units to a native-token base-unit fee. */
|
|
4324
|
+
function gasCost(options) {
|
|
4325
|
+
return (options.gasPrice * options.gasUnits).toString();
|
|
4326
|
+
}
|
|
4327
|
+
/** Returns the 404 used when no executable quote is available. */
|
|
3856
4328
|
function quoteNotAvailable(c) {
|
|
3857
4329
|
return Response.error(c, {
|
|
3858
4330
|
code: 'quote_not_available',
|
|
3859
|
-
message: 'No
|
|
4331
|
+
message: 'No configured exchange provider has an executable quote',
|
|
3860
4332
|
status: 404,
|
|
3861
4333
|
});
|
|
3862
4334
|
}
|
|
@@ -3964,18 +4436,6 @@ async function countOrderFills(c, options) {
|
|
|
3964
4436
|
ttl: Ttl.seconds(10),
|
|
3965
4437
|
}));
|
|
3966
4438
|
}
|
|
3967
|
-
/**
|
|
3968
|
-
* Per-key pair index derived from the existing per-base index. Built once
|
|
3969
|
-
* and memoized at the same cadence as the pair index itself so chained
|
|
3970
|
-
* `getOrder` lookups stay an O(1) `Map.get`.
|
|
3971
|
-
*/
|
|
3972
|
-
async function getPairIndexByKey(c, options) {
|
|
3973
|
-
const pairsByBase = await getPairIndex(c, options);
|
|
3974
|
-
const pairsByKey = new Map();
|
|
3975
|
-
for (const pair of pairsByBase.values())
|
|
3976
|
-
pairsByKey.set(pair.key.toLowerCase(), pair);
|
|
3977
|
-
return pairsByKey;
|
|
3978
|
-
}
|
|
3979
4439
|
/**
|
|
3980
4440
|
* Validates and shapes one `OrderFilled` row into the public `Fill` shape.
|
|
3981
4441
|
* Drops the row when any required column is malformed so the caller can omit
|
|
@@ -4009,4 +4469,7 @@ function parseOrderFillRow(row) {
|
|
|
4009
4469
|
transactionHash: transactionHash.data,
|
|
4010
4470
|
};
|
|
4011
4471
|
}
|
|
4472
|
+
class NativeDexAmountOutOfRangeError extends Error {
|
|
4473
|
+
name = 'Exchanges.NativeDexAmountOutOfRangeError';
|
|
4474
|
+
}
|
|
4012
4475
|
//# sourceMappingURL=exchanges.js.map
|