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
|
@@ -0,0 +1,1796 @@
|
|
|
1
|
+
import { Address, Base58, Bytes, Hash, Value as core_Value } from 'ox'
|
|
2
|
+
import * as z from 'zod/mini'
|
|
3
|
+
|
|
4
|
+
import * as core_Provider from '../Provider.js'
|
|
5
|
+
import * as Schema from '../Schema.js'
|
|
6
|
+
import * as Value from '../Value.js'
|
|
7
|
+
import * as Action from './Action.js'
|
|
8
|
+
import type * as core_Catalog from './Catalog.js'
|
|
9
|
+
import type * as core_Chain from './Chain.js'
|
|
10
|
+
import type * as core_Route from './Route.js'
|
|
11
|
+
import type * as core_Token from './Token.js'
|
|
12
|
+
import type * as Transfer from './Transfer.js'
|
|
13
|
+
|
|
14
|
+
/** Tempo token used when the caller omits `destinationToken`. */
|
|
15
|
+
const defaultDestinationToken = 'usdce'
|
|
16
|
+
|
|
17
|
+
/** Funding provider schemas. */
|
|
18
|
+
export namespace schema {
|
|
19
|
+
/** Bounded upstream error code safe for structured logs. */
|
|
20
|
+
export const ErrorCode = z.string().check(z.regex(/^[A-Za-z0-9_.:-]{1,64}$/))
|
|
21
|
+
|
|
22
|
+
/** Nested upstream error fields used to extract a stable code. */
|
|
23
|
+
export const Error = z.object({
|
|
24
|
+
code: z.optional(z.string()),
|
|
25
|
+
type: z.optional(z.string()),
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
/** Common upstream error body fields used to extract a stable code. */
|
|
29
|
+
export const ErrorBody = z.object({
|
|
30
|
+
_tag: z.optional(z.string()),
|
|
31
|
+
code: z.optional(z.string()),
|
|
32
|
+
error: z.optional(Error),
|
|
33
|
+
errorCode: z.optional(z.string()),
|
|
34
|
+
errorType: z.optional(z.string()),
|
|
35
|
+
type: z.optional(z.string()),
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
/** Positive decimal amount accepted by funding quote requests. */
|
|
39
|
+
export const PositiveDecimal = z.string().check(z.regex(/^(?=.*[1-9])\d+(\.\d+)?$/))
|
|
40
|
+
|
|
41
|
+
/** Positive base-unit amount accepted by funding quote requests. */
|
|
42
|
+
export const PositiveInteger = z.string().check(z.regex(/^(?=.*[1-9])\d+$/))
|
|
43
|
+
|
|
44
|
+
/** Normalized chain reference passed to funding providers. */
|
|
45
|
+
export const ChainRef = Schema.describe(
|
|
46
|
+
z.object({
|
|
47
|
+
addressFormat: z
|
|
48
|
+
.enum(['base58', 'base58check', 'hex'])
|
|
49
|
+
.check(
|
|
50
|
+
z.describe('Address encoding used by accounts and token identifiers on this chain.'),
|
|
51
|
+
z.meta({ examples: ['hex'] }),
|
|
52
|
+
),
|
|
53
|
+
id: z.string().check(z.describe('CAIP-2 chain id.'), z.meta({ examples: ['eip155:8453'] })),
|
|
54
|
+
kind: z
|
|
55
|
+
.enum(['evm', 'solana', 'tron'])
|
|
56
|
+
.check(
|
|
57
|
+
z.describe('Chain execution family used for provider routing.'),
|
|
58
|
+
z.meta({ examples: ['evm'] }),
|
|
59
|
+
),
|
|
60
|
+
name: z
|
|
61
|
+
.string()
|
|
62
|
+
.check(z.describe('Human-readable chain name.'), z.meta({ examples: ['Base'] })),
|
|
63
|
+
}),
|
|
64
|
+
'A normalized chain reference for funding quotes.',
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
/** Normalized token reference passed to funding providers. */
|
|
68
|
+
export const TokenRef = Schema.describe(
|
|
69
|
+
z.object({
|
|
70
|
+
address: z
|
|
71
|
+
.string()
|
|
72
|
+
.check(
|
|
73
|
+
z.describe('Contract address, mint, or issuer address on the token chain.'),
|
|
74
|
+
z.meta({ examples: ['0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'] }),
|
|
75
|
+
),
|
|
76
|
+
currency: z
|
|
77
|
+
.string()
|
|
78
|
+
.check(
|
|
79
|
+
z.describe('Monetary denomination represented by this token.'),
|
|
80
|
+
z.meta({ examples: ['USD'] }),
|
|
81
|
+
),
|
|
82
|
+
decimals: z
|
|
83
|
+
.number()
|
|
84
|
+
.check(
|
|
85
|
+
z.int(),
|
|
86
|
+
z.gte(0),
|
|
87
|
+
z.describe('Number of decimal places this token uses.'),
|
|
88
|
+
z.meta({ examples: [6] }),
|
|
89
|
+
),
|
|
90
|
+
name: z
|
|
91
|
+
.string()
|
|
92
|
+
.check(z.describe('Human-readable token name.'), z.meta({ examples: ['USD Coin'] })),
|
|
93
|
+
standard: z
|
|
94
|
+
.string()
|
|
95
|
+
.check(z.describe('Token standard on the token chain.'), z.meta({ examples: ['ERC-20'] })),
|
|
96
|
+
symbol: z
|
|
97
|
+
.string()
|
|
98
|
+
.check(z.describe('Short token ticker symbol.'), z.meta({ examples: ['USDC'] })),
|
|
99
|
+
tokenKey: z.string().check(
|
|
100
|
+
z.describe('Stable Tempo token key scoped to the token chain.'),
|
|
101
|
+
z.meta({
|
|
102
|
+
examples: ['eip155:8453/erc20:0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'],
|
|
103
|
+
}),
|
|
104
|
+
),
|
|
105
|
+
verified: z
|
|
106
|
+
.boolean()
|
|
107
|
+
.check(
|
|
108
|
+
z.describe('Whether Tempo recognizes this token in its funding quote inventory.'),
|
|
109
|
+
z.meta({ examples: [true] }),
|
|
110
|
+
),
|
|
111
|
+
}),
|
|
112
|
+
'A normalized token reference for funding quotes.',
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
/** Provider identity embedded in funding resources. */
|
|
116
|
+
export const ProviderRef = Schema.describe(
|
|
117
|
+
z.object({
|
|
118
|
+
id: z.string().check(z.describe('Stable provider id.'), z.meta({ examples: ['relay'] })),
|
|
119
|
+
name: z
|
|
120
|
+
.string()
|
|
121
|
+
.check(z.describe('Human-readable provider name.'), z.meta({ examples: ['Relay'] })),
|
|
122
|
+
}),
|
|
123
|
+
'Provider metadata embedded in a funding quote.',
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
/** Source amount unit accepted by a funding quote request. */
|
|
127
|
+
export const SourceAmountUnits = z
|
|
128
|
+
._default(z.enum(['baseUnits', 'decimal']), 'baseUnits')
|
|
129
|
+
.check(
|
|
130
|
+
z.describe('Whether `sourceAmount` is base units or a human-readable decimal.'),
|
|
131
|
+
z.meta({ examples: ['baseUnits', 'decimal'] }),
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
/** Normalized caller request passed to funding providers. */
|
|
135
|
+
export const QuoteRequest = z
|
|
136
|
+
.strictObject({
|
|
137
|
+
destinationToken: z
|
|
138
|
+
.optional(z.string())
|
|
139
|
+
.check(
|
|
140
|
+
z.describe('Tempo destination token symbol, address, or token key. Defaults to USDC.e.'),
|
|
141
|
+
z.meta({ examples: ['usdc.e'] }),
|
|
142
|
+
),
|
|
143
|
+
provider: z
|
|
144
|
+
.optional(z.string().check(z.minLength(1)))
|
|
145
|
+
.check(
|
|
146
|
+
z.describe(
|
|
147
|
+
'Only request a quote from this provider. Use an id returned by the funding providers endpoint, or omit it to query every available provider.',
|
|
148
|
+
),
|
|
149
|
+
z.meta({ examples: ['relay'] }),
|
|
150
|
+
),
|
|
151
|
+
sourceAmount: PositiveDecimal.check(
|
|
152
|
+
z.describe('Positive source token amount. Base units by default, so 1 USDC is `1000000`.'),
|
|
153
|
+
z.meta({ examples: ['1000000'] }),
|
|
154
|
+
),
|
|
155
|
+
sourceAmountUnits: SourceAmountUnits,
|
|
156
|
+
sourceChain: z
|
|
157
|
+
.string()
|
|
158
|
+
.check(
|
|
159
|
+
z.minLength(1),
|
|
160
|
+
z.describe(
|
|
161
|
+
'Source chain alias or stable id, such as `base`, `solana`, or `eip155:8453`.',
|
|
162
|
+
),
|
|
163
|
+
z.meta({ examples: ['base', 'eip155:8453'] }),
|
|
164
|
+
),
|
|
165
|
+
sourceToken: z
|
|
166
|
+
.string()
|
|
167
|
+
.check(
|
|
168
|
+
z.minLength(1),
|
|
169
|
+
z.describe(
|
|
170
|
+
'Source token symbol, contract address, or Tempo token key. Lookup is scoped to `sourceChain`; non-EVM addresses are case-sensitive. An unknown token returns an empty list.',
|
|
171
|
+
),
|
|
172
|
+
z.meta({ examples: ['usdc', '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'] }),
|
|
173
|
+
),
|
|
174
|
+
})
|
|
175
|
+
.check(z.describe('Query parameters for live funding quotes into Tempo.'))
|
|
176
|
+
|
|
177
|
+
/** Provider-specific quote status for the requested amount. */
|
|
178
|
+
export const QuoteStatus = z.enum(['available', 'thin', 'unknown', 'unavailable'])
|
|
179
|
+
|
|
180
|
+
/** Machine-readable provider quote quality tier. */
|
|
181
|
+
export const QualityTier = z.enum(['liquid', 'thin', 'unknown', 'unavailable'])
|
|
182
|
+
|
|
183
|
+
/** Quote data returned by a funding provider. */
|
|
184
|
+
export const GetQuoteResult = Schema.describe(
|
|
185
|
+
z.object({
|
|
186
|
+
expiresAt: z.optional(z.iso.datetime()),
|
|
187
|
+
destinationAmountMin: z.optional(Schema.DecimalString),
|
|
188
|
+
destinationAmount: z.optional(Schema.DecimalString),
|
|
189
|
+
quality: z.optional(
|
|
190
|
+
z.object({
|
|
191
|
+
estimatedSeconds: z.optional(z.number().check(z.int(), z.nonnegative())),
|
|
192
|
+
liquiditySource: z.string(),
|
|
193
|
+
sourceDetail: z.optional(z.string()),
|
|
194
|
+
tier: z.optional(QualityTier),
|
|
195
|
+
}),
|
|
196
|
+
),
|
|
197
|
+
sampledAt: z.iso.datetime(),
|
|
198
|
+
status: QuoteStatus,
|
|
199
|
+
}),
|
|
200
|
+
'Quote data returned by a funding provider.',
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
/** Executable preparation returned by a funding provider. */
|
|
204
|
+
export const PrepareResult = z.object({
|
|
205
|
+
action: Action.schema.Action,
|
|
206
|
+
correlation: z.object({
|
|
207
|
+
checkEndpoint: z.optional(z.string()),
|
|
208
|
+
requestId: z.string().check(z.minLength(1)),
|
|
209
|
+
}),
|
|
210
|
+
destinationAmount: PositiveInteger,
|
|
211
|
+
destinationAmountMin: PositiveInteger,
|
|
212
|
+
expiresAt: z.optional(z.iso.datetime()),
|
|
213
|
+
fees: z.array(
|
|
214
|
+
z.object({
|
|
215
|
+
amount: Schema.DecimalString,
|
|
216
|
+
side: z.enum(['destination', 'source']),
|
|
217
|
+
}),
|
|
218
|
+
),
|
|
219
|
+
quality: GetQuoteResult.shape.quality,
|
|
220
|
+
sampledAt: z.iso.datetime(),
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
/** Reusable deposit address provisioned by a funding provider. */
|
|
224
|
+
export const DepositAddressResult = z
|
|
225
|
+
.object({
|
|
226
|
+
address: z
|
|
227
|
+
.string()
|
|
228
|
+
.check(z.minLength(1), z.describe('Reusable source-chain deposit address.')),
|
|
229
|
+
correlation: z
|
|
230
|
+
.object({
|
|
231
|
+
checkEndpoint: z
|
|
232
|
+
.optional(z.string())
|
|
233
|
+
.check(z.describe('Provider status endpoint for the original address request.')),
|
|
234
|
+
requestId: z
|
|
235
|
+
.string()
|
|
236
|
+
.check(z.minLength(1), z.describe('Provider-issued address request identifier.')),
|
|
237
|
+
})
|
|
238
|
+
.check(z.describe('Private provider correlation retained for reconciliation.')),
|
|
239
|
+
destinationAmount: PositiveInteger,
|
|
240
|
+
destinationAmountMin: PositiveInteger,
|
|
241
|
+
expiresAt: z.optional(z.iso.datetime()),
|
|
242
|
+
fees: PrepareResult.shape.fees,
|
|
243
|
+
sampledAt: z.iso.datetime(),
|
|
244
|
+
})
|
|
245
|
+
.check(z.describe('Reusable deposit address and quoted delivery terms returned by a provider.'))
|
|
246
|
+
|
|
247
|
+
/** One provider request discovered for a reusable deposit address. */
|
|
248
|
+
export const DepositAddressRequest = z.object({
|
|
249
|
+
createdAt: z.iso.datetime(),
|
|
250
|
+
destinationTransactionHashes: z.array(z.string()),
|
|
251
|
+
id: z.string().check(z.minLength(1)),
|
|
252
|
+
sourceTransactionHashes: z.array(z.string()),
|
|
253
|
+
status: z.string().check(z.minLength(1)),
|
|
254
|
+
updatedAt: z.iso.datetime(),
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
/** One page of provider requests discovered for a reusable address. */
|
|
258
|
+
export const DepositAddressRequestsResult = z.object({
|
|
259
|
+
continuation: z.optional(z.string().check(z.minLength(1))),
|
|
260
|
+
requests: z.array(DepositAddressRequest),
|
|
261
|
+
})
|
|
262
|
+
|
|
263
|
+
/** Quote quality signals exposed to funding API callers. */
|
|
264
|
+
export const FundingQuoteQuality = Schema.describe(
|
|
265
|
+
z.object({
|
|
266
|
+
estimatedSeconds: z
|
|
267
|
+
.optional(z.number().check(z.int(), z.nonnegative()))
|
|
268
|
+
.check(
|
|
269
|
+
z.describe('Estimated settlement time in seconds, when known.'),
|
|
270
|
+
z.meta({ examples: [2] }),
|
|
271
|
+
),
|
|
272
|
+
liquiditySource: z
|
|
273
|
+
.string()
|
|
274
|
+
.check(
|
|
275
|
+
z.describe('Provider source for the live quote quality signal.'),
|
|
276
|
+
z.meta({ examples: ['providerQuote'] }),
|
|
277
|
+
),
|
|
278
|
+
sourceDetail: z
|
|
279
|
+
.optional(z.string())
|
|
280
|
+
.check(
|
|
281
|
+
z.describe('Provider-specific source or endpoint detail for the quality signal.'),
|
|
282
|
+
z.meta({ examples: ['providerEndpoint'] }),
|
|
283
|
+
),
|
|
284
|
+
tier: z
|
|
285
|
+
.enum(['liquid', 'thin'])
|
|
286
|
+
.check(
|
|
287
|
+
z.describe('Machine-readable quote quality tier for a successful quote.'),
|
|
288
|
+
z.meta({ examples: ['liquid'] }),
|
|
289
|
+
),
|
|
290
|
+
}),
|
|
291
|
+
'Machine-readable liquidity, fee, and source signals for a successful quote.',
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
/** Provider quote freshness data exposed to funding API callers. */
|
|
295
|
+
export const QuoteDetails = Schema.describe(
|
|
296
|
+
z.object({
|
|
297
|
+
expiresAt: z
|
|
298
|
+
.optional(z.iso.datetime())
|
|
299
|
+
.check(
|
|
300
|
+
z.describe('Timestamp after which the provider quote is no longer valid.'),
|
|
301
|
+
z.meta({ examples: ['2026-01-01T00:01:00Z'] }),
|
|
302
|
+
),
|
|
303
|
+
sampledAt: z.iso
|
|
304
|
+
.datetime()
|
|
305
|
+
.check(
|
|
306
|
+
z.describe('Timestamp for the live quote request.'),
|
|
307
|
+
z.meta({ examples: ['2026-01-01T00:00:00Z'] }),
|
|
308
|
+
),
|
|
309
|
+
}),
|
|
310
|
+
'Freshness data for a provider funding quote.',
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
/** Successful normalized funding quote returned to callers. */
|
|
314
|
+
export const FundingQuote = Schema.describe(
|
|
315
|
+
z.object({
|
|
316
|
+
destinationAmount: Schema.TokenAmount.check(z.describe('Expected destination amount.')),
|
|
317
|
+
destinationAmountMin: z
|
|
318
|
+
.optional(Schema.TokenAmount)
|
|
319
|
+
.check(
|
|
320
|
+
z.describe(
|
|
321
|
+
'Provider-derived minimum destination amount. Symbiosis and Squid quotes use a fixed 1% slippage tolerance.',
|
|
322
|
+
),
|
|
323
|
+
),
|
|
324
|
+
destinationChain: ChainRef.check(
|
|
325
|
+
z.describe('Destination chain, always Tempo mainnet in V1.'),
|
|
326
|
+
),
|
|
327
|
+
destinationToken: TokenRef.check(z.describe('Tempo token expected from this quote.')),
|
|
328
|
+
id: z
|
|
329
|
+
.string()
|
|
330
|
+
.check(
|
|
331
|
+
z.describe('Stable deterministic funding quote id.'),
|
|
332
|
+
z.meta({ examples: ['base-usdc-tempo-usdce-relay'] }),
|
|
333
|
+
),
|
|
334
|
+
provider: ProviderRef,
|
|
335
|
+
quality: FundingQuoteQuality,
|
|
336
|
+
quote: QuoteDetails,
|
|
337
|
+
sourceAmount: Schema.TokenAmount,
|
|
338
|
+
sourceChain: ChainRef.check(z.describe('Chain where the caller currently holds funds.')),
|
|
339
|
+
sourceToken: TokenRef.check(z.describe('Token the caller currently holds.')),
|
|
340
|
+
}),
|
|
341
|
+
'One successful provider-specific funding quote.',
|
|
342
|
+
)
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/** Chain metadata declared by a funding route. */
|
|
346
|
+
export type Chain = core_Chain.Chain
|
|
347
|
+
|
|
348
|
+
/** Token metadata declared by a funding route. */
|
|
349
|
+
export type Token = core_Token.Resolved
|
|
350
|
+
|
|
351
|
+
/** Provider ids accepted by funding quote requests. */
|
|
352
|
+
export type ProviderId = string
|
|
353
|
+
|
|
354
|
+
/** Provider-specific quote status for the requested amount. */
|
|
355
|
+
export type QuoteStatus = z.output<typeof schema.QuoteStatus>
|
|
356
|
+
|
|
357
|
+
/** Machine-readable quote quality tier. */
|
|
358
|
+
export type QualityTier = z.output<typeof schema.QualityTier>
|
|
359
|
+
|
|
360
|
+
/** Normalized chain reference passed to funding providers. */
|
|
361
|
+
export type ChainRef = z.output<typeof schema.ChainRef>
|
|
362
|
+
|
|
363
|
+
/** Normalized token amount passed to funding providers. */
|
|
364
|
+
export type TokenAmount = ReturnType<typeof resolveSourceAmount>
|
|
365
|
+
|
|
366
|
+
/** Normalized token reference passed to funding providers. */
|
|
367
|
+
export type TokenRef = z.output<typeof schema.TokenRef>
|
|
368
|
+
|
|
369
|
+
/** A normalized internal candidate passed to funding quote providers. */
|
|
370
|
+
export type QuoteCandidate = ReturnType<typeof createQuoteCandidate>
|
|
371
|
+
|
|
372
|
+
/** A normalized route candidate passed to deposit-address providers. */
|
|
373
|
+
export type DepositAddressCandidate = ReturnType<typeof createDepositAddressCandidate>
|
|
374
|
+
|
|
375
|
+
/** A successful normalized funding quote returned to callers. */
|
|
376
|
+
export type FundingQuote = z.output<typeof schema.FundingQuote>
|
|
377
|
+
|
|
378
|
+
/** Cache policy for a single funding quote request. */
|
|
379
|
+
export type CachePolicy = {
|
|
380
|
+
/** Whether providers should bypass their own quote or inventory caches. */
|
|
381
|
+
bypass: boolean
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/** Normalized caller request passed to funding providers. */
|
|
385
|
+
export type QuoteRequest = z.output<typeof schema.QuoteRequest>
|
|
386
|
+
|
|
387
|
+
/** Contract of the provider `getQuote` method. */
|
|
388
|
+
export declare namespace getQuote {
|
|
389
|
+
/** Input passed to a funding provider for one curated quote candidate. */
|
|
390
|
+
type Parameters = {
|
|
391
|
+
/** Curated candidate selected for live provider quoting. */
|
|
392
|
+
candidate: QuoteCandidate
|
|
393
|
+
/** Cache policy for provider-side discovery and quote lookups. */
|
|
394
|
+
cache: CachePolicy
|
|
395
|
+
/** Destination chain, always Tempo mainnet in V1. */
|
|
396
|
+
destinationChain: ChainRef
|
|
397
|
+
/** Tempo token expected from this quote. */
|
|
398
|
+
destinationToken: TokenRef
|
|
399
|
+
/** Normalized caller request that produced this quote candidate. */
|
|
400
|
+
request: QuoteRequest
|
|
401
|
+
/** Canonical funding route selected for this quote candidate. */
|
|
402
|
+
route: core_Route.Route
|
|
403
|
+
/** Source amount in base units and display form. */
|
|
404
|
+
sourceAmount: TokenAmount
|
|
405
|
+
/** Chain where the caller currently holds funds. */
|
|
406
|
+
sourceChain: ChainRef
|
|
407
|
+
/** Token the caller currently holds. */
|
|
408
|
+
sourceToken: TokenRef
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/** Quote data returned by a funding provider. */
|
|
412
|
+
type ReturnType = z.output<typeof schema.GetQuoteResult>
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/** Contract of the provider `prepareTransfer` method. */
|
|
416
|
+
export declare namespace prepareTransfer {
|
|
417
|
+
/** Private provider correlation retained for tracking, never exposed publicly. */
|
|
418
|
+
type Correlation = {
|
|
419
|
+
/** Provider status endpoint bound to this preparation, when returned. */
|
|
420
|
+
checkEndpoint?: string | undefined
|
|
421
|
+
/** Provider-issued request identifier. */
|
|
422
|
+
requestId: string
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/** Input passed to a funding provider preparing one executable transfer. */
|
|
426
|
+
type Parameters = {
|
|
427
|
+
/** Curated candidate selected for preparation. */
|
|
428
|
+
candidate: QuoteCandidate
|
|
429
|
+
/** Funding method the caller selected. */
|
|
430
|
+
method: Transfer.Method
|
|
431
|
+
/** Amount mode the caller selected. */
|
|
432
|
+
mode: Transfer.Mode
|
|
433
|
+
/** Final beneficiary on the destination chain. */
|
|
434
|
+
recipient: string
|
|
435
|
+
/** Source-chain account that signs the funding action. */
|
|
436
|
+
sender: string
|
|
437
|
+
/** Caller slippage bound in basis points. */
|
|
438
|
+
slippageBps?: number | undefined
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/** Executable preparation returned by a funding provider. */
|
|
442
|
+
type ReturnType = z.output<typeof schema.PrepareResult>
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/** Contract of the provider `createDepositAddress` method. */
|
|
446
|
+
export declare namespace createDepositAddress {
|
|
447
|
+
/** Input passed to a provider provisioning one reusable deposit address. */
|
|
448
|
+
type Parameters = {
|
|
449
|
+
/** Source token amount in base units used for initial route provisioning. */
|
|
450
|
+
amount: string
|
|
451
|
+
/** Curated reusable-address route selected for provisioning. */
|
|
452
|
+
candidate: DepositAddressCandidate
|
|
453
|
+
/** Final beneficiary on Tempo. */
|
|
454
|
+
recipient: string
|
|
455
|
+
/** Source-chain account that receives refunds. */
|
|
456
|
+
refundAddress: string
|
|
457
|
+
/** Whether Tempo guarantees normalized 1:1 delivery. */
|
|
458
|
+
subsidize: boolean
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/** Reusable address and private provider correlation. */
|
|
462
|
+
type ReturnType = z.output<typeof schema.DepositAddressResult>
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/** Contract of the provider `listDepositAddressRequests` method. */
|
|
466
|
+
export declare namespace listDepositAddressRequests {
|
|
467
|
+
/** Input passed to a provider when reconciling one reusable address. */
|
|
468
|
+
type Parameters = {
|
|
469
|
+
/** Reusable provider deposit address. */
|
|
470
|
+
address: string
|
|
471
|
+
/** Opaque provider cursor returned by the previous page. */
|
|
472
|
+
continuation?: string | undefined
|
|
473
|
+
/** Existing provider request to refresh directly. */
|
|
474
|
+
requestId?: string | undefined
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/** One page of normalized provider requests. */
|
|
478
|
+
type ReturnType = z.output<typeof schema.DepositAddressRequestsResult>
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/** Optional webhook capability implemented by a complete funding integration. */
|
|
482
|
+
export type Webhook = {
|
|
483
|
+
/** Authenticates, resolves, and enqueues one provider status event. */
|
|
484
|
+
receive(input: Webhook.receive.Parameters): Promise<Webhook.receive.ReturnType>
|
|
485
|
+
/** Authenticates a provider status event and returns its bounded hint. */
|
|
486
|
+
verify(input: Webhook.verify.Parameters): Webhook.verify.ReturnType
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/** Contracts for a funding provider webhook capability. */
|
|
490
|
+
export declare namespace Webhook {
|
|
491
|
+
/** Contracts for receiving one authenticated provider webhook. */
|
|
492
|
+
namespace receive {
|
|
493
|
+
/** Raw provider webhook request passed to a funding integration. */
|
|
494
|
+
type Parameters = {
|
|
495
|
+
/** Exact request body bytes decoded as UTF-8. */
|
|
496
|
+
body: string
|
|
497
|
+
/** Original provider webhook headers. */
|
|
498
|
+
headers: Headers
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/** Durable queue message emitted for one authenticated funding status hint. */
|
|
502
|
+
type Dispatchable = {
|
|
503
|
+
/** Stored funding deposit address id. */
|
|
504
|
+
addressId: string
|
|
505
|
+
/** Reconciliation lease fencing token, when a scheduled poll already claimed the address. */
|
|
506
|
+
pollLeaseVersion?: number | undefined
|
|
507
|
+
/** Optional provider request id that triggered reconciliation. */
|
|
508
|
+
requestId?: string | undefined
|
|
509
|
+
/** Reconciliation queue message discriminator. */
|
|
510
|
+
type: 'funding:deposit-address:reconcile'
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/** Safe disposition of one authenticated funding provider webhook. */
|
|
514
|
+
type ReturnType =
|
|
515
|
+
| { addressId: string; type: 'queued' }
|
|
516
|
+
| { type: 'ignored' }
|
|
517
|
+
| { type: 'unknown_address' }
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/** Contracts for verifying one provider webhook. */
|
|
521
|
+
namespace verify {
|
|
522
|
+
/** Raw provider webhook request passed to a funding integration. */
|
|
523
|
+
type Parameters = receive.Parameters
|
|
524
|
+
|
|
525
|
+
/** Authenticated provider hint extracted from a funding webhook. */
|
|
526
|
+
type ReturnType = {
|
|
527
|
+
/** Reusable provider address, when the provider attributed one. */
|
|
528
|
+
address?: string | undefined
|
|
529
|
+
/** Provider request id, when included in the event. */
|
|
530
|
+
requestId?: string | undefined
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/** A funding provider descriptor and live quote implementation. */
|
|
536
|
+
export type Provider<id extends string = string> = core_Provider.Provider<id, 'funding'> & {
|
|
537
|
+
/** Provisions a reusable funding deposit address, when supported. */
|
|
538
|
+
createDepositAddress?(
|
|
539
|
+
input: createDepositAddress.Parameters,
|
|
540
|
+
signal: AbortSignal,
|
|
541
|
+
): Promise<createDepositAddress.ReturnType>
|
|
542
|
+
/** Requests a live funding quote. */
|
|
543
|
+
getQuote(input: getQuote.Parameters, signal: AbortSignal): Promise<getQuote.ReturnType>
|
|
544
|
+
/** Lists requests discovered for a reusable deposit address, when supported. */
|
|
545
|
+
listDepositAddressRequests?(
|
|
546
|
+
input: listDepositAddressRequests.Parameters,
|
|
547
|
+
signal: AbortSignal,
|
|
548
|
+
): Promise<listDepositAddressRequests.ReturnType>
|
|
549
|
+
/** Prepares an executable funding transfer, when the provider supports it. */
|
|
550
|
+
prepareTransfer?(
|
|
551
|
+
input: prepareTransfer.Parameters,
|
|
552
|
+
signal: AbortSignal,
|
|
553
|
+
): Promise<prepareTransfer.ReturnType>
|
|
554
|
+
/** Receives authenticated provider status events, when configured. */
|
|
555
|
+
webhook?: Webhook | undefined
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/** Defines a funding provider from its identity and quote implementation. */
|
|
559
|
+
export function from<const id extends string>(options: from.Options<id>): Provider<id> {
|
|
560
|
+
if (options.id !== normalizeInput(options.id) || options.id.length === 0)
|
|
561
|
+
throw new ProviderConfigurationError('Provider ids must be lowercase and trimmed.')
|
|
562
|
+
return core_Provider.from({ ...options, type: 'funding' })
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
export declare namespace from {
|
|
566
|
+
/** Funding provider definition. */
|
|
567
|
+
type Options<id extends string> = Omit<Provider<id>, 'type'>
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
/** Narrows a registered provider to a funding provider. */
|
|
571
|
+
export function is(provider: core_Provider.Provider): provider is Provider {
|
|
572
|
+
return (
|
|
573
|
+
provider.type === 'funding' && 'getQuote' in provider && typeof provider.getQuote === 'function'
|
|
574
|
+
)
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
/** Narrows a funding provider to one that prepares executable transfers. */
|
|
578
|
+
export function canPrepareTransfer(provider: Provider): provider is Provider & {
|
|
579
|
+
prepareTransfer: NonNullable<Provider['prepareTransfer']>
|
|
580
|
+
} {
|
|
581
|
+
return typeof provider.prepareTransfer === 'function'
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/** Narrows a funding provider to one that provisions reusable deposit addresses. */
|
|
585
|
+
export function canCreateDepositAddress(provider: Provider): provider is Provider & {
|
|
586
|
+
createDepositAddress: NonNullable<Provider['createDepositAddress']>
|
|
587
|
+
} {
|
|
588
|
+
return typeof provider.createDepositAddress === 'function'
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/** Narrows a funding provider to one that tracks reusable deposit addresses. */
|
|
592
|
+
export function canListDepositAddressRequests(provider: Provider): provider is Provider & {
|
|
593
|
+
listDepositAddressRequests: NonNullable<Provider['listDepositAddressRequests']>
|
|
594
|
+
} {
|
|
595
|
+
return typeof provider.listDepositAddressRequests === 'function'
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/** Narrows a funding provider to one with authenticated webhook receipt. */
|
|
599
|
+
export function canReceiveWebhook(provider: Provider): provider is Provider & {
|
|
600
|
+
webhook: Webhook
|
|
601
|
+
} {
|
|
602
|
+
return provider.webhook !== undefined
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/** Funding provider method recorded by request diagnostics. */
|
|
606
|
+
export type ProviderOperation =
|
|
607
|
+
| 'createDepositAddress'
|
|
608
|
+
| 'getQuote'
|
|
609
|
+
| 'listDepositAddressRequests'
|
|
610
|
+
| 'prepareTransfer'
|
|
611
|
+
|
|
612
|
+
/** One provider attempt made while resolving a funding quote request. */
|
|
613
|
+
export type ProviderAttempt =
|
|
614
|
+
| {
|
|
615
|
+
/** Wall-clock duration of the provider attempt in milliseconds. */
|
|
616
|
+
durationMs: number
|
|
617
|
+
/** Provider method invoked by the attempt. */
|
|
618
|
+
operation: ProviderOperation
|
|
619
|
+
/** Successful or expected-unavailable provider outcome. */
|
|
620
|
+
outcome: 'available' | 'thin' | 'unavailable'
|
|
621
|
+
/** Provider that handled the quote candidate. */
|
|
622
|
+
provider: Provider
|
|
623
|
+
}
|
|
624
|
+
| {
|
|
625
|
+
/** Error thrown by the provider boundary. */
|
|
626
|
+
cause: unknown
|
|
627
|
+
/** Wall-clock duration of the provider attempt in milliseconds. */
|
|
628
|
+
durationMs: number
|
|
629
|
+
/** Provider method invoked by the attempt. */
|
|
630
|
+
operation: ProviderOperation
|
|
631
|
+
/** Failed provider outcome. */
|
|
632
|
+
outcome: 'failed'
|
|
633
|
+
/** Provider that handled the quote candidate. */
|
|
634
|
+
provider: Provider
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
/** Bounded result for one provider attempt. */
|
|
638
|
+
export type ProviderAttemptResult = {
|
|
639
|
+
/** Wall-clock duration of the provider attempt in milliseconds. */
|
|
640
|
+
durationMs: number
|
|
641
|
+
/** Failure class, present only when the provider attempt failed. */
|
|
642
|
+
failure?: failure.Result['failure'] | undefined
|
|
643
|
+
/** Provider identifier. */
|
|
644
|
+
id: string
|
|
645
|
+
/** Provider method invoked by the attempt. */
|
|
646
|
+
operation: ProviderOperation
|
|
647
|
+
/** Provider attempt outcome. */
|
|
648
|
+
outcome: ProviderAttempt['outcome']
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
/** A provider failure retained for bounded request diagnostics. */
|
|
652
|
+
export type ProviderFailure = {
|
|
653
|
+
/** Error thrown by the provider boundary. */
|
|
654
|
+
cause: unknown
|
|
655
|
+
/** Provider method that failed. */
|
|
656
|
+
operation: ProviderOperation
|
|
657
|
+
/** Provider that failed. */
|
|
658
|
+
provider: Provider
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
const defaultTimeoutMs = 2_000
|
|
662
|
+
|
|
663
|
+
/** Returns normalized chains and source tokens supported by quote providers. */
|
|
664
|
+
export function getChains(options: getChains.Options) {
|
|
665
|
+
const routes = getRoutes(options.catalog, options.providers)
|
|
666
|
+
const chains = uniqueBy(
|
|
667
|
+
routes.map((entry) => entry.route.source.chain),
|
|
668
|
+
(chain) => chain.id,
|
|
669
|
+
)
|
|
670
|
+
return chains.flatMap((chain) => {
|
|
671
|
+
const tokens = routes
|
|
672
|
+
.filter((entry) => entry.route.source.chain.id === chain.id)
|
|
673
|
+
.map((entry) => entry.route.source)
|
|
674
|
+
if (tokens.length === 0) return []
|
|
675
|
+
return [
|
|
676
|
+
{
|
|
677
|
+
...chainRef(chain),
|
|
678
|
+
tokens: uniqueBy(tokens, (token) => token.address).map(tokenRef),
|
|
679
|
+
},
|
|
680
|
+
]
|
|
681
|
+
})
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
export declare namespace getChains {
|
|
685
|
+
/** Options for getting provider-supported source chains. */
|
|
686
|
+
type Options = {
|
|
687
|
+
/** Compiled funding catalog containing provider routes. */
|
|
688
|
+
catalog: core_Catalog.Snapshot
|
|
689
|
+
/** Providers whose routes contribute source chains and tokens. */
|
|
690
|
+
providers: readonly Provider[]
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
/** Returns the supplied funding quote providers. */
|
|
695
|
+
export function getProviders(options: getProviders.Options) {
|
|
696
|
+
return options.providers
|
|
697
|
+
.filter((provider) => (options.catalog.routesByProvider.get(provider.id)?.length ?? 0) > 0)
|
|
698
|
+
.map((provider) => schema.ProviderRef.parse(provider))
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
export declare namespace getProviders {
|
|
702
|
+
/** Options for getting providers. */
|
|
703
|
+
type Options = {
|
|
704
|
+
/** Compiled funding catalog containing provider routes. */
|
|
705
|
+
catalog: core_Catalog.Snapshot
|
|
706
|
+
/** Funding providers included in this deployment. */
|
|
707
|
+
providers: readonly Provider[]
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
/** Returns successful live funding quotes from the supplied providers. */
|
|
712
|
+
export async function getQuotes(options: getQuotes.Options) {
|
|
713
|
+
const providers = options.providers ?? []
|
|
714
|
+
const operation = 'getQuote' satisfies ProviderOperation
|
|
715
|
+
const candidates = getQuoteCandidates(options).flatMap((candidate) => {
|
|
716
|
+
const provider = providers.find((entry) => entry.id === candidate.provider.id)
|
|
717
|
+
return provider ? [{ candidate, provider }] : []
|
|
718
|
+
})
|
|
719
|
+
const attempts = new Map<number, ProviderAttempt>()
|
|
720
|
+
const results = await Promise.allSettled(
|
|
721
|
+
candidates.map(async ({ candidate, provider }, index) => {
|
|
722
|
+
const start = performance.now()
|
|
723
|
+
try {
|
|
724
|
+
const result = await quoteCandidate(candidate, {
|
|
725
|
+
cache: options.cache ?? { bypass: false },
|
|
726
|
+
provider,
|
|
727
|
+
request: {
|
|
728
|
+
destinationToken: options.destinationToken,
|
|
729
|
+
provider: options.provider,
|
|
730
|
+
sourceAmount: options.sourceAmount,
|
|
731
|
+
sourceAmountUnits: options.sourceAmountUnits,
|
|
732
|
+
sourceChain: options.sourceChain,
|
|
733
|
+
sourceToken: options.sourceToken,
|
|
734
|
+
},
|
|
735
|
+
timeoutMs: options.providerTimeoutMs ?? defaultTimeoutMs,
|
|
736
|
+
})
|
|
737
|
+
attempts.set(index, {
|
|
738
|
+
durationMs: performance.now() - start,
|
|
739
|
+
operation,
|
|
740
|
+
outcome: result.outcome,
|
|
741
|
+
provider,
|
|
742
|
+
})
|
|
743
|
+
return 'quote' in result ? result.quote : undefined
|
|
744
|
+
} catch (cause) {
|
|
745
|
+
attempts.set(index, {
|
|
746
|
+
cause,
|
|
747
|
+
durationMs: performance.now() - start,
|
|
748
|
+
operation,
|
|
749
|
+
outcome: 'failed',
|
|
750
|
+
provider,
|
|
751
|
+
})
|
|
752
|
+
throw cause
|
|
753
|
+
}
|
|
754
|
+
}),
|
|
755
|
+
)
|
|
756
|
+
const values = [...candidates.keys()].flatMap((index) => {
|
|
757
|
+
const attempt = attempts.get(index)
|
|
758
|
+
return attempt ? [attempt] : []
|
|
759
|
+
})
|
|
760
|
+
for (const attempt of values) {
|
|
761
|
+
try {
|
|
762
|
+
options.onAttempt?.(attempt)
|
|
763
|
+
} catch {
|
|
764
|
+
// Observability hooks never alter funding quote behavior.
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
const quotes = results.flatMap((result) =>
|
|
768
|
+
result.status === 'fulfilled' && result.value ? [result.value] : [],
|
|
769
|
+
)
|
|
770
|
+
const failures = results.flatMap((result, index) =>
|
|
771
|
+
result.status === 'rejected'
|
|
772
|
+
? [
|
|
773
|
+
{
|
|
774
|
+
cause: result.reason,
|
|
775
|
+
operation,
|
|
776
|
+
provider: candidates[index]!.provider,
|
|
777
|
+
} satisfies ProviderFailure,
|
|
778
|
+
]
|
|
779
|
+
: [],
|
|
780
|
+
)
|
|
781
|
+
if (quotes.length === 0 && failures.length > 0) throw new ProviderQuoteError(failures, values)
|
|
782
|
+
return quotes
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
/** Returns internal quote candidates for a normalized caller request. */
|
|
786
|
+
export function getQuoteCandidates(options: getQuoteCandidates.Options) {
|
|
787
|
+
const { catalog, providers } = options
|
|
788
|
+
const amount = (
|
|
789
|
+
options.sourceAmountUnits === 'baseUnits' ? schema.PositiveInteger : schema.PositiveDecimal
|
|
790
|
+
).safeParse(options.sourceAmount)
|
|
791
|
+
if (!amount.success) throw new InvalidAmountError()
|
|
792
|
+
const sourceChain = resolveSourceChain(options.sourceChain, catalog)
|
|
793
|
+
const sourceToken = resolveSourceToken(sourceChain, options.sourceToken, catalog)
|
|
794
|
+
const destination = resolveDestinationToken(options.destinationToken, catalog)
|
|
795
|
+
const provider = options.provider ? resolveProvider(options.provider, providers) : undefined
|
|
796
|
+
|
|
797
|
+
if (providers.length === 0) return []
|
|
798
|
+
if (!sourceToken) return []
|
|
799
|
+
|
|
800
|
+
const sourceAmount = resolveSourceAmount({
|
|
801
|
+
amount: options.sourceAmount,
|
|
802
|
+
token: sourceToken,
|
|
803
|
+
units: options.sourceAmountUnits,
|
|
804
|
+
})
|
|
805
|
+
|
|
806
|
+
return getRoutes(catalog, providers)
|
|
807
|
+
.filter((entry) => entry.route.source.chain.id === sourceChain.id)
|
|
808
|
+
.filter((entry) => entry.route.source.address === sourceToken.address)
|
|
809
|
+
.filter((entry) => entry.route.destination.chain.id === destination.chain.id)
|
|
810
|
+
.filter((entry) => entry.route.destination.address === destination.address)
|
|
811
|
+
.filter((entry) => provider === undefined || entry.provider.id === provider.id)
|
|
812
|
+
.map((entry) =>
|
|
813
|
+
createQuoteCandidate({
|
|
814
|
+
destinationToken: entry.route.destination,
|
|
815
|
+
provider: entry.provider,
|
|
816
|
+
route: entry.route,
|
|
817
|
+
sourceAmount,
|
|
818
|
+
sourceToken: entry.route.source,
|
|
819
|
+
}),
|
|
820
|
+
)
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
export declare namespace getQuoteCandidates {
|
|
824
|
+
/** Options for selecting funding quote candidates. */
|
|
825
|
+
type Options = QuoteRequest & {
|
|
826
|
+
/** Compiled funding catalog containing provider routes. */
|
|
827
|
+
catalog: core_Catalog.Snapshot
|
|
828
|
+
/** Funding providers considered by the request. */
|
|
829
|
+
providers: readonly Provider[]
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
export declare namespace getQuotes {
|
|
834
|
+
/** Options for requesting live funding quotes. */
|
|
835
|
+
type Options = getQuoteCandidates.Options & {
|
|
836
|
+
/** Cache policy for provider-side discovery and quote lookups. */
|
|
837
|
+
cache?: CachePolicy | undefined
|
|
838
|
+
/** Receives one bounded observation for every provider attempt. */
|
|
839
|
+
onAttempt?: ((attempt: ProviderAttempt) => void) | undefined
|
|
840
|
+
/** Per-provider quote timeout in milliseconds. */
|
|
841
|
+
providerTimeoutMs?: number | undefined
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
const defaultPrepareTimeoutMs = 10_000
|
|
846
|
+
// Providers that return no quote validity window get a conservative default:
|
|
847
|
+
// the caller must sign and submit promptly, mirroring wallet quote UX.
|
|
848
|
+
const defaultQuoteTtlMs = 60_000
|
|
849
|
+
|
|
850
|
+
/**
|
|
851
|
+
* Provisions one reusable deposit address through the first deterministic
|
|
852
|
+
* capability-enabled provider. Returns `undefined` when no route is enabled.
|
|
853
|
+
*/
|
|
854
|
+
export async function createDepositAddress(
|
|
855
|
+
options: createDepositAddress.Options,
|
|
856
|
+
): Promise<createDepositAddress.Selection | undefined> {
|
|
857
|
+
const operation = 'createDepositAddress' satisfies ProviderOperation
|
|
858
|
+
if (!schema.PositiveInteger.safeParse(options.amount).success) throw new InvalidAmountError()
|
|
859
|
+
const candidates = getDepositAddressCandidates(options).sort((a, b) =>
|
|
860
|
+
a.provider.id.localeCompare(b.provider.id),
|
|
861
|
+
)
|
|
862
|
+
const selected = candidates[0]
|
|
863
|
+
if (!selected) return undefined
|
|
864
|
+
const recipient = normalizeAccountAddress(options.recipient, selected.candidate.destinationChain)
|
|
865
|
+
const refundAddress = normalizeAccountAddress(
|
|
866
|
+
options.refundAddress,
|
|
867
|
+
selected.candidate.sourceChain,
|
|
868
|
+
)
|
|
869
|
+
if (!recipient) throw new ProviderPayloadError()
|
|
870
|
+
if (!refundAddress) throw new InvalidRefundAddressError()
|
|
871
|
+
|
|
872
|
+
const start = performance.now()
|
|
873
|
+
try {
|
|
874
|
+
const parsed = schema.DepositAddressResult.safeParse(
|
|
875
|
+
await withTimeout(
|
|
876
|
+
(signal) =>
|
|
877
|
+
selected.provider.createDepositAddress(
|
|
878
|
+
{
|
|
879
|
+
amount: options.amount,
|
|
880
|
+
candidate: selected.candidate,
|
|
881
|
+
recipient,
|
|
882
|
+
refundAddress,
|
|
883
|
+
subsidize: options.subsidize,
|
|
884
|
+
},
|
|
885
|
+
signal,
|
|
886
|
+
),
|
|
887
|
+
options.providerTimeoutMs ?? defaultPrepareTimeoutMs,
|
|
888
|
+
),
|
|
889
|
+
)
|
|
890
|
+
if (!parsed.success) throw new ProviderPayloadError()
|
|
891
|
+
const result = parsed.data
|
|
892
|
+
if (!normalizeAccountAddress(result.address, selected.candidate.sourceChain))
|
|
893
|
+
throw new ProviderPayloadError()
|
|
894
|
+
if (BigInt(result.destinationAmountMin) > BigInt(result.destinationAmount))
|
|
895
|
+
throw new ProviderPayloadError()
|
|
896
|
+
if (result.expiresAt !== undefined && Date.parse(result.expiresAt) <= Date.now())
|
|
897
|
+
throw new ProviderPayloadError()
|
|
898
|
+
const attempt: ProviderAttempt = {
|
|
899
|
+
durationMs: performance.now() - start,
|
|
900
|
+
operation,
|
|
901
|
+
outcome: 'available',
|
|
902
|
+
provider: selected.provider,
|
|
903
|
+
}
|
|
904
|
+
try {
|
|
905
|
+
options.onAttempt?.(attempt)
|
|
906
|
+
} catch {
|
|
907
|
+
// Observability hooks never alter provisioning behavior.
|
|
908
|
+
}
|
|
909
|
+
return { ...selected, recipient, refundAddress, result }
|
|
910
|
+
} catch (cause) {
|
|
911
|
+
const attempt: ProviderAttempt =
|
|
912
|
+
cause instanceof ProviderUnavailableError
|
|
913
|
+
? {
|
|
914
|
+
durationMs: performance.now() - start,
|
|
915
|
+
operation,
|
|
916
|
+
outcome: 'unavailable',
|
|
917
|
+
provider: selected.provider,
|
|
918
|
+
}
|
|
919
|
+
: {
|
|
920
|
+
cause,
|
|
921
|
+
durationMs: performance.now() - start,
|
|
922
|
+
operation,
|
|
923
|
+
outcome: 'failed',
|
|
924
|
+
provider: selected.provider,
|
|
925
|
+
}
|
|
926
|
+
try {
|
|
927
|
+
options.onAttempt?.(attempt)
|
|
928
|
+
} catch {
|
|
929
|
+
// Observability hooks never alter provisioning behavior.
|
|
930
|
+
}
|
|
931
|
+
if (cause instanceof ProviderUnavailableError) return undefined
|
|
932
|
+
throw new ProviderQuoteError([{ cause, operation, provider: selected.provider }], [attempt])
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
export declare namespace createDepositAddress {
|
|
937
|
+
/** Options for provisioning one reusable deposit address. */
|
|
938
|
+
type Options = getDepositAddressCandidates.Options & {
|
|
939
|
+
/** Source token amount in base units used for initial route provisioning. */
|
|
940
|
+
amount: string
|
|
941
|
+
/** Receives one bounded observation for the provider attempt. */
|
|
942
|
+
onAttempt?: ((attempt: ProviderAttempt) => void) | undefined
|
|
943
|
+
/** Per-provider provisioning timeout in milliseconds. */
|
|
944
|
+
providerTimeoutMs?: number | undefined
|
|
945
|
+
/** Final beneficiary on Tempo. */
|
|
946
|
+
recipient: string
|
|
947
|
+
/** Source-chain account that receives refunds. */
|
|
948
|
+
refundAddress: string
|
|
949
|
+
/** Whether Tempo guarantees normalized 1:1 delivery. */
|
|
950
|
+
subsidize: boolean
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
/** Selected provider route and its reusable address. */
|
|
954
|
+
type Selection = {
|
|
955
|
+
/** Curated route used to provision the address. */
|
|
956
|
+
candidate: DepositAddressCandidate
|
|
957
|
+
/** Provider that provisioned the address. */
|
|
958
|
+
provider: Provider
|
|
959
|
+
/** Normalized final beneficiary on Tempo. */
|
|
960
|
+
recipient: string
|
|
961
|
+
/** Normalized source-chain refund account. */
|
|
962
|
+
refundAddress: string
|
|
963
|
+
/** Reusable address and private provider correlation. */
|
|
964
|
+
result: createDepositAddress.ReturnType
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
/**
|
|
969
|
+
* Prepares one executable transfer across capability-enabled candidates,
|
|
970
|
+
* selecting the best successful preparation. Returns `undefined` when no
|
|
971
|
+
* enabled corridor matches; throws {@link ProviderQuoteError} when every
|
|
972
|
+
* matching provider failed unexpectedly.
|
|
973
|
+
*/
|
|
974
|
+
export async function prepareTransfer(
|
|
975
|
+
options: prepareTransfer.Options,
|
|
976
|
+
): Promise<prepareTransfer.Selection | undefined> {
|
|
977
|
+
const operation = 'prepareTransfer' satisfies ProviderOperation
|
|
978
|
+
const candidates = getPrepareCandidates(options)
|
|
979
|
+
if (candidates.length === 0) return undefined
|
|
980
|
+
|
|
981
|
+
const attempts: ProviderAttempt[] = []
|
|
982
|
+
const results = await Promise.allSettled(
|
|
983
|
+
candidates.map(async ({ candidate, provider }) => {
|
|
984
|
+
const start = performance.now()
|
|
985
|
+
try {
|
|
986
|
+
const parsed = schema.PrepareResult.safeParse(
|
|
987
|
+
await withTimeout(
|
|
988
|
+
(signal) =>
|
|
989
|
+
provider.prepareTransfer(
|
|
990
|
+
{
|
|
991
|
+
candidate,
|
|
992
|
+
method: options.method,
|
|
993
|
+
mode: options.mode,
|
|
994
|
+
recipient: options.recipient,
|
|
995
|
+
sender: options.sender,
|
|
996
|
+
slippageBps: options.slippageBps,
|
|
997
|
+
},
|
|
998
|
+
signal,
|
|
999
|
+
),
|
|
1000
|
+
options.providerTimeoutMs ?? defaultPrepareTimeoutMs,
|
|
1001
|
+
),
|
|
1002
|
+
)
|
|
1003
|
+
if (!parsed.success) throw new ProviderPayloadError()
|
|
1004
|
+
const result = parsed.data
|
|
1005
|
+
const expiresAt =
|
|
1006
|
+
result.expiresAt ??
|
|
1007
|
+
new Date(Date.parse(result.sampledAt) + defaultQuoteTtlMs).toISOString()
|
|
1008
|
+
if (Date.parse(expiresAt) <= Date.now()) throw new ProviderPayloadError()
|
|
1009
|
+
if (BigInt(result.destinationAmountMin) > BigInt(result.destinationAmount))
|
|
1010
|
+
throw new ProviderPayloadError()
|
|
1011
|
+
// A provider that ignores the caller's slippage bound is unusable for
|
|
1012
|
+
// this request; enforce the bound against the quoted minimum.
|
|
1013
|
+
if (options.slippageBps !== undefined) {
|
|
1014
|
+
const basisPointScale = 10_000n
|
|
1015
|
+
const numerator = BigInt(result.destinationAmount) * BigInt(10_000 - options.slippageBps)
|
|
1016
|
+
const floor = (numerator + basisPointScale - 1n) / basisPointScale
|
|
1017
|
+
if (BigInt(result.destinationAmountMin) < floor) throw new ProviderPayloadError()
|
|
1018
|
+
}
|
|
1019
|
+
if (result.action.type === 'evm:calls')
|
|
1020
|
+
try {
|
|
1021
|
+
Action.validateEvmCalls({
|
|
1022
|
+
action: result.action,
|
|
1023
|
+
sourceAmount: candidate.sourceAmount.amount,
|
|
1024
|
+
sourceTokenAddress: candidate.sourceToken.address,
|
|
1025
|
+
})
|
|
1026
|
+
} catch (cause) {
|
|
1027
|
+
if (cause instanceof Action.InvalidActionError) throw new ProviderPayloadError()
|
|
1028
|
+
throw cause
|
|
1029
|
+
}
|
|
1030
|
+
attempts.push({
|
|
1031
|
+
durationMs: performance.now() - start,
|
|
1032
|
+
operation,
|
|
1033
|
+
outcome: 'available',
|
|
1034
|
+
provider,
|
|
1035
|
+
})
|
|
1036
|
+
return { candidate, provider, result: { ...result, expiresAt } }
|
|
1037
|
+
} catch (cause) {
|
|
1038
|
+
if (cause instanceof ProviderUnavailableError) {
|
|
1039
|
+
attempts.push({
|
|
1040
|
+
durationMs: performance.now() - start,
|
|
1041
|
+
operation,
|
|
1042
|
+
outcome: 'unavailable',
|
|
1043
|
+
provider,
|
|
1044
|
+
})
|
|
1045
|
+
return undefined
|
|
1046
|
+
}
|
|
1047
|
+
attempts.push({
|
|
1048
|
+
cause,
|
|
1049
|
+
durationMs: performance.now() - start,
|
|
1050
|
+
operation,
|
|
1051
|
+
outcome: 'failed',
|
|
1052
|
+
provider,
|
|
1053
|
+
})
|
|
1054
|
+
throw cause
|
|
1055
|
+
}
|
|
1056
|
+
}),
|
|
1057
|
+
)
|
|
1058
|
+
for (const attempt of attempts) {
|
|
1059
|
+
try {
|
|
1060
|
+
options.onAttempt?.(attempt)
|
|
1061
|
+
} catch {
|
|
1062
|
+
// Observability hooks never alter preparation behavior.
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
const prepared = results.flatMap((result) =>
|
|
1066
|
+
result.status === 'fulfilled' && result.value ? [result.value] : [],
|
|
1067
|
+
)
|
|
1068
|
+
if (prepared.length === 0) {
|
|
1069
|
+
const failures = results.flatMap((result, index) =>
|
|
1070
|
+
result.status === 'rejected'
|
|
1071
|
+
? [
|
|
1072
|
+
{
|
|
1073
|
+
cause: result.reason,
|
|
1074
|
+
operation,
|
|
1075
|
+
provider: candidates[index]!.provider,
|
|
1076
|
+
} satisfies ProviderFailure,
|
|
1077
|
+
]
|
|
1078
|
+
: [],
|
|
1079
|
+
)
|
|
1080
|
+
if (failures.length === 0) return undefined
|
|
1081
|
+
throw new ProviderQuoteError(failures, attempts)
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
// Deterministic selection: highest guaranteed minimum, then provider id.
|
|
1085
|
+
prepared.sort((a, b) => {
|
|
1086
|
+
const delta = BigInt(b.result.destinationAmountMin) - BigInt(a.result.destinationAmountMin)
|
|
1087
|
+
if (delta !== 0n) return delta > 0n ? 1 : -1
|
|
1088
|
+
return a.provider.id < b.provider.id ? -1 : 1
|
|
1089
|
+
})
|
|
1090
|
+
return prepared[0]!
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
export declare namespace prepareTransfer {
|
|
1094
|
+
/** Options for preparing one executable transfer. */
|
|
1095
|
+
type Options = getPrepareCandidates.Options & {
|
|
1096
|
+
/** Receives one bounded observation for every provider attempt. */
|
|
1097
|
+
onAttempt?: ((attempt: ProviderAttempt) => void) | undefined
|
|
1098
|
+
/** Per-provider preparation timeout in milliseconds. */
|
|
1099
|
+
providerTimeoutMs?: number | undefined
|
|
1100
|
+
/** Final beneficiary on the destination chain. */
|
|
1101
|
+
recipient: string
|
|
1102
|
+
/** Source-chain account that signs the funding action. */
|
|
1103
|
+
sender: string
|
|
1104
|
+
/** Caller slippage bound in basis points. */
|
|
1105
|
+
slippageBps?: number | undefined
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
/** The selected preparation with a guaranteed expiry. */
|
|
1109
|
+
type Selection = {
|
|
1110
|
+
/** Curated candidate the preparation was produced for. */
|
|
1111
|
+
candidate: QuoteCandidate
|
|
1112
|
+
/** Provider that produced the selected preparation. */
|
|
1113
|
+
provider: Provider
|
|
1114
|
+
/** The preparation, with a default expiry applied when the provider gave none. */
|
|
1115
|
+
result: prepareTransfer.ReturnType & { expiresAt: string }
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
/**
|
|
1120
|
+
* Returns capability-enabled reusable-address candidates for a route. Tokens
|
|
1121
|
+
* resolve within their chains and only provider delivery qualifies.
|
|
1122
|
+
*/
|
|
1123
|
+
export function getDepositAddressCandidates(options: getDepositAddressCandidates.Options) {
|
|
1124
|
+
const sourceChain = resolveSourceChain(options.sourceChain, options.catalog)
|
|
1125
|
+
const destinationChainId = `eip155:${options.destinationChainId}`
|
|
1126
|
+
|
|
1127
|
+
return options.catalog.routes.flatMap((entry) => {
|
|
1128
|
+
if (entry.route.source.chain.id !== sourceChain.id) return []
|
|
1129
|
+
if (entry.route.destination.chain.id !== destinationChainId) return []
|
|
1130
|
+
if (!matchesToken(entry.route.source, options.sourceToken)) return []
|
|
1131
|
+
if (!matchesToken(entry.route.destination, options.destinationToken)) return []
|
|
1132
|
+
if (!entry.capabilities?.depositAddress) return []
|
|
1133
|
+
const provider = options.providers.find((candidate) => candidate.id === entry.providerId)
|
|
1134
|
+
if (!provider || !canCreateDepositAddress(provider)) return []
|
|
1135
|
+
return [
|
|
1136
|
+
{ candidate: createDepositAddressCandidate({ provider, route: entry.route }), provider },
|
|
1137
|
+
]
|
|
1138
|
+
})
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
export declare namespace getDepositAddressCandidates {
|
|
1142
|
+
/** Options for selecting reusable deposit-address routes. */
|
|
1143
|
+
type Options = {
|
|
1144
|
+
/** Compiled funding catalog containing provider routes and capabilities. */
|
|
1145
|
+
catalog: core_Catalog.Snapshot
|
|
1146
|
+
/** Tempo destination chain selected by app composition. */
|
|
1147
|
+
destinationChainId: number
|
|
1148
|
+
/** Tempo destination token symbol, contract address, or token key. */
|
|
1149
|
+
destinationToken: string
|
|
1150
|
+
/** Funding providers considered by the request. */
|
|
1151
|
+
providers: readonly Provider[]
|
|
1152
|
+
/** Source chain CAIP-2 id, slug, or alias. */
|
|
1153
|
+
sourceChain: string
|
|
1154
|
+
/** Source token symbol, contract address, or token key. */
|
|
1155
|
+
sourceToken: string
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
/**
|
|
1160
|
+
* Returns capability-enabled preparation candidates for a creation request.
|
|
1161
|
+
* Tokens resolve within their chains. A route must enable the requested mode,
|
|
1162
|
+
* and its provider must implement `prepareTransfer`.
|
|
1163
|
+
*/
|
|
1164
|
+
export function getPrepareCandidates(options: getPrepareCandidates.Options) {
|
|
1165
|
+
const amount = schema.PositiveInteger.safeParse(options.sourceAmount)
|
|
1166
|
+
if (!amount.success) throw new InvalidAmountError()
|
|
1167
|
+
const sourceChain = resolveSourceChain(options.sourceChain, options.catalog)
|
|
1168
|
+
const destinationChainId = `eip155:${options.destinationChainId}`
|
|
1169
|
+
|
|
1170
|
+
return options.catalog.routes.flatMap((entry) => {
|
|
1171
|
+
if (entry.route.source.chain.id !== sourceChain.id) return []
|
|
1172
|
+
if (entry.route.destination.chain.id !== destinationChainId) return []
|
|
1173
|
+
if (!matchesToken(entry.route.source, options.sourceToken)) return []
|
|
1174
|
+
if (!matchesToken(entry.route.destination, options.destinationToken)) return []
|
|
1175
|
+
if (!entry.capabilities?.transfer?.modes.includes(options.mode)) return []
|
|
1176
|
+
const provider = options.providers.find((candidate) => candidate.id === entry.providerId)
|
|
1177
|
+
if (!provider || !canPrepareTransfer(provider)) return []
|
|
1178
|
+
return [
|
|
1179
|
+
{
|
|
1180
|
+
candidate: createQuoteCandidate({
|
|
1181
|
+
destinationToken: entry.route.destination,
|
|
1182
|
+
provider,
|
|
1183
|
+
route: entry.route,
|
|
1184
|
+
sourceAmount: resolveSourceAmount({
|
|
1185
|
+
amount: options.sourceAmount,
|
|
1186
|
+
token: entry.route.source,
|
|
1187
|
+
units: 'baseUnits',
|
|
1188
|
+
}),
|
|
1189
|
+
sourceToken: entry.route.source,
|
|
1190
|
+
}),
|
|
1191
|
+
provider,
|
|
1192
|
+
},
|
|
1193
|
+
]
|
|
1194
|
+
})
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
export declare namespace getPrepareCandidates {
|
|
1198
|
+
/** Options for selecting preparation candidates. */
|
|
1199
|
+
type Options = {
|
|
1200
|
+
/** Compiled funding catalog containing provider routes and capabilities. */
|
|
1201
|
+
catalog: core_Catalog.Snapshot
|
|
1202
|
+
/** Tempo destination chain selected by app composition. */
|
|
1203
|
+
destinationChainId: number
|
|
1204
|
+
/** Tempo destination token symbol, contract address, or token key. */
|
|
1205
|
+
destinationToken: string
|
|
1206
|
+
/** Funding method passed to provider preparation. */
|
|
1207
|
+
method: Transfer.Method
|
|
1208
|
+
/** Amount mode the caller selected. */
|
|
1209
|
+
mode: Transfer.Mode
|
|
1210
|
+
/** Funding providers considered by the request. */
|
|
1211
|
+
providers: readonly Provider[]
|
|
1212
|
+
/** Source amount in base units. */
|
|
1213
|
+
sourceAmount: string
|
|
1214
|
+
/** Source chain CAIP-2 id, slug, or alias. */
|
|
1215
|
+
sourceChain: string
|
|
1216
|
+
/** Source token symbol, contract address, or token key. */
|
|
1217
|
+
sourceToken: string
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
/** Source amount unit accepted by the funding quote request. */
|
|
1222
|
+
export type SourceAmountUnits = z.output<typeof schema.SourceAmountUnits>
|
|
1223
|
+
|
|
1224
|
+
/** Fetch implementation accepted by funding provider factories. */
|
|
1225
|
+
export type Fetch = typeof globalThis.fetch
|
|
1226
|
+
|
|
1227
|
+
/** Returns bounded provider failure details suitable for structured request logs. */
|
|
1228
|
+
export function failure(options: ProviderFailure): failure.Result {
|
|
1229
|
+
const { cause, operation, provider } = options
|
|
1230
|
+
if (
|
|
1231
|
+
cause instanceof ProviderTimeoutError ||
|
|
1232
|
+
(cause instanceof DOMException && cause.name === 'AbortError')
|
|
1233
|
+
)
|
|
1234
|
+
return { failure: 'timeout', id: provider.id, operation }
|
|
1235
|
+
if (cause instanceof ProviderResponseError) {
|
|
1236
|
+
const code = errorCode(cause.body)
|
|
1237
|
+
return {
|
|
1238
|
+
...(code === undefined ? {} : { code }),
|
|
1239
|
+
failure: 'http',
|
|
1240
|
+
id: provider.id,
|
|
1241
|
+
operation,
|
|
1242
|
+
status: cause.status,
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
if (cause instanceof ProviderPayloadError)
|
|
1246
|
+
return { failure: 'payload', id: provider.id, operation }
|
|
1247
|
+
if (cause instanceof ProviderRateLimitError)
|
|
1248
|
+
return { failure: 'rate_limit', id: provider.id, operation }
|
|
1249
|
+
if (cause instanceof TypeError) return { failure: 'network', id: provider.id, operation }
|
|
1250
|
+
return { failure: 'unknown', id: provider.id, operation }
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
export declare namespace failure {
|
|
1254
|
+
/** Bounded provider failure fields. */
|
|
1255
|
+
type Result = {
|
|
1256
|
+
/** Stable provider error code, when one is safe to retain. */
|
|
1257
|
+
code?: string | undefined
|
|
1258
|
+
/** Failure boundary that rejected the provider request. */
|
|
1259
|
+
failure: 'http' | 'network' | 'payload' | 'rate_limit' | 'timeout' | 'unknown'
|
|
1260
|
+
/** Provider identifier. */
|
|
1261
|
+
id: string
|
|
1262
|
+
/** Provider operation identifier. */
|
|
1263
|
+
operation: ProviderOperation
|
|
1264
|
+
/** Upstream HTTP status, when a response was received. */
|
|
1265
|
+
status?: number | undefined
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
/** Returns a supported expected-unavailable code from a provider response. */
|
|
1270
|
+
export function unavailable(cause: unknown, codes: readonly string[]) {
|
|
1271
|
+
if (!(cause instanceof ProviderResponseError) || cause.status < 400 || cause.status >= 500)
|
|
1272
|
+
return undefined
|
|
1273
|
+
const code = errorCode(cause.body)
|
|
1274
|
+
if (code && codes.includes(code)) return code
|
|
1275
|
+
return undefined
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
/** Requests and parses a JSON provider response. */
|
|
1279
|
+
export async function requestJson(url: URL, options: requestJson.Options) {
|
|
1280
|
+
const headers = { accept: 'application/json', ...options.headers }
|
|
1281
|
+
const init: RequestInit = {
|
|
1282
|
+
headers:
|
|
1283
|
+
options.body === undefined ? headers : { ...headers, 'content-type': 'application/json' },
|
|
1284
|
+
method: options.method ?? 'GET',
|
|
1285
|
+
signal: options.signal,
|
|
1286
|
+
}
|
|
1287
|
+
if (options.body !== undefined) init.body = JSON.stringify(options.body)
|
|
1288
|
+
const response = await options.fetch(url, init)
|
|
1289
|
+
const text = await response.text()
|
|
1290
|
+
const body = (() => {
|
|
1291
|
+
if (!text) return null
|
|
1292
|
+
try {
|
|
1293
|
+
return JSON.parse(text) as unknown
|
|
1294
|
+
} catch {
|
|
1295
|
+
return text
|
|
1296
|
+
}
|
|
1297
|
+
})()
|
|
1298
|
+
if (!response.ok) throw new ProviderResponseError(response.status, body)
|
|
1299
|
+
return body
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
export declare namespace requestJson {
|
|
1303
|
+
/** Provider request options. */
|
|
1304
|
+
type Options = {
|
|
1305
|
+
/** Optional JSON request body. */
|
|
1306
|
+
body?: unknown
|
|
1307
|
+
/** Fetch implementation. */
|
|
1308
|
+
fetch: Fetch
|
|
1309
|
+
/** Optional request headers. */
|
|
1310
|
+
headers?: Record<string, string> | undefined
|
|
1311
|
+
/** Optional HTTP method. */
|
|
1312
|
+
method?: string | undefined
|
|
1313
|
+
/** Request abort signal. */
|
|
1314
|
+
signal: AbortSignal
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
/** Creates a normalized expected-unavailable quote result. */
|
|
1319
|
+
export function unavailableResult(options: unavailableResult.Options): getQuote.ReturnType {
|
|
1320
|
+
return {
|
|
1321
|
+
quality: {
|
|
1322
|
+
liquiditySource: options.source,
|
|
1323
|
+
sourceDetail: `${options.detail}:${options.message}`,
|
|
1324
|
+
tier: 'unavailable',
|
|
1325
|
+
},
|
|
1326
|
+
sampledAt: options.now.toISOString(),
|
|
1327
|
+
status: 'unavailable',
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
export declare namespace unavailableResult {
|
|
1332
|
+
/** Expected-unavailable quote details. */
|
|
1333
|
+
type Options = {
|
|
1334
|
+
/** Provider operation detail. */
|
|
1335
|
+
detail: string
|
|
1336
|
+
/** Stable provider reason. */
|
|
1337
|
+
message: string
|
|
1338
|
+
/** Quote sample time. */
|
|
1339
|
+
now: Date
|
|
1340
|
+
/** Liquidity signal source. */
|
|
1341
|
+
source: string
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
function tokenKey(token: Token) {
|
|
1346
|
+
const namespace = (() => {
|
|
1347
|
+
if (token.chain.kind === 'solana') return 'token'
|
|
1348
|
+
if (token.chain.kind === 'tron') return 'trc20'
|
|
1349
|
+
return 'erc20'
|
|
1350
|
+
})()
|
|
1351
|
+
return `${token.chain.id}/${namespace}:${token.address}`
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
async function quoteCandidate(
|
|
1355
|
+
candidate: QuoteCandidate,
|
|
1356
|
+
options: {
|
|
1357
|
+
cache: CachePolicy
|
|
1358
|
+
provider: Provider
|
|
1359
|
+
request: QuoteRequest
|
|
1360
|
+
timeoutMs: number
|
|
1361
|
+
},
|
|
1362
|
+
) {
|
|
1363
|
+
const result = schema.GetQuoteResult.safeParse(
|
|
1364
|
+
await withTimeout(
|
|
1365
|
+
(signal) =>
|
|
1366
|
+
options.provider.getQuote(
|
|
1367
|
+
{
|
|
1368
|
+
candidate,
|
|
1369
|
+
cache: options.cache,
|
|
1370
|
+
destinationChain: candidate.destinationChain,
|
|
1371
|
+
destinationToken: candidate.destinationToken,
|
|
1372
|
+
request: options.request,
|
|
1373
|
+
route: candidate.route,
|
|
1374
|
+
sourceAmount: candidate.sourceAmount,
|
|
1375
|
+
sourceChain: candidate.sourceChain,
|
|
1376
|
+
sourceToken: candidate.sourceToken,
|
|
1377
|
+
},
|
|
1378
|
+
signal,
|
|
1379
|
+
),
|
|
1380
|
+
options.timeoutMs,
|
|
1381
|
+
),
|
|
1382
|
+
)
|
|
1383
|
+
if (!result.success) throw new ProviderPayloadError()
|
|
1384
|
+
const quote = result.data
|
|
1385
|
+
if (quote.status === 'unavailable') return { outcome: quote.status }
|
|
1386
|
+
if (
|
|
1387
|
+
(quote.status !== 'available' && quote.status !== 'thin') ||
|
|
1388
|
+
quote.destinationAmount === undefined ||
|
|
1389
|
+
quote.destinationAmount === null
|
|
1390
|
+
)
|
|
1391
|
+
throw new ProviderPayloadError()
|
|
1392
|
+
const destinationAmount = BigInt(quote.destinationAmount)
|
|
1393
|
+
const destinationAmountMin =
|
|
1394
|
+
quote.destinationAmountMin === undefined ? undefined : BigInt(quote.destinationAmountMin)
|
|
1395
|
+
if (
|
|
1396
|
+
destinationAmount === 0n ||
|
|
1397
|
+
destinationAmountMin === 0n ||
|
|
1398
|
+
(destinationAmountMin !== undefined && destinationAmountMin > destinationAmount)
|
|
1399
|
+
)
|
|
1400
|
+
throw new ProviderPayloadError()
|
|
1401
|
+
return {
|
|
1402
|
+
outcome: quote.status,
|
|
1403
|
+
quote: createQuote(candidate, {
|
|
1404
|
+
...quote,
|
|
1405
|
+
destinationAmount: quote.destinationAmount,
|
|
1406
|
+
status: quote.status,
|
|
1407
|
+
}),
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
function tokenRef(token: Token): TokenRef {
|
|
1412
|
+
return schema.TokenRef.parse({
|
|
1413
|
+
address: token.address,
|
|
1414
|
+
currency: token.currency,
|
|
1415
|
+
decimals: token.decimals,
|
|
1416
|
+
name: token.name,
|
|
1417
|
+
standard: token.standard,
|
|
1418
|
+
symbol: token.symbol,
|
|
1419
|
+
tokenKey: tokenKey(token),
|
|
1420
|
+
verified: true,
|
|
1421
|
+
})
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1424
|
+
function chainRef(chain: Chain): ChainRef {
|
|
1425
|
+
return schema.ChainRef.parse({
|
|
1426
|
+
addressFormat: chain.addressFormat,
|
|
1427
|
+
id: chain.id,
|
|
1428
|
+
kind: chain.kind,
|
|
1429
|
+
name: chain.name,
|
|
1430
|
+
})
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
function createDepositAddressCandidate(options: { provider: Provider; route: core_Route.Route }) {
|
|
1434
|
+
return {
|
|
1435
|
+
destinationChain: chainRef(options.route.destination.chain),
|
|
1436
|
+
destinationToken: tokenRef(options.route.destination),
|
|
1437
|
+
provider: schema.ProviderRef.parse(options.provider),
|
|
1438
|
+
route: options.route,
|
|
1439
|
+
sourceChain: chainRef(options.route.source.chain),
|
|
1440
|
+
sourceToken: tokenRef(options.route.source),
|
|
1441
|
+
} as const
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
function createQuoteCandidate(options: {
|
|
1445
|
+
destinationToken: Token
|
|
1446
|
+
provider: Provider
|
|
1447
|
+
route: core_Route.Route
|
|
1448
|
+
sourceAmount: ReturnType<typeof resolveSourceAmount>
|
|
1449
|
+
sourceToken: Token
|
|
1450
|
+
}) {
|
|
1451
|
+
return {
|
|
1452
|
+
destinationChain: chainRef(options.destinationToken.chain),
|
|
1453
|
+
destinationToken: tokenRef(options.destinationToken),
|
|
1454
|
+
id: [
|
|
1455
|
+
options.sourceToken.chain.slug,
|
|
1456
|
+
options.sourceToken.slug,
|
|
1457
|
+
options.destinationToken.chain.slug,
|
|
1458
|
+
options.destinationToken.slug,
|
|
1459
|
+
options.provider.id,
|
|
1460
|
+
].join('-'),
|
|
1461
|
+
provider: schema.ProviderRef.parse(options.provider),
|
|
1462
|
+
route: options.route,
|
|
1463
|
+
sourceAmount: options.sourceAmount,
|
|
1464
|
+
sourceChain: chainRef(options.sourceToken.chain),
|
|
1465
|
+
sourceToken: tokenRef(options.sourceToken),
|
|
1466
|
+
} as const
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
function normalizeInput(value: string) {
|
|
1470
|
+
return value.trim().toLowerCase()
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
function parseBaseUnits(value: string) {
|
|
1474
|
+
return BigInt(value).toString()
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
function parseDecimalUnits(value: string, decimals: number) {
|
|
1478
|
+
const fraction = value.split('.')[1]?.replace(/0+$/, '') ?? ''
|
|
1479
|
+
if (fraction.length > decimals) throw new InvalidAmountError()
|
|
1480
|
+
try {
|
|
1481
|
+
const amount = core_Value.from(value, decimals)
|
|
1482
|
+
if (amount <= 0n) throw new InvalidAmountError()
|
|
1483
|
+
return amount.toString()
|
|
1484
|
+
} catch (cause) {
|
|
1485
|
+
if (cause instanceof InvalidAmountError) throw cause
|
|
1486
|
+
throw new InvalidAmountError()
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
type SuccessfulQuoteResult = getQuote.ReturnType & {
|
|
1491
|
+
destinationAmount: string
|
|
1492
|
+
status: 'available' | 'thin'
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
function createQuote(candidate: QuoteCandidate, quote: SuccessfulQuoteResult): FundingQuote {
|
|
1496
|
+
return schema.FundingQuote.parse({
|
|
1497
|
+
destinationAmount: Value.tokenAmount({
|
|
1498
|
+
baseUnits: quote.destinationAmount,
|
|
1499
|
+
currency: candidate.destinationToken.currency,
|
|
1500
|
+
decimals: candidate.destinationToken.decimals,
|
|
1501
|
+
}),
|
|
1502
|
+
...(quote.destinationAmountMin !== undefined
|
|
1503
|
+
? {
|
|
1504
|
+
destinationAmountMin: Value.tokenAmount({
|
|
1505
|
+
baseUnits: quote.destinationAmountMin,
|
|
1506
|
+
currency: candidate.destinationToken.currency,
|
|
1507
|
+
decimals: candidate.destinationToken.decimals,
|
|
1508
|
+
}),
|
|
1509
|
+
}
|
|
1510
|
+
: {}),
|
|
1511
|
+
destinationChain: candidate.destinationChain,
|
|
1512
|
+
destinationToken: candidate.destinationToken,
|
|
1513
|
+
id: candidate.id,
|
|
1514
|
+
provider: candidate.provider,
|
|
1515
|
+
quality: {
|
|
1516
|
+
...(quote.quality?.estimatedSeconds !== undefined
|
|
1517
|
+
? { estimatedSeconds: quote.quality.estimatedSeconds }
|
|
1518
|
+
: {}),
|
|
1519
|
+
liquiditySource: quote.quality?.liquiditySource ?? 'providerQuote',
|
|
1520
|
+
...(quote.quality?.sourceDetail !== undefined
|
|
1521
|
+
? { sourceDetail: quote.quality.sourceDetail }
|
|
1522
|
+
: {}),
|
|
1523
|
+
tier: quote.status === 'thin' ? ('thin' as const) : ('liquid' as const),
|
|
1524
|
+
},
|
|
1525
|
+
quote: {
|
|
1526
|
+
...(quote.expiresAt !== undefined ? { expiresAt: quote.expiresAt } : {}),
|
|
1527
|
+
sampledAt: quote.sampledAt,
|
|
1528
|
+
},
|
|
1529
|
+
sourceAmount: Value.tokenAmount({
|
|
1530
|
+
baseUnits: candidate.sourceAmount.amount,
|
|
1531
|
+
currency: candidate.sourceToken.currency,
|
|
1532
|
+
decimals: candidate.sourceToken.decimals,
|
|
1533
|
+
}),
|
|
1534
|
+
sourceChain: candidate.sourceChain,
|
|
1535
|
+
sourceToken: candidate.sourceToken,
|
|
1536
|
+
})
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
function withTimeout<result>(fn: (signal: AbortSignal) => Promise<result>, timeoutMs: number) {
|
|
1540
|
+
const controller = new AbortController()
|
|
1541
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs)
|
|
1542
|
+
// Some provider implementations may not honor the signal, so the boundary also races them.
|
|
1543
|
+
return Promise.race([
|
|
1544
|
+
fn(controller.signal),
|
|
1545
|
+
new Promise<never>((_, reject) => {
|
|
1546
|
+
if (controller.signal.aborted) {
|
|
1547
|
+
reject(new ProviderTimeoutError())
|
|
1548
|
+
return
|
|
1549
|
+
}
|
|
1550
|
+
controller.signal.addEventListener('abort', () => reject(new ProviderTimeoutError()), {
|
|
1551
|
+
once: true,
|
|
1552
|
+
})
|
|
1553
|
+
}),
|
|
1554
|
+
]).finally(() => clearTimeout(timeout))
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1557
|
+
function errorCode(input: unknown) {
|
|
1558
|
+
const result = schema.ErrorBody.safeParse(input)
|
|
1559
|
+
if (!result.success) return undefined
|
|
1560
|
+
const body = result.data
|
|
1561
|
+
const code =
|
|
1562
|
+
body._tag ??
|
|
1563
|
+
body.code ??
|
|
1564
|
+
body.errorCode ??
|
|
1565
|
+
body.errorType ??
|
|
1566
|
+
body.type ??
|
|
1567
|
+
body.error?.code ??
|
|
1568
|
+
body.error?.type
|
|
1569
|
+
const parsed = schema.ErrorCode.safeParse(code)
|
|
1570
|
+
return parsed.success ? parsed.data : undefined
|
|
1571
|
+
}
|
|
1572
|
+
|
|
1573
|
+
function attemptResult(attempt: ProviderAttempt): ProviderAttemptResult {
|
|
1574
|
+
return {
|
|
1575
|
+
durationMs: attempt.durationMs,
|
|
1576
|
+
...(attempt.outcome === 'failed'
|
|
1577
|
+
? {
|
|
1578
|
+
failure: failure({
|
|
1579
|
+
cause: attempt.cause,
|
|
1580
|
+
operation: attempt.operation,
|
|
1581
|
+
provider: attempt.provider,
|
|
1582
|
+
}).failure,
|
|
1583
|
+
}
|
|
1584
|
+
: {}),
|
|
1585
|
+
id: attempt.provider.id,
|
|
1586
|
+
operation: attempt.operation,
|
|
1587
|
+
outcome: attempt.outcome,
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1591
|
+
function resolveDestinationToken(input: string | undefined, catalog: core_Catalog.Snapshot) {
|
|
1592
|
+
const destinations = uniqueBy(
|
|
1593
|
+
catalog.routes.map((entry) => entry.route.destination),
|
|
1594
|
+
(token) => `${token.chain.id}:${token.address}`,
|
|
1595
|
+
)
|
|
1596
|
+
if (input === undefined) {
|
|
1597
|
+
const destination = destinations.find((candidate) => candidate.slug === defaultDestinationToken)
|
|
1598
|
+
if (!destination) throw new UnsupportedDestinationTokenError()
|
|
1599
|
+
return destination
|
|
1600
|
+
}
|
|
1601
|
+
const destination = destinations.find((candidate) => matchesToken(candidate, input))
|
|
1602
|
+
if (!destination) throw new UnsupportedDestinationTokenError()
|
|
1603
|
+
return destination
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
function resolveProvider(input: string, providers: readonly Provider[]) {
|
|
1607
|
+
const provider = providers.find((candidate) => candidate.id === normalizeInput(input))
|
|
1608
|
+
if (!provider) throw new UnsupportedProviderError()
|
|
1609
|
+
return provider
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
function resolveSourceAmount(options: resolveSourceAmount.Options) {
|
|
1613
|
+
const amount =
|
|
1614
|
+
options.units === 'baseUnits'
|
|
1615
|
+
? parseBaseUnits(options.amount)
|
|
1616
|
+
: parseDecimalUnits(options.amount, options.token.decimals)
|
|
1617
|
+
return {
|
|
1618
|
+
amount,
|
|
1619
|
+
formatted: core_Value.format(BigInt(amount), options.token.decimals),
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1623
|
+
declare namespace resolveSourceAmount {
|
|
1624
|
+
type Options = {
|
|
1625
|
+
amount: string
|
|
1626
|
+
token: Token
|
|
1627
|
+
units: SourceAmountUnits
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
function resolveSourceToken(chain: Chain, input: string, catalog: core_Catalog.Snapshot) {
|
|
1632
|
+
const tokens = catalog.routes
|
|
1633
|
+
.filter((entry) => entry.route.source.chain.id === chain.id)
|
|
1634
|
+
.map((entry) => entry.route.source)
|
|
1635
|
+
return tokens.find((token) => matchesToken(token, input))
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1638
|
+
function matchesToken(token: Token, input: string) {
|
|
1639
|
+
const trimmed = input.trim()
|
|
1640
|
+
const normalized = normalizeInput(input)
|
|
1641
|
+
return (
|
|
1642
|
+
token.slug === normalized ||
|
|
1643
|
+
token.symbol.toLowerCase() === normalized ||
|
|
1644
|
+
matchesTokenIdentifier(token.chain, token.address, trimmed, normalized) ||
|
|
1645
|
+
matchesTokenIdentifier(token.chain, tokenKey(token), trimmed, normalized)
|
|
1646
|
+
)
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
function matchesTokenIdentifier(
|
|
1650
|
+
chain: Chain,
|
|
1651
|
+
candidate: string,
|
|
1652
|
+
trimmed: string,
|
|
1653
|
+
normalized: string,
|
|
1654
|
+
) {
|
|
1655
|
+
return chain.kind === 'evm' ? candidate.toLowerCase() === normalized : candidate === trimmed
|
|
1656
|
+
}
|
|
1657
|
+
|
|
1658
|
+
function resolveSourceChain(input: string, catalog: core_Catalog.Snapshot) {
|
|
1659
|
+
const normalized = normalizeInput(input)
|
|
1660
|
+
const chain = catalog.chainsByKey.get(normalized)
|
|
1661
|
+
if (!chain || !catalog.routes.some((entry) => entry.route.source.chain.id === chain.id))
|
|
1662
|
+
throw new UnsupportedSourceChainError()
|
|
1663
|
+
return chain
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
function getRoutes(catalog: core_Catalog.Snapshot, providers: readonly Provider[]) {
|
|
1667
|
+
return providers.flatMap((provider) =>
|
|
1668
|
+
(catalog.routesByProvider.get(provider.id) ?? []).map((route) => ({ provider, route })),
|
|
1669
|
+
)
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
function uniqueBy<const value>(values: readonly value[], key: (value: value) => string): value[] {
|
|
1673
|
+
const seen = new Set<string>()
|
|
1674
|
+
return values.filter((value) => {
|
|
1675
|
+
const id = key(value)
|
|
1676
|
+
if (seen.has(id)) return false
|
|
1677
|
+
seen.add(id)
|
|
1678
|
+
return true
|
|
1679
|
+
})
|
|
1680
|
+
}
|
|
1681
|
+
|
|
1682
|
+
function normalizeAccountAddress(value: string, chain: ChainRef): string | undefined {
|
|
1683
|
+
if (chain.kind === 'evm')
|
|
1684
|
+
return Address.validate(value, { strict: false }) ? Address.checksum(value) : undefined
|
|
1685
|
+
try {
|
|
1686
|
+
const bytes = Base58.toBytes(value)
|
|
1687
|
+
if (chain.kind === 'solana') return bytes.length === 32 ? value : undefined
|
|
1688
|
+
if (bytes.length !== 25 || bytes[0] !== 0x41) return undefined
|
|
1689
|
+
const payload = bytes.slice(0, 21)
|
|
1690
|
+
const checksum = Hash.sha256(Hash.sha256(payload), { as: 'Bytes' }).slice(0, 4)
|
|
1691
|
+
return Bytes.isEqual(bytes.slice(21), checksum) ? value : undefined
|
|
1692
|
+
} catch {
|
|
1693
|
+
return undefined
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
|
|
1697
|
+
/** Error thrown when the caller supplies an unsupported destination token. */
|
|
1698
|
+
export class UnsupportedDestinationTokenError extends Error {
|
|
1699
|
+
override name = 'FundingProvider.UnsupportedDestinationTokenError'
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1702
|
+
/** Error thrown when a provider webhook cannot be authenticated. */
|
|
1703
|
+
export class WebhookAuthenticationError extends Error {
|
|
1704
|
+
override name = 'FundingProvider.WebhookAuthenticationError'
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1707
|
+
/** Error thrown when an authenticated provider webhook has an invalid body. */
|
|
1708
|
+
export class WebhookPayloadError extends Error {
|
|
1709
|
+
override name = 'FundingProvider.WebhookPayloadError'
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1712
|
+
/** Error thrown when the caller supplies an invalid source amount. */
|
|
1713
|
+
export class InvalidAmountError extends Error {
|
|
1714
|
+
override name = 'FundingProvider.InvalidAmountError'
|
|
1715
|
+
}
|
|
1716
|
+
|
|
1717
|
+
/** Error thrown when the caller supplies an invalid source-chain refund address. */
|
|
1718
|
+
export class InvalidRefundAddressError extends Error {
|
|
1719
|
+
override name = 'FundingProvider.InvalidRefundAddressError'
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
/** Error thrown when provider deployment configuration is invalid. */
|
|
1723
|
+
export class ProviderConfigurationError extends Error {
|
|
1724
|
+
override name = 'FundingProvider.ProviderConfigurationError'
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
/** Error thrown when a provider response does not match the requested quote. */
|
|
1728
|
+
export class ProviderPayloadError extends Error {
|
|
1729
|
+
override name = 'FundingProvider.ProviderPayloadError'
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1732
|
+
/** Error thrown when a provider confirms that no executable route is available. */
|
|
1733
|
+
export class ProviderUnavailableError extends Error {
|
|
1734
|
+
override name = 'FundingProvider.ProviderUnavailableError'
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
/** Error thrown internally when a provider exceeds its quote timeout. */
|
|
1738
|
+
export class ProviderTimeoutError extends Error {
|
|
1739
|
+
override name = 'FundingProvider.ProviderTimeoutError'
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1742
|
+
/** Error thrown when an internal provider quota rejects a quote request. */
|
|
1743
|
+
export class ProviderRateLimitError extends Error {
|
|
1744
|
+
override name = 'FundingProvider.ProviderRateLimitError'
|
|
1745
|
+
}
|
|
1746
|
+
|
|
1747
|
+
/** Error thrown when a provider returns an unsuccessful HTTP response. */
|
|
1748
|
+
export class ProviderResponseError extends Error {
|
|
1749
|
+
override name = 'FundingProvider.ProviderResponseError'
|
|
1750
|
+
|
|
1751
|
+
constructor(
|
|
1752
|
+
/** Provider response status. */
|
|
1753
|
+
readonly status: number,
|
|
1754
|
+
/** Parsed provider response body. */
|
|
1755
|
+
readonly body: unknown,
|
|
1756
|
+
) {
|
|
1757
|
+
super(`Provider request failed with status ${status}`)
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
/** Error thrown when every matching provider fails to produce a quote. */
|
|
1762
|
+
export class ProviderQuoteError extends Error {
|
|
1763
|
+
override name = 'FundingProvider.ProviderQuoteError'
|
|
1764
|
+
|
|
1765
|
+
/** Provider failures that prevented a successful quote. */
|
|
1766
|
+
failures: readonly ProviderFailure[]
|
|
1767
|
+
|
|
1768
|
+
/** Bounded provider attempts retained for request logs. */
|
|
1769
|
+
fundingProviderAttempts: readonly ProviderAttemptResult[]
|
|
1770
|
+
|
|
1771
|
+
/** First bounded provider failure retained for request logs. */
|
|
1772
|
+
providerFailure?: failure.Result | undefined
|
|
1773
|
+
|
|
1774
|
+
/** Bounded provider failures retained when multiple providers failed. */
|
|
1775
|
+
providerFailures?: readonly failure.Result[] | undefined
|
|
1776
|
+
|
|
1777
|
+
constructor(failures: readonly ProviderFailure[], attempts: readonly ProviderAttempt[] = []) {
|
|
1778
|
+
super()
|
|
1779
|
+
this.failures = failures
|
|
1780
|
+
this.fundingProviderAttempts = attempts.map(attemptResult)
|
|
1781
|
+
const values = failures.map(failure)
|
|
1782
|
+
const first = values[0]
|
|
1783
|
+
if (first) this.providerFailure = first
|
|
1784
|
+
if (values.length > 1) this.providerFailures = values
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
/** Error thrown when the caller filters to an unknown provider. */
|
|
1789
|
+
export class UnsupportedProviderError extends Error {
|
|
1790
|
+
override name = 'FundingProvider.UnsupportedProviderError'
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1793
|
+
/** Error thrown when the caller supplies an unsupported source chain. */
|
|
1794
|
+
export class UnsupportedSourceChainError extends Error {
|
|
1795
|
+
override name = 'FundingProvider.UnsupportedSourceChainError'
|
|
1796
|
+
}
|