tapimo 0.7.0 → 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 +151 -95
- 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 +14377 -10165
- 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 +1231 -324
- 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.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 +5 -5
- 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 +265 -265
- 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 +49 -9
- package/dist/apps/data/routes/tokenlist.js.map +1 -1
- package/dist/apps/data/routes/tokens.d.ts +116 -88
- package/dist/apps/data/routes/tokens.d.ts.map +1 -1
- package/dist/apps/data/routes/tokens.js +198 -91
- package/dist/apps/data/routes/tokens.js.map +1 -1
- package/dist/apps/data/routes/transactions.d.ts +55 -55
- 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 +78 -29
- 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 +10 -10
- package/dist/apps/data/routes/valuation.js +2 -2
- package/dist/apps/data/routes/valuation.js.map +1 -1
- package/dist/apps/data/routes/verified-tokens.d.ts.map +1 -1
- package/dist/apps/data/routes/verified-tokens.js +34 -9
- package/dist/apps/data/routes/verified-tokens.js.map +1 -1
- package/dist/apps/data/routes/webhooks.d.ts +5 -3
- package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
- package/dist/apps/data/routes/webhooks.js +175 -65
- 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 +35 -35
- 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 +78 -78
- 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/usage.d.ts +80 -80
- 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 +184 -24
- 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 +16 -7
- 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 +35 -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 +4 -2
- package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
- package/dist/db/tables/sponsoredTransactions.js +14 -4
- 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 +9 -2
- package/dist/internal/EdgeCache.d.ts.map +1 -1
- package/dist/internal/EdgeCache.js +36 -9
- 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 +8 -3
- package/dist/internal/Schema.d.ts.map +1 -1
- package/dist/internal/Schema.js +24 -13
- 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 +189 -95
- 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 +38 -9
- 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.test.ts +15 -0
- package/src/apps/data/routes/tokenlist.ts +88 -22
- package/src/apps/data/routes/tokens.ts +262 -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/verified-tokens.test.ts +51 -0
- package/src/apps/data/routes/verified-tokens.ts +52 -15
- package/src/apps/data/routes/webhooks.test.ts +432 -33
- package/src/apps/data/routes/webhooks.ts +189 -79
- 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 +495 -64
- package/src/apps/relay/App.ts +234 -24
- package/src/apps/relay/Sponsorships.test.ts +51 -0
- package/src/apps/relay/Sponsorships.ts +19 -7
- 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.test.ts +88 -0
- package/src/db/tables/organizations.ts +42 -1
- package/src/db/tables/projects.ts +16 -0
- package/src/db/tables/requestUsage.ts +23 -0
- package/src/db/tables/sponsoredTransactions.test.ts +52 -2
- package/src/db/tables/sponsoredTransactions.ts +18 -6
- 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 +37 -5
- package/src/internal/EdgeCache.ts +39 -7
- 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.test.ts +13 -0
- package/src/internal/Schema.ts +41 -24
- 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
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
ContractFunctionRevertedError,
|
|
7
7
|
decodeFunctionData,
|
|
8
8
|
parseAbi,
|
|
9
|
+
parseEventLogs,
|
|
9
10
|
} from 'viem'
|
|
10
11
|
import { Abis, Actions, Addresses, Tick } from 'viem/tempo'
|
|
11
12
|
import * as z from 'zod/mini'
|
|
@@ -14,6 +15,7 @@ import type * as App from '../../../App.js'
|
|
|
14
15
|
import * as Auth from '../../../internal/Auth.js'
|
|
15
16
|
import * as Cache from '../../../internal/Cache.js'
|
|
16
17
|
import * as Cursor from '../../../internal/Cursor.js'
|
|
18
|
+
import * as ExchangeProvider from '../../../internal/exchange/Provider.js'
|
|
17
19
|
import * as OpenApi from '../../../internal/OpenApi.js'
|
|
18
20
|
import * as Response from '../../../internal/Response.js'
|
|
19
21
|
import * as Schema from '../../../internal/Schema.js'
|
|
@@ -22,6 +24,7 @@ import * as Timing from '../../../internal/Timing.js'
|
|
|
22
24
|
import * as Ttl from '../../../internal/Ttl.js'
|
|
23
25
|
import * as Value from '../../../internal/Value.js'
|
|
24
26
|
import * as VerifiedTokens from '../../../internal/VerifiedTokens.js'
|
|
27
|
+
import type * as Viem from '../../../internal/Viem.js'
|
|
25
28
|
import * as FxOracle from '../FxOracle.js'
|
|
26
29
|
import * as Tokens from './tokens.js'
|
|
27
30
|
import * as Valuation from './valuation.js'
|
|
@@ -32,6 +35,9 @@ const stablecoinDex = Addresses.stablecoinDex.toLowerCase()
|
|
|
32
35
|
|
|
33
36
|
const contractPausedSelector = AbiError.getSelector(AbiError.fromAbi(Abis.tip20, 'ContractPaused'))
|
|
34
37
|
|
|
38
|
+
/** Largest amount accepted by TIP-20 and external uint256 provider contracts. */
|
|
39
|
+
const maxProviderAmount = 2n ** 256n - 1n
|
|
40
|
+
|
|
35
41
|
// `OrderCancelled(uint128 orderId)` — emitted when a maker cancels a resting
|
|
36
42
|
// order. Used by the orders endpoint to exclude cancelled orders from the
|
|
37
43
|
// resting set.
|
|
@@ -241,25 +247,25 @@ export namespace schema {
|
|
|
241
247
|
.optional(z.nullable(Valuation.schema.Value))
|
|
242
248
|
.check(
|
|
243
249
|
z.describe(
|
|
244
|
-
'The amount’s nominal value in the requested `
|
|
250
|
+
'The amount’s nominal value in the requested `valuation.currency`. `null` when the token is ' +
|
|
245
251
|
'unverified, its display currency has no rate, or rates were unavailable.',
|
|
246
252
|
),
|
|
247
253
|
),
|
|
248
254
|
})
|
|
249
255
|
|
|
250
|
-
/** Schemas for creating an executable
|
|
256
|
+
/** Schemas for creating an executable exchange quote. */
|
|
251
257
|
export namespace createQuote {
|
|
252
258
|
const DestinationTokenAddress = Schema.tokenAddress(exampleBase)
|
|
253
259
|
const SourceTokenAddress = Schema.tokenAddress(exampleSourceToken)
|
|
254
260
|
|
|
255
|
-
/** Positive token amount accepted by
|
|
261
|
+
/** Positive token amount accepted by exchange providers. */
|
|
256
262
|
export const Amount = Schema.DecimalString.check(
|
|
257
263
|
z.refine(
|
|
258
264
|
(value) => {
|
|
259
265
|
const amount = BigInt(value)
|
|
260
|
-
return amount > 0n && amount <=
|
|
266
|
+
return amount > 0n && amount <= maxProviderAmount
|
|
261
267
|
},
|
|
262
|
-
{ error: 'Amount must be
|
|
268
|
+
{ error: 'Amount must be a positive uint256.' },
|
|
263
269
|
),
|
|
264
270
|
z.describe(
|
|
265
271
|
'Positive token amount in the token’s smallest unit, encoded as a decimal string.',
|
|
@@ -282,14 +288,20 @@ export namespace schema {
|
|
|
282
288
|
export const Query = z
|
|
283
289
|
.strictObject({
|
|
284
290
|
chainId: Schema.ChainIdQuery,
|
|
285
|
-
denomination: Schema.Denomination,
|
|
286
291
|
include: includeQuery,
|
|
292
|
+
'valuation.currency': Schema.Denomination,
|
|
287
293
|
})
|
|
288
|
-
.check(z.describe('Query parameters for creating
|
|
294
|
+
.check(z.describe('Query parameters for creating an exchange quote.'))
|
|
289
295
|
|
|
290
296
|
/** Quote request with one pinned side and caller-selected slippage. */
|
|
291
297
|
export const Request = z
|
|
292
298
|
.strictObject({
|
|
299
|
+
account: z
|
|
300
|
+
.optional(Schema.Address)
|
|
301
|
+
.check(
|
|
302
|
+
z.describe('Wallet that will sign and execute the swap.'),
|
|
303
|
+
z.meta({ examples: ['0x1111111111111111111111111111111111111111'] }),
|
|
304
|
+
),
|
|
293
305
|
amount: Amount.check(
|
|
294
306
|
z.describe(
|
|
295
307
|
'Pinned amount in base units: source amount for `exactSource`, destination amount for `exactDestination`.',
|
|
@@ -319,16 +331,22 @@ export namespace schema {
|
|
|
319
331
|
z.refine((request) => request.sourceToken !== request.destinationToken, {
|
|
320
332
|
error: 'Source and destination tokens must differ.',
|
|
321
333
|
}),
|
|
322
|
-
z.describe('Request for an executable quote
|
|
334
|
+
z.describe('Request for an executable quote from the configured exchange providers.'),
|
|
323
335
|
)
|
|
324
336
|
|
|
325
337
|
/** One call in the unsigned Tempo transaction plan. */
|
|
326
338
|
export const Call = z
|
|
327
339
|
.object({
|
|
328
|
-
data: Schema.Hex.check(
|
|
329
|
-
|
|
340
|
+
data: Schema.Hex.check(
|
|
341
|
+
z.describe('ABI-encoded call data.'),
|
|
342
|
+
z.meta({ examples: ['0x095ea7b3'] }),
|
|
343
|
+
),
|
|
344
|
+
to: Schema.Address.check(
|
|
345
|
+
z.describe('Contract or precompile that receives the call.'),
|
|
346
|
+
z.meta({ examples: [Addresses.stablecoinDex] }),
|
|
347
|
+
),
|
|
330
348
|
value: Schema.Quantity.check(
|
|
331
|
-
z.describe('Native token value sent with the call
|
|
349
|
+
z.describe('Native token value sent with the call.'),
|
|
332
350
|
z.meta({ examples: ['0x0'] }),
|
|
333
351
|
),
|
|
334
352
|
})
|
|
@@ -350,11 +368,11 @@ export namespace schema {
|
|
|
350
368
|
address: SourceTokenAddress.check(z.describe('TIP-20 token the swap spends.')),
|
|
351
369
|
})
|
|
352
370
|
|
|
353
|
-
const Transaction = z
|
|
371
|
+
export const Transaction = z
|
|
354
372
|
.object({
|
|
355
373
|
calls: z.array(Call).check(
|
|
356
|
-
z.
|
|
357
|
-
z.describe('
|
|
374
|
+
z.minLength(1),
|
|
375
|
+
z.describe('Calls to execute in order.'),
|
|
358
376
|
z.meta({
|
|
359
377
|
examples: [
|
|
360
378
|
[
|
|
@@ -375,7 +393,7 @@ export namespace schema {
|
|
|
375
393
|
/** Response-level valuation rate provenance. */
|
|
376
394
|
export const Meta = z
|
|
377
395
|
.object({
|
|
378
|
-
|
|
396
|
+
valuation: z
|
|
379
397
|
.optional(Valuation.schema.Pricing)
|
|
380
398
|
.check(
|
|
381
399
|
z.describe(
|
|
@@ -385,43 +403,225 @@ export namespace schema {
|
|
|
385
403
|
})
|
|
386
404
|
.check(z.describe('Response-level resources attached to this quote.'))
|
|
387
405
|
|
|
388
|
-
/**
|
|
389
|
-
export const
|
|
390
|
-
.
|
|
391
|
-
z.
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
406
|
+
/** Provider-neutral EIP-712 payload to sign before finalizing a quote. */
|
|
407
|
+
export const TypedData = z
|
|
408
|
+
.object({
|
|
409
|
+
domain: z.record(z.string(), z.unknown()).check(
|
|
410
|
+
z.describe('EIP-712 signing domain.'),
|
|
411
|
+
z.meta({
|
|
412
|
+
examples: [
|
|
413
|
+
{
|
|
414
|
+
chainId: 4217,
|
|
415
|
+
name: 'Permit2',
|
|
416
|
+
verifyingContract: '0x000000000022d473030f116ddee9f6b43ac78ba3',
|
|
417
|
+
},
|
|
418
|
+
],
|
|
419
|
+
}),
|
|
420
|
+
),
|
|
421
|
+
message: z.record(z.string(), z.unknown()).check(
|
|
422
|
+
z.describe('Values encoded by the primary EIP-712 type.'),
|
|
423
|
+
z.meta({
|
|
424
|
+
examples: [
|
|
425
|
+
{
|
|
426
|
+
details: {
|
|
427
|
+
amount: '1000000',
|
|
428
|
+
expiration: '4102444800',
|
|
429
|
+
nonce: '0',
|
|
430
|
+
token: exampleSourceToken,
|
|
431
|
+
},
|
|
432
|
+
sigDeadline: '4102444800',
|
|
433
|
+
spender: '0x1febb76be10aaf3a1402f04e8e835f2c382f7914',
|
|
434
|
+
},
|
|
435
|
+
],
|
|
436
|
+
}),
|
|
437
|
+
),
|
|
438
|
+
primaryType: z
|
|
439
|
+
.string()
|
|
440
|
+
.check(z.minLength(1))
|
|
441
|
+
.check(z.describe('Root EIP-712 type.'), z.meta({ examples: ['PermitSingle'] })),
|
|
442
|
+
types: z
|
|
443
|
+
.record(
|
|
444
|
+
z.string(),
|
|
445
|
+
z.array(
|
|
446
|
+
z.strictObject({
|
|
447
|
+
name: z.string(),
|
|
448
|
+
type: z.string(),
|
|
449
|
+
}),
|
|
417
450
|
),
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
451
|
+
)
|
|
452
|
+
.check(
|
|
453
|
+
z.describe('EIP-712 type definitions keyed by type name.'),
|
|
454
|
+
z.meta({
|
|
455
|
+
examples: [
|
|
456
|
+
{
|
|
457
|
+
PermitDetails: [
|
|
458
|
+
{ name: 'token', type: 'address' },
|
|
459
|
+
{ name: 'amount', type: 'uint160' },
|
|
460
|
+
{ name: 'expiration', type: 'uint48' },
|
|
461
|
+
{ name: 'nonce', type: 'uint48' },
|
|
462
|
+
],
|
|
463
|
+
PermitSingle: [
|
|
464
|
+
{ name: 'details', type: 'PermitDetails' },
|
|
465
|
+
{ name: 'spender', type: 'address' },
|
|
466
|
+
{ name: 'sigDeadline', type: 'uint256' },
|
|
467
|
+
],
|
|
468
|
+
},
|
|
469
|
+
],
|
|
470
|
+
}),
|
|
471
|
+
),
|
|
472
|
+
})
|
|
473
|
+
.check(z.describe('EIP-712 payload the wallet must sign before execution can continue.'))
|
|
474
|
+
|
|
475
|
+
const Provider = z
|
|
476
|
+
.string()
|
|
477
|
+
.check(z.describe('Provider selected for this route.'), z.meta({ examples: ['nativeDex'] }))
|
|
478
|
+
|
|
479
|
+
const Quote = {
|
|
480
|
+
gasEstimate: Schema.DecimalString.check(
|
|
481
|
+
z.describe('Estimated network fee in the chain native token’s base unit.'),
|
|
482
|
+
z.meta({ examples: ['150000000000000'] }),
|
|
483
|
+
),
|
|
484
|
+
provider: Provider,
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
const ApprovalRequired = {
|
|
488
|
+
approval: z.object({
|
|
489
|
+
calls: z.array(Call).check(
|
|
490
|
+
z.minLength(1),
|
|
491
|
+
z.describe('Approval calls to confirm before requesting a fresh quote.'),
|
|
492
|
+
z.meta({
|
|
493
|
+
examples: [
|
|
494
|
+
[
|
|
495
|
+
{
|
|
496
|
+
data: exampleApprovalCall.data,
|
|
497
|
+
to: exampleApprovalCall.to,
|
|
498
|
+
value: '0x0',
|
|
499
|
+
},
|
|
500
|
+
],
|
|
501
|
+
],
|
|
502
|
+
}),
|
|
503
|
+
),
|
|
504
|
+
}),
|
|
505
|
+
status: z
|
|
506
|
+
.literal('approvalRequired')
|
|
507
|
+
.check(
|
|
508
|
+
z.describe('Confirm the approvals, then request a fresh quote.'),
|
|
509
|
+
z.meta({ examples: ['approvalRequired'] }),
|
|
510
|
+
),
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
const Ready = {
|
|
514
|
+
status: z
|
|
515
|
+
.literal('ready')
|
|
516
|
+
.check(
|
|
517
|
+
z.describe('The returned calls can be executed now.'),
|
|
518
|
+
z.meta({ examples: ['ready'] }),
|
|
519
|
+
),
|
|
520
|
+
transaction: Transaction,
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
const SignatureRequired = {
|
|
524
|
+
continuation: z
|
|
525
|
+
.string()
|
|
526
|
+
.check(
|
|
527
|
+
z.minLength(1),
|
|
528
|
+
z.describe('Opaque state supplied to the finalization endpoint within 30 seconds.'),
|
|
529
|
+
z.meta({ examples: ['eyJwcm92aWRlciI6InVuaXN3YXAifQ'] }),
|
|
530
|
+
),
|
|
531
|
+
status: z
|
|
532
|
+
.literal('signatureRequired')
|
|
533
|
+
.check(
|
|
534
|
+
z.describe('Sign the typed data before final calldata can be built.'),
|
|
535
|
+
z.meta({ examples: ['signatureRequired'] }),
|
|
536
|
+
),
|
|
537
|
+
typedData: TypedData,
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
const ExactSource = {
|
|
541
|
+
destinationAmount: ValuedAmount.check(z.describe('Quoted destination amount.')),
|
|
542
|
+
destinationAmountMin: ValuedAmount.check(
|
|
543
|
+
z.describe('Minimum destination amount after slippage.'),
|
|
544
|
+
),
|
|
545
|
+
destinationToken: DestinationToken,
|
|
546
|
+
meta: z.optional(Meta).check(z.describe('Valuation rate provenance for this quote.')),
|
|
547
|
+
mode: z
|
|
548
|
+
.literal('exactSource')
|
|
549
|
+
.check(
|
|
550
|
+
z.describe('The source amount is fixed and the destination has a minimum.'),
|
|
551
|
+
z.meta({ examples: ['exactSource'] }),
|
|
552
|
+
),
|
|
553
|
+
sourceAmount: ValuedAmount.check(z.describe('Exact source amount.')),
|
|
554
|
+
sourceToken: SourceToken.check(z.describe('Token spent by the swap.')),
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
const ExactDestination = {
|
|
558
|
+
destinationAmount: ValuedAmount.check(z.describe('Exact destination amount.')),
|
|
559
|
+
destinationToken: DestinationToken.check(z.describe('Token received by the swap.')),
|
|
560
|
+
meta: z.optional(Meta).check(z.describe('Valuation rate provenance for this quote.')),
|
|
561
|
+
mode: z
|
|
562
|
+
.literal('exactDestination')
|
|
563
|
+
.check(
|
|
564
|
+
z.describe('The destination amount is fixed and the source has a maximum.'),
|
|
565
|
+
z.meta({ examples: ['exactDestination'] }),
|
|
566
|
+
),
|
|
567
|
+
sourceAmount: ValuedAmount.check(z.describe('Quoted source amount.')),
|
|
568
|
+
sourceAmountMax: ValuedAmount.check(z.describe('Maximum source amount after slippage.')),
|
|
569
|
+
sourceToken: SourceToken,
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/** Provider-neutral quote and the action needed to execute it. */
|
|
573
|
+
export const Response = z
|
|
574
|
+
.union([
|
|
575
|
+
z.object({ ...ApprovalRequired, ...ExactSource, ...Quote }),
|
|
576
|
+
z.object({ ...ExactSource, ...Quote, ...Ready }),
|
|
577
|
+
z.object({ ...ExactSource, ...Quote, ...SignatureRequired }),
|
|
578
|
+
z.object({ ...ApprovalRequired, ...ExactDestination, ...Quote }),
|
|
579
|
+
z.object({ ...ExactDestination, ...Quote, ...Ready }),
|
|
580
|
+
z.object({ ...ExactDestination, ...Quote, ...SignatureRequired }),
|
|
423
581
|
])
|
|
424
|
-
.check(z.describe('
|
|
582
|
+
.check(z.describe('Provider-neutral exchange quote with its next execution action.'))
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/** Schemas for finishing a quote after a provider-requested signature. */
|
|
586
|
+
export namespace executeQuote {
|
|
587
|
+
/** Signed continuation request. */
|
|
588
|
+
export const Request = z.strictObject({
|
|
589
|
+
account: Schema.Address.check(
|
|
590
|
+
z.describe('Wallet that signed and will execute the swap.'),
|
|
591
|
+
z.meta({ examples: ['0x1111111111111111111111111111111111111111'] }),
|
|
592
|
+
),
|
|
593
|
+
continuation: z
|
|
594
|
+
.string()
|
|
595
|
+
.check(
|
|
596
|
+
z.minLength(1),
|
|
597
|
+
z.maxLength(100_000),
|
|
598
|
+
z.describe('Opaque state returned by the quote request.'),
|
|
599
|
+
z.meta({ examples: ['eyJwcm92aWRlciI6InVuaXN3YXAifQ'] }),
|
|
600
|
+
),
|
|
601
|
+
provider: z
|
|
602
|
+
.string()
|
|
603
|
+
.check(
|
|
604
|
+
z.minLength(1),
|
|
605
|
+
z.describe('Provider that issued the continuation.'),
|
|
606
|
+
z.meta({ examples: ['uniswap'] }),
|
|
607
|
+
),
|
|
608
|
+
signature: Schema.Hex.check(
|
|
609
|
+
z.refine((value) => value.length === 132, { error: 'Signature must be 65 bytes.' }),
|
|
610
|
+
z.describe('65-byte EIP-712 signature requested by the quote.'),
|
|
611
|
+
z.meta({ examples: [`0x${'11'.repeat(65)}`] }),
|
|
612
|
+
),
|
|
613
|
+
})
|
|
614
|
+
|
|
615
|
+
/** Final transaction plan. */
|
|
616
|
+
export const Response = z.object({
|
|
617
|
+
provider: z
|
|
618
|
+
.string()
|
|
619
|
+
.check(
|
|
620
|
+
z.describe('Provider that built the transaction.'),
|
|
621
|
+
z.meta({ examples: ['uniswap'] }),
|
|
622
|
+
),
|
|
623
|
+
transaction: createQuote.Transaction,
|
|
624
|
+
})
|
|
425
625
|
}
|
|
426
626
|
|
|
427
627
|
/** Schemas for the getPairs operation. */
|
|
@@ -599,7 +799,6 @@ export namespace schema {
|
|
|
599
799
|
'blockNumber.to': Schema.blockNumberBound('swaps', 'to'),
|
|
600
800
|
chainId: Schema.ChainIdQuery,
|
|
601
801
|
cursor: Schema.Cursor,
|
|
602
|
-
denomination: Schema.Denomination,
|
|
603
802
|
include: includeQuery,
|
|
604
803
|
limit: Schema.Limit,
|
|
605
804
|
maker: z
|
|
@@ -625,6 +824,7 @@ export namespace schema {
|
|
|
625
824
|
transactionHash: z
|
|
626
825
|
.optional(Schema.Hash)
|
|
627
826
|
.check(z.describe('Only include swaps included in this transaction hash.')),
|
|
827
|
+
'valuation.currency': Schema.Denomination,
|
|
628
828
|
})
|
|
629
829
|
.check(
|
|
630
830
|
z.describe(
|
|
@@ -774,7 +974,7 @@ export namespace schema {
|
|
|
774
974
|
/** Page-level resources: valuation rate provenance. */
|
|
775
975
|
export const Meta = z
|
|
776
976
|
.object({
|
|
777
|
-
|
|
977
|
+
valuation: z
|
|
778
978
|
.optional(Valuation.schema.Pricing)
|
|
779
979
|
.check(
|
|
780
980
|
z.describe(
|
|
@@ -1532,19 +1732,20 @@ export function exchanges(options: exchanges.Options = {}) {
|
|
|
1532
1732
|
}),
|
|
1533
1733
|
OpenApi.describeRoute({
|
|
1534
1734
|
description:
|
|
1535
|
-
'
|
|
1735
|
+
'Attempts exchange providers in priority order and returns the first executable quote. This endpoint does not submit a transaction.',
|
|
1536
1736
|
operationId: 'createExchangeQuote',
|
|
1537
1737
|
responses: OpenApi.responses({
|
|
1538
1738
|
errors: {
|
|
1539
1739
|
400: { codes: ['body_invalid', 'query_invalid', 'quote_amount_out_of_range'] },
|
|
1540
1740
|
404: {
|
|
1541
1741
|
codes: ['quote_not_available'],
|
|
1542
|
-
description:
|
|
1742
|
+
description:
|
|
1743
|
+
'No configured provider can price an executable exchange for these terms.',
|
|
1543
1744
|
},
|
|
1544
1745
|
502: 'The Tempo RPC could not quote the swap or resolve token metadata.',
|
|
1545
1746
|
},
|
|
1546
1747
|
success: {
|
|
1547
|
-
description: 'A
|
|
1748
|
+
description: 'A provider-neutral quote and its next execution action.',
|
|
1548
1749
|
schema: schema.createQuote.Response,
|
|
1549
1750
|
},
|
|
1550
1751
|
}),
|
|
@@ -1565,8 +1766,8 @@ export function exchanges(options: exchanges.Options = {}) {
|
|
|
1565
1766
|
})
|
|
1566
1767
|
|
|
1567
1768
|
const request = c.req.valid('json')
|
|
1568
|
-
const
|
|
1569
|
-
const chainId =
|
|
1769
|
+
const query = c.req.valid('query')
|
|
1770
|
+
const chainId = query.chainId ?? c.get('chainId')
|
|
1570
1771
|
const client = c.get('getClient')(chainId)
|
|
1571
1772
|
const amount = BigInt(request.amount)
|
|
1572
1773
|
const slippageBps = BigInt(request.slippageBps)
|
|
@@ -1575,7 +1776,7 @@ export function exchanges(options: exchanges.Options = {}) {
|
|
|
1575
1776
|
try {
|
|
1576
1777
|
// Value quoted amounts via their curated display currency; snapshot
|
|
1577
1778
|
// or rate failures degrade the values to `null`, never the quote.
|
|
1578
|
-
const denomination =
|
|
1779
|
+
const denomination = query['valuation.currency'] ?? 'USD'
|
|
1579
1780
|
const snapshot = await VerifiedTokens.snapshot(c, chainId).catch(() => undefined)
|
|
1580
1781
|
const rates = await Valuation.ratesFor(c, {
|
|
1581
1782
|
currencies: snapshot
|
|
@@ -1605,13 +1806,16 @@ export function exchanges(options: exchanges.Options = {}) {
|
|
|
1605
1806
|
}),
|
|
1606
1807
|
})
|
|
1607
1808
|
|
|
1809
|
+
if (options.nativeDex === false || amount > maxSwapAmount)
|
|
1810
|
+
throw new ExchangeProvider.RouteUnavailableError()
|
|
1811
|
+
|
|
1608
1812
|
if (request.mode === 'exactSource') {
|
|
1609
1813
|
const destinationAmount = await Actions.dex.getSellQuote(client, {
|
|
1610
1814
|
amountIn: amount,
|
|
1611
1815
|
tokenIn: request.sourceToken,
|
|
1612
1816
|
tokenOut: request.destinationToken,
|
|
1613
1817
|
})
|
|
1614
|
-
if (destinationAmount === 0n)
|
|
1818
|
+
if (destinationAmount === 0n) throw new ExchangeProvider.RouteUnavailableError()
|
|
1615
1819
|
|
|
1616
1820
|
const minimumAmount =
|
|
1617
1821
|
(destinationAmount * (slippageDenominator - slippageBps) + slippageDenominator - 1n) /
|
|
@@ -1627,10 +1831,19 @@ export function exchanges(options: exchanges.Options = {}) {
|
|
|
1627
1831
|
tokenIn: request.sourceToken,
|
|
1628
1832
|
tokenOut: request.destinationToken,
|
|
1629
1833
|
})
|
|
1630
|
-
const
|
|
1834
|
+
const calls = [
|
|
1835
|
+
{ data: approve.data, to: approve.to, value: 0n },
|
|
1836
|
+
{ data: swap.data, to: swap.to, value: 0n },
|
|
1837
|
+
] as const
|
|
1838
|
+
const gasUnits = await client.estimateGas({
|
|
1839
|
+
...(request.account ? { account: request.account } : {}),
|
|
1840
|
+
calls,
|
|
1841
|
+
})
|
|
1842
|
+
const gasPrice = await client.getGasPrice()
|
|
1843
|
+
const tokensByAddress = await Tokens.resolveTokens(c, {
|
|
1631
1844
|
addresses: [request.destinationToken, request.sourceToken],
|
|
1632
1845
|
chainId,
|
|
1633
|
-
include:
|
|
1846
|
+
include: query.include,
|
|
1634
1847
|
})
|
|
1635
1848
|
const destinationToken = tokensByAddress.get(request.destinationToken)
|
|
1636
1849
|
const sourceToken = tokensByAddress.get(request.sourceToken)
|
|
@@ -1653,18 +1866,18 @@ export function exchanges(options: exchanges.Options = {}) {
|
|
|
1653
1866
|
...destinationToken,
|
|
1654
1867
|
address: request.destinationToken,
|
|
1655
1868
|
},
|
|
1656
|
-
...(rates ? { meta: {
|
|
1869
|
+
...(rates ? { meta: { valuation: Valuation.pricing(rates, oracle) } } : {}),
|
|
1870
|
+
gasEstimate: gasCost({ gasPrice, gasUnits }),
|
|
1657
1871
|
mode: request.mode,
|
|
1872
|
+
provider: 'nativeDex',
|
|
1658
1873
|
sourceAmount: valued(request.amount, request.sourceToken, sourceToken),
|
|
1659
1874
|
sourceToken: {
|
|
1660
1875
|
...sourceToken,
|
|
1661
1876
|
address: request.sourceToken,
|
|
1662
1877
|
},
|
|
1878
|
+
status: 'ready',
|
|
1663
1879
|
transaction: {
|
|
1664
|
-
calls:
|
|
1665
|
-
{ data: approve.data, to: approve.to, value: '0x0' },
|
|
1666
|
-
{ data: swap.data, to: swap.to, value: '0x0' },
|
|
1667
|
-
],
|
|
1880
|
+
calls: calls.map((call) => ({ ...call, value: '0x0' as const })),
|
|
1668
1881
|
chainId,
|
|
1669
1882
|
},
|
|
1670
1883
|
}),
|
|
@@ -1677,16 +1890,12 @@ export function exchanges(options: exchanges.Options = {}) {
|
|
|
1677
1890
|
tokenIn: request.sourceToken,
|
|
1678
1891
|
tokenOut: request.destinationToken,
|
|
1679
1892
|
})
|
|
1680
|
-
if (sourceAmount === 0n)
|
|
1893
|
+
if (sourceAmount === 0n) throw new ExchangeProvider.RouteUnavailableError()
|
|
1681
1894
|
|
|
1682
1895
|
const maximumAmount =
|
|
1683
|
-
(sourceAmount * (slippageDenominator + slippageBps)) /
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
code: 'quote_amount_out_of_range',
|
|
1687
|
-
message: 'Slippage-adjusted source amount exceeds the native DEX limit',
|
|
1688
|
-
status: 400,
|
|
1689
|
-
})
|
|
1896
|
+
(sourceAmount * (slippageDenominator + slippageBps) + slippageDenominator - 1n) /
|
|
1897
|
+
slippageDenominator
|
|
1898
|
+
if (maximumAmount > maxSwapAmount) throw new NativeDexAmountOutOfRangeError()
|
|
1690
1899
|
|
|
1691
1900
|
const approve = Actions.token.approve.call(client, {
|
|
1692
1901
|
amount: maximumAmount,
|
|
@@ -1699,10 +1908,19 @@ export function exchanges(options: exchanges.Options = {}) {
|
|
|
1699
1908
|
tokenIn: request.sourceToken,
|
|
1700
1909
|
tokenOut: request.destinationToken,
|
|
1701
1910
|
})
|
|
1702
|
-
const
|
|
1911
|
+
const calls = [
|
|
1912
|
+
{ data: approve.data, to: approve.to, value: 0n },
|
|
1913
|
+
{ data: swap.data, to: swap.to, value: 0n },
|
|
1914
|
+
] as const
|
|
1915
|
+
const gasUnits = await client.estimateGas({
|
|
1916
|
+
...(request.account ? { account: request.account } : {}),
|
|
1917
|
+
calls,
|
|
1918
|
+
})
|
|
1919
|
+
const gasPrice = await client.getGasPrice()
|
|
1920
|
+
const tokensByAddress = await Tokens.resolveTokens(c, {
|
|
1703
1921
|
addresses: [request.destinationToken, request.sourceToken],
|
|
1704
1922
|
chainId,
|
|
1705
|
-
include:
|
|
1923
|
+
include: query.include,
|
|
1706
1924
|
})
|
|
1707
1925
|
const destinationToken = tokensByAddress.get(request.destinationToken)
|
|
1708
1926
|
const sourceToken = tokensByAddress.get(request.sourceToken)
|
|
@@ -1716,34 +1934,209 @@ export function exchanges(options: exchanges.Options = {}) {
|
|
|
1716
1934
|
...destinationToken,
|
|
1717
1935
|
address: request.destinationToken,
|
|
1718
1936
|
},
|
|
1719
|
-
...(rates ? { meta: {
|
|
1937
|
+
...(rates ? { meta: { valuation: Valuation.pricing(rates, oracle) } } : {}),
|
|
1938
|
+
gasEstimate: gasCost({ gasPrice, gasUnits }),
|
|
1720
1939
|
mode: request.mode,
|
|
1940
|
+
provider: 'nativeDex',
|
|
1721
1941
|
sourceAmount: valued(sourceAmount, request.sourceToken, sourceToken),
|
|
1722
1942
|
sourceAmountMax: valued(maximumAmount, request.sourceToken, sourceToken),
|
|
1723
1943
|
sourceToken: {
|
|
1724
1944
|
...sourceToken,
|
|
1725
1945
|
address: request.sourceToken,
|
|
1726
1946
|
},
|
|
1947
|
+
status: 'ready',
|
|
1727
1948
|
transaction: {
|
|
1728
|
-
calls:
|
|
1729
|
-
{ data: approve.data, to: approve.to, value: '0x0' },
|
|
1730
|
-
{ data: swap.data, to: swap.to, value: '0x0' },
|
|
1731
|
-
],
|
|
1949
|
+
calls: calls.map((call) => ({ ...call, value: '0x0' as const })),
|
|
1732
1950
|
chainId,
|
|
1733
1951
|
},
|
|
1734
1952
|
}),
|
|
1735
1953
|
200,
|
|
1736
1954
|
)
|
|
1737
1955
|
} catch (cause) {
|
|
1738
|
-
if (
|
|
1956
|
+
if (cause instanceof Valuation.UnsupportedDenominationError)
|
|
1957
|
+
return Response.error(c, { code: 'query_invalid', message: cause.message, status: 400 })
|
|
1958
|
+
const amountOutOfRange =
|
|
1959
|
+
cause instanceof NativeDexAmountOutOfRangeError ||
|
|
1960
|
+
(request.mode === 'exactSource' && isQuoteAmountOutOfRange(cause))
|
|
1961
|
+
const providers = c.get('providers').filter(ExchangeProvider.is)
|
|
1962
|
+
if (amountOutOfRange && providers.length === 0)
|
|
1739
1963
|
return Response.error(c, {
|
|
1740
1964
|
code: 'quote_amount_out_of_range',
|
|
1741
1965
|
message: 'Quote amount exceeds the native DEX limit',
|
|
1742
1966
|
status: 400,
|
|
1743
1967
|
})
|
|
1744
|
-
if (
|
|
1745
|
-
|
|
1746
|
-
|
|
1968
|
+
if (
|
|
1969
|
+
!(cause instanceof ExchangeProvider.RouteUnavailableError) &&
|
|
1970
|
+
!isQuoteUnavailable(cause) &&
|
|
1971
|
+
!amountOutOfRange
|
|
1972
|
+
)
|
|
1973
|
+
return Response.upstream(c, cause)
|
|
1974
|
+
|
|
1975
|
+
if (!request.account) return quoteNotAvailable(c)
|
|
1976
|
+
|
|
1977
|
+
for (const provider of providers)
|
|
1978
|
+
try {
|
|
1979
|
+
const quote = await provider.quote(
|
|
1980
|
+
{
|
|
1981
|
+
account: request.account,
|
|
1982
|
+
amount: request.amount,
|
|
1983
|
+
chainId,
|
|
1984
|
+
destinationToken: request.destinationToken,
|
|
1985
|
+
mode: request.mode,
|
|
1986
|
+
slippageBps: request.slippageBps,
|
|
1987
|
+
sourceToken: request.sourceToken,
|
|
1988
|
+
},
|
|
1989
|
+
c.req.raw.signal,
|
|
1990
|
+
)
|
|
1991
|
+
if (quote.status === 'ready')
|
|
1992
|
+
await validateProviderCalls(client, {
|
|
1993
|
+
account: request.account,
|
|
1994
|
+
calls: quote.transaction.calls,
|
|
1995
|
+
execution: providerExecution({ quote, request }),
|
|
1996
|
+
})
|
|
1997
|
+
const [gasPrice, gasUnits] = await Promise.all([
|
|
1998
|
+
client.getGasPrice(),
|
|
1999
|
+
quote.status === 'approvalRequired'
|
|
2000
|
+
? client.estimateGas({
|
|
2001
|
+
account: request.account,
|
|
2002
|
+
calls: quote.approval.calls.map((call) => ({
|
|
2003
|
+
data: call.data,
|
|
2004
|
+
to: call.to,
|
|
2005
|
+
value: BigInt(call.value),
|
|
2006
|
+
})),
|
|
2007
|
+
})
|
|
2008
|
+
: Promise.resolve(BigInt(quote.gasUnits)),
|
|
2009
|
+
])
|
|
2010
|
+
return c.json(
|
|
2011
|
+
Response.validated(
|
|
2012
|
+
schema.createQuote.Response,
|
|
2013
|
+
await providerQuoteResponse(c, {
|
|
2014
|
+
chainId,
|
|
2015
|
+
gasPrice,
|
|
2016
|
+
gasUnits,
|
|
2017
|
+
include: query.include,
|
|
2018
|
+
oracle,
|
|
2019
|
+
query,
|
|
2020
|
+
quote,
|
|
2021
|
+
request,
|
|
2022
|
+
provider,
|
|
2023
|
+
}),
|
|
2024
|
+
),
|
|
2025
|
+
200,
|
|
2026
|
+
)
|
|
2027
|
+
} catch (error) {
|
|
2028
|
+
if (error instanceof ExchangeProvider.RouteUnavailableError) continue
|
|
2029
|
+
const failure = ExchangeProvider.failure(error, {
|
|
2030
|
+
chainId,
|
|
2031
|
+
operation: 'quote',
|
|
2032
|
+
provider,
|
|
2033
|
+
})
|
|
2034
|
+
if (failure) c.set('providerFailure', failure)
|
|
2035
|
+
return Response.upstream(c, error)
|
|
2036
|
+
}
|
|
2037
|
+
|
|
2038
|
+
return quoteNotAvailable(c)
|
|
2039
|
+
}
|
|
2040
|
+
},
|
|
2041
|
+
)
|
|
2042
|
+
.post(
|
|
2043
|
+
'/v1/exchange/quotes/execute',
|
|
2044
|
+
Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }),
|
|
2045
|
+
OpenApi.validate('query', schema.createQuote.Query, {
|
|
2046
|
+
code: 'query_invalid',
|
|
2047
|
+
message: 'Invalid query parameters',
|
|
2048
|
+
}),
|
|
2049
|
+
OpenApi.validate('json', schema.executeQuote.Request, {
|
|
2050
|
+
code: 'body_invalid',
|
|
2051
|
+
message: 'Invalid request body',
|
|
2052
|
+
}),
|
|
2053
|
+
OpenApi.describeRoute({
|
|
2054
|
+
description:
|
|
2055
|
+
'Finishes a provider quote after the wallet supplies the requested typed-data signature. This endpoint does not submit a transaction.',
|
|
2056
|
+
operationId: 'finalizeExchangeQuote',
|
|
2057
|
+
responses: OpenApi.responses({
|
|
2058
|
+
errors: {
|
|
2059
|
+
400: {
|
|
2060
|
+
codes: [
|
|
2061
|
+
'body_invalid',
|
|
2062
|
+
'query_invalid',
|
|
2063
|
+
'swap_continuation_invalid',
|
|
2064
|
+
'swap_provider_invalid',
|
|
2065
|
+
],
|
|
2066
|
+
},
|
|
2067
|
+
502: 'The selected provider could not build the swap right now.',
|
|
2068
|
+
},
|
|
2069
|
+
success: {
|
|
2070
|
+
description: 'The final unsigned calls needed to execute the swap.',
|
|
2071
|
+
schema: schema.executeQuote.Response,
|
|
2072
|
+
},
|
|
2073
|
+
}),
|
|
2074
|
+
summary: 'Finalize quote',
|
|
2075
|
+
tags: ['Exchange'],
|
|
2076
|
+
}),
|
|
2077
|
+
async (c) => {
|
|
2078
|
+
if (Auth.narrowAccess) return Auth.paidAccessError(c)
|
|
2079
|
+
if (OpenApi.narrowValidation)
|
|
2080
|
+
return OpenApi.validationError(c, {
|
|
2081
|
+
code: 'query_invalid',
|
|
2082
|
+
message: 'Invalid query parameters',
|
|
2083
|
+
})
|
|
2084
|
+
if (OpenApi.narrowValidation)
|
|
2085
|
+
return OpenApi.validationError(c, {
|
|
2086
|
+
code: 'body_invalid',
|
|
2087
|
+
message: 'Invalid request body',
|
|
2088
|
+
})
|
|
2089
|
+
|
|
2090
|
+
const request = c.req.valid('json')
|
|
2091
|
+
const chainId = c.req.valid('query').chainId ?? c.get('chainId')
|
|
2092
|
+
const provider = c
|
|
2093
|
+
.get('providers')
|
|
2094
|
+
.filter(ExchangeProvider.is)
|
|
2095
|
+
.find((candidate) => candidate.id === request.provider && candidate.finalizeQuote)
|
|
2096
|
+
if (!provider?.finalizeQuote)
|
|
2097
|
+
return Response.error(c, {
|
|
2098
|
+
code: 'swap_provider_invalid',
|
|
2099
|
+
message: 'The selected swap provider is not configured',
|
|
2100
|
+
status: 400,
|
|
2101
|
+
})
|
|
2102
|
+
|
|
2103
|
+
c.header('Cache-Control', 'no-store')
|
|
2104
|
+
try {
|
|
2105
|
+
const client = c.get('getClient')(chainId)
|
|
2106
|
+
const result = await provider.finalizeQuote(
|
|
2107
|
+
{
|
|
2108
|
+
account: request.account,
|
|
2109
|
+
chainId,
|
|
2110
|
+
continuation: request.continuation,
|
|
2111
|
+
signature: request.signature,
|
|
2112
|
+
},
|
|
2113
|
+
c.req.raw.signal,
|
|
2114
|
+
)
|
|
2115
|
+
await validateProviderCalls(client, {
|
|
2116
|
+
account: request.account,
|
|
2117
|
+
calls: result.calls,
|
|
2118
|
+
execution: result.execution,
|
|
2119
|
+
})
|
|
2120
|
+
return c.json(
|
|
2121
|
+
Response.validated(schema.executeQuote.Response, {
|
|
2122
|
+
provider: provider.id,
|
|
2123
|
+
transaction: { calls: result.calls, chainId },
|
|
2124
|
+
}),
|
|
2125
|
+
200,
|
|
2126
|
+
)
|
|
2127
|
+
} catch (cause) {
|
|
2128
|
+
if (cause instanceof ExchangeProvider.ProviderContinuationError)
|
|
2129
|
+
return Response.error(c, {
|
|
2130
|
+
code: 'swap_continuation_invalid',
|
|
2131
|
+
message: 'Invalid swap continuation',
|
|
2132
|
+
status: 400,
|
|
2133
|
+
})
|
|
2134
|
+
const failure = ExchangeProvider.failure(cause, {
|
|
2135
|
+
chainId,
|
|
2136
|
+
operation: 'finalize',
|
|
2137
|
+
provider,
|
|
2138
|
+
})
|
|
2139
|
+
if (failure) c.set('providerFailure', failure)
|
|
1747
2140
|
return Response.upstream(c, cause)
|
|
1748
2141
|
}
|
|
1749
2142
|
},
|
|
@@ -1793,11 +2186,6 @@ export function exchanges(options: exchanges.Options = {}) {
|
|
|
1793
2186
|
if (options.cursor !== undefined) Cache.setPolicy(c, Cache.policies.metadata)
|
|
1794
2187
|
|
|
1795
2188
|
try {
|
|
1796
|
-
// The pair index (base address → pair) resolves each fill's book
|
|
1797
|
-
// orientation (the order events only carry the base-side `token`;
|
|
1798
|
-
// the quote is intrinsic to it).
|
|
1799
|
-
const pairIndex = await getPairIndex(c, { chainId })
|
|
1800
|
-
|
|
1801
2189
|
const page = await getSwaps(c, {
|
|
1802
2190
|
chainId,
|
|
1803
2191
|
cursor: options.cursor,
|
|
@@ -1806,7 +2194,6 @@ export function exchanges(options: exchanges.Options = {}) {
|
|
|
1806
2194
|
limit: options.limit,
|
|
1807
2195
|
maker: options.maker,
|
|
1808
2196
|
order: options.order,
|
|
1809
|
-
pairIndex,
|
|
1810
2197
|
participant: options.participant,
|
|
1811
2198
|
taker: options.taker,
|
|
1812
2199
|
toBlock: options['blockNumber.to'],
|
|
@@ -1816,14 +2203,14 @@ export function exchanges(options: exchanges.Options = {}) {
|
|
|
1816
2203
|
|
|
1817
2204
|
// `route` spans every swap and fill side, so one lookup resolves each
|
|
1818
2205
|
// token once for required RPC metadata and requested curated fields.
|
|
1819
|
-
const tokensByAddress = await
|
|
2206
|
+
const tokensByAddress = await Tokens.resolveTokens(c, {
|
|
1820
2207
|
addresses: page.data.flatMap((swap) => swap.route),
|
|
1821
2208
|
chainId,
|
|
1822
2209
|
include: options.include,
|
|
1823
2210
|
})
|
|
1824
2211
|
// Value amounts via their curated display currency; snapshot or rate
|
|
1825
2212
|
// failures degrade the values to `null`, never the feed.
|
|
1826
|
-
const denomination = options.
|
|
2213
|
+
const denomination = options['valuation.currency'] ?? 'USD'
|
|
1827
2214
|
const snapshot =
|
|
1828
2215
|
page.data.length > 0
|
|
1829
2216
|
? await VerifiedTokens.snapshot(c, chainId).catch(() => undefined)
|
|
@@ -1894,7 +2281,7 @@ export function exchanges(options: exchanges.Options = {}) {
|
|
|
1894
2281
|
return c.json(
|
|
1895
2282
|
Response.validated(schema.getSwaps.Response, {
|
|
1896
2283
|
data,
|
|
1897
|
-
...(rates ? { meta: {
|
|
2284
|
+
...(rates ? { meta: { valuation: Valuation.pricing(rates, oracle) } } : {}),
|
|
1898
2285
|
nextCursor: page.nextCursor,
|
|
1899
2286
|
}),
|
|
1900
2287
|
200,
|
|
@@ -1982,7 +2369,7 @@ export function exchanges(options: exchanges.Options = {}) {
|
|
|
1982
2369
|
transactionHash: pair.transactionHash,
|
|
1983
2370
|
}))
|
|
1984
2371
|
if (options.include.includes('tokens') && data.length > 0) {
|
|
1985
|
-
const tokensByAddress = await
|
|
2372
|
+
const tokensByAddress = await Tokens.resolveTokens(c, {
|
|
1986
2373
|
addresses: data.flatMap((pair) => [pair.base.address, pair.quote.address]),
|
|
1987
2374
|
chainId,
|
|
1988
2375
|
include: tokenFields,
|
|
@@ -2079,7 +2466,7 @@ export function exchanges(options: exchanges.Options = {}) {
|
|
|
2079
2466
|
let baseToken: z.output<typeof schema.PairToken> = { address: target.base }
|
|
2080
2467
|
let quoteToken: z.output<typeof schema.PairToken> = { address: target.quote }
|
|
2081
2468
|
if (options.include.includes('tokens')) {
|
|
2082
|
-
const tokensByAddress = await
|
|
2469
|
+
const tokensByAddress = await Tokens.resolveTokens(c, {
|
|
2083
2470
|
addresses: [target.base, target.quote],
|
|
2084
2471
|
chainId,
|
|
2085
2472
|
include: tokenFields,
|
|
@@ -2154,18 +2541,21 @@ export function exchanges(options: exchanges.Options = {}) {
|
|
|
2154
2541
|
const chainId = options.chainId ?? c.get('chainId')
|
|
2155
2542
|
|
|
2156
2543
|
try {
|
|
2157
|
-
// The pair index (base address → pair) resolves the `base` selector
|
|
2158
|
-
// and each order's pair; the OrderPlaced scan only carries the
|
|
2159
|
-
// base-side `token`.
|
|
2160
|
-
const pairIndex = await getPairIndex(c, { chainId })
|
|
2161
|
-
|
|
2162
2544
|
// `base` selects the single pair it identifies — a pair's quote is
|
|
2163
2545
|
// intrinsic to its base token on-chain, so the base address alone
|
|
2164
2546
|
// is a complete selector.
|
|
2165
|
-
let pair:
|
|
2547
|
+
let pair: getPairsByBase.Pair | undefined
|
|
2166
2548
|
if (options.base !== undefined) {
|
|
2167
|
-
const target =
|
|
2168
|
-
|
|
2549
|
+
const target = (await getPairsByBase(c, { bases: [options.base], chainId })).get(
|
|
2550
|
+
options.base,
|
|
2551
|
+
)
|
|
2552
|
+
// The 404's quote-token hint scans the full pair index; fetch it
|
|
2553
|
+
// only on this miss path so page requests never pay for it.
|
|
2554
|
+
if (!target)
|
|
2555
|
+
return pairNotFoundError(c, {
|
|
2556
|
+
base: options.base,
|
|
2557
|
+
pairIndex: await getPairIndex(c, { chainId }),
|
|
2558
|
+
})
|
|
2169
2559
|
pair = target
|
|
2170
2560
|
}
|
|
2171
2561
|
|
|
@@ -2177,7 +2567,6 @@ export function exchanges(options: exchanges.Options = {}) {
|
|
|
2177
2567
|
order: options.order,
|
|
2178
2568
|
page: options.page,
|
|
2179
2569
|
pair,
|
|
2180
|
-
pairIndex,
|
|
2181
2570
|
side: options.side,
|
|
2182
2571
|
sort: options.sort,
|
|
2183
2572
|
})
|
|
@@ -2188,7 +2577,7 @@ export function exchanges(options: exchanges.Options = {}) {
|
|
|
2188
2577
|
// unavailable keeps just `address`.
|
|
2189
2578
|
let data = page.data
|
|
2190
2579
|
if (options.include.includes('tokens') && data.length > 0) {
|
|
2191
|
-
const tokensByAddress = await
|
|
2580
|
+
const tokensByAddress = await Tokens.resolveTokens(c, {
|
|
2192
2581
|
addresses: data.flatMap((o) => [o.pair.base.address, o.pair.quote.address]),
|
|
2193
2582
|
chainId,
|
|
2194
2583
|
include: tokenFields,
|
|
@@ -2512,7 +2901,7 @@ export function exchanges(options: exchanges.Options = {}) {
|
|
|
2512
2901
|
let base: z.output<typeof schema.PairToken> = { address: target.base }
|
|
2513
2902
|
let quote: z.output<typeof schema.PairToken> = { address: target.quote }
|
|
2514
2903
|
if (options.include.includes('tokens')) {
|
|
2515
|
-
const tokensByAddress = await
|
|
2904
|
+
const tokensByAddress = await Tokens.resolveTokens(c, {
|
|
2516
2905
|
addresses: [target.base, target.quote],
|
|
2517
2906
|
chainId,
|
|
2518
2907
|
include: tokenFields,
|
|
@@ -2614,7 +3003,7 @@ export function exchanges(options: exchanges.Options = {}) {
|
|
|
2614
3003
|
let base: z.output<typeof schema.PairToken> = { address: target.base }
|
|
2615
3004
|
let quote: z.output<typeof schema.PairToken> = { address: target.quote }
|
|
2616
3005
|
if (options.include.includes('tokens')) {
|
|
2617
|
-
const tokensByAddress = await
|
|
3006
|
+
const tokensByAddress = await Tokens.resolveTokens(c, {
|
|
2618
3007
|
addresses: [target.base, target.quote],
|
|
2619
3008
|
chainId,
|
|
2620
3009
|
include: tokenFields,
|
|
@@ -2641,6 +3030,8 @@ export declare namespace exchanges {
|
|
|
2641
3030
|
type Options = {
|
|
2642
3031
|
/** FX configuration backing amount valuation. */
|
|
2643
3032
|
fx?: Valuation.addresses.Fx | undefined
|
|
3033
|
+
/** Whether to try Tempo's native stablecoin DEX first. Enabled by default. */
|
|
3034
|
+
nativeDex?: boolean | undefined
|
|
2644
3035
|
}
|
|
2645
3036
|
}
|
|
2646
3037
|
|
|
@@ -2667,68 +3058,6 @@ function pairNotFoundError(
|
|
|
2667
3058
|
return Response.error(c, { code: 'pair_not_found', message, status: 404 })
|
|
2668
3059
|
}
|
|
2669
3060
|
|
|
2670
|
-
/** Resolves RPC token metadata and explicitly requested enrichments. Unresolvable addresses are omitted. */
|
|
2671
|
-
async function resolveTokensByAddress(
|
|
2672
|
-
c: Context<App.Environment>,
|
|
2673
|
-
options: {
|
|
2674
|
-
addresses: readonly z.output<typeof Schema.Address>[]
|
|
2675
|
-
chainId: z.output<typeof Schema.ChainId>
|
|
2676
|
-
include: readonly (typeof tokenFields)[number][]
|
|
2677
|
-
},
|
|
2678
|
-
) {
|
|
2679
|
-
const { addresses, chainId, include } = options
|
|
2680
|
-
const includeLogoUri = include.includes('token.logoUri')
|
|
2681
|
-
const includeVerified = include.includes('token.verified')
|
|
2682
|
-
type Token = Omit<z.output<typeof Tokens.schema.Token>, 'verified'> & {
|
|
2683
|
-
verified?: boolean | undefined
|
|
2684
|
-
}
|
|
2685
|
-
const tokensByAddress = new Map<string, Token>()
|
|
2686
|
-
const uniqueTokens = [...new Set(addresses)]
|
|
2687
|
-
if (uniqueTokens.length === 0) return tokensByAddress
|
|
2688
|
-
const snapshot =
|
|
2689
|
-
includeLogoUri || includeVerified
|
|
2690
|
-
? await VerifiedTokens.snapshot(c, chainId).catch(() => undefined)
|
|
2691
|
-
: undefined
|
|
2692
|
-
|
|
2693
|
-
const resolved = await Timing.time(c, 'tokens', () =>
|
|
2694
|
-
Promise.all(
|
|
2695
|
-
uniqueTokens.map(async (token) => {
|
|
2696
|
-
try {
|
|
2697
|
-
const [logoUri, metadata] = await Promise.all([
|
|
2698
|
-
includeLogoUri
|
|
2699
|
-
? Timing.time(c, 'token_logo', () =>
|
|
2700
|
-
Tokens.getTokenLogo(c, { address: token, chainId }),
|
|
2701
|
-
).catch(() => undefined)
|
|
2702
|
-
: undefined,
|
|
2703
|
-
Timing.time(c, 'token_metadata', () =>
|
|
2704
|
-
Tokens.getTokenMetadata(c, { address: token, chainId }),
|
|
2705
|
-
),
|
|
2706
|
-
])
|
|
2707
|
-
return [
|
|
2708
|
-
token,
|
|
2709
|
-
{
|
|
2710
|
-
address: token,
|
|
2711
|
-
currency: metadata.currency,
|
|
2712
|
-
decimals: metadata.decimals,
|
|
2713
|
-
id: token,
|
|
2714
|
-
logoUri: includeLogoUri
|
|
2715
|
-
? (logoUri ?? snapshot?.byAddress.get(token)?.logoUri ?? metadata.logoUri)
|
|
2716
|
-
: undefined,
|
|
2717
|
-
name: metadata.name,
|
|
2718
|
-
symbol: metadata.symbol,
|
|
2719
|
-
verified: includeVerified ? snapshot?.byAddress.has(token) : undefined,
|
|
2720
|
-
},
|
|
2721
|
-
] as const
|
|
2722
|
-
} catch {
|
|
2723
|
-
return [token, undefined] as const
|
|
2724
|
-
}
|
|
2725
|
-
}),
|
|
2726
|
-
),
|
|
2727
|
-
)
|
|
2728
|
-
for (const [token, metadata] of resolved) if (metadata) tokensByAddress.set(token, metadata)
|
|
2729
|
-
return tokensByAddress
|
|
2730
|
-
}
|
|
2731
|
-
|
|
2732
3061
|
async function getPairs(c: Context<App.Environment>, options: getPairs.Options) {
|
|
2733
3062
|
if (options.sort === 'liquidity') return getPairsByLiquidity(c, options)
|
|
2734
3063
|
return getPairsByCreation(c, options)
|
|
@@ -2974,6 +3303,110 @@ declare namespace getPairIndex {
|
|
|
2974
3303
|
}
|
|
2975
3304
|
}
|
|
2976
3305
|
|
|
3306
|
+
/**
|
|
3307
|
+
* Base-address chunk size for {@link getPairsByBase}. `tidx.fetch` transmits
|
|
3308
|
+
* queries as GET, so an unbounded `IN (...)` could overflow the request URI.
|
|
3309
|
+
*/
|
|
3310
|
+
const pairLookupBatchSize = 200
|
|
3311
|
+
|
|
3312
|
+
/**
|
|
3313
|
+
* Resolves the pairs for a set of book base addresses with one targeted
|
|
3314
|
+
* `dex_pairs` lookup, avoiding the full pair-index fetch (1MB+ on large
|
|
3315
|
+
* chains).
|
|
3316
|
+
*/
|
|
3317
|
+
async function getPairsByBase(c: Context<App.Environment>, options: getPairsByBase.Options) {
|
|
3318
|
+
const { bases, chainId } = options
|
|
3319
|
+
const pairs = new Map<string, getPairsByBase.Pair>()
|
|
3320
|
+
if (bases.length === 0) return pairs
|
|
3321
|
+
const tidx = c.get('getTidx')(chainId)
|
|
3322
|
+
|
|
3323
|
+
return Timing.time(c, 'pair_lookup', async () => {
|
|
3324
|
+
for (let i = 0; i < bases.length; i += pairLookupBatchSize) {
|
|
3325
|
+
const list = bases
|
|
3326
|
+
.slice(i, i + pairLookupBatchSize)
|
|
3327
|
+
.map((base) => `'${base}'`)
|
|
3328
|
+
.join(', ')
|
|
3329
|
+
// `LIMIT 1 BY base` with the ascending sort picks each base's oldest
|
|
3330
|
+
// row, the row the pair index's last-entry-wins `Map` build selects.
|
|
3331
|
+
const result = await tidx.fetch({
|
|
3332
|
+
chainId,
|
|
3333
|
+
engine: 'clickhouse',
|
|
3334
|
+
query: `
|
|
3335
|
+
SELECT key, base, quote
|
|
3336
|
+
FROM dex_pairs
|
|
3337
|
+
WHERE address = '${stablecoinDex}' AND base IN (${list})
|
|
3338
|
+
ORDER BY block_num ASC, log_idx ASC
|
|
3339
|
+
LIMIT 1 BY base
|
|
3340
|
+
` as string,
|
|
3341
|
+
})
|
|
3342
|
+
// Drop malformed rows, mirroring `parsePairRow`.
|
|
3343
|
+
for (const row of result.rows) {
|
|
3344
|
+
const key = Schema.Hash.safeParse(row['key'])
|
|
3345
|
+
const base = Schema.TokenAddress.safeParse(row['base'])
|
|
3346
|
+
const quote = Schema.TokenAddress.safeParse(row['quote'])
|
|
3347
|
+
if (key.success && base.success && quote.success)
|
|
3348
|
+
pairs.set(base.data, { base: base.data, key: key.data, quote: quote.data })
|
|
3349
|
+
}
|
|
3350
|
+
}
|
|
3351
|
+
return pairs
|
|
3352
|
+
})
|
|
3353
|
+
}
|
|
3354
|
+
|
|
3355
|
+
declare namespace getPairsByBase {
|
|
3356
|
+
type Options = {
|
|
3357
|
+
/** Book base addresses to resolve (lowercase). */
|
|
3358
|
+
bases: readonly string[]
|
|
3359
|
+
chainId: z.output<typeof Schema.ChainId>
|
|
3360
|
+
}
|
|
3361
|
+
/** Pair fields consumed by the swap and order feeds. */
|
|
3362
|
+
type Pair = {
|
|
3363
|
+
base: z.output<typeof Schema.TokenAddress>
|
|
3364
|
+
key: z.output<typeof Schema.Hash>
|
|
3365
|
+
quote: z.output<typeof Schema.TokenAddress>
|
|
3366
|
+
}
|
|
3367
|
+
}
|
|
3368
|
+
|
|
3369
|
+
/**
|
|
3370
|
+
* Resolves one pair by its book key with a targeted `dex_pairs` lookup,
|
|
3371
|
+
* covering books the bounded pair index ages out of its newest window.
|
|
3372
|
+
*/
|
|
3373
|
+
async function getPairByKey(c: Context<App.Environment>, options: getPairByKey.Options) {
|
|
3374
|
+
const { chainId, key } = options
|
|
3375
|
+
const tidx = c.get('getTidx')(chainId)
|
|
3376
|
+
|
|
3377
|
+
return Timing.time(c, 'pair_lookup', async () => {
|
|
3378
|
+
// The ascending sort picks the key's oldest row, matching the pair
|
|
3379
|
+
// index's last-entry-wins `Map` build.
|
|
3380
|
+
const result = await tidx.fetch({
|
|
3381
|
+
chainId,
|
|
3382
|
+
engine: 'clickhouse',
|
|
3383
|
+
query: `
|
|
3384
|
+
SELECT key, base, quote
|
|
3385
|
+
FROM dex_pairs
|
|
3386
|
+
WHERE address = '${stablecoinDex}' AND key = '${key}'
|
|
3387
|
+
ORDER BY block_num ASC, log_idx ASC
|
|
3388
|
+
LIMIT 1
|
|
3389
|
+
` as string,
|
|
3390
|
+
})
|
|
3391
|
+
const row = result.rows[0]
|
|
3392
|
+
if (!row) return undefined
|
|
3393
|
+
// Drop malformed rows, mirroring `parsePairRow`.
|
|
3394
|
+
const parsedKey = Schema.Hash.safeParse(row['key'])
|
|
3395
|
+
const base = Schema.TokenAddress.safeParse(row['base'])
|
|
3396
|
+
const quote = Schema.TokenAddress.safeParse(row['quote'])
|
|
3397
|
+
if (!parsedKey.success || !base.success || !quote.success) return undefined
|
|
3398
|
+
return { base: base.data, key: parsedKey.data, quote: quote.data }
|
|
3399
|
+
})
|
|
3400
|
+
}
|
|
3401
|
+
|
|
3402
|
+
declare namespace getPairByKey {
|
|
3403
|
+
type Options = {
|
|
3404
|
+
chainId: z.output<typeof Schema.ChainId>
|
|
3405
|
+
/** Book key (lowercase). */
|
|
3406
|
+
key: string
|
|
3407
|
+
}
|
|
3408
|
+
}
|
|
3409
|
+
|
|
2977
3410
|
/**
|
|
2978
3411
|
* Validates and shapes one `PairCreated` row into the internal pair shape.
|
|
2979
3412
|
* Returns `undefined` for malformed rows so the caller can drop them without
|
|
@@ -3075,7 +3508,6 @@ async function getSwaps(c: Context<App.Environment>, options: getSwaps.Options)
|
|
|
3075
3508
|
limit,
|
|
3076
3509
|
maker,
|
|
3077
3510
|
order,
|
|
3078
|
-
pairIndex,
|
|
3079
3511
|
participant,
|
|
3080
3512
|
taker,
|
|
3081
3513
|
toBlock,
|
|
@@ -3221,16 +3653,17 @@ async function getSwaps(c: Context<App.Environment>, options: getSwaps.Options)
|
|
|
3221
3653
|
}),
|
|
3222
3654
|
)
|
|
3223
3655
|
|
|
3224
|
-
// Each fill's book quote: from
|
|
3225
|
-
// the base token's on-chain
|
|
3226
|
-
//
|
|
3227
|
-
// `dex_pairs` row.
|
|
3656
|
+
// Each fill's book quote: from a targeted `dex_pairs` lookup of this
|
|
3657
|
+
// batch's bases when indexed, else the base token's on-chain
|
|
3658
|
+
// `quoteToken()` — some books predate the indexer's `PairCreated`
|
|
3659
|
+
// decode (genesis system books) and have no `dex_pairs` row.
|
|
3228
3660
|
const bases = [
|
|
3229
3661
|
...new Set([...states.values()].flatMap((events) => events.map((event) => event.token))),
|
|
3230
3662
|
]
|
|
3663
|
+
const pairs = await getPairsByBase(c, { bases, chainId })
|
|
3231
3664
|
const quoteByBase = new Map<string, z.output<typeof Schema.TokenAddress>>()
|
|
3232
3665
|
for (const bookBase of bases) {
|
|
3233
|
-
const indexed =
|
|
3666
|
+
const indexed = pairs.get(bookBase)
|
|
3234
3667
|
if (indexed) quoteByBase.set(bookBase, indexed.quote)
|
|
3235
3668
|
}
|
|
3236
3669
|
const fallback = await Timing.time(c, 'swap_quotes', () =>
|
|
@@ -3517,8 +3950,6 @@ declare namespace getSwaps {
|
|
|
3517
3950
|
maker?: z.output<typeof Schema.Address> | undefined
|
|
3518
3951
|
/** Sort direction over `(block_num, first fill log_idx)`. */
|
|
3519
3952
|
order: 'asc' | 'desc'
|
|
3520
|
-
/** Pair index (base address → pair) used to orient each fill's book. */
|
|
3521
|
-
pairIndex: Map<string, getPairs.Row>
|
|
3522
3953
|
/** Either-side filter — the taker or any fill's maker. */
|
|
3523
3954
|
participant?: z.output<typeof Schema.Address> | undefined
|
|
3524
3955
|
taker?: z.output<typeof Schema.Address> | undefined
|
|
@@ -4321,11 +4752,11 @@ const orderCursorTickBias = 32768
|
|
|
4321
4752
|
* `remaining = OrderPlaced.amount - sum(OrderFilled.amountFilled)`; orders
|
|
4322
4753
|
* with an `OrderCancelled` event are excluded outright. Each row is annotated
|
|
4323
4754
|
* with its pair: the scoped feed reuses the resolved `pair`, the unscoped
|
|
4324
|
-
* feed resolves
|
|
4325
|
-
* unknown are dropped).
|
|
4755
|
+
* feed resolves the page's base tokens with one targeted `dex_pairs` lookup
|
|
4756
|
+
* (rows whose pair is unknown are dropped).
|
|
4326
4757
|
*/
|
|
4327
4758
|
async function getOrders(c: Context<App.Environment>, options: getOrders.Options) {
|
|
4328
|
-
const { chainId, cursor, limit, maker, order, page, pair,
|
|
4759
|
+
const { chainId, cursor, limit, maker, order, page, pair, side, sort } = options
|
|
4329
4760
|
const store = c.get('store')
|
|
4330
4761
|
|
|
4331
4762
|
return Timing.time(c, 'orders', async () => {
|
|
@@ -4357,9 +4788,12 @@ async function getOrders(c: Context<App.Environment>, options: getOrders.Options
|
|
|
4357
4788
|
sort,
|
|
4358
4789
|
})
|
|
4359
4790
|
|
|
4791
|
+
const bases = pair ? [] : [...new Set(pageRows.map((row) => row.token))]
|
|
4792
|
+
const pairsByBase = await getPairsByBase(c, { bases, chainId })
|
|
4793
|
+
|
|
4360
4794
|
const data: z.output<typeof schema.getOrders.Order>[] = []
|
|
4361
4795
|
for (const row of pageRows) {
|
|
4362
|
-
const rowPair = pair ??
|
|
4796
|
+
const rowPair = pair ?? pairsByBase.get(row.token)
|
|
4363
4797
|
if (!rowPair) continue
|
|
4364
4798
|
const shaped = shapeRestingOrder(row)
|
|
4365
4799
|
if (!shaped) continue
|
|
@@ -4391,9 +4825,7 @@ declare namespace getOrders {
|
|
|
4391
4825
|
/** Sort direction applied to whatever `sort` selects. */
|
|
4392
4826
|
order: 'asc' | 'desc'
|
|
4393
4827
|
/** When set, scope the snapshot to this resolved pair. */
|
|
4394
|
-
pair?:
|
|
4395
|
-
/** Pair index (base address → pair) used to resolve unscoped rows. */
|
|
4396
|
-
pairIndex: Map<string, getPairs.Row>
|
|
4828
|
+
pair?: getPairsByBase.Pair | undefined
|
|
4397
4829
|
/** Restrict to one side of the book. */
|
|
4398
4830
|
side?: 'bid' | 'ask' | undefined
|
|
4399
4831
|
/** Sort key. `tick` ranks by price; `time` orders by placement (block, log). */
|
|
@@ -4696,10 +5128,16 @@ async function loadRestingOrders(
|
|
|
4696
5128
|
|
|
4697
5129
|
const truncated = result.rows.length > scanCap
|
|
4698
5130
|
const placedRows = result.rows.slice(0, scanCap)
|
|
5131
|
+
// `dex_orders` can carry duplicate rows per placement; keep the first
|
|
5132
|
+
// (newest) copy so pages emit each order once and a duplicate straddling an
|
|
5133
|
+
// IN-batch boundary can't double-count fills.
|
|
4699
5134
|
const placed: RestingOrder[] = []
|
|
5135
|
+
const seen = new Set<string>()
|
|
4700
5136
|
for (const row of placedRows) {
|
|
4701
5137
|
const parsed = parsePlacedRow(row)
|
|
4702
|
-
if (parsed
|
|
5138
|
+
if (!parsed || seen.has(parsed.orderId)) continue
|
|
5139
|
+
seen.add(parsed.orderId)
|
|
5140
|
+
placed.push(parsed)
|
|
4703
5141
|
}
|
|
4704
5142
|
if (placed.length === 0) return { orders: [], truncated }
|
|
4705
5143
|
|
|
@@ -4765,12 +5203,14 @@ export async function resolveBookReserves(
|
|
|
4765
5203
|
const tidx = c.get('getTidx')(chainId)
|
|
4766
5204
|
|
|
4767
5205
|
// Scan the newest `scanCap` `OrderPlaced` rows per base. `LIMIT ... BY token`
|
|
4768
|
-
// is the ClickHouse fair cap
|
|
4769
|
-
//
|
|
4770
|
-
//
|
|
5206
|
+
// is the ClickHouse fair cap over raw rows; `rawPerToken` flips `truncated`
|
|
5207
|
+
// when a token's window overflows, since unfetched older rows may hold unique
|
|
5208
|
+
// placements even when duplicates keep the unique count under the cap.
|
|
4771
5209
|
let truncated = false
|
|
4772
5210
|
const placed: RestingOrder[] = []
|
|
4773
5211
|
const perToken = new Map<string, number>()
|
|
5212
|
+
const rawPerToken = new Map<string, number>()
|
|
5213
|
+
const seen = new Set<string>()
|
|
4774
5214
|
for (let i = 0; i < unique.length; i += reserveBaseInBatchSize) {
|
|
4775
5215
|
const group = unique.slice(i, i + reserveBaseInBatchSize)
|
|
4776
5216
|
const list = group.map((base) => `'${base}'`).join(', ')
|
|
@@ -4788,11 +5228,15 @@ export async function resolveBookReserves(
|
|
|
4788
5228
|
for (const row of result.rows) {
|
|
4789
5229
|
const parsed = parsePlacedRow(row)
|
|
4790
5230
|
if (!parsed) continue
|
|
5231
|
+
const raw = (rawPerToken.get(parsed.token) ?? 0) + 1
|
|
5232
|
+
rawPerToken.set(parsed.token, raw)
|
|
5233
|
+
if (raw > scanCap) truncated = true
|
|
5234
|
+
// Duplicate placement rows (see `loadRestingOrders`) can't add the same
|
|
5235
|
+
// order's remaining liquidity twice; the raw probe above still counts them.
|
|
5236
|
+
if (seen.has(parsed.orderId)) continue
|
|
4791
5237
|
const count = perToken.get(parsed.token) ?? 0
|
|
4792
|
-
if (count >= scanCap)
|
|
4793
|
-
|
|
4794
|
-
continue
|
|
4795
|
-
}
|
|
5238
|
+
if (count >= scanCap) continue
|
|
5239
|
+
seen.add(parsed.orderId)
|
|
4796
5240
|
perToken.set(parsed.token, count + 1)
|
|
4797
5241
|
placed.push(parsed)
|
|
4798
5242
|
}
|
|
@@ -4908,6 +5352,9 @@ async function fetchCancelledByIds(
|
|
|
4908
5352
|
const cancelled = new Set<string>()
|
|
4909
5353
|
if (orderIds.length === 0) return cancelled
|
|
4910
5354
|
const tidx = c.get('getTidx')(chainId)
|
|
5355
|
+
// Chunks resolve serially: the managed indexer rejects bursts of concurrent
|
|
5356
|
+
// chunk queries (~2-3 in flight), and the cancel/fill helpers already
|
|
5357
|
+
// overlap via `Promise.all`.
|
|
4911
5358
|
for (let i = 0; i < orderIds.length; i += orderInBatchSize) {
|
|
4912
5359
|
const batch = orderIds.slice(i, i + orderInBatchSize)
|
|
4913
5360
|
const result = await tidx.fetch({
|
|
@@ -4942,6 +5389,9 @@ async function fetchFillSumsByIds(
|
|
|
4942
5389
|
const sums = new Map<string, bigint>()
|
|
4943
5390
|
if (orderIds.length === 0) return sums
|
|
4944
5391
|
const tidx = c.get('getTidx')(chainId)
|
|
5392
|
+
// Chunks resolve serially: the managed indexer rejects bursts of concurrent
|
|
5393
|
+
// chunk queries (~2-3 in flight), and the cancel/fill helpers already
|
|
5394
|
+
// overlap via `Promise.all`.
|
|
4945
5395
|
for (let i = 0; i < orderIds.length; i += orderInBatchSize) {
|
|
4946
5396
|
const batch = orderIds.slice(i, i + orderInBatchSize)
|
|
4947
5397
|
const result = await tidx.fetch({
|
|
@@ -5055,31 +5505,28 @@ async function getOrder(c: Context<App.Environment>, options: getOrder.Options)
|
|
|
5055
5505
|
Store.memoize(
|
|
5056
5506
|
async () => {
|
|
5057
5507
|
// The on-chain DEX exposes the full order struct (placement params
|
|
5058
|
-
// plus current `remaining`) in one view call.
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
throw cause
|
|
5070
|
-
}),
|
|
5071
|
-
),
|
|
5072
|
-
getPairIndexByKey(c, { chainId }),
|
|
5073
|
-
])
|
|
5508
|
+
// plus current `remaining`) in one view call.
|
|
5509
|
+
const chainOrder = await Timing.time(c, 'order_dex_get', () =>
|
|
5510
|
+
// The DEX reverts with `OrderDoesNotExist()` for ids it no longer
|
|
5511
|
+
// holds (never placed, or filled/cancelled and cleared), rather
|
|
5512
|
+
// than returning the zero struct. Map that revert to not-found so
|
|
5513
|
+
// the route answers 404 instead of bubbling up as a 502.
|
|
5514
|
+
client.dex.getOrder({ orderId: BigInt(orderId) }).catch((cause) => {
|
|
5515
|
+
if (isOrderDoesNotExist(cause)) return undefined
|
|
5516
|
+
throw cause
|
|
5517
|
+
}),
|
|
5518
|
+
)
|
|
5074
5519
|
|
|
5075
5520
|
// The DEX returns the zero struct (or reverts, handled above) when an
|
|
5076
5521
|
// order id is unknown.
|
|
5077
5522
|
if (!chainOrder || chainOrder.orderId === 0n) return undefined
|
|
5078
5523
|
|
|
5079
|
-
//
|
|
5080
|
-
//
|
|
5081
|
-
|
|
5082
|
-
|
|
5524
|
+
// Targeted lookup off the returned `bookKey`; the bounded pair index
|
|
5525
|
+
// misses books outside its newest window, 404ing live orders.
|
|
5526
|
+
const pair = await getPairByKey(c, {
|
|
5527
|
+
chainId,
|
|
5528
|
+
key: chainOrder.bookKey.toLowerCase(),
|
|
5529
|
+
})
|
|
5083
5530
|
if (!pair) return undefined
|
|
5084
5531
|
|
|
5085
5532
|
const tick = chainOrder.tick
|
|
@@ -5151,11 +5598,187 @@ function isOrderDoesNotExist(error: unknown): boolean {
|
|
|
5151
5598
|
)
|
|
5152
5599
|
}
|
|
5153
5600
|
|
|
5154
|
-
|
|
5601
|
+
async function providerQuoteResponse(
|
|
5602
|
+
c: Context<App.Environment>,
|
|
5603
|
+
options: {
|
|
5604
|
+
chainId: number
|
|
5605
|
+
gasPrice: bigint
|
|
5606
|
+
gasUnits: bigint
|
|
5607
|
+
include: readonly z.output<typeof schema.createQuote.Include>[]
|
|
5608
|
+
oracle: FxOracle.Oracle
|
|
5609
|
+
provider: ExchangeProvider.Provider
|
|
5610
|
+
query: z.output<typeof schema.createQuote.Query>
|
|
5611
|
+
quote: ExchangeProvider.QuoteResult
|
|
5612
|
+
request: z.output<typeof schema.createQuote.Request>
|
|
5613
|
+
},
|
|
5614
|
+
) {
|
|
5615
|
+
const { chainId, gasPrice, gasUnits, oracle, provider, query, quote, request } = options
|
|
5616
|
+
const tokensByAddress = await Tokens.resolveTokens(c, {
|
|
5617
|
+
addresses: [request.destinationToken, request.sourceToken],
|
|
5618
|
+
chainId,
|
|
5619
|
+
include: options.include,
|
|
5620
|
+
})
|
|
5621
|
+
const destinationToken = tokensByAddress.get(request.destinationToken)
|
|
5622
|
+
const sourceToken = tokensByAddress.get(request.sourceToken)
|
|
5623
|
+
if (!destinationToken || !sourceToken)
|
|
5624
|
+
throw new Error('Unable to resolve exchange quote token metadata')
|
|
5625
|
+
|
|
5626
|
+
const denomination = query['valuation.currency'] ?? 'USD'
|
|
5627
|
+
const snapshot = await VerifiedTokens.snapshot(c, chainId).catch(() => undefined)
|
|
5628
|
+
const rates = await Valuation.ratesFor(c, {
|
|
5629
|
+
currencies: snapshot
|
|
5630
|
+
? [request.destinationToken, request.sourceToken].flatMap((address) => {
|
|
5631
|
+
const held = snapshot.byAddress.get(address.toLowerCase())?.currency
|
|
5632
|
+
return held === undefined ? [] : [held]
|
|
5633
|
+
})
|
|
5634
|
+
: [],
|
|
5635
|
+
denomination,
|
|
5636
|
+
oracle,
|
|
5637
|
+
})
|
|
5638
|
+
const valued = (
|
|
5639
|
+
baseUnits: bigint | string,
|
|
5640
|
+
address: string,
|
|
5641
|
+
token: { currency: string; decimals: number },
|
|
5642
|
+
) => ({
|
|
5643
|
+
...Value.tokenAmount({ baseUnits, currency: token.currency, decimals: token.decimals }),
|
|
5644
|
+
valuation: Valuation.valuationFor({
|
|
5645
|
+
amount: BigInt(baseUnits),
|
|
5646
|
+
denomination,
|
|
5647
|
+
rates,
|
|
5648
|
+
token: snapshot?.byAddress.get(address.toLowerCase()),
|
|
5649
|
+
}),
|
|
5650
|
+
})
|
|
5651
|
+
const execution =
|
|
5652
|
+
quote.status === 'ready'
|
|
5653
|
+
? {
|
|
5654
|
+
status: quote.status,
|
|
5655
|
+
transaction: { calls: [...quote.transaction.calls], chainId },
|
|
5656
|
+
}
|
|
5657
|
+
: quote.status === 'approvalRequired'
|
|
5658
|
+
? { approval: { calls: [...quote.approval.calls] }, status: quote.status }
|
|
5659
|
+
: {
|
|
5660
|
+
continuation: quote.continuation,
|
|
5661
|
+
status: quote.status,
|
|
5662
|
+
typedData: quote.typedData,
|
|
5663
|
+
}
|
|
5664
|
+
const common = {
|
|
5665
|
+
destinationToken: { ...destinationToken, address: request.destinationToken },
|
|
5666
|
+
...execution,
|
|
5667
|
+
...(rates ? { meta: { valuation: Valuation.pricing(rates, oracle) } } : {}),
|
|
5668
|
+
gasEstimate: gasCost({ gasPrice, gasUnits }),
|
|
5669
|
+
provider: provider.id,
|
|
5670
|
+
sourceToken: { ...sourceToken, address: request.sourceToken },
|
|
5671
|
+
}
|
|
5672
|
+
|
|
5673
|
+
if (request.mode === 'exactSource') {
|
|
5674
|
+
if (!quote.minimumDestinationAmount) throw new ExchangeProvider.ProviderPayloadError()
|
|
5675
|
+
return {
|
|
5676
|
+
...common,
|
|
5677
|
+
destinationAmount: valued(
|
|
5678
|
+
quote.destinationAmount,
|
|
5679
|
+
request.destinationToken,
|
|
5680
|
+
destinationToken,
|
|
5681
|
+
),
|
|
5682
|
+
destinationAmountMin: valued(
|
|
5683
|
+
quote.minimumDestinationAmount,
|
|
5684
|
+
request.destinationToken,
|
|
5685
|
+
destinationToken,
|
|
5686
|
+
),
|
|
5687
|
+
mode: request.mode,
|
|
5688
|
+
sourceAmount: valued(quote.sourceAmount, request.sourceToken, sourceToken),
|
|
5689
|
+
}
|
|
5690
|
+
}
|
|
5691
|
+
|
|
5692
|
+
if (!quote.maximumSourceAmount) throw new ExchangeProvider.ProviderPayloadError()
|
|
5693
|
+
return {
|
|
5694
|
+
...common,
|
|
5695
|
+
destinationAmount: valued(quote.destinationAmount, request.destinationToken, destinationToken),
|
|
5696
|
+
mode: request.mode,
|
|
5697
|
+
sourceAmount: valued(quote.sourceAmount, request.sourceToken, sourceToken),
|
|
5698
|
+
sourceAmountMax: valued(quote.maximumSourceAmount, request.sourceToken, sourceToken),
|
|
5699
|
+
}
|
|
5700
|
+
}
|
|
5701
|
+
|
|
5702
|
+
function providerExecution(options: providerExecution.Options): ExchangeProvider.Execution {
|
|
5703
|
+
const { quote, request } = options
|
|
5704
|
+
return {
|
|
5705
|
+
destinationAmount: quote.destinationAmount,
|
|
5706
|
+
destinationToken: request.destinationToken,
|
|
5707
|
+
gasUnits: quote.gasUnits,
|
|
5708
|
+
...(quote.maximumSourceAmount ? { maximumSourceAmount: quote.maximumSourceAmount } : {}),
|
|
5709
|
+
...(quote.minimumDestinationAmount
|
|
5710
|
+
? { minimumDestinationAmount: quote.minimumDestinationAmount }
|
|
5711
|
+
: {}),
|
|
5712
|
+
mode: request.mode,
|
|
5713
|
+
sourceAmount: quote.sourceAmount,
|
|
5714
|
+
sourceToken: request.sourceToken,
|
|
5715
|
+
}
|
|
5716
|
+
}
|
|
5717
|
+
|
|
5718
|
+
declare namespace providerExecution {
|
|
5719
|
+
type Options = {
|
|
5720
|
+
quote: ExchangeProvider.QuoteResult
|
|
5721
|
+
request: z.output<typeof schema.createQuote.Request>
|
|
5722
|
+
}
|
|
5723
|
+
}
|
|
5724
|
+
|
|
5725
|
+
async function validateProviderCalls(
|
|
5726
|
+
client: Viem.getClient.ReturnType,
|
|
5727
|
+
options: validateProviderCalls.Options,
|
|
5728
|
+
) {
|
|
5729
|
+
try {
|
|
5730
|
+
const { results } = await Actions.simulate.simulateCalls(client, {
|
|
5731
|
+
account: options.account,
|
|
5732
|
+
calls: options.calls.map((call) => ({
|
|
5733
|
+
data: call.data,
|
|
5734
|
+
to: call.to,
|
|
5735
|
+
value: BigInt(call.value),
|
|
5736
|
+
})),
|
|
5737
|
+
traceTransfers: true,
|
|
5738
|
+
})
|
|
5739
|
+
if (results.some((result) => result.status !== 'success'))
|
|
5740
|
+
throw new ExchangeProvider.ProviderPayloadError()
|
|
5741
|
+
|
|
5742
|
+
const logs = results.flatMap((result) => result.logs ?? [])
|
|
5743
|
+
const transfers = parseEventLogs({
|
|
5744
|
+
abi: [AbiEvent.fromAbi(Abis.tip20, 'Transfer')],
|
|
5745
|
+
eventName: 'Transfer',
|
|
5746
|
+
logs,
|
|
5747
|
+
}).map((log) => ({
|
|
5748
|
+
amount: log.args.amount,
|
|
5749
|
+
from: log.args.from,
|
|
5750
|
+
to: log.args.to,
|
|
5751
|
+
token: log.address,
|
|
5752
|
+
}))
|
|
5753
|
+
ExchangeProvider.validateExecution({
|
|
5754
|
+
account: options.account,
|
|
5755
|
+
execution: options.execution,
|
|
5756
|
+
transfers,
|
|
5757
|
+
})
|
|
5758
|
+
} catch (cause) {
|
|
5759
|
+
if (cause instanceof ExchangeProvider.ProviderPayloadError) throw cause
|
|
5760
|
+
throw new ExchangeProvider.ProviderPayloadError()
|
|
5761
|
+
}
|
|
5762
|
+
}
|
|
5763
|
+
|
|
5764
|
+
declare namespace validateProviderCalls {
|
|
5765
|
+
type Options = {
|
|
5766
|
+
account: `0x${string}`
|
|
5767
|
+
calls: readonly ExchangeProvider.Call[]
|
|
5768
|
+
execution: ExchangeProvider.Execution
|
|
5769
|
+
}
|
|
5770
|
+
}
|
|
5771
|
+
|
|
5772
|
+
/** Converts estimated gas units to a native-token base-unit fee. */
|
|
5773
|
+
function gasCost(options: { gasPrice: bigint; gasUnits: bigint }) {
|
|
5774
|
+
return (options.gasPrice * options.gasUnits).toString()
|
|
5775
|
+
}
|
|
5776
|
+
|
|
5777
|
+
/** Returns the 404 used when no executable quote is available. */
|
|
5155
5778
|
function quoteNotAvailable(c: Context<App.Environment>) {
|
|
5156
5779
|
return Response.error(c, {
|
|
5157
5780
|
code: 'quote_not_available',
|
|
5158
|
-
message: 'No
|
|
5781
|
+
message: 'No configured exchange provider has an executable quote',
|
|
5159
5782
|
status: 404,
|
|
5160
5783
|
})
|
|
5161
5784
|
}
|
|
@@ -5309,18 +5932,6 @@ declare namespace countOrderFills {
|
|
|
5309
5932
|
}
|
|
5310
5933
|
}
|
|
5311
5934
|
|
|
5312
|
-
/**
|
|
5313
|
-
* Per-key pair index derived from the existing per-base index. Built once
|
|
5314
|
-
* and memoized at the same cadence as the pair index itself so chained
|
|
5315
|
-
* `getOrder` lookups stay an O(1) `Map.get`.
|
|
5316
|
-
*/
|
|
5317
|
-
async function getPairIndexByKey(c: Context<App.Environment>, options: getPairIndex.Options) {
|
|
5318
|
-
const pairsByBase = await getPairIndex(c, options)
|
|
5319
|
-
const pairsByKey = new Map<string, getPairs.Row>()
|
|
5320
|
-
for (const pair of pairsByBase.values()) pairsByKey.set(pair.key.toLowerCase(), pair)
|
|
5321
|
-
return pairsByKey
|
|
5322
|
-
}
|
|
5323
|
-
|
|
5324
5935
|
/**
|
|
5325
5936
|
* Validates and shapes one `OrderFilled` row into the public `Fill` shape.
|
|
5326
5937
|
* Drops the row when any required column is malformed so the caller can omit
|
|
@@ -5358,3 +5969,7 @@ function parseOrderFillRow(
|
|
|
5358
5969
|
transactionHash: transactionHash.data,
|
|
5359
5970
|
}
|
|
5360
5971
|
}
|
|
5972
|
+
|
|
5973
|
+
class NativeDexAmountOutOfRangeError extends Error {
|
|
5974
|
+
override name = 'Exchanges.NativeDexAmountOutOfRangeError'
|
|
5975
|
+
}
|