tapimo 0.14.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -4
- package/dist/ApiKey.js +1 -1
- package/dist/ApiKey.js.map +1 -1
- package/dist/ApiKeys.d.ts +95 -14
- package/dist/ApiKeys.d.ts.map +1 -1
- package/dist/ApiKeys.js +360 -49
- package/dist/ApiKeys.js.map +1 -1
- package/dist/App.d.ts +12457 -10365
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js +300 -22
- package/dist/App.js.map +1 -1
- package/dist/Assets.d.ts.map +1 -1
- package/dist/Assets.js +2 -1
- package/dist/Assets.js.map +1 -1
- package/dist/Handler.d.ts +0 -1
- package/dist/Handler.d.ts.map +1 -1
- package/dist/Handler.js +0 -1
- package/dist/Handler.js.map +1 -1
- package/dist/Scope.d.ts +13 -5
- package/dist/Scope.d.ts.map +1 -1
- package/dist/Scope.js +16 -5
- package/dist/Scope.js.map +1 -1
- package/dist/Webhooks.js +1 -1
- package/dist/Webhooks.js.map +1 -1
- package/dist/admin/App.d.ts +3057 -549
- package/dist/admin/App.d.ts.map +1 -1
- package/dist/admin/App.js +26 -5
- package/dist/admin/App.js.map +1 -1
- package/dist/admin/apps/api-keys.d.ts +159 -7
- package/dist/admin/apps/api-keys.d.ts.map +1 -1
- package/dist/admin/apps/api-keys.js +95 -43
- package/dist/admin/apps/api-keys.js.map +1 -1
- package/dist/admin/apps/earn-vaults.d.ts +1398 -0
- package/dist/admin/apps/earn-vaults.d.ts.map +1 -1
- package/dist/admin/apps/earn-vaults.js +463 -7
- package/dist/admin/apps/earn-vaults.js.map +1 -1
- package/dist/admin/apps/organizations.d.ts +267 -15
- package/dist/admin/apps/organizations.d.ts.map +1 -1
- package/dist/admin/apps/organizations.js +241 -25
- package/dist/admin/apps/organizations.js.map +1 -1
- package/dist/admin/apps/routes-support.d.ts +95 -0
- package/dist/admin/apps/routes-support.d.ts.map +1 -0
- package/dist/admin/apps/routes-support.js +151 -0
- package/dist/admin/apps/routes-support.js.map +1 -0
- package/dist/admin/apps/routes.d.ts +2764 -0
- package/dist/admin/apps/routes.d.ts.map +1 -0
- package/dist/admin/apps/routes.js +728 -0
- package/dist/admin/apps/routes.js.map +1 -0
- package/dist/admin/apps/subsidies.d.ts +501 -0
- package/dist/admin/apps/subsidies.d.ts.map +1 -0
- package/dist/admin/apps/subsidies.js +384 -0
- package/dist/admin/apps/subsidies.js.map +1 -0
- package/dist/admin/apps/verified-tokens.d.ts +88 -88
- package/dist/admin/apps/verified-tokens.d.ts.map +1 -1
- package/dist/admin/apps/verified-tokens.js +3 -3
- package/dist/admin/apps/verified-tokens.js.map +1 -1
- package/dist/admin/ui.generated.d.ts +1 -1
- package/dist/admin/ui.generated.d.ts.map +1 -1
- package/dist/admin/ui.generated.js +129 -69
- package/dist/admin/ui.generated.js.map +1 -1
- package/dist/analytics/Analytics.d.ts +5 -2
- package/dist/analytics/Analytics.d.ts.map +1 -1
- package/dist/analytics/Analytics.js +31 -1
- package/dist/analytics/Analytics.js.map +1 -1
- package/dist/analytics/tables/requestEvents.d.ts +2 -1
- package/dist/analytics/tables/requestEvents.d.ts.map +1 -1
- package/dist/analytics/tables/requestEvents.js +10 -1
- package/dist/analytics/tables/requestEvents.js.map +1 -1
- package/dist/analytics/tables/routesLifecycleIntervals.d.ts +72 -0
- package/dist/analytics/tables/routesLifecycleIntervals.d.ts.map +1 -0
- package/dist/analytics/tables/routesLifecycleIntervals.js +56 -0
- package/dist/analytics/tables/routesLifecycleIntervals.js.map +1 -0
- package/dist/apps/Zones.d.ts +21 -12526
- package/dist/apps/Zones.d.ts.map +1 -1
- package/dist/apps/Zones.js +37 -5
- package/dist/apps/Zones.js.map +1 -1
- package/dist/apps/data/App.d.ts +3971 -2595
- package/dist/apps/data/App.d.ts.map +1 -1
- package/dist/apps/data/App.js +76 -21
- package/dist/apps/data/App.js.map +1 -1
- package/dist/apps/data/routes/activities.d.ts +364 -34
- package/dist/apps/data/routes/activities.d.ts.map +1 -1
- package/dist/apps/data/routes/activities.js +495 -190
- package/dist/apps/data/routes/activities.js.map +1 -1
- package/dist/apps/data/routes/addresses.d.ts +72 -0
- package/dist/apps/data/routes/addresses.d.ts.map +1 -1
- package/dist/apps/data/routes/blocks.d.ts +37 -37
- package/dist/apps/data/routes/coingecko.d.ts.map +1 -1
- package/dist/apps/data/routes/coingecko.js +47 -21
- package/dist/apps/data/routes/coingecko.js.map +1 -1
- package/dist/apps/data/routes/earn.d.ts +1450 -337
- package/dist/apps/data/routes/earn.d.ts.map +1 -1
- package/dist/apps/data/routes/earn.js +1226 -144
- package/dist/apps/data/routes/earn.js.map +1 -1
- package/dist/apps/data/routes/fee-amm.d.ts +5 -0
- package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
- package/dist/apps/data/routes/fee-amm.js +31 -19
- package/dist/apps/data/routes/fee-amm.js.map +1 -1
- package/dist/apps/data/routes/indexer.d.ts +125 -0
- package/dist/apps/data/routes/indexer.d.ts.map +1 -1
- package/dist/apps/data/routes/indexer.js +83 -27
- package/dist/apps/data/routes/indexer.js.map +1 -1
- package/dist/apps/data/routes/rpc.d.ts +507 -33
- package/dist/apps/data/routes/rpc.d.ts.map +1 -1
- package/dist/apps/data/routes/rpc.js +266 -156
- package/dist/apps/data/routes/rpc.js.map +1 -1
- package/dist/apps/data/routes/tokenlist.d.ts +47 -15
- package/dist/apps/data/routes/tokenlist.d.ts.map +1 -1
- package/dist/apps/data/routes/tokenlist.js +68 -11
- package/dist/apps/data/routes/tokenlist.js.map +1 -1
- package/dist/apps/data/routes/tokens.d.ts +2 -0
- package/dist/apps/data/routes/tokens.d.ts.map +1 -1
- package/dist/apps/data/routes/tokens.js +26 -14
- package/dist/apps/data/routes/tokens.js.map +1 -1
- package/dist/apps/data/routes/transfers.d.ts +28 -12
- package/dist/apps/data/routes/transfers.d.ts.map +1 -1
- package/dist/apps/data/routes/transfers.js +9 -7
- package/dist/apps/data/routes/transfers.js.map +1 -1
- package/dist/apps/data/routes/valuation.d.ts +30 -30
- package/dist/apps/data/routes/verified-tokens.d.ts +9 -9
- package/dist/apps/data/routes/verified-tokens.d.ts.map +1 -1
- package/dist/apps/data/routes/verified-tokens.js +64 -20
- package/dist/apps/data/routes/verified-tokens.js.map +1 -1
- package/dist/apps/data/routes/webhooks.d.ts +613 -176
- package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
- package/dist/apps/data/routes/webhooks.js +291 -195
- package/dist/apps/data/routes/webhooks.js.map +1 -1
- package/dist/apps/data/routes/zones.d.ts.map +1 -1
- package/dist/apps/data/routes/zones.js +20 -12
- package/dist/apps/data/routes/zones.js.map +1 -1
- package/dist/apps/docs/reference.js +2 -2
- package/dist/apps/docs/reference.js.map +1 -1
- package/dist/apps/index.d.ts +1 -1
- package/dist/apps/index.d.ts.map +1 -1
- package/dist/apps/index.js +1 -1
- package/dist/apps/index.js.map +1 -1
- package/dist/apps/management/App.d.ts +3763 -3385
- package/dist/apps/management/App.d.ts.map +1 -1
- package/dist/apps/management/App.js +5 -14
- package/dist/apps/management/App.js.map +1 -1
- package/dist/apps/management/Billing.d.ts +48 -7
- package/dist/apps/management/Billing.d.ts.map +1 -1
- package/dist/apps/management/Billing.js +204 -25
- package/dist/apps/management/Billing.js.map +1 -1
- package/dist/apps/management/routes/api-keys.d.ts +106 -4
- package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
- package/dist/apps/management/routes/api-keys.js +43 -15
- package/dist/apps/management/routes/api-keys.js.map +1 -1
- package/dist/apps/management/routes/billing.d.ts +290 -4
- package/dist/apps/management/routes/billing.d.ts.map +1 -1
- package/dist/apps/management/routes/billing.js +274 -49
- package/dist/apps/management/routes/billing.js.map +1 -1
- package/dist/apps/management/routes/faucet.d.ts +6 -6
- package/dist/apps/management/routes/faucet.js +1 -1
- package/dist/apps/management/routes/faucet.js.map +1 -1
- package/dist/apps/management/routes/invitations.d.ts +77 -2
- package/dist/apps/management/routes/invitations.d.ts.map +1 -1
- package/dist/apps/management/routes/invitations.js +117 -13
- package/dist/apps/management/routes/invitations.js.map +1 -1
- package/dist/apps/management/routes/invite-links.d.ts +4 -4
- package/dist/apps/management/routes/me.d.ts.map +1 -1
- package/dist/apps/management/routes/me.js +6 -2
- package/dist/apps/management/routes/me.js.map +1 -1
- package/dist/apps/management/routes/members.d.ts +30 -30
- package/dist/apps/management/routes/orgs.d.ts +18 -2
- package/dist/apps/management/routes/orgs.d.ts.map +1 -1
- package/dist/apps/management/routes/orgs.js +52 -12
- package/dist/apps/management/routes/orgs.js.map +1 -1
- package/dist/apps/management/routes/projects.d.ts +4 -4
- package/dist/apps/management/routes/projects.d.ts.map +1 -1
- package/dist/apps/management/routes/projects.js +6 -1
- package/dist/apps/management/routes/projects.js.map +1 -1
- package/dist/apps/management/routes/scopes.d.ts.map +1 -1
- package/dist/apps/management/routes/scopes.js +4 -1
- package/dist/apps/management/routes/scopes.js.map +1 -1
- package/dist/apps/management/routes/usage.d.ts +24 -24
- package/dist/apps/management/routes/usage.js +21 -4
- package/dist/apps/management/routes/usage.js.map +1 -1
- package/dist/apps/management/routes/verified-token-requests.d.ts +2 -2
- package/dist/apps/management/routes/webhooks.d.ts +280 -214
- package/dist/apps/management/routes/webhooks.d.ts.map +1 -1
- package/dist/apps/management/routes/webhooks.js +58 -12
- package/dist/apps/management/routes/webhooks.js.map +1 -1
- package/dist/apps/mcp.d.ts +1 -1
- package/dist/apps/mcp.js +7 -7
- package/dist/apps/mcp.js.map +1 -1
- package/dist/apps/mpp/App.d.ts.map +1 -1
- package/dist/apps/mpp/App.js +35 -7
- package/dist/apps/mpp/App.js.map +1 -1
- package/dist/apps/mpp/internal/Adapter.d.ts +2 -0
- package/dist/apps/mpp/internal/Adapter.d.ts.map +1 -1
- package/dist/apps/mpp/internal/Adapter.js +30 -1
- package/dist/apps/mpp/internal/Adapter.js.map +1 -1
- package/dist/apps/mpp/internal/Policy.d.ts +22 -4
- package/dist/apps/mpp/internal/Policy.d.ts.map +1 -1
- package/dist/apps/mpp/internal/Policy.js +24 -6
- package/dist/apps/mpp/internal/Policy.js.map +1 -1
- package/dist/apps/mpp/internal/Sponsorship.d.ts +3 -0
- package/dist/apps/mpp/internal/Sponsorship.d.ts.map +1 -1
- package/dist/apps/mpp/internal/Sponsorship.js +6 -3
- package/dist/apps/mpp/internal/Sponsorship.js.map +1 -1
- package/dist/apps/relay/App.d.ts +2 -0
- package/dist/apps/relay/App.d.ts.map +1 -1
- package/dist/apps/relay/App.js +134 -75
- package/dist/apps/relay/App.js.map +1 -1
- package/dist/apps/relay/Sponsorships.d.ts +5 -3
- package/dist/apps/relay/Sponsorships.d.ts.map +1 -1
- package/dist/apps/relay/Sponsorships.js +209 -28
- package/dist/apps/relay/Sponsorships.js.map +1 -1
- package/dist/apps/{funding → routes}/Access.d.ts +4 -4
- package/dist/apps/routes/Access.d.ts.map +1 -0
- package/dist/apps/{funding → routes}/Access.js +4 -4
- package/dist/apps/routes/Access.js.map +1 -0
- package/dist/apps/{funding → routes}/App.d.ts +418 -124
- package/dist/apps/{funding → routes}/App.d.ts.map +1 -1
- package/dist/apps/{funding → routes}/App.js +16 -16
- package/dist/apps/routes/App.js.map +1 -0
- package/dist/apps/routes/Inventory.d.ts.map +1 -0
- package/dist/apps/{funding → routes}/Inventory.js +2 -2
- package/dist/apps/routes/Inventory.js.map +1 -0
- package/dist/apps/routes/index.d.ts +2 -0
- package/dist/apps/routes/index.d.ts.map +1 -0
- package/dist/apps/routes/index.js +2 -0
- package/dist/apps/routes/index.js.map +1 -0
- package/dist/apps/{funding → routes}/routes/chains.d.ts +7 -7
- package/dist/apps/routes/routes/chains.d.ts.map +1 -0
- package/dist/apps/{funding → routes}/routes/chains.js +25 -25
- package/dist/apps/routes/routes/chains.js.map +1 -0
- package/dist/apps/{funding → routes}/routes/deposit-addresses.d.ts +107 -43
- package/dist/apps/routes/routes/deposit-addresses.d.ts.map +1 -0
- package/dist/apps/{funding → routes}/routes/deposit-addresses.js +497 -222
- package/dist/apps/routes/routes/deposit-addresses.js.map +1 -0
- package/dist/apps/{funding → routes}/routes/providers.d.ts +8 -8
- package/dist/apps/routes/routes/providers.d.ts.map +1 -0
- package/dist/apps/routes/routes/providers.js +57 -0
- package/dist/apps/routes/routes/providers.js.map +1 -0
- package/dist/apps/{funding → routes}/routes/quotes.d.ts +19 -16
- package/dist/apps/routes/routes/quotes.d.ts.map +1 -0
- package/dist/apps/{funding → routes}/routes/quotes.js +55 -38
- package/dist/apps/routes/routes/quotes.js.map +1 -0
- package/dist/apps/{funding → routes}/routes/transfers.d.ts +379 -74
- package/dist/apps/routes/routes/transfers.d.ts.map +1 -0
- package/dist/apps/routes/routes/transfers.js +1140 -0
- package/dist/apps/routes/routes/transfers.js.map +1 -0
- package/dist/cli/Cli.d.ts +30 -0
- package/dist/cli/Cli.d.ts.map +1 -1
- package/dist/cli/commands/admin.d.ts +36 -0
- package/dist/cli/commands/admin.d.ts.map +1 -1
- package/dist/cli/commands/admin.js +273 -0
- package/dist/cli/commands/admin.js.map +1 -1
- package/dist/cloudflare.d.ts +16 -14
- package/dist/cloudflare.d.ts.map +1 -1
- package/dist/cloudflare.js +26 -21
- package/dist/cloudflare.js.map +1 -1
- package/dist/db/Db.d.ts +63 -21
- package/dist/db/Db.d.ts.map +1 -1
- package/dist/db/Db.js +1030 -15
- package/dist/db/Db.js.map +1 -1
- package/dist/db/Schema.d.ts +780 -133
- package/dist/db/Schema.d.ts.map +1 -1
- package/dist/db/Schema.js +575 -162
- package/dist/db/Schema.js.map +1 -1
- package/dist/db/tables/apiKeyAdmissionBootstraps.d.ts +4 -0
- package/dist/db/tables/apiKeyAdmissionBootstraps.d.ts.map +1 -0
- package/dist/db/tables/apiKeyAdmissionBootstraps.js +2 -0
- package/dist/db/tables/apiKeyAdmissionBootstraps.js.map +1 -0
- package/dist/db/tables/apiKeyAdmissions.d.ts +73 -0
- package/dist/db/tables/apiKeyAdmissions.d.ts.map +1 -0
- package/dist/db/tables/apiKeyAdmissions.js +142 -0
- package/dist/db/tables/apiKeyAdmissions.js.map +1 -0
- package/dist/db/tables/apiKeyOwnerAdmissions.d.ts +4 -0
- package/dist/db/tables/apiKeyOwnerAdmissions.d.ts.map +1 -0
- package/dist/db/tables/apiKeyOwnerAdmissions.js +2 -0
- package/dist/db/tables/apiKeyOwnerAdmissions.js.map +1 -0
- package/dist/db/tables/apiKeyOwnerTombstones.d.ts +20 -0
- package/dist/db/tables/apiKeyOwnerTombstones.d.ts.map +1 -0
- package/dist/db/tables/apiKeyOwnerTombstones.js +57 -0
- package/dist/db/tables/apiKeyOwnerTombstones.js.map +1 -0
- package/dist/db/tables/apiKeyRevocations.d.ts +21 -0
- package/dist/db/tables/apiKeyRevocations.d.ts.map +1 -0
- package/dist/db/tables/apiKeyRevocations.js +98 -0
- package/dist/db/tables/apiKeyRevocations.js.map +1 -0
- package/dist/db/tables/authAccounts.d.ts +47 -0
- package/dist/db/tables/authAccounts.d.ts.map +1 -0
- package/dist/db/tables/authAccounts.js +72 -0
- package/dist/db/tables/authAccounts.js.map +1 -0
- package/dist/db/tables/authSessions.d.ts +12 -0
- package/dist/db/tables/authSessions.d.ts.map +1 -0
- package/dist/db/tables/authSessions.js +2 -0
- package/dist/db/tables/authSessions.js.map +1 -0
- package/dist/db/tables/authVerifications.d.ts +12 -0
- package/dist/db/tables/authVerifications.d.ts.map +1 -0
- package/dist/db/tables/authVerifications.js +2 -0
- package/dist/db/tables/authVerifications.js.map +1 -0
- package/dist/db/tables/invitations.d.ts +17 -1
- package/dist/db/tables/invitations.d.ts.map +1 -1
- package/dist/db/tables/invitations.js +123 -43
- package/dist/db/tables/invitations.js.map +1 -1
- package/dist/db/tables/memberships.d.ts +8 -0
- package/dist/db/tables/memberships.d.ts.map +1 -1
- package/dist/db/tables/memberships.js +51 -2
- package/dist/db/tables/memberships.js.map +1 -1
- package/dist/db/tables/organizations.d.ts +32 -10
- package/dist/db/tables/organizations.d.ts.map +1 -1
- package/dist/db/tables/organizations.js +110 -49
- package/dist/db/tables/organizations.js.map +1 -1
- package/dist/db/tables/projects.d.ts +2 -0
- package/dist/db/tables/projects.d.ts.map +1 -1
- package/dist/db/tables/projects.js +12 -3
- package/dist/db/tables/projects.js.map +1 -1
- package/dist/db/tables/requestUsage.d.ts.map +1 -1
- package/dist/db/tables/requestUsage.js.map +1 -1
- package/dist/db/tables/rewardAccounts.d.ts +86 -0
- package/dist/db/tables/rewardAccounts.d.ts.map +1 -0
- package/dist/db/tables/rewardAccounts.js +88 -0
- package/dist/db/tables/rewardAccounts.js.map +1 -0
- package/dist/db/tables/rewardCampaignDistributors.d.ts +36 -0
- package/dist/db/tables/rewardCampaignDistributors.d.ts.map +1 -0
- package/dist/db/tables/rewardCampaignDistributors.js +30 -0
- package/dist/db/tables/rewardCampaignDistributors.js.map +1 -0
- package/dist/db/tables/rewardCampaigns.d.ts +171 -0
- package/dist/db/tables/rewardCampaigns.d.ts.map +1 -0
- package/dist/db/tables/rewardCampaigns.js +392 -0
- package/dist/db/tables/rewardCampaigns.js.map +1 -0
- package/dist/db/tables/rewardCredits.d.ts +53 -0
- package/dist/db/tables/rewardCredits.d.ts.map +1 -0
- package/dist/db/tables/rewardCredits.js +63 -0
- package/dist/db/tables/rewardCredits.js.map +1 -0
- package/dist/db/tables/rewardEligibilityAssociations.d.ts +61 -0
- package/dist/db/tables/rewardEligibilityAssociations.d.ts.map +1 -0
- package/dist/db/tables/rewardEligibilityAssociations.js +103 -0
- package/dist/db/tables/rewardEligibilityAssociations.js.map +1 -0
- package/dist/db/tables/rewardRuns.d.ts +188 -0
- package/dist/db/tables/rewardRuns.d.ts.map +1 -0
- package/dist/db/tables/rewardRuns.js +278 -0
- package/dist/db/tables/rewardRuns.js.map +1 -0
- package/dist/db/tables/rewardTransactionAttempts.d.ts +100 -0
- package/dist/db/tables/rewardTransactionAttempts.d.ts.map +1 -0
- package/dist/db/tables/rewardTransactionAttempts.js +163 -0
- package/dist/db/tables/rewardTransactionAttempts.js.map +1 -0
- package/dist/db/tables/routesCatalog.d.ts +58 -0
- package/dist/db/tables/routesCatalog.d.ts.map +1 -0
- package/dist/db/tables/{fundingCatalog.js → routesCatalog.js} +19 -19
- package/dist/db/tables/routesCatalog.js.map +1 -0
- package/dist/db/tables/routesDepositAddresses.d.ts +476 -0
- package/dist/db/tables/routesDepositAddresses.d.ts.map +1 -0
- package/dist/db/tables/routesDepositAddresses.js +587 -0
- package/dist/db/tables/routesDepositAddresses.js.map +1 -0
- package/dist/db/tables/{fundingDepositRequestObservations.d.ts → routesDepositRequestObservations.d.ts} +6 -6
- package/dist/db/tables/routesDepositRequestObservations.d.ts.map +1 -0
- package/dist/db/tables/{fundingDepositRequestObservations.js → routesDepositRequestObservations.js} +6 -6
- package/dist/db/tables/routesDepositRequestObservations.js.map +1 -0
- package/dist/db/tables/{fundingDeposits.d.ts → routesDeposits.d.ts} +210 -22
- package/dist/db/tables/routesDeposits.d.ts.map +1 -0
- package/dist/db/tables/routesDeposits.js +576 -0
- package/dist/db/tables/routesDeposits.js.map +1 -0
- package/dist/db/tables/routesIdempotency.d.ts +166 -0
- package/dist/db/tables/routesIdempotency.d.ts.map +1 -0
- package/dist/db/tables/routesIdempotency.js +330 -0
- package/dist/db/tables/routesIdempotency.js.map +1 -0
- package/dist/db/tables/routesSubsidies.d.ts +27 -0
- package/dist/db/tables/routesSubsidies.d.ts.map +1 -0
- package/dist/db/tables/routesSubsidies.js +45 -0
- package/dist/db/tables/routesSubsidies.js.map +1 -0
- package/dist/db/tables/{fundingTransferEvents.d.ts → routesTransferEvents.d.ts} +3 -3
- package/dist/db/tables/routesTransferEvents.d.ts.map +1 -0
- package/dist/db/tables/{fundingTransferEvents.js → routesTransferEvents.js} +3 -3
- package/dist/db/tables/routesTransferEvents.js.map +1 -0
- package/dist/db/tables/routesTransferSubsidies.d.ts +19 -0
- package/dist/db/tables/routesTransferSubsidies.d.ts.map +1 -0
- package/dist/db/tables/routesTransferSubsidies.js +17 -0
- package/dist/db/tables/routesTransferSubsidies.js.map +1 -0
- package/dist/db/tables/routesTransferSubsidyNonces.d.ts +51 -0
- package/dist/db/tables/routesTransferSubsidyNonces.d.ts.map +1 -0
- package/dist/db/tables/routesTransferSubsidyNonces.js +82 -0
- package/dist/db/tables/routesTransferSubsidyNonces.js.map +1 -0
- package/dist/db/tables/routesTransferTransactions.d.ts +77 -0
- package/dist/db/tables/routesTransferTransactions.d.ts.map +1 -0
- package/dist/db/tables/{fundingTransferTransactions.js → routesTransferTransactions.js} +31 -13
- package/dist/db/tables/routesTransferTransactions.js.map +1 -0
- package/dist/db/tables/routesTransfers.d.ts +319 -0
- package/dist/db/tables/routesTransfers.d.ts.map +1 -0
- package/dist/db/tables/routesTransfers.js +372 -0
- package/dist/db/tables/routesTransfers.js.map +1 -0
- package/dist/db/tables/sponsoredTransactions.d.ts +75 -20
- package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
- package/dist/db/tables/sponsoredTransactions.js +124 -54
- package/dist/db/tables/sponsoredTransactions.js.map +1 -1
- package/dist/db/tables/sponsorshipAttributions.d.ts +69 -0
- package/dist/db/tables/sponsorshipAttributions.d.ts.map +1 -0
- package/dist/db/tables/sponsorshipAttributions.js +77 -0
- package/dist/db/tables/sponsorshipAttributions.js.map +1 -0
- package/dist/db/tables/sponsorshipReconciliationCursors.d.ts +22 -0
- package/dist/db/tables/sponsorshipReconciliationCursors.d.ts.map +1 -0
- package/dist/db/tables/sponsorshipReconciliationCursors.js +45 -0
- package/dist/db/tables/sponsorshipReconciliationCursors.js.map +1 -0
- package/dist/db/tables/stripeCustomers.d.ts +11 -0
- package/dist/db/tables/stripeCustomers.d.ts.map +1 -1
- package/dist/db/tables/stripeCustomers.js +13 -0
- package/dist/db/tables/stripeCustomers.js.map +1 -1
- package/dist/db/tables/users.d.ts +17 -1
- package/dist/db/tables/users.d.ts.map +1 -1
- package/dist/db/tables/users.js +47 -2
- package/dist/db/tables/users.js.map +1 -1
- package/dist/db/tables/webhookQueueEvents.d.ts.map +1 -1
- package/dist/db/tables/webhookQueueEvents.js +5 -1
- package/dist/db/tables/webhookQueueEvents.js.map +1 -1
- package/dist/db/tables/webhookSubscriptions.d.ts +19 -11
- package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
- package/dist/db/tables/webhookSubscriptions.js +45 -13
- package/dist/db/tables/webhookSubscriptions.js.map +1 -1
- package/dist/handlers/internal/executionError.d.ts +2 -2
- package/dist/handlers/internal/executionError.d.ts.map +1 -1
- package/dist/handlers/internal/executionError.js +1 -2
- package/dist/handlers/internal/executionError.js.map +1 -1
- package/dist/handlers/internal/multisig.d.ts +4 -232
- package/dist/handlers/internal/multisig.d.ts.map +1 -1
- package/dist/handlers/internal/multisig.js +11 -537
- package/dist/handlers/internal/multisig.js.map +1 -1
- package/dist/handlers/internal/sponsorship.d.ts +19 -8
- package/dist/handlers/internal/sponsorship.d.ts.map +1 -1
- package/dist/handlers/internal/sponsorship.js +13 -9
- package/dist/handlers/internal/sponsorship.js.map +1 -1
- package/dist/handlers/relay.d.ts +9 -12
- package/dist/handlers/relay.d.ts.map +1 -1
- package/dist/handlers/relay.js +81 -85
- package/dist/handlers/relay.js.map +1 -1
- package/dist/index.d.ts +0 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -17
- package/dist/index.js.map +1 -1
- package/dist/internal/AssetResponse.d.ts +12 -0
- package/dist/internal/AssetResponse.d.ts.map +1 -0
- package/dist/internal/AssetResponse.js +21 -0
- package/dist/internal/AssetResponse.js.map +1 -0
- package/dist/internal/Auth.d.ts +48 -12
- package/dist/internal/Auth.d.ts.map +1 -1
- package/dist/internal/Auth.js +603 -175
- package/dist/internal/Auth.js.map +1 -1
- package/dist/internal/BetterAuth.d.ts +1488 -0
- package/dist/internal/BetterAuth.d.ts.map +1 -0
- package/dist/internal/BetterAuth.js +253 -0
- package/dist/internal/BetterAuth.js.map +1 -0
- package/dist/internal/Cache.d.ts +2 -0
- package/dist/internal/Cache.d.ts.map +1 -1
- package/dist/internal/Cache.js +2 -0
- package/dist/internal/Cache.js.map +1 -1
- package/dist/internal/EarnRates.d.ts +26 -3
- package/dist/internal/EarnRates.d.ts.map +1 -1
- package/dist/internal/EarnRates.js +84 -19
- package/dist/internal/EarnRates.js.map +1 -1
- package/dist/internal/EarnSharePrices.d.ts +120 -0
- package/dist/internal/EarnSharePrices.d.ts.map +1 -0
- package/dist/internal/EarnSharePrices.js +179 -0
- package/dist/internal/EarnSharePrices.js.map +1 -0
- package/dist/internal/EarnVaults.d.ts +4 -0
- package/dist/internal/EarnVaults.d.ts.map +1 -1
- package/dist/internal/EarnVaults.js +27 -10
- package/dist/internal/EarnVaults.js.map +1 -1
- package/dist/internal/Email.d.ts +37 -0
- package/dist/internal/Email.d.ts.map +1 -0
- package/dist/internal/Email.js +16 -0
- package/dist/internal/Email.js.map +1 -0
- package/dist/internal/Log.d.ts +32 -28
- package/dist/internal/Log.d.ts.map +1 -1
- package/dist/internal/Log.js +18 -11
- package/dist/internal/Log.js.map +1 -1
- package/dist/internal/MetricSink.d.ts +3 -0
- package/dist/internal/MetricSink.d.ts.map +1 -1
- package/dist/internal/MetricSink.js +67 -8
- package/dist/internal/MetricSink.js.map +1 -1
- package/dist/internal/Mpp.d.ts.map +1 -1
- package/dist/internal/Mpp.js +20 -25
- package/dist/internal/Mpp.js.map +1 -1
- package/dist/internal/OpenApi.d.ts +26 -3
- package/dist/internal/OpenApi.d.ts.map +1 -1
- package/dist/internal/OpenApi.js +25 -10
- package/dist/internal/OpenApi.js.map +1 -1
- package/dist/internal/Provider.d.ts +1 -1
- package/dist/internal/Provider.d.ts.map +1 -1
- package/dist/internal/RateLimit.d.ts.map +1 -1
- package/dist/internal/RateLimit.js +13 -1
- package/dist/internal/RateLimit.js.map +1 -1
- package/dist/internal/Store.d.ts +16 -0
- package/dist/internal/Store.d.ts.map +1 -1
- package/dist/internal/Store.js +59 -8
- package/dist/internal/Store.js.map +1 -1
- package/dist/internal/Tidx.d.ts +9 -2
- package/dist/internal/Tidx.d.ts.map +1 -1
- package/dist/internal/Tidx.js +78 -11
- package/dist/internal/Tidx.js.map +1 -1
- package/dist/internal/Timing.d.ts +26 -0
- package/dist/internal/Timing.d.ts.map +1 -1
- package/dist/internal/Timing.js +63 -5
- package/dist/internal/Timing.js.map +1 -1
- package/dist/internal/VercelOidc.d.ts +94 -0
- package/dist/internal/VercelOidc.d.ts.map +1 -0
- package/dist/internal/VercelOidc.js +128 -0
- package/dist/internal/VercelOidc.js.map +1 -0
- package/dist/internal/VerifiedTokens.d.ts +2 -8
- package/dist/internal/VerifiedTokens.d.ts.map +1 -1
- package/dist/internal/VerifiedTokens.js +24 -24
- package/dist/internal/VerifiedTokens.js.map +1 -1
- package/dist/internal/Viem.d.ts +30 -2067
- package/dist/internal/Viem.d.ts.map +1 -1
- package/dist/internal/Viem.js +167 -17
- package/dist/internal/Viem.js.map +1 -1
- package/dist/internal/Webhooks.d.ts +12 -4
- package/dist/internal/Webhooks.d.ts.map +1 -1
- package/dist/internal/Webhooks.js +9 -3
- package/dist/internal/Webhooks.js.map +1 -1
- package/dist/internal/ZoneRpc.d.ts +7 -0
- package/dist/internal/ZoneRpc.d.ts.map +1 -0
- package/dist/internal/ZoneRpc.js +49 -0
- package/dist/internal/ZoneRpc.js.map +1 -0
- package/dist/internal/index.d.ts +3 -1
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +3 -1
- package/dist/internal/index.js.map +1 -1
- package/dist/internal/rewards/Audit.d.ts +88 -0
- package/dist/internal/rewards/Audit.d.ts.map +1 -0
- package/dist/internal/rewards/Audit.js +134 -0
- package/dist/internal/rewards/Audit.js.map +1 -0
- package/dist/internal/rewards/Campaigns.d.ts +572 -0
- package/dist/internal/rewards/Campaigns.d.ts.map +1 -0
- package/dist/internal/rewards/Campaigns.js +531 -0
- package/dist/internal/rewards/Campaigns.js.map +1 -0
- package/dist/internal/rewards/Credits.d.ts +76 -0
- package/dist/internal/rewards/Credits.d.ts.map +1 -0
- package/dist/internal/rewards/Credits.js +95 -0
- package/dist/internal/rewards/Credits.js.map +1 -0
- package/dist/internal/rewards/Events.d.ts +100 -0
- package/dist/internal/rewards/Events.d.ts.map +1 -0
- package/dist/internal/rewards/Events.js +340 -0
- package/dist/internal/rewards/Events.js.map +1 -0
- package/dist/internal/rewards/Projection.d.ts +237 -0
- package/dist/internal/rewards/Projection.d.ts.map +1 -0
- package/dist/internal/rewards/Projection.js +616 -0
- package/dist/internal/rewards/Projection.js.map +1 -0
- package/dist/internal/rewards/Rates.d.ts +44 -0
- package/dist/internal/rewards/Rates.d.ts.map +1 -0
- package/dist/internal/rewards/Rates.js +60 -0
- package/dist/internal/rewards/Rates.js.map +1 -0
- package/dist/internal/rewards/Read.d.ts +158 -0
- package/dist/internal/rewards/Read.d.ts.map +1 -0
- package/dist/internal/rewards/Read.js +292 -0
- package/dist/internal/rewards/Read.js.map +1 -0
- package/dist/internal/rewards/Runner.d.ts +164 -0
- package/dist/internal/rewards/Runner.d.ts.map +1 -0
- package/dist/internal/rewards/Runner.js +1778 -0
- package/dist/internal/rewards/Runner.js.map +1 -0
- package/dist/internal/rewards/Signer.d.ts +224 -0
- package/dist/internal/rewards/Signer.d.ts.map +1 -0
- package/dist/internal/rewards/Signer.js +135 -0
- package/dist/internal/rewards/Signer.js.map +1 -0
- package/dist/internal/rewards/index.d.ts +15 -0
- package/dist/internal/rewards/index.d.ts.map +1 -0
- package/dist/internal/rewards/index.js +15 -0
- package/dist/internal/rewards/index.js.map +1 -0
- package/dist/internal/{funding → routes}/Action.d.ts +12 -1
- package/dist/internal/routes/Action.d.ts.map +1 -0
- package/dist/internal/{funding → routes}/Action.js +17 -9
- package/dist/internal/routes/Action.js.map +1 -0
- package/dist/internal/{funding → routes}/Catalog.d.ts +20 -20
- package/dist/internal/routes/Catalog.d.ts.map +1 -0
- package/dist/internal/{funding → routes}/Catalog.js +29 -29
- package/dist/internal/routes/Catalog.js.map +1 -0
- package/dist/internal/{funding → routes}/Chain.d.ts +10 -10
- package/dist/internal/routes/Chain.d.ts.map +1 -0
- package/dist/internal/{funding → routes}/Chain.js +3 -3
- package/dist/internal/routes/Chain.js.map +1 -0
- package/dist/internal/{funding → routes}/Deposit.d.ts +45 -23
- package/dist/internal/routes/Deposit.d.ts.map +1 -0
- package/dist/internal/{funding → routes}/Deposit.js +60 -27
- package/dist/internal/routes/Deposit.js.map +1 -0
- package/dist/internal/{funding → routes}/DepositAddress.d.ts +56 -27
- package/dist/internal/routes/DepositAddress.d.ts.map +1 -0
- package/dist/internal/{funding → routes}/DepositAddress.js +95 -33
- package/dist/internal/routes/DepositAddress.js.map +1 -0
- package/dist/internal/{funding → routes}/DepositWebhook.d.ts +4 -4
- package/dist/internal/routes/DepositWebhook.d.ts.map +1 -0
- package/dist/internal/{funding → routes}/DepositWebhook.js +4 -4
- package/dist/internal/routes/DepositWebhook.js.map +1 -0
- package/dist/internal/routes/Economics.d.ts +25 -0
- package/dist/internal/routes/Economics.d.ts.map +1 -0
- package/dist/internal/routes/Economics.js +28 -0
- package/dist/internal/routes/Economics.js.map +1 -0
- package/dist/internal/{funding → routes}/Evidence.d.ts +3 -3
- package/dist/internal/routes/Evidence.d.ts.map +1 -0
- package/dist/internal/{funding → routes}/Evidence.js +7 -7
- package/dist/internal/routes/Evidence.js.map +1 -0
- package/dist/internal/routes/Observability.d.ts +154 -0
- package/dist/internal/routes/Observability.d.ts.map +1 -0
- package/dist/internal/routes/Observability.js +389 -0
- package/dist/internal/routes/Observability.js.map +1 -0
- package/dist/internal/{funding → routes}/Provider.d.ts +311 -105
- package/dist/internal/routes/Provider.d.ts.map +1 -0
- package/dist/internal/{funding → routes}/Provider.js +229 -98
- package/dist/internal/routes/Provider.js.map +1 -0
- package/dist/internal/{funding → routes}/Reconciliation.d.ts +11 -6
- package/dist/internal/routes/Reconciliation.d.ts.map +1 -0
- package/dist/internal/{funding → routes}/Reconciliation.js +408 -158
- package/dist/internal/routes/Reconciliation.js.map +1 -0
- package/dist/internal/routes/Route.d.ts +21 -0
- package/dist/internal/routes/Route.d.ts.map +1 -0
- package/dist/internal/{funding → routes}/Route.js +1 -1
- package/dist/internal/routes/Route.js.map +1 -0
- package/dist/internal/{funding → routes}/SourceObservation.d.ts +6 -6
- package/dist/internal/routes/SourceObservation.d.ts.map +1 -0
- package/dist/internal/{funding → routes}/SourceObservation.js +8 -8
- package/dist/internal/routes/SourceObservation.js.map +1 -0
- package/dist/internal/{funding → routes}/Subsidy.d.ts +48 -3
- package/dist/internal/routes/Subsidy.d.ts.map +1 -0
- package/dist/internal/{funding → routes}/Subsidy.js +43 -3
- package/dist/internal/routes/Subsidy.js.map +1 -0
- package/dist/internal/{funding → routes}/Token.d.ts +4 -4
- package/dist/internal/routes/Token.d.ts.map +1 -0
- package/dist/internal/{funding → routes}/Token.js +3 -3
- package/dist/internal/routes/Token.js.map +1 -0
- package/dist/internal/{funding → routes}/Transfer.d.ts +241 -46
- package/dist/internal/routes/Transfer.d.ts.map +1 -0
- package/dist/internal/routes/Transfer.js +728 -0
- package/dist/internal/routes/Transfer.js.map +1 -0
- package/dist/internal/{funding → routes}/TransferReconciliation.d.ts +13 -10
- package/dist/internal/routes/TransferReconciliation.d.ts.map +1 -0
- package/dist/internal/routes/TransferReconciliation.js +422 -0
- package/dist/internal/routes/TransferReconciliation.js.map +1 -0
- package/dist/internal/routes/TransferSubsidy.d.ts +201 -0
- package/dist/internal/routes/TransferSubsidy.d.ts.map +1 -0
- package/dist/internal/routes/TransferSubsidy.js +256 -0
- package/dist/internal/routes/TransferSubsidy.js.map +1 -0
- package/dist/internal/{funding → routes}/TransferWebhook.d.ts +5 -5
- package/dist/internal/routes/TransferWebhook.d.ts.map +1 -0
- package/dist/internal/{funding → routes}/TransferWebhook.js +3 -3
- package/dist/internal/routes/TransferWebhook.js.map +1 -0
- package/dist/internal/{funding → routes}/index.d.ts +2 -0
- package/dist/internal/routes/index.d.ts.map +1 -0
- package/dist/internal/{funding → routes}/index.js +2 -0
- package/dist/internal/routes/index.js.map +1 -0
- package/dist/internal/{funding → routes}/providers/across.d.ts +4 -4
- package/dist/internal/routes/providers/across.d.ts.map +1 -0
- package/dist/internal/{funding → routes}/providers/across.js +13 -13
- package/dist/internal/routes/providers/across.js.map +1 -0
- package/dist/internal/{funding → routes}/providers/relay.d.ts +21 -12
- package/dist/internal/routes/providers/relay.d.ts.map +1 -0
- package/dist/internal/{funding → routes}/providers/relay.js +194 -110
- package/dist/internal/routes/providers/relay.js.map +1 -0
- package/dist/internal/{funding → routes}/providers/rhino.d.ts +4 -4
- package/dist/internal/routes/providers/rhino.d.ts.map +1 -0
- package/dist/internal/{funding → routes}/providers/rhino.js +10 -10
- package/dist/internal/routes/providers/rhino.js.map +1 -0
- package/dist/internal/{funding → routes}/providers/squid.d.ts +4 -4
- package/dist/internal/routes/providers/squid.d.ts.map +1 -0
- package/dist/internal/{funding → routes}/providers/squid.js +14 -14
- package/dist/internal/routes/providers/squid.js.map +1 -0
- package/dist/internal/{funding → routes}/providers/stargate.d.ts +46 -18
- package/dist/internal/routes/providers/stargate.d.ts.map +1 -0
- package/dist/internal/routes/providers/stargate.js +898 -0
- package/dist/internal/routes/providers/stargate.js.map +1 -0
- package/dist/internal/{funding → routes}/providers/symbiosis.d.ts +4 -4
- package/dist/internal/routes/providers/symbiosis.d.ts.map +1 -0
- package/dist/internal/{funding → routes}/providers/symbiosis.js +30 -20
- package/dist/internal/routes/providers/symbiosis.js.map +1 -0
- package/dist/internal/webhookDestinations/slack.js +12 -12
- package/dist/internal/webhookDestinations/slack.js.map +1 -1
- package/dist/providers/index.d.ts +12 -12
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +12 -12
- package/dist/providers/index.js.map +1 -1
- package/dist/server.d.ts +19 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +19 -0
- package/dist/server.js.map +1 -0
- package/package.json +15 -4
- package/src/ApiKey.ts +1 -1
- package/src/ApiKeys.test.ts +1033 -3
- package/src/ApiKeys.ts +489 -48
- package/src/App.test-d.ts +1 -1
- package/src/App.test.ts +216 -25
- package/src/App.ts +334 -31
- package/src/Assets.test.ts +2 -2
- package/src/Assets.ts +3 -1
- package/src/Auth.test-d.ts +1 -1
- package/src/Client.test-d.ts +539 -110
- package/src/Handler.ts +0 -1
- package/src/OpenApi.contract.test.ts +195 -0
- package/src/Scope.ts +17 -5
- package/src/Webhooks.ts +1 -1
- package/src/admin/App.test.ts +30 -2
- package/src/admin/App.ts +42 -6
- package/src/admin/apps/api-keys.test.ts +267 -5
- package/src/admin/apps/api-keys.ts +100 -50
- package/src/admin/apps/earn-vaults.test.ts +158 -0
- package/src/admin/apps/earn-vaults.ts +679 -6
- package/src/admin/apps/organizations.test.ts +306 -17
- package/src/admin/apps/organizations.ts +299 -24
- package/src/admin/apps/routes-support.test.ts +200 -0
- package/src/admin/apps/routes-support.ts +201 -0
- package/src/admin/apps/routes.test.ts +450 -0
- package/src/admin/apps/routes.ts +896 -0
- package/src/admin/apps/scopes.test.ts +15 -5
- package/src/admin/apps/subsidies.test.ts +306 -0
- package/src/admin/apps/subsidies.ts +457 -0
- package/src/admin/apps/verified-tokens.test.ts +8 -3
- package/src/admin/apps/verified-tokens.ts +3 -3
- package/src/admin/ui/plugin.ts +1 -2
- package/src/admin/ui/src/components/RewardCampaignForm.tsx +1009 -0
- package/src/admin/ui/src/lib/config.ts +11 -2
- package/src/admin/ui/src/lib/earn-vaults.ts +2 -2
- package/src/admin/ui/src/lib/organizations.test.ts +83 -50
- package/src/admin/ui/src/lib/organizations.ts +106 -25
- package/src/admin/ui/src/lib/query-client.ts +1 -1
- package/src/admin/ui/src/lib/reward-campaigns.ts +136 -0
- package/src/admin/ui/src/lib/routes.test.ts +88 -0
- package/src/admin/ui/src/lib/routes.ts +304 -0
- package/src/admin/ui/src/lib/subsidies.ts +75 -0
- package/src/admin/ui/src/routeTree.gen.ts +63 -0
- package/src/admin/ui/src/routes/__root.tsx +12 -1
- package/src/admin/ui/src/routes/api-keys.tsx +196 -84
- package/src/admin/ui/src/routes/earn.vaults_.$vaultId.edit.tsx +105 -70
- package/src/admin/ui/src/routes/organizations_.$orgId.tsx +239 -23
- package/src/admin/ui/src/routes/routes.tsx +1615 -0
- package/src/admin/ui/src/routes/routes_.support.tsx +248 -0
- package/src/admin/ui/src/routes/subsidies.tsx +799 -0
- package/src/admin/ui.generated.ts +144 -69
- package/src/analytics/Analytics.test.ts +108 -18
- package/src/analytics/Analytics.ts +38 -6
- package/src/analytics/tables/requestEvents.test.ts +100 -0
- package/src/analytics/tables/requestEvents.ts +10 -1
- package/src/analytics/tables/routesLifecycleIntervals.ts +140 -0
- package/src/apps/Zones.test.ts +15 -0
- package/src/apps/Zones.ts +52 -5
- package/src/apps/composition.test.ts +68 -60
- package/src/apps/data/App.test.ts +154 -2
- package/src/apps/data/App.ts +88 -28
- package/src/apps/data/routes/activities.test.ts +419 -7
- package/src/apps/data/routes/activities.ts +683 -216
- package/src/apps/data/routes/balances.test.ts +2 -2
- package/src/apps/data/routes/blocks.test.ts +46 -1
- package/src/apps/data/routes/coingecko.test.ts +419 -1
- package/src/apps/data/routes/coingecko.ts +309 -253
- package/src/apps/data/routes/earn.discovery.test.ts +274 -0
- package/src/apps/data/routes/earn.test.ts +1294 -17
- package/src/apps/data/routes/earn.ts +1838 -321
- package/src/apps/data/routes/exchanges.test.ts +12 -15
- package/src/apps/data/routes/fee-amm.test.ts +224 -0
- package/src/apps/data/routes/fee-amm.ts +191 -160
- package/src/apps/data/routes/indexer.test.ts +389 -0
- package/src/apps/data/routes/indexer.ts +165 -69
- package/src/apps/data/routes/receipts.test.ts +1 -1
- package/src/apps/data/routes/rpc.test.ts +352 -8
- package/src/apps/data/routes/rpc.ts +407 -219
- package/src/apps/data/routes/rpc.zone.test.ts +340 -0
- package/src/apps/data/routes/tokenlist.test.ts +285 -0
- package/src/apps/data/routes/tokenlist.ts +173 -88
- package/src/apps/data/routes/tokens.test.ts +93 -3
- package/src/apps/data/routes/tokens.ts +39 -23
- package/src/apps/data/routes/transactions.test.ts +1 -1
- package/src/apps/data/routes/transfers.test.ts +56 -24
- package/src/apps/data/routes/transfers.ts +19 -8
- package/src/apps/data/routes/valuation.test.ts +1 -1
- package/src/apps/data/routes/verified-tokens.test.ts +345 -0
- package/src/apps/data/routes/verified-tokens.ts +99 -29
- package/src/apps/data/routes/webhooks.test.ts +645 -83
- package/src/apps/data/routes/webhooks.ts +1089 -857
- package/src/apps/data/routes/zones.test.ts +148 -71
- package/src/apps/data/routes/zones.ts +71 -55
- package/src/apps/docs/reference.ts +2 -2
- package/src/apps/index.ts +1 -1
- package/src/apps/management/App.ts +9 -51
- package/src/apps/management/Billing.test.ts +375 -14
- package/src/apps/management/Billing.ts +265 -29
- package/src/apps/management/routes/api-keys.test.ts +269 -7
- package/src/apps/management/routes/api-keys.ts +61 -20
- package/src/apps/management/routes/billing.test.ts +477 -15
- package/src/apps/management/routes/billing.ts +377 -50
- package/src/apps/management/routes/faucet.test.ts +1 -1
- package/src/apps/management/routes/faucet.ts +1 -1
- package/src/apps/management/routes/invitations.test.ts +270 -3
- package/src/apps/management/routes/invitations.ts +185 -15
- package/src/apps/management/routes/invoicePreview.test.ts +549 -0
- package/src/apps/management/routes/me.test.ts +246 -5
- package/src/apps/management/routes/me.ts +7 -2
- package/src/apps/management/routes/members.test.ts +108 -0
- package/src/apps/management/routes/orgs.test.ts +191 -3
- package/src/apps/management/routes/orgs.ts +58 -11
- package/src/apps/management/routes/projects.test.ts +33 -3
- package/src/apps/management/routes/projects.ts +6 -1
- package/src/apps/management/routes/scopes.test.ts +30 -2
- package/src/apps/management/routes/scopes.ts +4 -1
- package/src/apps/management/routes/usage.test.ts +32 -0
- package/src/apps/management/routes/usage.ts +22 -4
- package/src/apps/management/routes/webhooks.test.ts +49 -26
- package/src/apps/management/routes/webhooks.ts +78 -22
- package/src/apps/mcp.test.ts +6 -6
- package/src/apps/mcp.ts +7 -7
- package/src/apps/mpp/App.ts +37 -7
- package/src/apps/mpp/Mpp.test.ts +49 -8
- package/src/apps/mpp/Mpp.zone.test.ts +219 -0
- package/src/apps/mpp/internal/Adapter.ts +34 -0
- package/src/apps/mpp/internal/Policy.test.ts +86 -31
- package/src/apps/mpp/internal/Policy.ts +49 -7
- package/src/apps/mpp/internal/Sponsorship.test.ts +207 -0
- package/src/apps/mpp/internal/Sponsorship.ts +9 -3
- package/src/apps/relay/App.test.ts +839 -64
- package/src/apps/relay/App.ts +148 -81
- package/src/apps/relay/App.zone-billing.test.ts +257 -0
- package/src/apps/relay/Sponsorships.test.ts +67 -4
- package/src/apps/relay/Sponsorships.ts +233 -32
- package/src/apps/relay/Sponsorships.zone.test.ts +102 -0
- package/src/apps/{funding → routes}/Access.ts +6 -6
- package/src/apps/routes/App.test.ts +165 -0
- package/src/apps/routes/App.ts +96 -0
- package/src/apps/{funding → routes}/Inventory.ts +2 -2
- package/src/apps/routes/index.ts +1 -0
- package/src/apps/{funding → routes}/routes/chains.test.ts +66 -66
- package/src/apps/{funding → routes}/routes/chains.ts +23 -23
- package/src/apps/{funding → routes}/routes/deposit-addresses.test.ts +1358 -458
- package/src/apps/{funding → routes}/routes/deposit-addresses.ts +566 -246
- package/src/apps/{funding → routes}/routes/providers.test.ts +27 -33
- package/src/apps/{funding → routes}/routes/providers.ts +23 -23
- package/src/apps/{funding → routes}/routes/quotes.test.ts +298 -41
- package/src/apps/{funding → routes}/routes/quotes.ts +57 -40
- package/src/apps/{funding → routes}/routes/transfers.test.ts +1100 -353
- package/src/apps/routes/routes/transfers.ts +1332 -0
- package/src/cli/Cli.test.ts +1 -1
- package/src/cli/commands/admin.test.ts +748 -1
- package/src/cli/commands/admin.ts +278 -0
- package/src/cloudflare.ts +52 -47
- package/src/db/Db.test.ts +245 -2
- package/src/db/Db.ts +1476 -34
- package/src/db/Schema.ts +729 -228
- package/src/db/tables/apiKeyAdmissionBootstraps.ts +4 -0
- package/src/db/tables/apiKeyAdmissions.ts +218 -0
- package/src/db/tables/apiKeyOwnerAdmissions.ts +4 -0
- package/src/db/tables/apiKeyOwnerTombstones.ts +81 -0
- package/src/db/tables/apiKeyRevocations.test.ts +74 -0
- package/src/db/tables/apiKeyRevocations.ts +121 -0
- package/src/db/tables/authAccounts.ts +105 -0
- package/src/db/tables/authSessions.ts +13 -0
- package/src/db/tables/authVerifications.ts +13 -0
- package/src/db/tables/invitations.ts +142 -45
- package/src/db/tables/memberships.ts +79 -3
- package/src/db/tables/organizations.test.ts +690 -13
- package/src/db/tables/organizations.ts +139 -55
- package/src/db/tables/projects.test.ts +16 -0
- package/src/db/tables/projects.ts +13 -3
- package/src/db/tables/requestUsage.ts +4 -1
- package/src/db/tables/rewardAccounts.ts +178 -0
- package/src/db/tables/rewardCampaignDistributors.ts +68 -0
- package/src/db/tables/rewardCampaigns.test.ts +1388 -0
- package/src/db/tables/rewardCampaigns.ts +647 -0
- package/src/db/tables/rewardCredits.ts +110 -0
- package/src/db/tables/rewardEligibilityAssociations.test.ts +271 -0
- package/src/db/tables/rewardEligibilityAssociations.ts +184 -0
- package/src/db/tables/rewardRuns.ts +514 -0
- package/src/db/tables/rewardTransactionAttempts.ts +272 -0
- package/src/db/tables/routesCatalog.test.ts +185 -0
- package/src/db/tables/routesCatalog.ts +163 -0
- package/src/db/tables/routesDepositAddresses.test.ts +1048 -0
- package/src/db/tables/routesDepositAddresses.ts +1008 -0
- package/src/db/tables/{fundingDepositRequestObservations.test.ts → routesDepositRequestObservations.test.ts} +13 -14
- package/src/db/tables/{fundingDepositRequestObservations.ts → routesDepositRequestObservations.ts} +10 -10
- package/src/db/tables/{fundingDeposits.test.ts → routesDeposits.test.ts} +316 -46
- package/src/db/tables/routesDeposits.ts +1062 -0
- package/src/db/tables/routesIdempotency.test.ts +796 -0
- package/src/db/tables/routesIdempotency.ts +496 -0
- package/src/db/tables/routesSubsidies.test.ts +120 -0
- package/src/db/tables/routesSubsidies.ts +71 -0
- package/src/db/tables/{fundingTransferEvents.ts → routesTransferEvents.ts} +4 -4
- package/src/db/tables/routesTransferSubsidies.ts +38 -0
- package/src/db/tables/routesTransferSubsidyNonces.ts +124 -0
- package/src/db/tables/routesTransferTransactions.test.ts +195 -0
- package/src/db/tables/{fundingTransferTransactions.ts → routesTransferTransactions.ts} +63 -18
- package/src/db/tables/routesTransfers.test.ts +338 -0
- package/src/db/tables/routesTransfers.ts +662 -0
- package/src/db/tables/sponsoredTransactions.test.ts +269 -45
- package/src/db/tables/sponsoredTransactions.ts +225 -65
- package/src/db/tables/sponsorshipAttributions.test.ts +160 -0
- package/src/db/tables/sponsorshipAttributions.ts +168 -0
- package/src/db/tables/sponsorshipReconciliationCursors.test.ts +115 -0
- package/src/db/tables/sponsorshipReconciliationCursors.ts +67 -0
- package/src/db/tables/stripeCustomers.test.ts +85 -0
- package/src/db/tables/stripeCustomers.ts +24 -0
- package/src/db/tables/users.test.ts +129 -0
- package/src/db/tables/users.ts +49 -3
- package/src/db/tables/webhookQueueEvents.ts +8 -1
- package/src/db/tables/webhookSubscriptions.ts +95 -20
- package/src/handlers/internal/executionError.ts +3 -4
- package/src/handlers/internal/multisig.ts +13 -816
- package/src/handlers/internal/sponsorship.ts +26 -10
- package/src/handlers/relay.test-d.ts +9 -1
- package/src/handlers/relay.test.ts +823 -3
- package/src/handlers/relay.ts +127 -107
- package/src/index.test-d.ts +7 -0
- package/src/index.ts +0 -17
- package/src/internal/AssetResponse.ts +26 -0
- package/src/internal/Auth.test.ts +1564 -9
- package/src/internal/Auth.ts +833 -239
- package/src/internal/BetterAuth.test.ts +242 -0
- package/src/internal/BetterAuth.ts +349 -0
- package/src/internal/Cache.ts +2 -0
- package/src/internal/EarnRates.test.ts +17 -0
- package/src/internal/EarnRates.ts +124 -31
- package/src/internal/EarnSharePrices.test.ts +182 -0
- package/src/internal/EarnSharePrices.ts +313 -0
- package/src/internal/EarnVaults.test.ts +21 -0
- package/src/internal/EarnVaults.ts +33 -11
- package/src/internal/Email.ts +54 -0
- package/src/internal/Idempotency.test.ts +2 -2
- package/src/internal/Log.test-d.ts +8 -7
- package/src/internal/Log.test.ts +114 -16
- package/src/internal/Log.ts +53 -40
- package/src/internal/MetricSink.test.ts +313 -26
- package/src/internal/MetricSink.ts +73 -8
- package/src/internal/Mpp.test.ts +31 -0
- package/src/internal/Mpp.ts +21 -24
- package/src/internal/OpenApi.ts +45 -12
- package/src/internal/Provider.test.ts +1 -1
- package/src/internal/Provider.ts +1 -1
- package/src/internal/RateLimit.test.ts +21 -3
- package/src/internal/RateLimit.ts +12 -1
- package/src/internal/Store.test-d.ts +1 -1
- package/src/internal/Store.test.ts +151 -8
- package/src/internal/Store.ts +76 -9
- package/src/internal/Tidx.test.ts +59 -8
- package/src/internal/Tidx.ts +86 -14
- package/src/internal/Timing.test.ts +77 -0
- package/src/internal/Timing.ts +83 -6
- package/src/internal/VercelOidc.test.ts +188 -0
- package/src/internal/VercelOidc.ts +193 -0
- package/src/internal/VerifiedTokens.test.ts +60 -6
- package/src/internal/VerifiedTokens.ts +21 -24
- package/src/internal/Viem.batch.test.ts +80 -0
- package/src/internal/Viem.test.ts +201 -2
- package/src/internal/Viem.ts +221 -25
- package/src/internal/Webhooks.test.ts +85 -6
- package/src/internal/Webhooks.ts +22 -4
- package/src/internal/ZoneRpc.ts +50 -0
- package/src/internal/exchange/Provider.test.ts +2 -2
- package/src/internal/index.test.ts +3 -1
- package/src/internal/index.ts +3 -1
- package/src/internal/rewards/Audit.ts +231 -0
- package/src/internal/rewards/Campaigns.test.ts +1234 -0
- package/src/internal/rewards/Campaigns.ts +1205 -0
- package/src/internal/rewards/Credits.ts +165 -0
- package/src/internal/rewards/Events.local.test.ts +113 -0
- package/src/internal/rewards/Events.test.ts +152 -0
- package/src/internal/rewards/Events.ts +468 -0
- package/src/internal/rewards/Projection.test.ts +681 -0
- package/src/internal/rewards/Projection.ts +987 -0
- package/src/internal/rewards/Rates.test.ts +171 -0
- package/src/internal/rewards/Rates.ts +110 -0
- package/src/internal/rewards/Read.test.ts +501 -0
- package/src/internal/rewards/Read.ts +476 -0
- package/src/internal/rewards/Runner.checkpoint.test.ts +80 -0
- package/src/internal/rewards/Runner.states.test.ts +188 -0
- package/src/internal/rewards/Runner.test.ts +90 -0
- package/src/internal/rewards/Runner.ts +2229 -0
- package/src/internal/rewards/Signer.test.ts +79 -0
- package/src/internal/rewards/Signer.ts +180 -0
- package/src/internal/rewards/index.ts +14 -0
- package/src/internal/{funding → routes}/Action.test.ts +63 -14
- package/src/internal/{funding → routes}/Action.ts +35 -8
- package/src/internal/{funding → routes}/Catalog.test.ts +3 -3
- package/src/internal/{funding → routes}/Catalog.ts +39 -39
- package/src/internal/{funding → routes}/Chain.test.ts +1 -1
- package/src/internal/{funding → routes}/Chain.ts +11 -11
- package/src/internal/{funding → routes}/Deposit.test.ts +1 -1
- package/src/internal/{funding → routes}/Deposit.ts +93 -45
- package/src/internal/{funding → routes}/DepositAddress.test.ts +11 -3
- package/src/internal/{funding → routes}/DepositAddress.ts +132 -53
- package/src/internal/{funding → routes}/DepositWebhook.test.ts +61 -18
- package/src/internal/{funding → routes}/DepositWebhook.ts +9 -9
- package/src/internal/routes/Economics.test.ts +42 -0
- package/src/internal/routes/Economics.ts +47 -0
- package/src/internal/{funding → routes}/Evidence.test.ts +6 -6
- package/src/internal/{funding → routes}/Evidence.ts +9 -9
- package/src/internal/routes/Observability.test.ts +636 -0
- package/src/internal/routes/Observability.ts +668 -0
- package/src/internal/{funding → routes}/Provider.test.ts +489 -153
- package/src/internal/{funding → routes}/Provider.ts +489 -186
- package/src/internal/{funding → routes}/Reconciliation.local.test.ts +84 -12
- package/src/internal/{funding → routes}/Reconciliation.test.ts +1213 -279
- package/src/internal/{funding → routes}/Reconciliation.ts +501 -203
- package/src/internal/routes/Reconciliation.unattributed.test.ts +250 -0
- package/src/internal/{funding → routes}/Route.ts +7 -7
- package/src/internal/{funding → routes}/SourceObservation.test.ts +13 -14
- package/src/internal/{funding → routes}/SourceObservation.ts +13 -13
- package/src/internal/{funding → routes}/Subsidy.local.test.ts +7 -7
- package/src/internal/routes/Subsidy.test.ts +169 -0
- package/src/internal/{funding → routes}/Subsidy.ts +86 -6
- package/src/internal/{funding → routes}/Token.test.ts +1 -1
- package/src/internal/{funding → routes}/Token.ts +5 -5
- package/src/internal/routes/Transfer.test.ts +1199 -0
- package/src/internal/routes/Transfer.ts +1206 -0
- package/src/internal/routes/TransferReconciliation.test.ts +731 -0
- package/src/internal/routes/TransferReconciliation.ts +527 -0
- package/src/internal/routes/TransferSubsidy.test.ts +172 -0
- package/src/internal/routes/TransferSubsidy.ts +447 -0
- package/src/internal/{funding → routes}/TransferWebhook.test.ts +13 -13
- package/src/internal/{funding → routes}/TransferWebhook.ts +7 -7
- package/src/internal/{funding → routes}/index.test.ts +5 -3
- package/src/internal/{funding → routes}/index.ts +2 -0
- package/src/internal/{funding → routes}/providers/across.ts +16 -16
- package/src/internal/{funding → routes}/providers/index.test.ts +157 -44
- package/src/internal/{funding → routes}/providers/relay.test.ts +165 -32
- package/src/internal/{funding → routes}/providers/relay.ts +228 -121
- package/src/internal/{funding → routes}/providers/rhino.ts +16 -16
- package/src/internal/{funding → routes}/providers/squid.ts +17 -17
- package/src/internal/routes/providers/stargate.test.ts +728 -0
- package/src/internal/routes/providers/stargate.ts +1276 -0
- package/src/internal/{funding → routes}/providers/symbiosis.ts +64 -24
- package/src/internal/webhookDestinations/slack.ts +10 -10
- package/src/providers/index.ts +13 -13
- package/src/server.ts +18 -0
- package/dist/apps/funding/Access.d.ts.map +0 -1
- package/dist/apps/funding/Access.js.map +0 -1
- package/dist/apps/funding/App.js.map +0 -1
- package/dist/apps/funding/Inventory.d.ts.map +0 -1
- package/dist/apps/funding/Inventory.js.map +0 -1
- package/dist/apps/funding/ProviderAttempts.d.ts +0 -5
- package/dist/apps/funding/ProviderAttempts.d.ts.map +0 -1
- package/dist/apps/funding/ProviderAttempts.js +0 -24
- package/dist/apps/funding/ProviderAttempts.js.map +0 -1
- package/dist/apps/funding/index.d.ts +0 -2
- package/dist/apps/funding/index.d.ts.map +0 -1
- package/dist/apps/funding/index.js +0 -2
- package/dist/apps/funding/index.js.map +0 -1
- package/dist/apps/funding/routes/chains.d.ts.map +0 -1
- package/dist/apps/funding/routes/chains.js.map +0 -1
- package/dist/apps/funding/routes/deposit-addresses.d.ts.map +0 -1
- package/dist/apps/funding/routes/deposit-addresses.js.map +0 -1
- package/dist/apps/funding/routes/providers.d.ts.map +0 -1
- package/dist/apps/funding/routes/providers.js +0 -57
- package/dist/apps/funding/routes/providers.js.map +0 -1
- package/dist/apps/funding/routes/quotes.d.ts.map +0 -1
- package/dist/apps/funding/routes/quotes.js.map +0 -1
- package/dist/apps/funding/routes/transfers.d.ts.map +0 -1
- package/dist/apps/funding/routes/transfers.js +0 -828
- package/dist/apps/funding/routes/transfers.js.map +0 -1
- package/dist/db/tables/fundingCatalog.d.ts +0 -58
- package/dist/db/tables/fundingCatalog.d.ts.map +0 -1
- package/dist/db/tables/fundingCatalog.js.map +0 -1
- package/dist/db/tables/fundingDepositAddresses.d.ts +0 -192
- package/dist/db/tables/fundingDepositAddresses.d.ts.map +0 -1
- package/dist/db/tables/fundingDepositAddresses.js +0 -235
- package/dist/db/tables/fundingDepositAddresses.js.map +0 -1
- package/dist/db/tables/fundingDepositRequestObservations.d.ts.map +0 -1
- package/dist/db/tables/fundingDepositRequestObservations.js.map +0 -1
- package/dist/db/tables/fundingDeposits.d.ts.map +0 -1
- package/dist/db/tables/fundingDeposits.js +0 -295
- package/dist/db/tables/fundingDeposits.js.map +0 -1
- package/dist/db/tables/fundingIdempotency.d.ts +0 -91
- package/dist/db/tables/fundingIdempotency.d.ts.map +0 -1
- package/dist/db/tables/fundingIdempotency.js +0 -103
- package/dist/db/tables/fundingIdempotency.js.map +0 -1
- package/dist/db/tables/fundingTransferEvents.d.ts.map +0 -1
- package/dist/db/tables/fundingTransferEvents.js.map +0 -1
- package/dist/db/tables/fundingTransferTransactions.d.ts +0 -53
- package/dist/db/tables/fundingTransferTransactions.d.ts.map +0 -1
- package/dist/db/tables/fundingTransferTransactions.js.map +0 -1
- package/dist/db/tables/fundingTransfers.d.ts +0 -99
- package/dist/db/tables/fundingTransfers.d.ts.map +0 -1
- package/dist/db/tables/fundingTransfers.js +0 -110
- package/dist/db/tables/fundingTransfers.js.map +0 -1
- package/dist/internal/funding/Action.d.ts.map +0 -1
- package/dist/internal/funding/Action.js.map +0 -1
- package/dist/internal/funding/Catalog.d.ts.map +0 -1
- package/dist/internal/funding/Catalog.js.map +0 -1
- package/dist/internal/funding/Chain.d.ts.map +0 -1
- package/dist/internal/funding/Chain.js.map +0 -1
- package/dist/internal/funding/Deposit.d.ts.map +0 -1
- package/dist/internal/funding/Deposit.js.map +0 -1
- package/dist/internal/funding/DepositAddress.d.ts.map +0 -1
- package/dist/internal/funding/DepositAddress.js.map +0 -1
- package/dist/internal/funding/DepositWebhook.d.ts.map +0 -1
- package/dist/internal/funding/DepositWebhook.js.map +0 -1
- package/dist/internal/funding/Evidence.d.ts.map +0 -1
- package/dist/internal/funding/Evidence.js.map +0 -1
- package/dist/internal/funding/Provider.d.ts.map +0 -1
- package/dist/internal/funding/Provider.js.map +0 -1
- package/dist/internal/funding/Reconciliation.d.ts.map +0 -1
- package/dist/internal/funding/Reconciliation.js.map +0 -1
- package/dist/internal/funding/Route.d.ts +0 -21
- package/dist/internal/funding/Route.d.ts.map +0 -1
- package/dist/internal/funding/Route.js.map +0 -1
- package/dist/internal/funding/SourceObservation.d.ts.map +0 -1
- package/dist/internal/funding/SourceObservation.js.map +0 -1
- package/dist/internal/funding/Subsidy.d.ts.map +0 -1
- package/dist/internal/funding/Subsidy.js.map +0 -1
- package/dist/internal/funding/Token.d.ts.map +0 -1
- package/dist/internal/funding/Token.js.map +0 -1
- package/dist/internal/funding/Transfer.d.ts.map +0 -1
- package/dist/internal/funding/Transfer.js +0 -462
- package/dist/internal/funding/Transfer.js.map +0 -1
- package/dist/internal/funding/TransferReconciliation.d.ts.map +0 -1
- package/dist/internal/funding/TransferReconciliation.js +0 -192
- package/dist/internal/funding/TransferReconciliation.js.map +0 -1
- package/dist/internal/funding/TransferWebhook.d.ts.map +0 -1
- package/dist/internal/funding/TransferWebhook.js.map +0 -1
- package/dist/internal/funding/index.d.ts.map +0 -1
- package/dist/internal/funding/index.js.map +0 -1
- package/dist/internal/funding/providers/across.d.ts.map +0 -1
- package/dist/internal/funding/providers/across.js.map +0 -1
- package/dist/internal/funding/providers/relay.d.ts.map +0 -1
- package/dist/internal/funding/providers/relay.js.map +0 -1
- package/dist/internal/funding/providers/rhino.d.ts.map +0 -1
- package/dist/internal/funding/providers/rhino.js.map +0 -1
- package/dist/internal/funding/providers/squid.d.ts.map +0 -1
- package/dist/internal/funding/providers/squid.js.map +0 -1
- package/dist/internal/funding/providers/stargate.d.ts.map +0 -1
- package/dist/internal/funding/providers/stargate.js +0 -579
- package/dist/internal/funding/providers/stargate.js.map +0 -1
- package/dist/internal/funding/providers/symbiosis.d.ts.map +0 -1
- package/dist/internal/funding/providers/symbiosis.js.map +0 -1
- package/src/apps/funding/App.test.ts +0 -78
- package/src/apps/funding/App.ts +0 -88
- package/src/apps/funding/ProviderAttempts.ts +0 -26
- package/src/apps/funding/index.ts +0 -1
- package/src/apps/funding/routes/transfers.ts +0 -987
- package/src/db/tables/fundingCatalog.test.ts +0 -122
- package/src/db/tables/fundingCatalog.ts +0 -163
- package/src/db/tables/fundingDepositAddresses.test.ts +0 -608
- package/src/db/tables/fundingDepositAddresses.ts +0 -443
- package/src/db/tables/fundingDeposits.ts +0 -572
- package/src/db/tables/fundingIdempotency.test.ts +0 -182
- package/src/db/tables/fundingIdempotency.ts +0 -180
- package/src/db/tables/fundingTransferTransactions.test.ts +0 -112
- package/src/db/tables/fundingTransfers.test.ts +0 -115
- package/src/db/tables/fundingTransfers.ts +0 -189
- package/src/handlers/internal/multisig.test.ts +0 -818
- package/src/internal/funding/Subsidy.test.ts +0 -75
- package/src/internal/funding/Transfer.test.ts +0 -524
- package/src/internal/funding/Transfer.ts +0 -762
- package/src/internal/funding/TransferReconciliation.test.ts +0 -147
- package/src/internal/funding/TransferReconciliation.ts +0 -264
- package/src/internal/funding/providers/stargate.test.ts +0 -328
- package/src/internal/funding/providers/stargate.ts +0 -856
- /package/dist/apps/{funding → routes}/Inventory.d.ts +0 -0
- /package/src/internal/{funding → routes}/Route.test.ts +0 -0
|
@@ -1,23 +1,30 @@
|
|
|
1
|
-
import { Value } from 'ox'
|
|
1
|
+
import { AbiFunction, Hex, Value } from 'ox'
|
|
2
2
|
import { decodeFunctionData, erc20Abi, maxUint256 } from 'viem'
|
|
3
3
|
import { base } from 'viem/chains'
|
|
4
4
|
import { tempoMainnet } from 'viem/tempo/chains'
|
|
5
5
|
|
|
6
6
|
import * as Anvil from '../../../../test/Anvil.js'
|
|
7
7
|
import * as TestApp from '../../../../test/App.js'
|
|
8
|
-
import * as
|
|
9
|
-
import * as
|
|
8
|
+
import * as TestRoutes from '../../../../test/Routes.js'
|
|
9
|
+
import * as RoutesIdempotencyTable from '../../../db/tables/routesIdempotency.js'
|
|
10
|
+
import * as Organizations from '../../../db/tables/organizations.js'
|
|
11
|
+
import * as RoutesSubsidies from '../../../db/tables/routesSubsidies.js'
|
|
12
|
+
import * as StripeCustomers from '../../../db/tables/stripeCustomers.js'
|
|
10
13
|
import * as Cache from '../../../internal/Cache.js'
|
|
11
|
-
import * as
|
|
12
|
-
import * as
|
|
13
|
-
import * as
|
|
14
|
-
import * as
|
|
15
|
-
import * as
|
|
14
|
+
import type * as RoutesAction from '../../../internal/routes/Action.js'
|
|
15
|
+
import * as RoutesCatalog from '../../../internal/routes/Catalog.js'
|
|
16
|
+
import * as RoutesChain from '../../../internal/routes/Chain.js'
|
|
17
|
+
import type * as RoutesObservability from '../../../internal/routes/Observability.js'
|
|
18
|
+
import * as RoutesProvider from '../../../internal/routes/Provider.js'
|
|
19
|
+
import * as RoutesTransfer from '../../../internal/routes/Transfer.js'
|
|
20
|
+
import * as RoutesTransferReconciliation from '../../../internal/routes/TransferReconciliation.js'
|
|
21
|
+
import * as RoutesTransferSubsidy from '../../../internal/routes/TransferSubsidy.js'
|
|
16
22
|
import * as Idempotency from '../../../internal/Idempotency.js'
|
|
17
|
-
import * as
|
|
18
|
-
import * as
|
|
23
|
+
import type * as Log from '../../../internal/Log.js'
|
|
24
|
+
import * as Relay from '../../../internal/routes/providers/relay.js'
|
|
25
|
+
import * as Stargate from '../../../internal/routes/providers/stargate.js'
|
|
19
26
|
import * as Webhooks from '../../../internal/Webhooks.js'
|
|
20
|
-
import * as
|
|
27
|
+
import * as Routes from './transfers.js'
|
|
21
28
|
|
|
22
29
|
const db = TestApp.database()
|
|
23
30
|
const destinationTransactionHash =
|
|
@@ -37,14 +44,14 @@ const executableProviders = [
|
|
|
37
44
|
id: 'stargate',
|
|
38
45
|
},
|
|
39
46
|
] as const
|
|
40
|
-
const stargateConfiguration =
|
|
47
|
+
const stargateConfiguration = TestRoutes.snapshot.routesByProvider
|
|
41
48
|
.get('stargate')!
|
|
42
49
|
.find((candidate) => candidate.route.source.chain.id === 'eip155:8453')!.configuration!
|
|
43
50
|
|
|
44
|
-
beforeAll(() =>
|
|
51
|
+
beforeAll(() => TestRoutes.publish(db))
|
|
45
52
|
|
|
46
53
|
function create(options: TestApp.create.Options = {}) {
|
|
47
|
-
return TestApp.create({ ...options, db })
|
|
54
|
+
return TestApp.create({ ...options, db: options.db ?? db })
|
|
48
55
|
}
|
|
49
56
|
|
|
50
57
|
type ContractResponse = {
|
|
@@ -55,6 +62,7 @@ type ContractResponse = {
|
|
|
55
62
|
type JsonSchema = {
|
|
56
63
|
$ref?: string | undefined
|
|
57
64
|
additionalProperties?: boolean | undefined
|
|
65
|
+
description?: string | undefined
|
|
58
66
|
examples?: readonly unknown[] | undefined
|
|
59
67
|
properties?: Record<string, JsonSchema> | undefined
|
|
60
68
|
required?: readonly string[] | undefined
|
|
@@ -70,11 +78,11 @@ function dereference(spec: ComponentSpec, schema: JsonSchema): JsonSchema {
|
|
|
70
78
|
return spec.components.schemas[name]!
|
|
71
79
|
}
|
|
72
80
|
|
|
73
|
-
describe('GET /
|
|
74
|
-
test('requires the
|
|
81
|
+
describe('GET /routes/transfers', () => {
|
|
82
|
+
test('requires the routes:read scope', async () => {
|
|
75
83
|
const app = transfersApp()
|
|
76
|
-
expect((await app.request('/v1/
|
|
77
|
-
const forbidden = await app.request('/v1/
|
|
84
|
+
expect((await app.request('/v1/routes/transfers')).status).toBe(401)
|
|
85
|
+
const forbidden = await app.request('/v1/routes/transfers', as(TestApp.key))
|
|
78
86
|
expect(forbidden.status).toBe(403)
|
|
79
87
|
})
|
|
80
88
|
|
|
@@ -83,10 +91,10 @@ describe('GET /funding/transfers', () => {
|
|
|
83
91
|
const first = await seedTransfer()
|
|
84
92
|
const second = await seedTransfer()
|
|
85
93
|
const third = await seedTransfer()
|
|
86
|
-
await seedTransfer({ orgId:
|
|
94
|
+
await seedTransfer({ orgId: routesForeign.orgId })
|
|
87
95
|
|
|
88
|
-
const response = await app.request('/v1/
|
|
89
|
-
headers: { 'tempo-api-key':
|
|
96
|
+
const response = await app.request('/v1/routes/transfers?limit=5', {
|
|
97
|
+
headers: { 'tempo-api-key': routesReader.token },
|
|
90
98
|
})
|
|
91
99
|
expect(response.status).toBe(200)
|
|
92
100
|
expect(response.headers.get('cache-control')).toBe(Cache.policies.feed)
|
|
@@ -95,13 +103,13 @@ describe('GET /funding/transfers', () => {
|
|
|
95
103
|
expect(response.headers.get('vary')).toBe(
|
|
96
104
|
'Accept-Encoding, Authorization, Tempo-API-Key, X-API-Key',
|
|
97
105
|
)
|
|
98
|
-
const body = await TestApp.json(response,
|
|
106
|
+
const body = await TestApp.json(response, Routes.schema.listRoutesTransfers.Response)
|
|
99
107
|
expect(body.data.map((transfer) => transfer.id)).toEqual([third.id, second.id, first.id])
|
|
100
108
|
expect(body.nextCursor).toBeNull()
|
|
101
109
|
expect(body.meta).toBeUndefined()
|
|
102
110
|
|
|
103
|
-
const unchanged = await app.request('/v1/
|
|
104
|
-
headers: { 'if-none-match': etag, 'tempo-api-key':
|
|
111
|
+
const unchanged = await app.request('/v1/routes/transfers?limit=5', {
|
|
112
|
+
headers: { 'if-none-match': etag, 'tempo-api-key': routesReader.token },
|
|
105
113
|
})
|
|
106
114
|
expect(unchanged.status).toBe(304)
|
|
107
115
|
expect(unchanged.headers.get('cache-control')).toBe(Cache.policies.feed)
|
|
@@ -110,8 +118,8 @@ describe('GET /funding/transfers', () => {
|
|
|
110
118
|
)
|
|
111
119
|
|
|
112
120
|
const paged = await TestApp.json(
|
|
113
|
-
await app.request(`/v1/
|
|
114
|
-
|
|
121
|
+
await app.request(`/v1/routes/transfers?limit=5&cursor=${second.id}`, as(routesReader)),
|
|
122
|
+
Routes.schema.listRoutesTransfers.Response,
|
|
115
123
|
)
|
|
116
124
|
expect(paged.data.map((transfer) => transfer.id)).toEqual([first.id])
|
|
117
125
|
})
|
|
@@ -119,17 +127,17 @@ describe('GET /funding/transfers', () => {
|
|
|
119
127
|
test('filters by status and embeds the capped count on request', async () => {
|
|
120
128
|
const app = transfersApp()
|
|
121
129
|
const expired = await seedTransfer()
|
|
122
|
-
await
|
|
130
|
+
await RoutesTransfer.transition(db, {
|
|
123
131
|
expectedVersion: 1,
|
|
124
132
|
id: expired.id,
|
|
125
133
|
status: 'expired',
|
|
126
134
|
})
|
|
127
135
|
|
|
128
136
|
const response = await app.request(
|
|
129
|
-
'/v1/
|
|
130
|
-
as(
|
|
137
|
+
'/v1/routes/transfers?status=expired&include=totalCount',
|
|
138
|
+
as(routesReader),
|
|
131
139
|
)
|
|
132
|
-
const body = await TestApp.json(response,
|
|
140
|
+
const body = await TestApp.json(response, Routes.schema.listRoutesTransfers.Response)
|
|
133
141
|
expect(body.data.map((transfer) => transfer.id)).toEqual([expired.id])
|
|
134
142
|
expect(body.data[0]?.status).toBe('expired')
|
|
135
143
|
expect(body.meta).toEqual({ totalCount: 1, totalCountCapped: false })
|
|
@@ -137,35 +145,35 @@ describe('GET /funding/transfers', () => {
|
|
|
137
145
|
|
|
138
146
|
test('narrows project-attributed keys to their project', async () => {
|
|
139
147
|
const app = transfersApp()
|
|
140
|
-
const scoped = await seedTransfer({ projectId:
|
|
148
|
+
const scoped = await seedTransfer({ projectId: routesProjectReader.projectId })
|
|
141
149
|
|
|
142
150
|
const body = await TestApp.json(
|
|
143
|
-
await app.request('/v1/
|
|
144
|
-
|
|
151
|
+
await app.request('/v1/routes/transfers?limit=200', as(routesProjectReader)),
|
|
152
|
+
Routes.schema.listRoutesTransfers.Response,
|
|
145
153
|
)
|
|
146
154
|
expect(body.data.map((transfer) => transfer.id)).toEqual([scoped.id])
|
|
147
155
|
|
|
148
156
|
// The organization-attributed key sees the project row too.
|
|
149
157
|
const orgBody = await TestApp.json(
|
|
150
|
-
await app.request('/v1/
|
|
151
|
-
|
|
158
|
+
await app.request('/v1/routes/transfers?limit=200', as(routesReader)),
|
|
159
|
+
Routes.schema.listRoutesTransfers.Response,
|
|
152
160
|
)
|
|
153
161
|
expect(orgBody.data.map((transfer) => transfer.id)).toContain(scoped.id)
|
|
154
162
|
})
|
|
155
163
|
|
|
156
164
|
test('rejects invalid query parameters', async () => {
|
|
157
165
|
const app = transfersApp()
|
|
158
|
-
const response = await app.request('/v1/
|
|
166
|
+
const response = await app.request('/v1/routes/transfers?status=bogus', as(routesReader))
|
|
159
167
|
expect(response.status).toBe(400)
|
|
160
168
|
})
|
|
161
169
|
})
|
|
162
170
|
|
|
163
|
-
describe('GET /
|
|
171
|
+
describe('GET /routes/transfers/:id', () => {
|
|
164
172
|
test('returns the owned transfer directly, without an action', async () => {
|
|
165
173
|
const app = transfersApp()
|
|
166
174
|
const record = await seedTransfer()
|
|
167
|
-
const response = await app.request(`/v1/
|
|
168
|
-
headers: { 'tempo-api-key':
|
|
175
|
+
const response = await app.request(`/v1/routes/transfers/${record.id}`, {
|
|
176
|
+
headers: { 'tempo-api-key': routesReader.token },
|
|
169
177
|
})
|
|
170
178
|
expect(response.status).toBe(200)
|
|
171
179
|
expect({
|
|
@@ -180,12 +188,12 @@ describe('GET /funding/transfers/:id', () => {
|
|
|
180
188
|
expect(response.headers.get('vary')).toBe(
|
|
181
189
|
'Accept-Encoding, Authorization, Tempo-API-Key, X-API-Key',
|
|
182
190
|
)
|
|
183
|
-
const body = await TestApp.json(response,
|
|
184
|
-
expect(body).toEqual(
|
|
191
|
+
const body = await TestApp.json(response, Routes.schema.getRoutesTransfer.Response)
|
|
192
|
+
expect(body).toEqual(RoutesTransfer.toPublic(record))
|
|
185
193
|
expect('action' in body).toBe(false)
|
|
186
194
|
|
|
187
|
-
const repeated = await app.request(`/v1/
|
|
188
|
-
headers: { 'if-none-match': '"stale"', 'tempo-api-key':
|
|
195
|
+
const repeated = await app.request(`/v1/routes/transfers/${record.id}`, {
|
|
196
|
+
headers: { 'if-none-match': '"stale"', 'tempo-api-key': routesReader.token },
|
|
189
197
|
})
|
|
190
198
|
expect({
|
|
191
199
|
cacheControl: repeated.headers.get('cache-control'),
|
|
@@ -204,72 +212,199 @@ describe('GET /funding/transfers/:id', () => {
|
|
|
204
212
|
const app = transfersApp()
|
|
205
213
|
const record = await seedTransfer()
|
|
206
214
|
|
|
207
|
-
const foreign = await app.request(`/v1/
|
|
215
|
+
const foreign = await app.request(`/v1/routes/transfers/${record.id}`, as(routesForeign))
|
|
208
216
|
expect(foreign.status).toBe(404)
|
|
209
217
|
expect(((await foreign.json()) as { error: { code: string } }).error.code).toBe(
|
|
210
|
-
'
|
|
218
|
+
'routes_transfer_not_found',
|
|
211
219
|
)
|
|
212
220
|
|
|
213
|
-
const project = await app.request(
|
|
214
|
-
`/v1/funding/transfers/${record.id}`,
|
|
215
|
-
as(fundingProjectReader),
|
|
216
|
-
)
|
|
221
|
+
const project = await app.request(`/v1/routes/transfers/${record.id}`, as(routesProjectReader))
|
|
217
222
|
expect(project.status).toBe(404)
|
|
218
223
|
|
|
219
224
|
const absent = await app.request(
|
|
220
|
-
'/v1/
|
|
221
|
-
as(
|
|
225
|
+
'/v1/routes/transfers/rtr_000000000000000_000000000000000000000000',
|
|
226
|
+
as(routesReader),
|
|
222
227
|
)
|
|
223
228
|
expect(absent.status).toBe(404)
|
|
224
229
|
})
|
|
225
230
|
})
|
|
226
231
|
|
|
227
|
-
describe('POST /
|
|
228
|
-
test('requires
|
|
232
|
+
describe('POST /routes/transfers/:id/source-transactions', () => {
|
|
233
|
+
test('requires routes write access and validates the transaction hash array', async () => {
|
|
229
234
|
const app = transfersApp()
|
|
230
235
|
const transfer = await seedTransfer()
|
|
231
|
-
const path = `/v1/
|
|
236
|
+
const path = `/v1/routes/transfers/${transfer.id}/source-transactions`
|
|
232
237
|
expect((await app.request(path, { method: 'POST' })).status).toBe(401)
|
|
233
|
-
expect((await app.request(path, { ...as(
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
238
|
+
expect((await app.request(path, { ...as(routesReader), method: 'POST' })).status).toBe(403)
|
|
239
|
+
for (const body of [
|
|
240
|
+
{ transactionHashes: [] },
|
|
241
|
+
{ transactionHashes: ['0xinvalid'] },
|
|
242
|
+
{
|
|
243
|
+
transactionHashes: Array.from(
|
|
244
|
+
{ length: 11 },
|
|
245
|
+
(_, index) => `0x${index.toString(16).padStart(64, '0')}`,
|
|
246
|
+
),
|
|
247
|
+
},
|
|
248
|
+
])
|
|
249
|
+
expect(
|
|
250
|
+
(
|
|
251
|
+
await app.request(path, {
|
|
252
|
+
body: JSON.stringify(body),
|
|
253
|
+
headers: { ...as(routesWriter).headers, 'content-type': 'application/json' },
|
|
254
|
+
method: 'POST',
|
|
255
|
+
})
|
|
256
|
+
).status,
|
|
257
|
+
).toBe(400)
|
|
243
258
|
})
|
|
244
259
|
|
|
245
|
-
test('
|
|
260
|
+
test('accepts singular and plural requests before reporting missing reconciliation', async () => {
|
|
246
261
|
const app = transfersApp()
|
|
247
262
|
const transfer = await seedTransfer()
|
|
248
|
-
const
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
263
|
+
const transactionHash = `0x${'aa'.repeat(32)}`
|
|
264
|
+
for (const body of [{ transactionHash }, { transactionHashes: [transactionHash] }]) {
|
|
265
|
+
const response = await app.request(
|
|
266
|
+
`/v1/routes/transfers/${transfer.id}/source-transactions`,
|
|
267
|
+
{
|
|
268
|
+
body: JSON.stringify(body),
|
|
269
|
+
headers: { ...as(routesWriter).headers, 'content-type': 'application/json' },
|
|
270
|
+
method: 'POST',
|
|
271
|
+
},
|
|
272
|
+
)
|
|
273
|
+
expect(response.status).toBe(501)
|
|
274
|
+
}
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
test('records source routes and dispatches reconciliation once', async () => {
|
|
278
|
+
const database = TestApp.databaseFactory()
|
|
279
|
+
const setup = database()
|
|
280
|
+
await TestRoutes.publish(setup)
|
|
281
|
+
const firstVerified = Promise.withResolvers<void>()
|
|
282
|
+
const intervals: RoutesObservability.LifecycleInterval[] = []
|
|
283
|
+
const messages: RoutesTransferReconciliation.Message[] = []
|
|
284
|
+
const releaseFirst = Promise.withResolvers<void>()
|
|
285
|
+
const secondVerified = Promise.withResolvers<void>()
|
|
286
|
+
let verifications = 0
|
|
287
|
+
const provider = RoutesProvider.from({
|
|
288
|
+
...Stargate.stargate(),
|
|
289
|
+
async verifySourceTransaction({ transactionHash }) {
|
|
290
|
+
verifications++
|
|
291
|
+
if (verifications === 1) {
|
|
292
|
+
firstVerified.resolve()
|
|
293
|
+
await releaseFirst.promise
|
|
294
|
+
} else secondVerified.resolve()
|
|
295
|
+
return {
|
|
296
|
+
destinationAmount: '980000',
|
|
297
|
+
providerState: {},
|
|
298
|
+
transactionHash,
|
|
299
|
+
type: 'verified',
|
|
300
|
+
}
|
|
301
|
+
},
|
|
252
302
|
})
|
|
253
|
-
|
|
303
|
+
const app = transfersApp({
|
|
304
|
+
db: database,
|
|
305
|
+
routes: {
|
|
306
|
+
async dispatchTransferReconciliation(message) {
|
|
307
|
+
messages.push(message)
|
|
308
|
+
},
|
|
309
|
+
async recordLifecycleInterval(interval) {
|
|
310
|
+
intervals.push(interval)
|
|
311
|
+
},
|
|
312
|
+
},
|
|
313
|
+
providers: [provider],
|
|
314
|
+
})
|
|
315
|
+
const transfer = await RoutesTransfer.create(setup, {
|
|
316
|
+
apiKeyId: routesReader.id,
|
|
317
|
+
environment: 'production',
|
|
318
|
+
id: RoutesTransfer.generateId(new Date(Date.UTC(2026, 0, 2, 0, 0, seedSecond++))),
|
|
319
|
+
orgId: routesReader.orgId,
|
|
320
|
+
snapshot: TestRoutes.transferSnapshot({ provider: { id: 'stargate', name: 'Stargate' } }),
|
|
321
|
+
})
|
|
322
|
+
const request = {
|
|
323
|
+
body: JSON.stringify({ transactionHashes: [`0x${'aa'.repeat(32)}`] }),
|
|
324
|
+
headers: { ...as(routesWriter).headers, 'content-type': 'application/json' },
|
|
325
|
+
method: 'POST',
|
|
326
|
+
} as const
|
|
327
|
+
const path = `/v1/routes/transfers/${transfer.id}/source-transactions`
|
|
328
|
+
|
|
329
|
+
const first = app.request(path, request)
|
|
330
|
+
await firstVerified.promise
|
|
331
|
+
const second = app.request(path, request)
|
|
332
|
+
await secondVerified.promise
|
|
333
|
+
releaseFirst.resolve()
|
|
334
|
+
const [response, replay] = await Promise.all([first, second])
|
|
335
|
+
expect(response.status).toBe(200)
|
|
336
|
+
expect(await response.json()).toMatchObject({ destinationAmount: { baseUnits: '980000' } })
|
|
337
|
+
expect(replay.status).toBe(200)
|
|
338
|
+
expect(intervals).toEqual([
|
|
339
|
+
expect.objectContaining({
|
|
340
|
+
routesEnvironment: 'production',
|
|
341
|
+
method: 'transaction',
|
|
342
|
+
provider: 'stargate',
|
|
343
|
+
resourceId: transfer.id,
|
|
344
|
+
stage: 'source_routes',
|
|
345
|
+
}),
|
|
346
|
+
])
|
|
347
|
+
expect(messages).toEqual([{ transferId: transfer.id, type: 'routes:transfer:reconcile' }])
|
|
254
348
|
})
|
|
255
349
|
|
|
256
350
|
test('does not expose a transfer owned by another organization', async () => {
|
|
257
|
-
const tracker =
|
|
351
|
+
const tracker = RoutesTransferReconciliation.createTracker({
|
|
352
|
+
db,
|
|
353
|
+
providers: [Stargate.stargate()],
|
|
354
|
+
})
|
|
258
355
|
const app = transfersApp({
|
|
259
|
-
|
|
356
|
+
routes: {
|
|
260
357
|
async dispatchTransferReconciliation(message) {
|
|
261
358
|
await tracker.reconcile(message)
|
|
262
359
|
},
|
|
263
360
|
},
|
|
264
361
|
})
|
|
265
362
|
const transfer = await seedTransfer()
|
|
266
|
-
const response = await app.request(`/v1/
|
|
267
|
-
body: JSON.stringify({
|
|
268
|
-
headers: { ...as(
|
|
363
|
+
const response = await app.request(`/v1/routes/transfers/${transfer.id}/source-transactions`, {
|
|
364
|
+
body: JSON.stringify({ transactionHashes: [`0x${'aa'.repeat(32)}`] }),
|
|
365
|
+
headers: { ...as(routesForeign).headers, 'content-type': 'application/json' },
|
|
269
366
|
method: 'POST',
|
|
270
367
|
})
|
|
271
368
|
expect(response.status).toBe(404)
|
|
272
369
|
})
|
|
370
|
+
|
|
371
|
+
test('waits for every source verification before reporting provider attempts', async () => {
|
|
372
|
+
const entries: Log.Entry[] = []
|
|
373
|
+
const transactionHashes = [`0x${'aa'.repeat(32)}`, `0x${'bb'.repeat(32)}`]
|
|
374
|
+
const provider = RoutesProvider.from({
|
|
375
|
+
...Stargate.stargate(),
|
|
376
|
+
async verifySourceTransaction({ transactionHash }) {
|
|
377
|
+
if (transactionHash === transactionHashes[0]) throw new Error('upstream unavailable')
|
|
378
|
+
await new Promise((resolve) => setTimeout(resolve, 0))
|
|
379
|
+
return { type: 'pending' }
|
|
380
|
+
},
|
|
381
|
+
})
|
|
382
|
+
const app = transfersApp({
|
|
383
|
+
routes: { async dispatchTransferReconciliation() {} },
|
|
384
|
+
logger: (entry) => void entries.push(entry),
|
|
385
|
+
providers: [provider],
|
|
386
|
+
})
|
|
387
|
+
const transfer = await seedTransfer({
|
|
388
|
+
snapshot: TestRoutes.transferSnapshot({ provider: { id: 'stargate', name: 'Stargate' } }),
|
|
389
|
+
})
|
|
390
|
+
|
|
391
|
+
const response = await app.request(`/v1/routes/transfers/${transfer.id}/source-transactions`, {
|
|
392
|
+
body: JSON.stringify({ transactionHashes }),
|
|
393
|
+
headers: { ...as(routesWriter).headers, 'content-type': 'application/json' },
|
|
394
|
+
method: 'POST',
|
|
395
|
+
})
|
|
396
|
+
|
|
397
|
+
expect(response.status).toBe(502)
|
|
398
|
+
expect(
|
|
399
|
+
entries[0]?.routesProviderAttempts?.map(({ operation, outcome }) => ({
|
|
400
|
+
operation,
|
|
401
|
+
outcome,
|
|
402
|
+
})),
|
|
403
|
+
).toEqual([
|
|
404
|
+
{ operation: 'verifySourceTransaction', outcome: 'failed' },
|
|
405
|
+
{ operation: 'verifySourceTransaction', outcome: 'success' },
|
|
406
|
+
])
|
|
407
|
+
})
|
|
273
408
|
})
|
|
274
409
|
|
|
275
410
|
const createBody = {
|
|
@@ -311,10 +446,10 @@ function postTransfer(
|
|
|
311
446
|
app: ReturnType<typeof create>,
|
|
312
447
|
options: { body?: unknown; idempotencyKey?: string | undefined; key?: { token: string } } = {},
|
|
313
448
|
) {
|
|
314
|
-
return app.request('/v1/
|
|
449
|
+
return app.request('/v1/routes/transfers', {
|
|
315
450
|
body: JSON.stringify(options.body ?? createBody),
|
|
316
451
|
headers: {
|
|
317
|
-
authorization: `Bearer ${(options.key ??
|
|
452
|
+
authorization: `Bearer ${(options.key ?? routesWriter).token}`,
|
|
318
453
|
'content-type': 'application/json',
|
|
319
454
|
...(options.idempotencyKey === undefined
|
|
320
455
|
? {}
|
|
@@ -324,15 +459,17 @@ function postTransfer(
|
|
|
324
459
|
})
|
|
325
460
|
}
|
|
326
461
|
|
|
327
|
-
describe('POST /
|
|
328
|
-
function providerResponse(
|
|
462
|
+
describe('POST /routes/transfers', () => {
|
|
463
|
+
function providerResponse(
|
|
464
|
+
options: { sourceToken?: string | undefined } = {},
|
|
465
|
+
): RoutesProvider.prepareTransfer.ReturnType {
|
|
329
466
|
const spender = `0x${'44'.repeat(20)}`
|
|
330
467
|
return {
|
|
331
468
|
action: {
|
|
332
469
|
calls: [
|
|
333
470
|
{
|
|
334
471
|
data: `0x095ea7b3${spender.slice(2).padStart(64, '0')}${(1_000_000).toString(16).padStart(64, '0')}`,
|
|
335
|
-
to: createBody.sourceToken,
|
|
472
|
+
to: options.sourceToken ?? createBody.sourceToken,
|
|
336
473
|
value: '0x0',
|
|
337
474
|
},
|
|
338
475
|
{ data: '0xe8017952', to: spender, value: '0x0' },
|
|
@@ -354,10 +491,10 @@ describe('POST /funding/transfers', () => {
|
|
|
354
491
|
}
|
|
355
492
|
|
|
356
493
|
function provider(
|
|
357
|
-
prepareTransfer: NonNullable<
|
|
494
|
+
prepareTransfer: NonNullable<RoutesProvider.Provider['prepareTransfer']> = async () =>
|
|
358
495
|
providerResponse(),
|
|
359
496
|
) {
|
|
360
|
-
return
|
|
497
|
+
return RoutesProvider.from({
|
|
361
498
|
...Relay.relay(),
|
|
362
499
|
prepareTransfer,
|
|
363
500
|
})
|
|
@@ -365,16 +502,16 @@ describe('POST /funding/transfers', () => {
|
|
|
365
502
|
|
|
366
503
|
let idempotencySequence = 0
|
|
367
504
|
function nextIdempotencyKey() {
|
|
368
|
-
return `
|
|
505
|
+
return `routes_test_${idempotencySequence++}`
|
|
369
506
|
}
|
|
370
507
|
|
|
371
|
-
test('requires
|
|
508
|
+
test('requires routes:write and an Idempotency-Key', async () => {
|
|
372
509
|
const app = transfersApp({
|
|
373
510
|
providers: [provider()],
|
|
374
511
|
})
|
|
375
512
|
const forbidden = await postTransfer(app, {
|
|
376
513
|
idempotencyKey: nextIdempotencyKey(),
|
|
377
|
-
key:
|
|
514
|
+
key: routesReader,
|
|
378
515
|
})
|
|
379
516
|
expect(forbidden.status).toBe(403)
|
|
380
517
|
|
|
@@ -386,7 +523,7 @@ describe('POST /funding/transfers', () => {
|
|
|
386
523
|
})
|
|
387
524
|
|
|
388
525
|
test('creates a transfer with the selected executable quote', async () => {
|
|
389
|
-
const inputs:
|
|
526
|
+
const inputs: RoutesProvider.prepareTransfer.Parameters[] = []
|
|
390
527
|
const app = transfersApp({
|
|
391
528
|
providers: [
|
|
392
529
|
provider(async (input) => {
|
|
@@ -401,7 +538,7 @@ describe('POST /funding/transfers', () => {
|
|
|
401
538
|
})
|
|
402
539
|
expect(response.status).toBe(200)
|
|
403
540
|
expect(response.headers.get('cache-control')).toBe('no-store')
|
|
404
|
-
const body = await TestApp.json(response,
|
|
541
|
+
const body = await TestApp.json(response, Routes.schema.createRoutesTransfer.Response)
|
|
405
542
|
|
|
406
543
|
expect(inputs[0]).toMatchObject({
|
|
407
544
|
method: 'transaction',
|
|
@@ -426,30 +563,232 @@ describe('POST /funding/transfers', () => {
|
|
|
426
563
|
|
|
427
564
|
// Reads return the same transfer without the action; the private
|
|
428
565
|
// correlation never leaves the row.
|
|
429
|
-
const read = await app.request(`/v1/
|
|
430
|
-
const readBody = await TestApp.json(read,
|
|
566
|
+
const read = await app.request(`/v1/routes/transfers/${body.id}`, as(routesWriter))
|
|
567
|
+
const readBody = await TestApp.json(read, Routes.schema.getRoutesTransfer.Response)
|
|
431
568
|
expect('action' in readBody).toBe(false)
|
|
432
569
|
expect(JSON.stringify(readBody)).not.toContain('ab'.repeat(32))
|
|
433
570
|
const row = await db.kysely
|
|
434
|
-
.selectFrom('
|
|
571
|
+
.selectFrom('routes_transfers')
|
|
435
572
|
.select(['providerState'])
|
|
436
573
|
.where('id', '=', body.id)
|
|
437
574
|
.executeTakeFirstOrThrow()
|
|
438
575
|
expect(row.providerState).toEqual({ requestId: `0x${'ab'.repeat(32)}` })
|
|
439
576
|
})
|
|
440
577
|
|
|
578
|
+
test('rejects completion when the owner is deleted after the initial claim', async () => {
|
|
579
|
+
const suffix = nextIdempotencyKey()
|
|
580
|
+
const key = {
|
|
581
|
+
id: `key_${suffix}`,
|
|
582
|
+
orgId: `org_${suffix}`,
|
|
583
|
+
scopes: ['routes:write'],
|
|
584
|
+
token: `secret_${suffix}`,
|
|
585
|
+
} satisfies TestApp.kvStore.Key
|
|
586
|
+
await Organizations.create(db, { id: key.orgId, name: 'Transfer deletion race' })
|
|
587
|
+
const entered = Promise.withResolvers<void>()
|
|
588
|
+
const release = Promise.withResolvers<void>()
|
|
589
|
+
const app = create({
|
|
590
|
+
auth: { keys: [key] },
|
|
591
|
+
defaultChainId: tempoMainnet.id,
|
|
592
|
+
providers: [
|
|
593
|
+
provider(async () => {
|
|
594
|
+
entered.resolve()
|
|
595
|
+
await release.promise
|
|
596
|
+
return providerResponse()
|
|
597
|
+
}),
|
|
598
|
+
],
|
|
599
|
+
})
|
|
600
|
+
const idempotencyKey = nextIdempotencyKey()
|
|
601
|
+
const creation = postTransfer(app, { idempotencyKey, key })
|
|
602
|
+
await entered.promise
|
|
603
|
+
|
|
604
|
+
await expect(
|
|
605
|
+
db.kysely
|
|
606
|
+
.selectFrom('routes_idempotency_requests')
|
|
607
|
+
.select('status')
|
|
608
|
+
.where('apiKeyId', '=', key.id)
|
|
609
|
+
.where('keyHash', '=', Idempotency.inputHash(idempotencyKey))
|
|
610
|
+
.executeTakeFirstOrThrow(),
|
|
611
|
+
).resolves.toEqual({ status: 'pending' })
|
|
612
|
+
expect(await Organizations.deleteOrganization(db, key.orgId)).toBe(true)
|
|
613
|
+
release.resolve()
|
|
614
|
+
const response = await creation
|
|
615
|
+
|
|
616
|
+
expect(response.status).toBe(403)
|
|
617
|
+
await expect(response.json()).resolves.toMatchObject({
|
|
618
|
+
error: {
|
|
619
|
+
code: 'api_key_forbidden',
|
|
620
|
+
message: 'API key organization no longer exists.',
|
|
621
|
+
},
|
|
622
|
+
})
|
|
623
|
+
await expect(
|
|
624
|
+
db.kysely
|
|
625
|
+
.selectFrom('routes_transfers')
|
|
626
|
+
.select('id')
|
|
627
|
+
.where('orgId', '=', key.orgId)
|
|
628
|
+
.execute(),
|
|
629
|
+
).resolves.toEqual([])
|
|
630
|
+
await expect(
|
|
631
|
+
db.kysely
|
|
632
|
+
.selectFrom('routes_idempotency_requests')
|
|
633
|
+
.select(['response', 'status', 'transferId'])
|
|
634
|
+
.where('apiKeyId', '=', key.id)
|
|
635
|
+
.where('keyHash', '=', Idempotency.inputHash(idempotencyKey))
|
|
636
|
+
.execute(),
|
|
637
|
+
).resolves.toEqual([])
|
|
638
|
+
})
|
|
639
|
+
|
|
640
|
+
test('requires configuration and records normalized subsidy terms', async () => {
|
|
641
|
+
const request = {
|
|
642
|
+
...createBody,
|
|
643
|
+
destinationChain: 'base',
|
|
644
|
+
destinationToken: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
|
|
645
|
+
sourceChain: 'tempo',
|
|
646
|
+
sourceToken: '0x20c000000000000000000000b9537d11c60e8b50',
|
|
647
|
+
subsidize: true,
|
|
648
|
+
}
|
|
649
|
+
const outbound = RoutesProvider.from({
|
|
650
|
+
...Relay.relay(),
|
|
651
|
+
id: 'stargate',
|
|
652
|
+
name: 'Stargate',
|
|
653
|
+
async prepareTransfer() {
|
|
654
|
+
return providerResponse({ sourceToken: request.sourceToken })
|
|
655
|
+
},
|
|
656
|
+
})
|
|
657
|
+
const idempotencyKey = nextIdempotencyKey()
|
|
658
|
+
const unavailable = await postTransfer(transfersApp({ providers: [outbound] }), {
|
|
659
|
+
body: request,
|
|
660
|
+
idempotencyKey,
|
|
661
|
+
})
|
|
662
|
+
expect(unavailable.status).toBe(501)
|
|
663
|
+
|
|
664
|
+
await Organizations.create(db, { id: routesWriter.orgId, name: routesWriter.orgId })
|
|
665
|
+
await RoutesSubsidies.upsertOrganization(db, {
|
|
666
|
+
frequency: 'tx',
|
|
667
|
+
maxAmount: '5',
|
|
668
|
+
orgId: routesWriter.orgId,
|
|
669
|
+
})
|
|
670
|
+
await StripeCustomers.create(db, {
|
|
671
|
+
orgId: routesWriter.orgId,
|
|
672
|
+
stripeCustomerId: 'cus_routes_transfer_subsidy',
|
|
673
|
+
})
|
|
674
|
+
await StripeCustomers.setStatus(db, routesWriter.orgId, 'active')
|
|
675
|
+
const upstream = await postTransfer(
|
|
676
|
+
transfersApp({
|
|
677
|
+
providers: [outbound],
|
|
678
|
+
routes: {
|
|
679
|
+
transferSubsidy: {
|
|
680
|
+
account: `0x${'77'.repeat(20)}`,
|
|
681
|
+
async check() {
|
|
682
|
+
throw new RoutesTransferSubsidy.InventoryUpstreamError(
|
|
683
|
+
new Error('Destination RPC unavailable.'),
|
|
684
|
+
)
|
|
685
|
+
},
|
|
686
|
+
policy: { maxAmount: '5' },
|
|
687
|
+
},
|
|
688
|
+
},
|
|
689
|
+
}),
|
|
690
|
+
{ body: request, idempotencyKey: nextIdempotencyKey() },
|
|
691
|
+
)
|
|
692
|
+
expect(upstream.status).toBe(502)
|
|
693
|
+
await expect(upstream.json()).resolves.toMatchObject({ error: { code: 'upstream_error' } })
|
|
694
|
+
const limited = await postTransfer(
|
|
695
|
+
transfersApp({
|
|
696
|
+
providers: [outbound],
|
|
697
|
+
routes: { transferSubsidy: transferSubsidy('0.015') },
|
|
698
|
+
}),
|
|
699
|
+
{ body: request, idempotencyKey: nextIdempotencyKey() },
|
|
700
|
+
)
|
|
701
|
+
expect(limited.status).toBe(403)
|
|
702
|
+
await expect(limited.json()).resolves.toMatchObject({
|
|
703
|
+
error: { code: 'routes_subsidy_limit_exceeded' },
|
|
704
|
+
})
|
|
705
|
+
const response = await postTransfer(
|
|
706
|
+
transfersApp({
|
|
707
|
+
providers: [outbound],
|
|
708
|
+
routes: { transferSubsidy: transferSubsidy('5') },
|
|
709
|
+
}),
|
|
710
|
+
{
|
|
711
|
+
body: request,
|
|
712
|
+
idempotencyKey,
|
|
713
|
+
},
|
|
714
|
+
)
|
|
715
|
+
expect(response.status).toBe(200)
|
|
716
|
+
const body = await TestApp.json(response, Routes.schema.createRoutesTransfer.Response)
|
|
717
|
+
expect(body).toMatchObject({
|
|
718
|
+
destinationAmount: { baseUnits: '990000' },
|
|
719
|
+
destinationAmountRequired: { baseUnits: '1000000' },
|
|
720
|
+
subsidize: true,
|
|
721
|
+
})
|
|
722
|
+
const row = await db.kysely
|
|
723
|
+
.selectFrom('routes_transfers')
|
|
724
|
+
.select([
|
|
725
|
+
'providerState',
|
|
726
|
+
'subsidyAccount',
|
|
727
|
+
'subsidyChainId',
|
|
728
|
+
'subsidyCommitmentAmount',
|
|
729
|
+
'subsidyNativeAmount',
|
|
730
|
+
'subsidyTokenAddress',
|
|
731
|
+
])
|
|
732
|
+
.where('id', '=', body.id)
|
|
733
|
+
.executeTakeFirstOrThrow()
|
|
734
|
+
expect(row.providerState).not.toHaveProperty('transferSubsidyPolicy')
|
|
735
|
+
expect(row).toMatchObject({
|
|
736
|
+
subsidyAccount: `0x${'77'.repeat(20)}`,
|
|
737
|
+
subsidyChainId: 'eip155:8453',
|
|
738
|
+
subsidyCommitmentAmount: { baseUnits: '20000' },
|
|
739
|
+
subsidyNativeAmount: '100',
|
|
740
|
+
subsidyTokenAddress: request.destinationToken,
|
|
741
|
+
})
|
|
742
|
+
const replay = await postTransfer(transfersApp({ providers: [outbound] }), {
|
|
743
|
+
body: request,
|
|
744
|
+
idempotencyKey,
|
|
745
|
+
})
|
|
746
|
+
expect(replay.status).toBe(200)
|
|
747
|
+
await expect(replay.json()).resolves.toMatchObject({ id: body.id })
|
|
748
|
+
const mismatch = await postTransfer(transfersApp({ providers: [outbound] }), {
|
|
749
|
+
body: { ...request, amount: '2000000' },
|
|
750
|
+
idempotencyKey,
|
|
751
|
+
})
|
|
752
|
+
expect(mismatch.status).toBe(409)
|
|
753
|
+
await expect(mismatch.json()).resolves.toMatchObject({
|
|
754
|
+
error: { code: 'idempotency_conflict' },
|
|
755
|
+
})
|
|
756
|
+
|
|
757
|
+
await RoutesCatalog.publish(db, {
|
|
758
|
+
...TestRoutes.data,
|
|
759
|
+
tokens: TestRoutes.data.tokens.map((token) =>
|
|
760
|
+
token.id === 'usdce' ? { ...token, currency: 'EUR' } : token,
|
|
761
|
+
),
|
|
762
|
+
})
|
|
763
|
+
try {
|
|
764
|
+
const incompatible = await postTransfer(
|
|
765
|
+
transfersApp({
|
|
766
|
+
providers: [outbound],
|
|
767
|
+
routes: { transferSubsidy: transferSubsidy('5') },
|
|
768
|
+
}),
|
|
769
|
+
{ body: request, idempotencyKey: nextIdempotencyKey() },
|
|
770
|
+
)
|
|
771
|
+
expect(incompatible.status).toBe(400)
|
|
772
|
+
await expect(incompatible.json()).resolves.toMatchObject({
|
|
773
|
+
error: { code: 'body_invalid' },
|
|
774
|
+
})
|
|
775
|
+
} finally {
|
|
776
|
+
await TestRoutes.publish(db)
|
|
777
|
+
}
|
|
778
|
+
})
|
|
779
|
+
|
|
441
780
|
test('dispatches staged webhook updates after creation commits', async () => {
|
|
442
781
|
const subscription = await Webhooks.createSubscription(db, {
|
|
443
782
|
chainId: tempoMainnet.id,
|
|
444
|
-
destination: { type: 'url', url: 'https://example.com/webhooks/
|
|
783
|
+
destination: { type: 'url', url: 'https://example.com/webhooks/routes-transfers' },
|
|
445
784
|
environment: 'production',
|
|
446
|
-
eventType: '
|
|
785
|
+
eventType: 'routes:transfer.updated',
|
|
447
786
|
filters: { status: 'awaiting-source' },
|
|
448
|
-
owner: { orgId:
|
|
787
|
+
owner: { orgId: routesWriter.orgId, type: 'api_key' },
|
|
449
788
|
})
|
|
450
789
|
const references: Webhooks.QueueReference[] = []
|
|
451
790
|
const app = transfersApp({
|
|
452
|
-
|
|
791
|
+
routes: {
|
|
453
792
|
async dispatchTransferUpdates(staged) {
|
|
454
793
|
const reference = staged[0]!
|
|
455
794
|
const queued = await db.kysely
|
|
@@ -480,7 +819,7 @@ describe('POST /funding/transfers', () => {
|
|
|
480
819
|
})
|
|
481
820
|
|
|
482
821
|
expect(response.status).toBe(200)
|
|
483
|
-
const body = await TestApp.json(response,
|
|
822
|
+
const body = await TestApp.json(response, Routes.schema.createRoutesTransfer.Response)
|
|
484
823
|
expect(body.provider.id).toBe('relay')
|
|
485
824
|
})
|
|
486
825
|
|
|
@@ -524,7 +863,7 @@ describe('POST /funding/transfers', () => {
|
|
|
524
863
|
idempotencyKey: nextIdempotencyKey(),
|
|
525
864
|
})
|
|
526
865
|
expect(response.status).toBe(200)
|
|
527
|
-
const body = await TestApp.json(response,
|
|
866
|
+
const body = await TestApp.json(response, Routes.schema.createRoutesTransfer.Response)
|
|
528
867
|
|
|
529
868
|
expect(body.fees).toMatchObject([
|
|
530
869
|
{
|
|
@@ -560,7 +899,7 @@ describe('POST /funding/transfers', () => {
|
|
|
560
899
|
},
|
|
561
900
|
idempotencyKey: nextIdempotencyKey(),
|
|
562
901
|
})
|
|
563
|
-
const body = await TestApp.json(response,
|
|
902
|
+
const body = await TestApp.json(response, Routes.schema.createRoutesTransfer.Response)
|
|
564
903
|
results.push({
|
|
565
904
|
destinationToken: body.destinationToken.symbol,
|
|
566
905
|
name: identifier.name,
|
|
@@ -625,9 +964,12 @@ describe('POST /funding/transfers', () => {
|
|
|
625
964
|
providers: [provider()],
|
|
626
965
|
})
|
|
627
966
|
const idempotencyKey = nextIdempotencyKey()
|
|
628
|
-
await
|
|
629
|
-
apiKeyId:
|
|
967
|
+
await RoutesIdempotencyTable.claim(db, {
|
|
968
|
+
apiKeyId: routesWriter.id,
|
|
969
|
+
irrevocable: false,
|
|
630
970
|
keyHash: Idempotency.inputHash(idempotencyKey),
|
|
971
|
+
operation: RoutesIdempotencyTable.operations.transfer,
|
|
972
|
+
orgId: routesWriter.orgId,
|
|
631
973
|
requestHash: Idempotency.inputHash(createBody),
|
|
632
974
|
ttlMs: 60_000,
|
|
633
975
|
})
|
|
@@ -642,21 +984,24 @@ describe('POST /funding/transfers', () => {
|
|
|
642
984
|
const idempotencyKey = nextIdempotencyKey()
|
|
643
985
|
const keyHash = Idempotency.inputHash(idempotencyKey)
|
|
644
986
|
const before = await db.kysely
|
|
645
|
-
.selectFrom('
|
|
987
|
+
.selectFrom('routes_transfers')
|
|
646
988
|
.select(({ fn }) => fn.countAll<number>().as('count'))
|
|
647
989
|
.executeTakeFirstOrThrow()
|
|
648
990
|
const app = transfersApp({
|
|
649
991
|
providers: [
|
|
650
992
|
provider(async () => {
|
|
651
993
|
await db.kysely
|
|
652
|
-
.updateTable('
|
|
994
|
+
.updateTable('routes_idempotency_requests')
|
|
653
995
|
.set({ expiresAt: new Date(0).toISOString() })
|
|
654
|
-
.where('apiKeyId', '=',
|
|
996
|
+
.where('apiKeyId', '=', routesWriter.id)
|
|
655
997
|
.where('keyHash', '=', keyHash)
|
|
656
998
|
.execute()
|
|
657
|
-
await
|
|
658
|
-
apiKeyId:
|
|
999
|
+
await RoutesIdempotencyTable.claim(db, {
|
|
1000
|
+
apiKeyId: routesWriter.id,
|
|
1001
|
+
irrevocable: false,
|
|
659
1002
|
keyHash,
|
|
1003
|
+
operation: RoutesIdempotencyTable.operations.transfer,
|
|
1004
|
+
orgId: routesWriter.orgId,
|
|
660
1005
|
requestHash: Idempotency.inputHash(createBody),
|
|
661
1006
|
ttlMs: 60_000,
|
|
662
1007
|
})
|
|
@@ -668,7 +1013,7 @@ describe('POST /funding/transfers', () => {
|
|
|
668
1013
|
const response = await postTransfer(app, { idempotencyKey })
|
|
669
1014
|
expect(response.status).toBe(500)
|
|
670
1015
|
const after = await db.kysely
|
|
671
|
-
.selectFrom('
|
|
1016
|
+
.selectFrom('routes_transfers')
|
|
672
1017
|
.select(({ fn }) => fn.countAll<number>().as('count'))
|
|
673
1018
|
.executeTakeFirstOrThrow()
|
|
674
1019
|
expect(after.count).toBe(before.count)
|
|
@@ -702,6 +1047,35 @@ describe('POST /funding/transfers', () => {
|
|
|
702
1047
|
idempotencyKey: nextIdempotencyKey(),
|
|
703
1048
|
})
|
|
704
1049
|
expect(unknownToken.status).toBe(404)
|
|
1050
|
+
|
|
1051
|
+
const unknownChain = await postTransfer(app, {
|
|
1052
|
+
body: { ...createBody, destinationChain: 'bitcoin' },
|
|
1053
|
+
idempotencyKey: nextIdempotencyKey(),
|
|
1054
|
+
})
|
|
1055
|
+
expect(unknownChain.status).toBe(404)
|
|
1056
|
+
})
|
|
1057
|
+
|
|
1058
|
+
test.each([
|
|
1059
|
+
['recipient', { recipient: 'invalid' }],
|
|
1060
|
+
['sender', { sender: 'invalid' }],
|
|
1061
|
+
] as const)('rejects a route-invalid %s before calling the provider', async (_field, body) => {
|
|
1062
|
+
let calls = 0
|
|
1063
|
+
const app = transfersApp({
|
|
1064
|
+
providers: [
|
|
1065
|
+
provider(async () => {
|
|
1066
|
+
calls++
|
|
1067
|
+
return providerResponse()
|
|
1068
|
+
}),
|
|
1069
|
+
],
|
|
1070
|
+
})
|
|
1071
|
+
const response = await postTransfer(app, {
|
|
1072
|
+
body: { ...createBody, ...body },
|
|
1073
|
+
idempotencyKey: nextIdempotencyKey(),
|
|
1074
|
+
})
|
|
1075
|
+
|
|
1076
|
+
expect(response.status).toBe(400)
|
|
1077
|
+
expect(((await response.json()) as { error: { code: string } }).error.code).toBe('body_invalid')
|
|
1078
|
+
expect(calls).toBe(0)
|
|
705
1079
|
})
|
|
706
1080
|
|
|
707
1081
|
test('releases the claim after a provider failure', async () => {
|
|
@@ -751,7 +1125,7 @@ describe('POST /funding/transfers', () => {
|
|
|
751
1125
|
})
|
|
752
1126
|
})
|
|
753
1127
|
|
|
754
|
-
describe.skipIf(!Anvil.available)('POST /
|
|
1128
|
+
describe.skipIf(!Anvil.available)('POST /routes/transfers (forked localnet)', () => {
|
|
755
1129
|
/**
|
|
756
1130
|
* Storage slot of Circle FiatToken's `balanceAndBlacklistStates` mapping.
|
|
757
1131
|
* `anvil_dealERC20` cannot probe it because balances pack a blacklist bit,
|
|
@@ -762,7 +1136,7 @@ describe.skipIf(!Anvil.available)('POST /funding/transfers (forked localnet)', (
|
|
|
762
1136
|
|
|
763
1137
|
for (const executable of executableProviders) {
|
|
764
1138
|
describe(executable.id, () => {
|
|
765
|
-
const route =
|
|
1139
|
+
const route = TestRoutes.snapshot.routes.find(
|
|
766
1140
|
(entry) =>
|
|
767
1141
|
entry.route.source.chain.id === `eip155:${base.id}` &&
|
|
768
1142
|
entry.route.source.symbol === 'USDC' &&
|
|
@@ -806,7 +1180,7 @@ describe.skipIf(!Anvil.available)('POST /funding/transfers (forked localnet)', (
|
|
|
806
1180
|
|
|
807
1181
|
const response = await createTransfer(`bridge_${executable.id}_${sender.address}`)
|
|
808
1182
|
expect(response.status).toBe(200)
|
|
809
|
-
const transfer = await TestApp.json(response,
|
|
1183
|
+
const transfer = await TestApp.json(response, Routes.schema.createRoutesTransfer.Response)
|
|
810
1184
|
expect(transfer.action.type).toBe('evm:calls')
|
|
811
1185
|
if (transfer.action.type !== 'evm:calls') return
|
|
812
1186
|
expect(transfer.action.calls.length).toBeGreaterThan(0)
|
|
@@ -819,7 +1193,7 @@ describe.skipIf(!Anvil.available)('POST /funding/transfers (forked localnet)', (
|
|
|
819
1193
|
},
|
|
820
1194
|
])
|
|
821
1195
|
const row = await db.kysely
|
|
822
|
-
.selectFrom('
|
|
1196
|
+
.selectFrom('routes_transfers')
|
|
823
1197
|
.select('providerState')
|
|
824
1198
|
.where('id', '=', transfer.id)
|
|
825
1199
|
.executeTakeFirstOrThrow()
|
|
@@ -853,11 +1227,18 @@ describe.skipIf(!Anvil.available)('POST /funding/transfers (forked localnet)', (
|
|
|
853
1227
|
await expect(
|
|
854
1228
|
Stargate.verifySourceTransaction({
|
|
855
1229
|
configuration: stargateConfiguration,
|
|
1230
|
+
destinationAmountMin: transfer.destinationAmountMin!.baseUnits,
|
|
1231
|
+
destinationChain: RoutesChain.from({
|
|
1232
|
+
id: 'eip155:4217',
|
|
1233
|
+
name: 'Tempo',
|
|
1234
|
+
rpcUrls: [tempoMainnet.rpcUrls.default.http[0]!],
|
|
1235
|
+
slug: 'tempo',
|
|
1236
|
+
}),
|
|
856
1237
|
destinationTokenAddress: transfer.destinationToken.address,
|
|
857
1238
|
recipient: transfer.recipient,
|
|
858
1239
|
sender: sender.address,
|
|
859
1240
|
sourceAmount: transfer.sourceAmount.baseUnits,
|
|
860
|
-
sourceChain:
|
|
1241
|
+
sourceChain: RoutesChain.from({
|
|
861
1242
|
id: 'eip155:8453',
|
|
862
1243
|
name: 'Base',
|
|
863
1244
|
rpcUrls: [anvil.rpcUrl],
|
|
@@ -872,7 +1253,7 @@ describe.skipIf(!Anvil.available)('POST /funding/transfers (forked localnet)', (
|
|
|
872
1253
|
})
|
|
873
1254
|
|
|
874
1255
|
if (executable.id === 'stargate')
|
|
875
|
-
test('
|
|
1256
|
+
test('registers non-atomic calls and reopens them after an execution reorg', async () => {
|
|
876
1257
|
await Anvil.setErc20Balance(anvil.client, {
|
|
877
1258
|
address: sender.address,
|
|
878
1259
|
amount,
|
|
@@ -881,10 +1262,7 @@ describe.skipIf(!Anvil.available)('POST /funding/transfers (forked localnet)', (
|
|
|
881
1262
|
})
|
|
882
1263
|
const response = await createTransfer(`bridge_reorg_${sender.address}`)
|
|
883
1264
|
expect(response.status).toBe(200)
|
|
884
|
-
const transfer = await TestApp.json(
|
|
885
|
-
response,
|
|
886
|
-
Funding.schema.createFundingTransfer.Response,
|
|
887
|
-
)
|
|
1265
|
+
const transfer = await TestApp.json(response, Routes.schema.createRoutesTransfer.Response)
|
|
888
1266
|
expect(transfer.action.type).toBe('evm:calls')
|
|
889
1267
|
if (transfer.action.type !== 'evm:calls') return
|
|
890
1268
|
|
|
@@ -908,15 +1286,15 @@ describe.skipIf(!Anvil.available)('POST /funding/transfers (forked localnet)', (
|
|
|
908
1286
|
)
|
|
909
1287
|
const sourceReceipt = receipts.at(-1)!
|
|
910
1288
|
const transactionHash = sourceReceipt.transactionHash
|
|
911
|
-
await
|
|
912
|
-
...
|
|
913
|
-
chains:
|
|
1289
|
+
await RoutesCatalog.publish(db, {
|
|
1290
|
+
...TestRoutes.data,
|
|
1291
|
+
chains: TestRoutes.data.chains.map((chain) =>
|
|
914
1292
|
chain.id === 'eip155:8453' ? { ...chain, rpcUrls: [anvil.rpcUrl] } : chain,
|
|
915
1293
|
),
|
|
916
1294
|
})
|
|
917
|
-
const messages:
|
|
1295
|
+
const messages: RoutesTransferReconciliation.Message[] = []
|
|
918
1296
|
const app = transfersApp({
|
|
919
|
-
|
|
1297
|
+
routes: {
|
|
920
1298
|
async dispatchTransferReconciliation(message) {
|
|
921
1299
|
messages.push(message)
|
|
922
1300
|
},
|
|
@@ -924,35 +1302,38 @@ describe.skipIf(!Anvil.available)('POST /funding/transfers (forked localnet)', (
|
|
|
924
1302
|
providers: [Stargate.stargate()],
|
|
925
1303
|
})
|
|
926
1304
|
const registered = await app.request(
|
|
927
|
-
`/v1/
|
|
1305
|
+
`/v1/routes/transfers/${transfer.id}/source-transactions`,
|
|
928
1306
|
{
|
|
929
|
-
body: JSON.stringify({
|
|
930
|
-
|
|
1307
|
+
body: JSON.stringify({
|
|
1308
|
+
transactionHashes: receipts.map((receipt) => receipt.transactionHash),
|
|
1309
|
+
}),
|
|
1310
|
+
headers: { ...as(routesWriter).headers, 'content-type': 'application/json' },
|
|
931
1311
|
method: 'POST',
|
|
932
1312
|
},
|
|
933
1313
|
)
|
|
934
1314
|
expect(registered.status).toBe(200)
|
|
935
1315
|
expect(messages).toEqual([
|
|
936
|
-
{ transferId: transfer.id, type: '
|
|
1316
|
+
{ transferId: transfer.id, type: 'routes:transfer:reconcile' },
|
|
937
1317
|
])
|
|
938
1318
|
|
|
939
1319
|
await anvil.client.revert({ id: checkpoint })
|
|
940
1320
|
reverted = true
|
|
941
|
-
const tracker =
|
|
1321
|
+
const tracker = RoutesTransferReconciliation.createTracker({
|
|
942
1322
|
db,
|
|
943
1323
|
async dispatch(message) {
|
|
944
1324
|
messages.push(message)
|
|
945
1325
|
},
|
|
1326
|
+
providers: [Stargate.stargate()],
|
|
946
1327
|
})
|
|
947
1328
|
await expect(tracker.reconcile(messages[0]!)).resolves.toEqual({ type: 'pending' })
|
|
948
1329
|
expect(messages[1]).toEqual({
|
|
949
1330
|
attempt: 1,
|
|
950
1331
|
transferId: transfer.id,
|
|
951
|
-
type: '
|
|
1332
|
+
type: 'routes:transfer:reconcile',
|
|
952
1333
|
})
|
|
953
1334
|
|
|
954
1335
|
const pending = await db.kysely
|
|
955
|
-
.selectFrom('
|
|
1336
|
+
.selectFrom('routes_transfers')
|
|
956
1337
|
.select(['snapshot', 'status', 'version'])
|
|
957
1338
|
.where('id', '=', transfer.id)
|
|
958
1339
|
.executeTakeFirstOrThrow()
|
|
@@ -961,7 +1342,7 @@ describe.skipIf(!Anvil.available)('POST /funding/transfers (forked localnet)', (
|
|
|
961
1342
|
status: pending.status,
|
|
962
1343
|
version: pending.version,
|
|
963
1344
|
}).toEqual({
|
|
964
|
-
sourceTransactionHashes: [transactionHash],
|
|
1345
|
+
sourceTransactionHashes: [transactionHash, receipts[0]!.transactionHash],
|
|
965
1346
|
status: 'processing',
|
|
966
1347
|
version: 2,
|
|
967
1348
|
})
|
|
@@ -972,7 +1353,7 @@ describe.skipIf(!Anvil.available)('POST /funding/transfers (forked localnet)', (
|
|
|
972
1353
|
await expect(tracker.reconcile(messages[1]!)).resolves.toEqual({ type: 'reopened' })
|
|
973
1354
|
|
|
974
1355
|
const record = await db.kysely
|
|
975
|
-
.selectFrom('
|
|
1356
|
+
.selectFrom('routes_transfers')
|
|
976
1357
|
.select(['snapshot', 'status', 'version'])
|
|
977
1358
|
.where('id', '=', transfer.id)
|
|
978
1359
|
.executeTakeFirstOrThrow()
|
|
@@ -987,21 +1368,21 @@ describe.skipIf(!Anvil.available)('POST /funding/transfers (forked localnet)', (
|
|
|
987
1368
|
})
|
|
988
1369
|
expect(
|
|
989
1370
|
await db.kysely
|
|
990
|
-
.selectFrom('
|
|
1371
|
+
.selectFrom('routes_transfer_transactions')
|
|
991
1372
|
.selectAll()
|
|
992
1373
|
.where('transferId', '=', transfer.id)
|
|
993
1374
|
.execute(),
|
|
994
1375
|
).toEqual([])
|
|
995
1376
|
} finally {
|
|
996
1377
|
if (!reverted) await anvil.client.revert({ id: checkpoint })
|
|
997
|
-
await
|
|
1378
|
+
await TestRoutes.publish(db)
|
|
998
1379
|
}
|
|
999
1380
|
})
|
|
1000
1381
|
|
|
1001
1382
|
test('bounds the approval to the quoted source spend', async () => {
|
|
1002
1383
|
const response = await createTransfer(`bridge_bounds_${executable.id}_${sender.address}`)
|
|
1003
1384
|
expect(response.status).toBe(200)
|
|
1004
|
-
const transfer = await TestApp.json(response,
|
|
1385
|
+
const transfer = await TestApp.json(response, Routes.schema.createRoutesTransfer.Response)
|
|
1005
1386
|
if (transfer.action.type !== 'evm:calls') return
|
|
1006
1387
|
|
|
1007
1388
|
const approval = transfer.action.calls.find((call) =>
|
|
@@ -1024,7 +1405,7 @@ describe.skipIf(!Anvil.available)('POST /funding/transfers (forked localnet)', (
|
|
|
1024
1405
|
})
|
|
1025
1406
|
|
|
1026
1407
|
describe.skipIf(!Anvil.available)(
|
|
1027
|
-
'POST /
|
|
1408
|
+
'POST /routes/transfers/:id/source-transactions (forked localnet)',
|
|
1028
1409
|
() => {
|
|
1029
1410
|
const trackingDb = TestApp.database()
|
|
1030
1411
|
let destination: Anvil.start.ReturnType
|
|
@@ -1035,9 +1416,9 @@ describe.skipIf(!Anvil.available)(
|
|
|
1035
1416
|
Anvil.start({ chain: tempoMainnet, forkUrl: tempoMainnet.rpcUrls.default.http[0]! }),
|
|
1036
1417
|
Anvil.start({ chain: base, forkUrl: base.rpcUrls.default.http[0]! }),
|
|
1037
1418
|
])
|
|
1038
|
-
await
|
|
1039
|
-
...
|
|
1040
|
-
chains:
|
|
1419
|
+
await RoutesCatalog.publish(trackingDb, {
|
|
1420
|
+
...TestRoutes.data,
|
|
1421
|
+
chains: TestRoutes.data.chains.map((chain) => {
|
|
1041
1422
|
if (chain.id === 'eip155:4217') return { ...chain, rpcUrls: [destination.rpcUrl] }
|
|
1042
1423
|
if (chain.id === 'eip155:8453') return { ...chain, rpcUrls: [source.rpcUrl] }
|
|
1043
1424
|
return chain
|
|
@@ -1049,7 +1430,7 @@ describe.skipIf(!Anvil.available)(
|
|
|
1049
1430
|
await Promise.all([destination?.stop(), source?.stop()])
|
|
1050
1431
|
})
|
|
1051
1432
|
|
|
1052
|
-
test('backfills legacy state and completes
|
|
1433
|
+
test('backfills legacy state and completes despite a foreign source claim', async () => {
|
|
1053
1434
|
const destinationReceipt = await destination.client.getTransactionReceipt({
|
|
1054
1435
|
hash: destinationTransactionHash,
|
|
1055
1436
|
})
|
|
@@ -1067,7 +1448,7 @@ describe.skipIf(!Anvil.available)(
|
|
|
1067
1448
|
formatted: '0.2',
|
|
1068
1449
|
} as const
|
|
1069
1450
|
const snapshot = {
|
|
1070
|
-
...
|
|
1451
|
+
...TestRoutes.transferSnapshot({
|
|
1071
1452
|
destinationAmount: amount,
|
|
1072
1453
|
destinationAmountMin: amount,
|
|
1073
1454
|
provider: { id: 'stargate', name: 'Stargate' },
|
|
@@ -1080,20 +1461,40 @@ describe.skipIf(!Anvil.available)(
|
|
|
1080
1461
|
sampledAt,
|
|
1081
1462
|
},
|
|
1082
1463
|
}
|
|
1083
|
-
const
|
|
1084
|
-
|
|
1464
|
+
const subscriptions = await Promise.all(
|
|
1465
|
+
[routesForeign, routesWriter].map((key) =>
|
|
1466
|
+
Webhooks.createSubscription(trackingDb, {
|
|
1467
|
+
chainId: 4217,
|
|
1468
|
+
destination: { type: 'url', url: 'https://example.com/routes' },
|
|
1469
|
+
environment: 'production',
|
|
1470
|
+
eventType: 'routes:transfer.updated',
|
|
1471
|
+
owner: { orgId: key.orgId, type: 'api_key' },
|
|
1472
|
+
}),
|
|
1473
|
+
),
|
|
1474
|
+
)
|
|
1475
|
+
const transfer = await RoutesTransfer.create(trackingDb, {
|
|
1476
|
+
apiKeyId: routesWriter.id,
|
|
1477
|
+
environment: 'production',
|
|
1478
|
+
orgId: routesWriter.orgId,
|
|
1479
|
+
snapshot,
|
|
1480
|
+
})
|
|
1481
|
+
const foreign = await RoutesTransfer.create(trackingDb, {
|
|
1482
|
+
apiKeyId: routesForeign.id,
|
|
1085
1483
|
environment: 'production',
|
|
1086
|
-
orgId:
|
|
1484
|
+
orgId: routesForeign.orgId,
|
|
1087
1485
|
snapshot,
|
|
1088
1486
|
})
|
|
1089
|
-
const tracker =
|
|
1090
|
-
|
|
1487
|
+
const tracker = RoutesTransferReconciliation.createTracker({
|
|
1488
|
+
db: trackingDb,
|
|
1489
|
+
providers: [Stargate.stargate()],
|
|
1490
|
+
})
|
|
1491
|
+
const messages: RoutesTransferReconciliation.Message[] = []
|
|
1091
1492
|
let dispatchEnabled = true
|
|
1092
1493
|
const app = TestApp.create({
|
|
1093
|
-
auth: { keys: [
|
|
1494
|
+
auth: { keys: [routesForeign, routesWriter] },
|
|
1094
1495
|
db: trackingDb,
|
|
1095
1496
|
defaultChainId: tempoMainnet.id,
|
|
1096
|
-
|
|
1497
|
+
routes: {
|
|
1097
1498
|
async dispatchTransferReconciliation(message) {
|
|
1098
1499
|
if (!dispatchEnabled) throw new Error('reconciliation unavailable')
|
|
1099
1500
|
messages.push(message)
|
|
@@ -1101,19 +1502,32 @@ describe.skipIf(!Anvil.available)(
|
|
|
1101
1502
|
},
|
|
1102
1503
|
providers: [Stargate.stargate()],
|
|
1103
1504
|
})
|
|
1104
|
-
const path = `/v1/
|
|
1505
|
+
const path = `/v1/routes/transfers/${transfer.id}/source-transactions`
|
|
1105
1506
|
const registration = {
|
|
1106
1507
|
body: JSON.stringify({
|
|
1107
|
-
|
|
1508
|
+
transactionHashes: [sourceTransactionHash],
|
|
1108
1509
|
}),
|
|
1109
|
-
headers: { ...as(
|
|
1510
|
+
headers: { ...as(routesWriter).headers, 'content-type': 'application/json' },
|
|
1110
1511
|
method: 'POST',
|
|
1111
1512
|
}
|
|
1513
|
+
const foreignResponse = await app.request(
|
|
1514
|
+
`/v1/routes/transfers/${foreign.id}/source-transactions`,
|
|
1515
|
+
{
|
|
1516
|
+
...registration,
|
|
1517
|
+
headers: { ...as(routesForeign).headers, 'content-type': 'application/json' },
|
|
1518
|
+
},
|
|
1519
|
+
)
|
|
1520
|
+
expect(foreignResponse.status).toBe(200)
|
|
1521
|
+
expect(
|
|
1522
|
+
(await app.request(`/v1/routes/transfers/${foreign.id}`, as(routesWriter))).status,
|
|
1523
|
+
).toBe(404)
|
|
1524
|
+
expect(await tracker.reconcile(messages[0]!)).toEqual({ type: 'completed' })
|
|
1525
|
+
|
|
1112
1526
|
const response = await app.request(path, registration)
|
|
1113
1527
|
expect(response.status).toBe(200)
|
|
1114
1528
|
const registered = await TestApp.json(
|
|
1115
1529
|
response,
|
|
1116
|
-
|
|
1530
|
+
Routes.schema.registerRoutesTransferSourceTransaction.Response,
|
|
1117
1531
|
)
|
|
1118
1532
|
expect({
|
|
1119
1533
|
sourceTransactionHashes: registered.sourceTransactionHashes,
|
|
@@ -1127,7 +1541,7 @@ describe.skipIf(!Anvil.available)(
|
|
|
1127
1541
|
version: 2,
|
|
1128
1542
|
})
|
|
1129
1543
|
const stored = await trackingDb.kysely
|
|
1130
|
-
.selectFrom('
|
|
1544
|
+
.selectFrom('routes_transfers')
|
|
1131
1545
|
.select('providerState')
|
|
1132
1546
|
.where('id', '=', transfer.id)
|
|
1133
1547
|
.executeTakeFirstOrThrow()
|
|
@@ -1149,12 +1563,15 @@ describe.skipIf(!Anvil.available)(
|
|
|
1149
1563
|
if (typeof destinationBlockNumber !== 'string')
|
|
1150
1564
|
throw new Error('Expected a backfilled destination block number.')
|
|
1151
1565
|
expect(BigInt(destinationBlockNumber)).toBeLessThanOrEqual(destinationReceipt.blockNumber)
|
|
1152
|
-
expect(messages).toEqual([
|
|
1153
|
-
|
|
1566
|
+
expect(messages).toEqual([
|
|
1567
|
+
{ transferId: foreign.id, type: 'routes:transfer:reconcile' },
|
|
1568
|
+
{ transferId: transfer.id, type: 'routes:transfer:reconcile' },
|
|
1569
|
+
])
|
|
1570
|
+
await tracker.reconcile(messages[1]!)
|
|
1154
1571
|
|
|
1155
1572
|
const completed = await TestApp.json(
|
|
1156
|
-
await app.request(`/v1/
|
|
1157
|
-
|
|
1573
|
+
await app.request(`/v1/routes/transfers/${transfer.id}`, as(routesWriter)),
|
|
1574
|
+
Routes.schema.getRoutesTransfer.Response,
|
|
1158
1575
|
)
|
|
1159
1576
|
expect({
|
|
1160
1577
|
destinationTransactionHashes: completed.destinationTransactionHashes,
|
|
@@ -1166,24 +1583,47 @@ describe.skipIf(!Anvil.available)(
|
|
|
1166
1583
|
version: 3,
|
|
1167
1584
|
})
|
|
1168
1585
|
|
|
1586
|
+
const events = await trackingDb.kysely
|
|
1587
|
+
.selectFrom('webhook_queue_events')
|
|
1588
|
+
.select(['envelope', 'subscriptionId'])
|
|
1589
|
+
.where(
|
|
1590
|
+
'subscriptionId',
|
|
1591
|
+
'in',
|
|
1592
|
+
subscriptions.map(({ id }) => id),
|
|
1593
|
+
)
|
|
1594
|
+
.execute()
|
|
1595
|
+
for (const [index, record] of [foreign, transfer].entries()) {
|
|
1596
|
+
const own = events.filter(
|
|
1597
|
+
({ subscriptionId }) => subscriptionId === subscriptions[index]!.id,
|
|
1598
|
+
)
|
|
1599
|
+
expect(own.map(({ envelope }) => envelope.data)).toEqual(
|
|
1600
|
+
expect.arrayContaining([
|
|
1601
|
+
expect.objectContaining({ id: record.id, status: 'awaiting-source', version: 1 }),
|
|
1602
|
+
expect.objectContaining({ id: record.id, status: 'processing', version: 2 }),
|
|
1603
|
+
expect.objectContaining({ id: record.id, status: 'completed', version: 3 }),
|
|
1604
|
+
]),
|
|
1605
|
+
)
|
|
1606
|
+
expect(own).toHaveLength(3)
|
|
1607
|
+
}
|
|
1608
|
+
|
|
1169
1609
|
dispatchEnabled = false
|
|
1170
1610
|
const replayed = await TestApp.json(
|
|
1171
1611
|
await app.request(path, registration),
|
|
1172
|
-
|
|
1612
|
+
Routes.schema.registerRoutesTransferSourceTransaction.Response,
|
|
1173
1613
|
)
|
|
1174
1614
|
expect({ status: replayed.status, version: replayed.version }).toEqual({
|
|
1175
1615
|
status: 'completed',
|
|
1176
1616
|
version: 3,
|
|
1177
1617
|
})
|
|
1178
1618
|
|
|
1179
|
-
const other = await
|
|
1180
|
-
apiKeyId:
|
|
1619
|
+
const other = await RoutesTransfer.create(trackingDb, {
|
|
1620
|
+
apiKeyId: routesWriter.id,
|
|
1181
1621
|
environment: 'production',
|
|
1182
|
-
orgId:
|
|
1622
|
+
orgId: routesWriter.orgId,
|
|
1183
1623
|
snapshot,
|
|
1184
1624
|
})
|
|
1185
1625
|
const conflict = await app.request(
|
|
1186
|
-
`/v1/
|
|
1626
|
+
`/v1/routes/transfers/${other.id}/source-transactions`,
|
|
1187
1627
|
registration,
|
|
1188
1628
|
)
|
|
1189
1629
|
expect(conflict.status).toBe(409)
|
|
@@ -1191,17 +1631,17 @@ describe.skipIf(!Anvil.available)(
|
|
|
1191
1631
|
'source_transaction_conflict',
|
|
1192
1632
|
)
|
|
1193
1633
|
|
|
1194
|
-
const pending = await
|
|
1195
|
-
apiKeyId:
|
|
1634
|
+
const pending = await RoutesTransfer.create(trackingDb, {
|
|
1635
|
+
apiKeyId: routesWriter.id,
|
|
1196
1636
|
environment: 'production',
|
|
1197
|
-
orgId:
|
|
1637
|
+
orgId: routesWriter.orgId,
|
|
1198
1638
|
snapshot,
|
|
1199
1639
|
})
|
|
1200
1640
|
const pendingResponse = await app.request(
|
|
1201
|
-
`/v1/
|
|
1641
|
+
`/v1/routes/transfers/${pending.id}/source-transactions`,
|
|
1202
1642
|
{
|
|
1203
1643
|
...registration,
|
|
1204
|
-
body: JSON.stringify({
|
|
1644
|
+
body: JSON.stringify({ transactionHashes: [`0x${'99'.repeat(32)}`] }),
|
|
1205
1645
|
},
|
|
1206
1646
|
)
|
|
1207
1647
|
expect(pendingResponse.status).toBe(409)
|
|
@@ -1209,25 +1649,186 @@ describe.skipIf(!Anvil.available)(
|
|
|
1209
1649
|
'source_transaction_pending',
|
|
1210
1650
|
)
|
|
1211
1651
|
})
|
|
1652
|
+
|
|
1653
|
+
test('registers all five Tempo Stargate calls and rejects mismatched fee terms', async () => {
|
|
1654
|
+
const sourceTransactionHashes = [
|
|
1655
|
+
'0xec00883936af1eb22402c471cf05827ac161d78e832ea771ff3b936d4e5d7517',
|
|
1656
|
+
'0x55e22e5308d6261bb3ef04233cf29d85f342b5bf7ab2db0e34382be52a029b7e',
|
|
1657
|
+
'0x75761272e9a8365636b0f4038f9908f18461d4f7083c6aa610831b81db681812',
|
|
1658
|
+
'0xe840e103cfe4d62f9de0439f14f1010bae8f455585797577cb85fef3a77bc56b',
|
|
1659
|
+
'0x56c9ad54ea6213b2091434efa82dcc072a800876c85c1a2068d1202af18e73b6',
|
|
1660
|
+
]
|
|
1661
|
+
const routeConfiguration = {
|
|
1662
|
+
destinationPoolAddress: '0x27a16dc786820B16E5c9028b75B99F6f604b5d26',
|
|
1663
|
+
poolAddress: '0x8c76e2F6C5ceDA9AA7772e7efF30280226c44392',
|
|
1664
|
+
}
|
|
1665
|
+
const amount = {
|
|
1666
|
+
baseUnits: '200000',
|
|
1667
|
+
currency: 'USD',
|
|
1668
|
+
decimals: 6,
|
|
1669
|
+
formatted: '0.2',
|
|
1670
|
+
} as const
|
|
1671
|
+
const fee = {
|
|
1672
|
+
amount: { baseUnits: '500000', currency: 'USD', decimals: 6, formatted: '0.5' },
|
|
1673
|
+
side: 'source',
|
|
1674
|
+
token: {
|
|
1675
|
+
address: '0x20c0000000000000000000000000000000000000',
|
|
1676
|
+
currency: 'USD',
|
|
1677
|
+
decimals: 6,
|
|
1678
|
+
name: 'pathUSD',
|
|
1679
|
+
standard: 'TIP-20',
|
|
1680
|
+
symbol: 'pathUSD',
|
|
1681
|
+
tokenKey: 'eip155:4217/erc20:0x20c0000000000000000000000000000000000000',
|
|
1682
|
+
verified: true,
|
|
1683
|
+
},
|
|
1684
|
+
type: 'provider',
|
|
1685
|
+
} as const
|
|
1686
|
+
const snapshot = TestRoutes.transferSnapshot({
|
|
1687
|
+
destinationAmount: {
|
|
1688
|
+
baseUnits: '199979',
|
|
1689
|
+
currency: 'USD',
|
|
1690
|
+
decimals: 6,
|
|
1691
|
+
formatted: '0.199979',
|
|
1692
|
+
},
|
|
1693
|
+
destinationAmountMin: {
|
|
1694
|
+
baseUnits: '199979',
|
|
1695
|
+
currency: 'USD',
|
|
1696
|
+
decimals: 6,
|
|
1697
|
+
formatted: '0.199979',
|
|
1698
|
+
},
|
|
1699
|
+
destinationChain: {
|
|
1700
|
+
addressFormat: 'hex',
|
|
1701
|
+
id: 'eip155:8453',
|
|
1702
|
+
kind: 'evm',
|
|
1703
|
+
name: 'Base',
|
|
1704
|
+
},
|
|
1705
|
+
destinationToken: {
|
|
1706
|
+
address: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
|
|
1707
|
+
currency: 'USD',
|
|
1708
|
+
decimals: 6,
|
|
1709
|
+
name: 'USD Coin',
|
|
1710
|
+
standard: 'ERC-20',
|
|
1711
|
+
symbol: 'USDC',
|
|
1712
|
+
tokenKey: 'eip155:8453/erc20:0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
|
|
1713
|
+
verified: true,
|
|
1714
|
+
},
|
|
1715
|
+
fees: [fee],
|
|
1716
|
+
provider: { id: 'stargate', name: 'Stargate' },
|
|
1717
|
+
quote: {
|
|
1718
|
+
expiresAt: '2026-09-03T16:04:31.000Z',
|
|
1719
|
+
sampledAt: '2026-09-03T16:03:31.000Z',
|
|
1720
|
+
},
|
|
1721
|
+
recipient: '0xa8a89a017cd431c31af421f7d829e9418a5016ba',
|
|
1722
|
+
sender: '0x3063088c6f4ac4dd3f96a411d5fb68173d113def',
|
|
1723
|
+
sourceAmount: amount,
|
|
1724
|
+
sourceChain: {
|
|
1725
|
+
addressFormat: 'hex',
|
|
1726
|
+
id: 'eip155:4217',
|
|
1727
|
+
kind: 'evm',
|
|
1728
|
+
name: 'Tempo',
|
|
1729
|
+
},
|
|
1730
|
+
sourceToken: {
|
|
1731
|
+
address: '0x20c000000000000000000000b9537d11c60e8b50',
|
|
1732
|
+
currency: 'USD',
|
|
1733
|
+
decimals: 6,
|
|
1734
|
+
name: 'Bridged USDC (Stargate)',
|
|
1735
|
+
standard: 'TIP-20',
|
|
1736
|
+
symbol: 'USDC.e',
|
|
1737
|
+
tokenKey: 'eip155:4217/erc20:0x20c000000000000000000000b9537d11c60e8b50',
|
|
1738
|
+
verified: true,
|
|
1739
|
+
},
|
|
1740
|
+
})
|
|
1741
|
+
const app = TestApp.create({
|
|
1742
|
+
auth: { keys: [routesWriter] },
|
|
1743
|
+
db: trackingDb,
|
|
1744
|
+
defaultChainId: tempoMainnet.id,
|
|
1745
|
+
providers: [
|
|
1746
|
+
Stargate.stargate({
|
|
1747
|
+
fetch(input, init) {
|
|
1748
|
+
// Anvil cannot decode Tempo type-0x76 receipts, so immutable source evidence is read from production.
|
|
1749
|
+
return globalThis.fetch(
|
|
1750
|
+
typeof input === 'string' && input.startsWith(destination.rpcUrl)
|
|
1751
|
+
? tempoMainnet.rpcUrls.default.http[0]!
|
|
1752
|
+
: input,
|
|
1753
|
+
init,
|
|
1754
|
+
)
|
|
1755
|
+
},
|
|
1756
|
+
}),
|
|
1757
|
+
],
|
|
1758
|
+
routes: { async dispatchTransferReconciliation() {} },
|
|
1759
|
+
})
|
|
1760
|
+
const transfer = await RoutesTransfer.create(trackingDb, {
|
|
1761
|
+
apiKeyId: routesWriter.id,
|
|
1762
|
+
environment: 'production',
|
|
1763
|
+
orgId: routesWriter.orgId,
|
|
1764
|
+
providerState: { destinationBlockNumber: '0', routeConfiguration },
|
|
1765
|
+
snapshot,
|
|
1766
|
+
})
|
|
1767
|
+
const response = await app.request(
|
|
1768
|
+
`/v1/routes/transfers/${transfer.id}/source-transactions`,
|
|
1769
|
+
{
|
|
1770
|
+
body: JSON.stringify({ transactionHashes: sourceTransactionHashes }),
|
|
1771
|
+
headers: { ...as(routesWriter).headers, 'content-type': 'application/json' },
|
|
1772
|
+
method: 'POST',
|
|
1773
|
+
},
|
|
1774
|
+
)
|
|
1775
|
+
expect(response.status).toBe(200)
|
|
1776
|
+
const registered = await TestApp.json(
|
|
1777
|
+
response,
|
|
1778
|
+
Routes.schema.registerRoutesTransferSourceTransaction.Response,
|
|
1779
|
+
)
|
|
1780
|
+
expect(registered.sourceTransactionHashes).toEqual([
|
|
1781
|
+
sourceTransactionHashes[4],
|
|
1782
|
+
...sourceTransactionHashes.slice(0, 4),
|
|
1783
|
+
])
|
|
1784
|
+
|
|
1785
|
+
const malformed = await RoutesTransfer.create(trackingDb, {
|
|
1786
|
+
apiKeyId: routesWriter.id,
|
|
1787
|
+
environment: 'production',
|
|
1788
|
+
orgId: routesWriter.orgId,
|
|
1789
|
+
providerState: { destinationBlockNumber: '0', routeConfiguration },
|
|
1790
|
+
snapshot: {
|
|
1791
|
+
...snapshot,
|
|
1792
|
+
fees: [
|
|
1793
|
+
{
|
|
1794
|
+
...fee,
|
|
1795
|
+
amount: { ...fee.amount, baseUnits: '500001', formatted: '0.500001' },
|
|
1796
|
+
},
|
|
1797
|
+
],
|
|
1798
|
+
},
|
|
1799
|
+
})
|
|
1800
|
+
const rejected = await app.request(
|
|
1801
|
+
`/v1/routes/transfers/${malformed.id}/source-transactions`,
|
|
1802
|
+
{
|
|
1803
|
+
body: JSON.stringify({ transactionHashes: sourceTransactionHashes }),
|
|
1804
|
+
headers: { ...as(routesWriter).headers, 'content-type': 'application/json' },
|
|
1805
|
+
method: 'POST',
|
|
1806
|
+
},
|
|
1807
|
+
)
|
|
1808
|
+
expect(rejected.status).toBe(400)
|
|
1809
|
+
expect(((await rejected.json()) as { error: { code: string } }).error.code).toBe(
|
|
1810
|
+
'source_transaction_invalid',
|
|
1811
|
+
)
|
|
1812
|
+
})
|
|
1212
1813
|
},
|
|
1213
1814
|
)
|
|
1214
1815
|
|
|
1215
|
-
describe('POST /
|
|
1816
|
+
describe('POST /routes/transfers/{destination}', () => {
|
|
1216
1817
|
test.each([
|
|
1217
1818
|
{ body: vaultTransferBody, destination: 'vault' },
|
|
1218
1819
|
{ body: zoneTransferBody, destination: 'zone' },
|
|
1219
1820
|
] as const)('validates and returns 501 for $destination transfers', async (options) => {
|
|
1220
1821
|
const app = transfersApp()
|
|
1221
1822
|
const before = await db.kysely
|
|
1222
|
-
.selectFrom('
|
|
1823
|
+
.selectFrom('routes_transfers')
|
|
1223
1824
|
.select(({ fn }) => fn.countAll<number>().as('count'))
|
|
1224
1825
|
.executeTakeFirstOrThrow()
|
|
1225
|
-
const response = await app.request(`/v1/
|
|
1826
|
+
const response = await app.request(`/v1/routes/transfers/${options.destination}`, {
|
|
1226
1827
|
body: JSON.stringify(options.body),
|
|
1227
1828
|
headers: {
|
|
1228
|
-
authorization: `Bearer ${
|
|
1829
|
+
authorization: `Bearer ${routesWriter.token}`,
|
|
1229
1830
|
'content-type': 'application/json',
|
|
1230
|
-
'idempotency-key': `
|
|
1831
|
+
'idempotency-key': `routes_${options.destination}_unimplemented`,
|
|
1231
1832
|
},
|
|
1232
1833
|
method: 'POST',
|
|
1233
1834
|
})
|
|
@@ -1238,7 +1839,7 @@ describe('POST /funding/transfers/{destination}', () => {
|
|
|
1238
1839
|
'not_implemented',
|
|
1239
1840
|
)
|
|
1240
1841
|
const after = await db.kysely
|
|
1241
|
-
.selectFrom('
|
|
1842
|
+
.selectFrom('routes_transfers')
|
|
1242
1843
|
.select(({ fn }) => fn.countAll<number>().as('count'))
|
|
1243
1844
|
.executeTakeFirstOrThrow()
|
|
1244
1845
|
expect(after.count).toBe(before.count)
|
|
@@ -1246,10 +1847,10 @@ describe('POST /funding/transfers/{destination}', () => {
|
|
|
1246
1847
|
|
|
1247
1848
|
test('requires the header and validates destination fields', async () => {
|
|
1248
1849
|
const app = transfersApp()
|
|
1249
|
-
const missingHeader = await app.request('/v1/
|
|
1850
|
+
const missingHeader = await app.request('/v1/routes/transfers/vault', {
|
|
1250
1851
|
body: JSON.stringify(vaultTransferBody),
|
|
1251
1852
|
headers: {
|
|
1252
|
-
authorization: `Bearer ${
|
|
1853
|
+
authorization: `Bearer ${routesWriter.token}`,
|
|
1253
1854
|
'content-type': 'application/json',
|
|
1254
1855
|
},
|
|
1255
1856
|
method: 'POST',
|
|
@@ -1259,12 +1860,12 @@ describe('POST /funding/transfers/{destination}', () => {
|
|
|
1259
1860
|
'idempotency_key_required',
|
|
1260
1861
|
)
|
|
1261
1862
|
|
|
1262
|
-
const invalidZone = await app.request('/v1/
|
|
1863
|
+
const invalidZone = await app.request('/v1/routes/transfers/zone', {
|
|
1263
1864
|
body: JSON.stringify({ ...zoneTransferBody, destinationChain: '421700001' }),
|
|
1264
1865
|
headers: {
|
|
1265
|
-
authorization: `Bearer ${
|
|
1866
|
+
authorization: `Bearer ${routesWriter.token}`,
|
|
1266
1867
|
'content-type': 'application/json',
|
|
1267
|
-
'idempotency-key': '
|
|
1868
|
+
'idempotency-key': 'routes_zone_invalid',
|
|
1268
1869
|
},
|
|
1269
1870
|
method: 'POST',
|
|
1270
1871
|
})
|
|
@@ -1275,21 +1876,21 @@ describe('POST /funding/transfers/{destination}', () => {
|
|
|
1275
1876
|
})
|
|
1276
1877
|
})
|
|
1277
1878
|
|
|
1278
|
-
describe('
|
|
1879
|
+
describe('route transfers OpenAPI', () => {
|
|
1279
1880
|
test('publishes generator-ready transfer contracts', async () => {
|
|
1280
1881
|
const spec = await (await create({ auth: false }).request('/openapi.json')).json()
|
|
1281
1882
|
const detailPath = Object.keys(spec.paths).find(
|
|
1282
|
-
(path) => path.includes('/v1/
|
|
1883
|
+
(path) => path.includes('/v1/routes/transfers/{') && !path.endsWith('/source-transactions'),
|
|
1283
1884
|
)!
|
|
1284
1885
|
const sourceTransactionPath = Object.keys(spec.paths).find((path) =>
|
|
1285
1886
|
path.endsWith('/source-transactions'),
|
|
1286
1887
|
)!
|
|
1287
1888
|
const operations = {
|
|
1288
|
-
create: spec.paths['/v1/
|
|
1289
|
-
createVault: spec.paths['/v1/
|
|
1290
|
-
createZone: spec.paths['/v1/
|
|
1889
|
+
create: spec.paths['/v1/routes/transfers'].post,
|
|
1890
|
+
createVault: spec.paths['/v1/routes/transfers/vault'].post,
|
|
1891
|
+
createZone: spec.paths['/v1/routes/transfers/zone'].post,
|
|
1291
1892
|
get: spec.paths[detailPath].get,
|
|
1292
|
-
list: spec.paths['/v1/
|
|
1893
|
+
list: spec.paths['/v1/routes/transfers'].get,
|
|
1293
1894
|
registerSourceTransaction: spec.paths[sourceTransactionPath].post,
|
|
1294
1895
|
}
|
|
1295
1896
|
const summarize = (operation: (typeof operations)[keyof typeof operations]) => ({
|
|
@@ -1308,34 +1909,34 @@ describe('funding transfers OpenAPI', () => {
|
|
|
1308
1909
|
|
|
1309
1910
|
expect({
|
|
1310
1911
|
components: [
|
|
1311
|
-
'
|
|
1312
|
-
'
|
|
1313
|
-
'
|
|
1314
|
-
'
|
|
1315
|
-
'
|
|
1316
|
-
'
|
|
1317
|
-
'
|
|
1318
|
-
'
|
|
1319
|
-
'
|
|
1320
|
-
'
|
|
1321
|
-
'
|
|
1322
|
-
'
|
|
1323
|
-
'
|
|
1912
|
+
'CreateRoutesTransferRequest',
|
|
1913
|
+
'CreateRoutesTransferVaultRequest',
|
|
1914
|
+
'CreateRoutesTransferZoneRequest',
|
|
1915
|
+
'CreatedRoutesTransfer',
|
|
1916
|
+
'RoutesAction',
|
|
1917
|
+
'RoutesActionCall',
|
|
1918
|
+
'RoutesEvmCallsAction',
|
|
1919
|
+
'RoutesTransfer',
|
|
1920
|
+
'RoutesTransferFee',
|
|
1921
|
+
'RoutesTransferList',
|
|
1922
|
+
'RoutesTransferQuote',
|
|
1923
|
+
'RoutesTransferStatusReason',
|
|
1924
|
+
'RegisterRoutesTransferSourceTransactionRequest',
|
|
1324
1925
|
].filter((name) => spec.components.schemas[name]),
|
|
1325
1926
|
formats: {
|
|
1326
|
-
createdAt: spec.components.schemas.
|
|
1327
|
-
quoteExpiresAt: spec.components.schemas.
|
|
1328
|
-
quoteSampledAt: spec.components.schemas.
|
|
1329
|
-
updatedAt: spec.components.schemas.
|
|
1927
|
+
createdAt: spec.components.schemas.RoutesTransfer.properties.createdAt.format,
|
|
1928
|
+
quoteExpiresAt: spec.components.schemas.RoutesTransferQuote.properties.expiresAt.format,
|
|
1929
|
+
quoteSampledAt: spec.components.schemas.RoutesTransferQuote.properties.sampledAt.format,
|
|
1930
|
+
updatedAt: spec.components.schemas.RoutesTransfer.properties.updatedAt.format,
|
|
1330
1931
|
},
|
|
1331
1932
|
models: {
|
|
1332
|
-
action: spec.components.schemas.
|
|
1333
|
-
createdAction: spec.components.schemas.
|
|
1334
|
-
evmCall: spec.components.schemas.
|
|
1335
|
-
feeToken: spec.components.schemas.
|
|
1336
|
-
list: spec.components.schemas.
|
|
1337
|
-
quote: spec.components.schemas.
|
|
1338
|
-
statusReason: spec.components.schemas.
|
|
1933
|
+
action: spec.components.schemas.RoutesAction.oneOf,
|
|
1934
|
+
createdAction: spec.components.schemas.CreatedRoutesTransfer.properties.action,
|
|
1935
|
+
evmCall: spec.components.schemas.RoutesEvmCallsAction.properties.calls.items,
|
|
1936
|
+
feeToken: spec.components.schemas.RoutesTransferFee.properties.token,
|
|
1937
|
+
list: spec.components.schemas.RoutesTransferList.properties.data.items,
|
|
1938
|
+
quote: spec.components.schemas.RoutesTransfer.properties.quote,
|
|
1939
|
+
statusReason: spec.components.schemas.RoutesTransfer.properties.statusReason,
|
|
1339
1940
|
},
|
|
1340
1941
|
operations: {
|
|
1341
1942
|
create: summarize(operations.create),
|
|
@@ -1363,25 +1964,24 @@ describe('funding transfers OpenAPI', () => {
|
|
|
1363
1964
|
quoteNotAvailable:
|
|
1364
1965
|
spec.components.schemas.QuoteNotAvailableError.properties.error.properties.code.enum,
|
|
1365
1966
|
transferNotFound:
|
|
1366
|
-
spec.components.schemas.
|
|
1367
|
-
.enum,
|
|
1967
|
+
spec.components.schemas.RoutesTransferNotFoundError.properties.error.properties.code.enum,
|
|
1368
1968
|
},
|
|
1369
1969
|
}).toMatchInlineSnapshot(`
|
|
1370
1970
|
{
|
|
1371
1971
|
"components": [
|
|
1372
|
-
"
|
|
1373
|
-
"
|
|
1374
|
-
"
|
|
1375
|
-
"
|
|
1376
|
-
"
|
|
1377
|
-
"
|
|
1378
|
-
"
|
|
1379
|
-
"
|
|
1380
|
-
"
|
|
1381
|
-
"
|
|
1382
|
-
"
|
|
1383
|
-
"
|
|
1384
|
-
"
|
|
1972
|
+
"CreateRoutesTransferRequest",
|
|
1973
|
+
"CreateRoutesTransferVaultRequest",
|
|
1974
|
+
"CreateRoutesTransferZoneRequest",
|
|
1975
|
+
"CreatedRoutesTransfer",
|
|
1976
|
+
"RoutesAction",
|
|
1977
|
+
"RoutesActionCall",
|
|
1978
|
+
"RoutesEvmCallsAction",
|
|
1979
|
+
"RoutesTransfer",
|
|
1980
|
+
"RoutesTransferFee",
|
|
1981
|
+
"RoutesTransferList",
|
|
1982
|
+
"RoutesTransferQuote",
|
|
1983
|
+
"RoutesTransferStatusReason",
|
|
1984
|
+
"RegisterRoutesTransferSourceTransactionRequest",
|
|
1385
1985
|
],
|
|
1386
1986
|
"formats": {
|
|
1387
1987
|
"createdAt": "date-time",
|
|
@@ -1392,26 +1992,26 @@ describe('funding transfers OpenAPI', () => {
|
|
|
1392
1992
|
"models": {
|
|
1393
1993
|
"action": [
|
|
1394
1994
|
{
|
|
1395
|
-
"$ref": "#/components/schemas/
|
|
1995
|
+
"$ref": "#/components/schemas/RoutesEvmCallsAction",
|
|
1396
1996
|
},
|
|
1397
1997
|
],
|
|
1398
1998
|
"createdAction": {
|
|
1399
|
-
"$ref": "#/components/schemas/
|
|
1999
|
+
"$ref": "#/components/schemas/RoutesAction",
|
|
1400
2000
|
},
|
|
1401
2001
|
"evmCall": {
|
|
1402
|
-
"$ref": "#/components/schemas/
|
|
2002
|
+
"$ref": "#/components/schemas/RoutesActionCall",
|
|
1403
2003
|
},
|
|
1404
2004
|
"feeToken": {
|
|
1405
|
-
"$ref": "#/components/schemas/
|
|
2005
|
+
"$ref": "#/components/schemas/RoutesToken",
|
|
1406
2006
|
},
|
|
1407
2007
|
"list": {
|
|
1408
|
-
"$ref": "#/components/schemas/
|
|
2008
|
+
"$ref": "#/components/schemas/RoutesTransfer",
|
|
1409
2009
|
},
|
|
1410
2010
|
"quote": {
|
|
1411
|
-
"$ref": "#/components/schemas/
|
|
2011
|
+
"$ref": "#/components/schemas/RoutesTransferQuote",
|
|
1412
2012
|
},
|
|
1413
2013
|
"statusReason": {
|
|
1414
|
-
"$ref": "#/components/schemas/
|
|
2014
|
+
"$ref": "#/components/schemas/RoutesTransferStatusReason",
|
|
1415
2015
|
},
|
|
1416
2016
|
},
|
|
1417
2017
|
"operationErrorCodes": {
|
|
@@ -1439,7 +2039,7 @@ describe('funding transfers OpenAPI', () => {
|
|
|
1439
2039
|
"quote_not_available",
|
|
1440
2040
|
],
|
|
1441
2041
|
"transferNotFound": [
|
|
1442
|
-
"
|
|
2042
|
+
"routes_transfer_not_found",
|
|
1443
2043
|
],
|
|
1444
2044
|
},
|
|
1445
2045
|
"operations": {
|
|
@@ -1452,7 +2052,7 @@ describe('funding transfers OpenAPI', () => {
|
|
|
1452
2052
|
"$ref": "#/components/schemas/AuthenticationError",
|
|
1453
2053
|
},
|
|
1454
2054
|
"403": {
|
|
1455
|
-
"$ref": "#/components/schemas/
|
|
2055
|
+
"$ref": "#/components/schemas/ApiKeyForbiddenOrApiKeyIpForbiddenOrBillingPastDueOrBillingRequiredOrForbiddenOrRoutesSubsidyLimitExceededOrRoutesSubsidyNotEnabledError",
|
|
1456
2056
|
},
|
|
1457
2057
|
"404": {
|
|
1458
2058
|
"$ref": "#/components/schemas/QuoteNotAvailableError",
|
|
@@ -1462,17 +2062,23 @@ describe('funding transfers OpenAPI', () => {
|
|
|
1462
2062
|
},
|
|
1463
2063
|
"429": "#/components/responses/RateLimited",
|
|
1464
2064
|
"500": "#/components/responses/InternalError",
|
|
2065
|
+
"501": {
|
|
2066
|
+
"$ref": "#/components/schemas/NotImplemented501Error",
|
|
2067
|
+
},
|
|
1465
2068
|
"502": {
|
|
1466
2069
|
"$ref": "#/components/schemas/UpstreamError",
|
|
1467
2070
|
},
|
|
2071
|
+
"503": {
|
|
2072
|
+
"$ref": "#/components/schemas/SubsidyInventoryUnavailableOrSubsidySignerUnavailableError",
|
|
2073
|
+
},
|
|
1468
2074
|
"504": "#/components/responses/RequestTimeout",
|
|
1469
2075
|
},
|
|
1470
|
-
"operationId": "
|
|
2076
|
+
"operationId": "createRoutesTransfer",
|
|
1471
2077
|
"request": {
|
|
1472
|
-
"$ref": "#/components/schemas/
|
|
2078
|
+
"$ref": "#/components/schemas/CreateRoutesTransferRequest",
|
|
1473
2079
|
},
|
|
1474
2080
|
"response": {
|
|
1475
|
-
"$ref": "#/components/schemas/
|
|
2081
|
+
"$ref": "#/components/schemas/CreatedRoutesTransfer",
|
|
1476
2082
|
},
|
|
1477
2083
|
},
|
|
1478
2084
|
"createVault": {
|
|
@@ -1493,9 +2099,9 @@ describe('funding transfers OpenAPI', () => {
|
|
|
1493
2099
|
},
|
|
1494
2100
|
"504": "#/components/responses/RequestTimeout",
|
|
1495
2101
|
},
|
|
1496
|
-
"operationId": "
|
|
2102
|
+
"operationId": "createRoutesTransferVault",
|
|
1497
2103
|
"request": {
|
|
1498
|
-
"$ref": "#/components/schemas/
|
|
2104
|
+
"$ref": "#/components/schemas/CreateRoutesTransferVaultRequest",
|
|
1499
2105
|
},
|
|
1500
2106
|
"response": undefined,
|
|
1501
2107
|
},
|
|
@@ -1517,9 +2123,9 @@ describe('funding transfers OpenAPI', () => {
|
|
|
1517
2123
|
},
|
|
1518
2124
|
"504": "#/components/responses/RequestTimeout",
|
|
1519
2125
|
},
|
|
1520
|
-
"operationId": "
|
|
2126
|
+
"operationId": "createRoutesTransferZone",
|
|
1521
2127
|
"request": {
|
|
1522
|
-
"$ref": "#/components/schemas/
|
|
2128
|
+
"$ref": "#/components/schemas/CreateRoutesTransferZoneRequest",
|
|
1523
2129
|
},
|
|
1524
2130
|
"response": undefined,
|
|
1525
2131
|
},
|
|
@@ -1535,7 +2141,7 @@ describe('funding transfers OpenAPI', () => {
|
|
|
1535
2141
|
"$ref": "#/components/schemas/ForbiddenError",
|
|
1536
2142
|
},
|
|
1537
2143
|
"404": {
|
|
1538
|
-
"$ref": "#/components/schemas/
|
|
2144
|
+
"$ref": "#/components/schemas/RoutesTransferNotFoundError",
|
|
1539
2145
|
},
|
|
1540
2146
|
"429": "#/components/responses/RateLimited",
|
|
1541
2147
|
"500": "#/components/responses/InternalError",
|
|
@@ -1544,10 +2150,10 @@ describe('funding transfers OpenAPI', () => {
|
|
|
1544
2150
|
},
|
|
1545
2151
|
"504": "#/components/responses/RequestTimeout",
|
|
1546
2152
|
},
|
|
1547
|
-
"operationId": "
|
|
2153
|
+
"operationId": "getRoutesTransfer",
|
|
1548
2154
|
"request": undefined,
|
|
1549
2155
|
"response": {
|
|
1550
|
-
"$ref": "#/components/schemas/
|
|
2156
|
+
"$ref": "#/components/schemas/RoutesTransfer",
|
|
1551
2157
|
},
|
|
1552
2158
|
},
|
|
1553
2159
|
"list": {
|
|
@@ -1568,10 +2174,10 @@ describe('funding transfers OpenAPI', () => {
|
|
|
1568
2174
|
},
|
|
1569
2175
|
"504": "#/components/responses/RequestTimeout",
|
|
1570
2176
|
},
|
|
1571
|
-
"operationId": "
|
|
2177
|
+
"operationId": "listRoutesTransfers",
|
|
1572
2178
|
"request": undefined,
|
|
1573
2179
|
"response": {
|
|
1574
|
-
"$ref": "#/components/schemas/
|
|
2180
|
+
"$ref": "#/components/schemas/RoutesTransferList",
|
|
1575
2181
|
},
|
|
1576
2182
|
},
|
|
1577
2183
|
"registerSourceTransaction": {
|
|
@@ -1586,10 +2192,10 @@ describe('funding transfers OpenAPI', () => {
|
|
|
1586
2192
|
"$ref": "#/components/schemas/ForbiddenError",
|
|
1587
2193
|
},
|
|
1588
2194
|
"404": {
|
|
1589
|
-
"$ref": "#/components/schemas/
|
|
2195
|
+
"$ref": "#/components/schemas/RoutesTransferNotFoundError",
|
|
1590
2196
|
},
|
|
1591
2197
|
"409": {
|
|
1592
|
-
"$ref": "#/components/schemas/
|
|
2198
|
+
"$ref": "#/components/schemas/RoutesTransferNotAwaitingSourceOrSourceTransactionConflictOrSourceTransactionPendingError",
|
|
1593
2199
|
},
|
|
1594
2200
|
"429": "#/components/responses/RateLimited",
|
|
1595
2201
|
"500": "#/components/responses/InternalError",
|
|
@@ -1601,12 +2207,12 @@ describe('funding transfers OpenAPI', () => {
|
|
|
1601
2207
|
},
|
|
1602
2208
|
"504": "#/components/responses/RequestTimeout",
|
|
1603
2209
|
},
|
|
1604
|
-
"operationId": "
|
|
2210
|
+
"operationId": "registerRoutesTransferSourceTransaction",
|
|
1605
2211
|
"request": {
|
|
1606
|
-
"$ref": "#/components/schemas/
|
|
2212
|
+
"$ref": "#/components/schemas/RegisterRoutesTransferSourceTransactionRequest",
|
|
1607
2213
|
},
|
|
1608
2214
|
"response": {
|
|
1609
|
-
"$ref": "#/components/schemas/
|
|
2215
|
+
"$ref": "#/components/schemas/RoutesTransfer",
|
|
1610
2216
|
},
|
|
1611
2217
|
},
|
|
1612
2218
|
},
|
|
@@ -1616,7 +2222,24 @@ describe('funding transfers OpenAPI', () => {
|
|
|
1616
2222
|
|
|
1617
2223
|
test('publishes an executable account transfer example', async () => {
|
|
1618
2224
|
const app = create({ auth: false })
|
|
1619
|
-
type TransferExample = {
|
|
2225
|
+
type TransferExample = {
|
|
2226
|
+
action: RoutesAction.EvmCalls
|
|
2227
|
+
destinationAmountMin: { baseUnits: string }
|
|
2228
|
+
destinationAmountRequired: { baseUnits: string }
|
|
2229
|
+
destinationChain: { id: string }
|
|
2230
|
+
destinationToken: { address: string }
|
|
2231
|
+
fees: readonly {
|
|
2232
|
+
amount: { baseUnits: string }
|
|
2233
|
+
side: string
|
|
2234
|
+
token: { address?: string | undefined; standard: string; symbol: string }
|
|
2235
|
+
}[]
|
|
2236
|
+
recipient: string
|
|
2237
|
+
sender: string
|
|
2238
|
+
sourceAmount: { baseUnits: string }
|
|
2239
|
+
sourceChain: { id: string }
|
|
2240
|
+
sourceToken: { address: string }
|
|
2241
|
+
subsidize: boolean
|
|
2242
|
+
}
|
|
1620
2243
|
type Operation = {
|
|
1621
2244
|
requestBody: {
|
|
1622
2245
|
content: Record<string, { schema: JsonSchema }>
|
|
@@ -1625,16 +2248,127 @@ describe('funding transfers OpenAPI', () => {
|
|
|
1625
2248
|
}
|
|
1626
2249
|
type Spec = ComponentSpec & { paths: Record<string, { post: Operation }> }
|
|
1627
2250
|
const spec = (await (await app.request('/openapi.json')).json()) as Spec
|
|
1628
|
-
const operation = spec.paths['/v1/
|
|
2251
|
+
const operation = spec.paths['/v1/routes/transfers']!.post
|
|
1629
2252
|
const request = dereference(spec, operation.requestBody.content['application/json']!.schema)
|
|
2253
|
+
const response = operation.responses['200']!.content['application/json']!.example
|
|
1630
2254
|
|
|
1631
2255
|
expect({
|
|
1632
|
-
request:
|
|
1633
|
-
|
|
1634
|
-
|
|
2256
|
+
request: {
|
|
2257
|
+
destinationChain: request.properties!['destinationChain']!.examples,
|
|
2258
|
+
destinationToken: request.properties!['destinationToken']!.examples,
|
|
2259
|
+
sourceChain: request.properties!['sourceChain']!.examples,
|
|
2260
|
+
sourceToken: request.properties!['sourceToken']!.examples,
|
|
2261
|
+
subsidyDescription: request.properties!['subsidize']!.description,
|
|
2262
|
+
subsidize: request.properties!['subsidize']!.examples,
|
|
2263
|
+
},
|
|
2264
|
+
response,
|
|
1635
2265
|
}).toEqual({
|
|
1636
|
-
request:
|
|
1637
|
-
|
|
2266
|
+
request: {
|
|
2267
|
+
destinationChain: ['base', 'ethereum', 'tempo', 'eip155:8453'],
|
|
2268
|
+
destinationToken: ['usdc', 'pathusd'],
|
|
2269
|
+
sourceChain: ['tempo', 'base', 'ethereum', 'eip155:4217'],
|
|
2270
|
+
sourceToken: ['usdce', 'usdc'],
|
|
2271
|
+
subsidyDescription:
|
|
2272
|
+
'Guarantees normalized 1:1 delivery for exact-source Tempo USD transfers to Base or Ethereum. A Tempo Admin must enable subsidies for the organization.',
|
|
2273
|
+
subsidize: [true],
|
|
2274
|
+
},
|
|
2275
|
+
response: expect.objectContaining({
|
|
2276
|
+
action: expect.objectContaining({ type: 'evm:calls' }),
|
|
2277
|
+
destinationAmountMin: expect.objectContaining({ baseUnits: '974398' }),
|
|
2278
|
+
destinationAmountRequired: expect.objectContaining({ baseUnits: '1000000' }),
|
|
2279
|
+
destinationChain: expect.objectContaining({ id: 'eip155:8453' }),
|
|
2280
|
+
destinationToken: expect.objectContaining({
|
|
2281
|
+
address: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
|
|
2282
|
+
}),
|
|
2283
|
+
fees: [
|
|
2284
|
+
expect.objectContaining({
|
|
2285
|
+
amount: expect.objectContaining({ baseUnits: '10000' }),
|
|
2286
|
+
side: 'source',
|
|
2287
|
+
token: expect.objectContaining({
|
|
2288
|
+
address: '0x20c0000000000000000000000000000000000000',
|
|
2289
|
+
standard: 'TIP-20',
|
|
2290
|
+
symbol: 'pathUSD',
|
|
2291
|
+
}),
|
|
2292
|
+
}),
|
|
2293
|
+
],
|
|
2294
|
+
sourceChain: expect.objectContaining({ id: 'eip155:4217' }),
|
|
2295
|
+
sourceToken: expect.objectContaining({
|
|
2296
|
+
address: '0x20c000000000000000000000b9537d11c60e8b50',
|
|
2297
|
+
}),
|
|
2298
|
+
subsidize: true,
|
|
2299
|
+
}),
|
|
2300
|
+
})
|
|
2301
|
+
const calls = response.action.calls
|
|
2302
|
+
expect(calls).toHaveLength(5)
|
|
2303
|
+
expect(calls.map((call) => ({ to: call.to, value: call.value }))).toEqual([
|
|
2304
|
+
{ to: response.sourceToken.address, value: '0x0' },
|
|
2305
|
+
{ to: response.fees[0]!.token.address, value: '0x0' },
|
|
2306
|
+
{ to: '0x0cEb237E109eE22374a567c6b09F373C73FA4cBb', value: '0x0' },
|
|
2307
|
+
{ to: '0x0cEb237E109eE22374a567c6b09F373C73FA4cBb', value: '0x0' },
|
|
2308
|
+
{ to: '0x8c76e2f6c5ceda9aa7772e7eff30280226c44392', value: '0x0' },
|
|
2309
|
+
])
|
|
2310
|
+
const approve = AbiFunction.from('function approve(address spender, uint256 amount)')
|
|
2311
|
+
const wrap = AbiFunction.from('function wrap(address token, address to, uint256 amount)')
|
|
2312
|
+
const send = AbiFunction.from(
|
|
2313
|
+
'function send((uint32 dstEid, bytes32 to, uint256 amountLD, uint256 minAmountLD, bytes extraOptions, bytes composeMsg, bytes oftCmd) sendParam, (uint256 nativeFee, uint256 lzTokenFee) fee, address refundAddress) payable returns ((bytes32 guid, uint64 nonce, (uint256 nativeFee, uint256 lzTokenFee) fee) msgReceipt, (uint256 amountSentLD, uint256 amountReceivedLD) oftReceipt)',
|
|
2314
|
+
)
|
|
2315
|
+
expect(AbiFunction.decodeData(approve, calls[0]!.data as Hex.Hex)).toEqual([
|
|
2316
|
+
'0x8c76e2f6c5ceda9aa7772e7eff30280226c44392',
|
|
2317
|
+
1_000_000n,
|
|
2318
|
+
])
|
|
2319
|
+
expect(AbiFunction.decodeData(approve, calls[1]!.data as Hex.Hex)).toEqual([
|
|
2320
|
+
'0x0ceb237e109ee22374a567c6b09f373c73fa4cbb',
|
|
2321
|
+
10_000n,
|
|
2322
|
+
])
|
|
2323
|
+
expect(AbiFunction.decodeData(wrap, calls[2]!.data as Hex.Hex)).toEqual([
|
|
2324
|
+
'0x20c0000000000000000000000000000000000000',
|
|
2325
|
+
response.sender,
|
|
2326
|
+
10_000n,
|
|
2327
|
+
])
|
|
2328
|
+
expect(AbiFunction.decodeData(approve, calls[3]!.data as Hex.Hex)).toEqual([
|
|
2329
|
+
'0x8c76e2f6c5ceda9aa7772e7eff30280226c44392',
|
|
2330
|
+
10_000n,
|
|
2331
|
+
])
|
|
2332
|
+
const [sendParameters, messagingFee, refundAddress] = AbiFunction.decodeData(
|
|
2333
|
+
send,
|
|
2334
|
+
calls[4]!.data as Hex.Hex,
|
|
2335
|
+
)
|
|
2336
|
+
expect(sendParameters).toMatchObject({
|
|
2337
|
+
amountLD: 1_000_000n,
|
|
2338
|
+
dstEid: 30_184,
|
|
2339
|
+
minAmountLD: 974_398n,
|
|
2340
|
+
})
|
|
2341
|
+
expect(messagingFee).toEqual({ lzTokenFee: 0n, nativeFee: 10_000n })
|
|
2342
|
+
expect(refundAddress).toBe(response.sender)
|
|
2343
|
+
expect(
|
|
2344
|
+
Stargate.validateAction({
|
|
2345
|
+
action: response.action,
|
|
2346
|
+
configuration: {
|
|
2347
|
+
destinationPoolAddress: '0x27a16dc786820b16e5c9028b75b99f6f604b5d26',
|
|
2348
|
+
poolAddress: '0x8c76e2f6c5ceda9aa7772e7eff30280226c44392',
|
|
2349
|
+
},
|
|
2350
|
+
destinationAmountMin: response.destinationAmountMin.baseUnits,
|
|
2351
|
+
destinationChainId: response.destinationChain.id,
|
|
2352
|
+
destinationTokenAddress: response.destinationToken.address,
|
|
2353
|
+
recipient: response.recipient,
|
|
2354
|
+
sender: response.sender,
|
|
2355
|
+
sourceAmount: response.sourceAmount.baseUnits,
|
|
2356
|
+
sourceChainId: response.sourceChain.id,
|
|
2357
|
+
sourceTokenAddress: response.sourceToken.address,
|
|
2358
|
+
}),
|
|
2359
|
+
).toEqual({
|
|
2360
|
+
tokenApprovals: [
|
|
2361
|
+
{
|
|
2362
|
+
amount: '10000',
|
|
2363
|
+
spender: '0x0cEb237E109eE22374a567c6b09F373C73FA4cBb',
|
|
2364
|
+
token: '0x20C0000000000000000000000000000000000000',
|
|
2365
|
+
},
|
|
2366
|
+
{
|
|
2367
|
+
amount: '10000',
|
|
2368
|
+
spender: '0x8c76e2F6C5ceDA9AA7772e7efF30280226c44392',
|
|
2369
|
+
token: '0x0cEb237E109eE22374a567c6b09F373C73FA4cBb',
|
|
2370
|
+
},
|
|
2371
|
+
],
|
|
1638
2372
|
})
|
|
1639
2373
|
})
|
|
1640
2374
|
|
|
@@ -1649,7 +2383,7 @@ describe('funding transfers OpenAPI', () => {
|
|
|
1649
2383
|
const spec = (await (await app.request('/openapi.json')).json()) as Spec
|
|
1650
2384
|
const properties = dereference(
|
|
1651
2385
|
spec,
|
|
1652
|
-
spec.paths['/v1/
|
|
2386
|
+
spec.paths['/v1/routes/deposit-addresses']!.post.requestBody.content['application/json']!
|
|
1653
2387
|
.schema,
|
|
1654
2388
|
).properties!
|
|
1655
2389
|
|
|
@@ -1683,19 +2417,19 @@ describe('funding transfers OpenAPI', () => {
|
|
|
1683
2417
|
}
|
|
1684
2418
|
const spec = (await (await app.request('/openapi.json')).json()) as Spec
|
|
1685
2419
|
const detailPath = Object.keys(spec.paths).find(
|
|
1686
|
-
(path) => path.includes('/v1/
|
|
2420
|
+
(path) => path.includes('/v1/routes/transfers/{') && !path.endsWith('/source-transactions'),
|
|
1687
2421
|
)!
|
|
1688
2422
|
const sourceTransactionPath = Object.keys(spec.paths).find((path) =>
|
|
1689
2423
|
path.endsWith('/source-transactions'),
|
|
1690
2424
|
)!
|
|
1691
2425
|
const depositAddressPath = Object.keys(spec.paths).find(
|
|
1692
2426
|
(path) =>
|
|
1693
|
-
path.includes('/v1/
|
|
2427
|
+
path.includes('/v1/routes/deposit-addresses/{') &&
|
|
1694
2428
|
!path.endsWith('/deposits') &&
|
|
1695
2429
|
!path.endsWith('/reconcile'),
|
|
1696
2430
|
)!
|
|
1697
2431
|
const depositPath = Object.keys(spec.paths).find((path) =>
|
|
1698
|
-
path.includes('/v1/
|
|
2432
|
+
path.includes('/v1/routes/deposits/{'),
|
|
1699
2433
|
)!
|
|
1700
2434
|
const reconcilePath = Object.keys(spec.paths).find((path) => path.endsWith('/reconcile'))!
|
|
1701
2435
|
const summarize = (operation: Operation) => ({
|
|
@@ -1703,23 +2437,23 @@ describe('funding transfers OpenAPI', () => {
|
|
|
1703
2437
|
summary: operation.summary,
|
|
1704
2438
|
})
|
|
1705
2439
|
const operations = {
|
|
1706
|
-
account: summarize(spec.paths['/v1/
|
|
1707
|
-
chains: summarize(spec.paths['/v1/
|
|
2440
|
+
account: summarize(spec.paths['/v1/routes/transfers']!.post!),
|
|
2441
|
+
chains: summarize(spec.paths['/v1/routes/chains']!.get!),
|
|
1708
2442
|
deposit: summarize(spec.paths[depositPath]!.get!),
|
|
1709
2443
|
depositAddress: summarize(spec.paths[depositAddressPath]!.get!),
|
|
1710
|
-
depositAddressCreate: summarize(spec.paths['/v1/
|
|
1711
|
-
depositAddressList: summarize(spec.paths['/v1/
|
|
2444
|
+
depositAddressCreate: summarize(spec.paths['/v1/routes/deposit-addresses']!.post!),
|
|
2445
|
+
depositAddressList: summarize(spec.paths['/v1/routes/deposit-addresses']!.get!),
|
|
1712
2446
|
depositAddressReconcile: summarize(spec.paths[reconcilePath]!.post!),
|
|
1713
|
-
deposits: summarize(spec.paths['/v1/
|
|
2447
|
+
deposits: summarize(spec.paths['/v1/routes/deposits']!.get!),
|
|
1714
2448
|
detail: summarize(spec.paths[detailPath]!.get!),
|
|
1715
|
-
list: summarize(spec.paths['/v1/
|
|
1716
|
-
providers: summarize(spec.paths['/v1/
|
|
1717
|
-
quotes: summarize(spec.paths['/v1/
|
|
2449
|
+
list: summarize(spec.paths['/v1/routes/transfers']!.get!),
|
|
2450
|
+
providers: summarize(spec.paths['/v1/routes/providers']!.get!),
|
|
2451
|
+
quotes: summarize(spec.paths['/v1/routes/quotes']!.get!),
|
|
1718
2452
|
sourceTransaction: summarize(spec.paths[sourceTransactionPath]!.post!),
|
|
1719
|
-
vault: summarize(spec.paths['/v1/
|
|
1720
|
-
zone: summarize(spec.paths['/v1/
|
|
2453
|
+
vault: summarize(spec.paths['/v1/routes/transfers/vault']!.post!),
|
|
2454
|
+
zone: summarize(spec.paths['/v1/routes/transfers/zone']!.post!),
|
|
1721
2455
|
}
|
|
1722
|
-
const category = spec['x-tagGroups'].find((group) => group.name === '
|
|
2456
|
+
const category = spec['x-tagGroups'].find((group) => group.name === 'Routes API')
|
|
1723
2457
|
const categoryTags = new Set(category?.tags)
|
|
1724
2458
|
const sidebar = Object.values(spec.paths).flatMap((path) =>
|
|
1725
2459
|
[path.get, path.post].flatMap((operation) =>
|
|
@@ -1736,10 +2470,10 @@ describe('funding transfers OpenAPI', () => {
|
|
|
1736
2470
|
sidebar,
|
|
1737
2471
|
}).toMatchInlineSnapshot(`
|
|
1738
2472
|
{
|
|
1739
|
-
"category": "
|
|
2473
|
+
"category": "Routes API",
|
|
1740
2474
|
"operations": {
|
|
1741
2475
|
"account": {
|
|
1742
|
-
"description": "Creates a transfer
|
|
2476
|
+
"description": "Creates a durable transfer between supported chains, including optional normalized destination subsidies.",
|
|
1743
2477
|
"summary": "Create transfer",
|
|
1744
2478
|
},
|
|
1745
2479
|
"chains": {
|
|
@@ -1751,19 +2485,19 @@ describe('funding transfers OpenAPI', () => {
|
|
|
1751
2485
|
"summary": "Get deposit",
|
|
1752
2486
|
},
|
|
1753
2487
|
"depositAddress": {
|
|
1754
|
-
"description": "Returns one reusable
|
|
2488
|
+
"description": "Returns one reusable route deposit address.",
|
|
1755
2489
|
"summary": "Get deposit address",
|
|
1756
2490
|
},
|
|
1757
2491
|
"depositAddressCreate": {
|
|
1758
|
-
"description": "Creates or returns a reusable deposit address for
|
|
2492
|
+
"description": "Creates or returns a reusable deposit address for routes a Tempo account.",
|
|
1759
2493
|
"summary": "Create deposit address",
|
|
1760
2494
|
},
|
|
1761
2495
|
"depositAddressList": {
|
|
1762
|
-
"description": "Lists reusable
|
|
2496
|
+
"description": "Lists reusable route deposit addresses, newest first.",
|
|
1763
2497
|
"summary": "List deposit addresses",
|
|
1764
2498
|
},
|
|
1765
2499
|
"depositAddressReconcile": {
|
|
1766
|
-
"description": "Queues an immediate provider reconciliation for one reusable
|
|
2500
|
+
"description": "Queues an immediate provider reconciliation for one reusable route deposit address.",
|
|
1767
2501
|
"summary": "Reconcile deposit address",
|
|
1768
2502
|
},
|
|
1769
2503
|
"deposits": {
|
|
@@ -1783,11 +2517,11 @@ describe('funding transfers OpenAPI', () => {
|
|
|
1783
2517
|
"summary": "Get providers",
|
|
1784
2518
|
},
|
|
1785
2519
|
"quotes": {
|
|
1786
|
-
"description": "Returns live quotes for transferring stablecoins
|
|
2520
|
+
"description": "Returns live quotes for transferring stablecoins between supported chains.",
|
|
1787
2521
|
"summary": "Get quotes",
|
|
1788
2522
|
},
|
|
1789
2523
|
"sourceTransaction": {
|
|
1790
|
-
"description": "Registers
|
|
2524
|
+
"description": "Registers verified source transactions once per organization, environment, and project.",
|
|
1791
2525
|
"summary": "Register source transaction",
|
|
1792
2526
|
},
|
|
1793
2527
|
"vault": {
|
|
@@ -1839,7 +2573,7 @@ describe('funding transfers OpenAPI', () => {
|
|
|
1839
2573
|
const creationSchema = (path: string) =>
|
|
1840
2574
|
dereference(spec, spec.paths[path]!.post!.requestBody.content['application/json']!.schema)
|
|
1841
2575
|
expect(
|
|
1842
|
-
creationSchema('/v1/
|
|
2576
|
+
creationSchema('/v1/routes/deposit-addresses').required?.includes('subsidize') ?? false,
|
|
1843
2577
|
).toMatchInlineSnapshot(`false`)
|
|
1844
2578
|
const summarize = (path: string) => {
|
|
1845
2579
|
const schema = creationSchema(path)
|
|
@@ -1850,21 +2584,22 @@ describe('funding transfers OpenAPI', () => {
|
|
|
1850
2584
|
}
|
|
1851
2585
|
|
|
1852
2586
|
expect({
|
|
1853
|
-
account: summarize('/v1/
|
|
1854
|
-
depositAddress: summarize('/v1/
|
|
2587
|
+
account: summarize('/v1/routes/transfers'),
|
|
2588
|
+
depositAddress: summarize('/v1/routes/deposit-addresses'),
|
|
1855
2589
|
depositAddressResponses: Object.keys(
|
|
1856
|
-
spec.paths['/v1/
|
|
2590
|
+
spec.paths['/v1/routes/deposit-addresses']!.post!.responses,
|
|
1857
2591
|
),
|
|
1858
|
-
vault: summarize('/v1/
|
|
1859
|
-
vaultResponses: Object.keys(spec.paths['/v1/
|
|
1860
|
-
zone: summarize('/v1/
|
|
1861
|
-
zoneResponses: Object.keys(spec.paths['/v1/
|
|
2592
|
+
vault: summarize('/v1/routes/transfers/vault'),
|
|
2593
|
+
vaultResponses: Object.keys(spec.paths['/v1/routes/transfers/vault']!.post!.responses),
|
|
2594
|
+
zone: summarize('/v1/routes/transfers/zone'),
|
|
2595
|
+
zoneResponses: Object.keys(spec.paths['/v1/routes/transfers/zone']!.post!.responses),
|
|
1862
2596
|
}).toMatchInlineSnapshot(`
|
|
1863
2597
|
{
|
|
1864
2598
|
"account": {
|
|
1865
2599
|
"additionalProperties": false,
|
|
1866
2600
|
"properties": [
|
|
1867
2601
|
"amount",
|
|
2602
|
+
"destinationChain",
|
|
1868
2603
|
"destinationToken",
|
|
1869
2604
|
"mode",
|
|
1870
2605
|
"provider",
|
|
@@ -1873,6 +2608,7 @@ describe('funding transfers OpenAPI', () => {
|
|
|
1873
2608
|
"slippageBps",
|
|
1874
2609
|
"sourceChain",
|
|
1875
2610
|
"sourceToken",
|
|
2611
|
+
"subsidize",
|
|
1876
2612
|
],
|
|
1877
2613
|
},
|
|
1878
2614
|
"depositAddress": {
|
|
@@ -1962,13 +2698,13 @@ describe('funding transfers OpenAPI', () => {
|
|
|
1962
2698
|
}
|
|
1963
2699
|
>
|
|
1964
2700
|
}
|
|
1965
|
-
const operation = spec.paths['/v1/
|
|
2701
|
+
const operation = spec.paths['/v1/routes/transfers']!.get
|
|
1966
2702
|
const fields = Object.keys(operation.responses['200']!.content['application/json']!.example.data[0]!) // prettier-ignore
|
|
1967
2703
|
expect(fields).toEqual([...fields].sort())
|
|
1968
2704
|
for (const route of [
|
|
1969
2705
|
operation,
|
|
1970
|
-
spec.paths['/v1/
|
|
1971
|
-
spec.paths['/v1/
|
|
2706
|
+
spec.paths['/v1/routes/deposit-addresses']!.get,
|
|
2707
|
+
spec.paths['/v1/routes/deposits']!.get,
|
|
1972
2708
|
])
|
|
1973
2709
|
for (const parameter of route.parameters ?? [])
|
|
1974
2710
|
expect(parameter.example ?? parameter.schema?.examples, parameter.name).toBeDefined()
|
|
@@ -1990,70 +2726,70 @@ describe('funding transfers OpenAPI', () => {
|
|
|
1990
2726
|
>
|
|
1991
2727
|
}
|
|
1992
2728
|
const detailPath = Object.keys(spec.paths).find(
|
|
1993
|
-
(path) => path.includes('/v1/
|
|
2729
|
+
(path) => path.includes('/v1/routes/transfers/{') && !path.endsWith('/source-transactions'),
|
|
1994
2730
|
)
|
|
1995
2731
|
const sourceTransactionPath = Object.keys(spec.paths).find((path) =>
|
|
1996
2732
|
path.endsWith('/source-transactions'),
|
|
1997
2733
|
)
|
|
1998
2734
|
const depositAddressPath = Object.keys(spec.paths).find(
|
|
1999
2735
|
(path) =>
|
|
2000
|
-
path.includes('/v1/
|
|
2736
|
+
path.includes('/v1/routes/deposit-addresses/{') &&
|
|
2001
2737
|
!path.endsWith('/deposits') &&
|
|
2002
2738
|
!path.endsWith('/reconcile'),
|
|
2003
2739
|
)
|
|
2004
2740
|
const depositPath = Object.keys(spec.paths).find((path) =>
|
|
2005
|
-
path.includes('/v1/
|
|
2741
|
+
path.includes('/v1/routes/deposits/{'),
|
|
2006
2742
|
)
|
|
2007
2743
|
const reconcilePath = Object.keys(spec.paths).find((path) => path.endsWith('/reconcile'))
|
|
2008
2744
|
expect({
|
|
2009
2745
|
deposit: depositPath && spec.paths[depositPath]?.get.operationId,
|
|
2010
2746
|
depositAddress: depositAddressPath && spec.paths[depositAddressPath]?.get.operationId,
|
|
2011
|
-
depositAddressCreate: spec.paths['/v1/
|
|
2747
|
+
depositAddressCreate: spec.paths['/v1/routes/deposit-addresses']?.post?.operationId,
|
|
2012
2748
|
depositAddressCreateScopes:
|
|
2013
|
-
spec.paths['/v1/
|
|
2014
|
-
depositAddressList: spec.paths['/v1/
|
|
2749
|
+
spec.paths['/v1/routes/deposit-addresses']?.post?.['x-required-scopes'],
|
|
2750
|
+
depositAddressList: spec.paths['/v1/routes/deposit-addresses']?.get.operationId,
|
|
2015
2751
|
depositAddressListScopes:
|
|
2016
|
-
spec.paths['/v1/
|
|
2752
|
+
spec.paths['/v1/routes/deposit-addresses']?.get['x-required-scopes'],
|
|
2017
2753
|
depositAddressReconcile: reconcilePath && spec.paths[reconcilePath]?.post?.operationId,
|
|
2018
2754
|
depositAddressReconcileScopes:
|
|
2019
2755
|
reconcilePath && spec.paths[reconcilePath]?.post?.['x-required-scopes'],
|
|
2020
2756
|
depositAddressScopes:
|
|
2021
2757
|
depositAddressPath && spec.paths[depositAddressPath]?.get['x-required-scopes'],
|
|
2022
2758
|
depositScopes: depositPath && spec.paths[depositPath]?.get['x-required-scopes'],
|
|
2023
|
-
deposits: spec.paths['/v1/
|
|
2024
|
-
depositsScopes: spec.paths['/v1/
|
|
2759
|
+
deposits: spec.paths['/v1/routes/deposits']?.get.operationId,
|
|
2760
|
+
depositsScopes: spec.paths['/v1/routes/deposits']?.get['x-required-scopes'],
|
|
2025
2761
|
detail: detailPath && spec.paths[detailPath]?.get.operationId,
|
|
2026
2762
|
detailScopes: detailPath && spec.paths[detailPath]?.get['x-required-scopes'],
|
|
2027
|
-
list: spec.paths['/v1/
|
|
2028
|
-
listScopes: spec.paths['/v1/
|
|
2029
|
-
requiredCreateHeader: spec.paths['/v1/
|
|
2763
|
+
list: spec.paths['/v1/routes/transfers']?.get.operationId,
|
|
2764
|
+
listScopes: spec.paths['/v1/routes/transfers']?.get['x-required-scopes'],
|
|
2765
|
+
requiredCreateHeader: spec.paths['/v1/routes/transfers']?.post?.parameters.find(
|
|
2030
2766
|
(parameter) => parameter.name === 'idempotency-key',
|
|
2031
2767
|
),
|
|
2032
2768
|
sourceTransaction:
|
|
2033
2769
|
sourceTransactionPath && spec.paths[sourceTransactionPath]?.post?.operationId,
|
|
2034
2770
|
sourceTransactionScopes:
|
|
2035
2771
|
sourceTransactionPath && spec.paths[sourceTransactionPath]?.post?.['x-required-scopes'],
|
|
2036
|
-
vault: spec.paths['/v1/
|
|
2037
|
-
vaultScopes: spec.paths['/v1/
|
|
2038
|
-
zone: spec.paths['/v1/
|
|
2039
|
-
zoneScopes: spec.paths['/v1/
|
|
2772
|
+
vault: spec.paths['/v1/routes/transfers/vault']?.post?.operationId,
|
|
2773
|
+
vaultScopes: spec.paths['/v1/routes/transfers/vault']?.post?.['x-required-scopes'],
|
|
2774
|
+
zone: spec.paths['/v1/routes/transfers/zone']?.post?.operationId,
|
|
2775
|
+
zoneScopes: spec.paths['/v1/routes/transfers/zone']?.post?.['x-required-scopes'],
|
|
2040
2776
|
}).toEqual({
|
|
2041
|
-
deposit: '
|
|
2042
|
-
depositAddress: '
|
|
2043
|
-
depositAddressCreate: '
|
|
2044
|
-
depositAddressCreateScopes: ['
|
|
2045
|
-
depositAddressList: '
|
|
2046
|
-
depositAddressListScopes: ['
|
|
2047
|
-
depositAddressReconcile: '
|
|
2048
|
-
depositAddressReconcileScopes: ['
|
|
2049
|
-
depositAddressScopes: ['
|
|
2050
|
-
depositScopes: ['
|
|
2051
|
-
deposits: '
|
|
2052
|
-
depositsScopes: ['
|
|
2053
|
-
detail: '
|
|
2054
|
-
detailScopes: ['
|
|
2055
|
-
list: '
|
|
2056
|
-
listScopes: ['
|
|
2777
|
+
deposit: 'getRoutesDeposit',
|
|
2778
|
+
depositAddress: 'getRoutesDepositAddress',
|
|
2779
|
+
depositAddressCreate: 'createRoutesDepositAddress',
|
|
2780
|
+
depositAddressCreateScopes: ['routes:write'],
|
|
2781
|
+
depositAddressList: 'listRoutesDepositAddresses',
|
|
2782
|
+
depositAddressListScopes: ['routes:read'],
|
|
2783
|
+
depositAddressReconcile: 'reconcileRoutesDepositAddress',
|
|
2784
|
+
depositAddressReconcileScopes: ['routes:write'],
|
|
2785
|
+
depositAddressScopes: ['routes:read'],
|
|
2786
|
+
depositScopes: ['routes:read'],
|
|
2787
|
+
deposits: 'listRoutesDeposits',
|
|
2788
|
+
depositsScopes: ['routes:read'],
|
|
2789
|
+
detail: 'getRoutesTransfer',
|
|
2790
|
+
detailScopes: ['routes:read'],
|
|
2791
|
+
list: 'listRoutesTransfers',
|
|
2792
|
+
listScopes: ['routes:read'],
|
|
2057
2793
|
requiredCreateHeader: expect.objectContaining({
|
|
2058
2794
|
description: expect.stringContaining('24 hours'),
|
|
2059
2795
|
in: 'header',
|
|
@@ -2061,69 +2797,80 @@ describe('funding transfers OpenAPI', () => {
|
|
|
2061
2797
|
required: true,
|
|
2062
2798
|
schema: expect.any(Object),
|
|
2063
2799
|
}),
|
|
2064
|
-
sourceTransaction: '
|
|
2065
|
-
sourceTransactionScopes: ['
|
|
2066
|
-
vault: '
|
|
2067
|
-
vaultScopes: ['
|
|
2068
|
-
zone: '
|
|
2069
|
-
zoneScopes: ['
|
|
2800
|
+
sourceTransaction: 'registerRoutesTransferSourceTransaction',
|
|
2801
|
+
sourceTransactionScopes: ['routes:write'],
|
|
2802
|
+
vault: 'createRoutesTransferVault',
|
|
2803
|
+
vaultScopes: ['routes:write'],
|
|
2804
|
+
zone: 'createRoutesTransferZone',
|
|
2805
|
+
zoneScopes: ['routes:write'],
|
|
2070
2806
|
})
|
|
2071
2807
|
})
|
|
2072
2808
|
})
|
|
2073
2809
|
|
|
2074
|
-
const
|
|
2075
|
-
id: '
|
|
2076
|
-
orgId: '
|
|
2077
|
-
scopes: ['
|
|
2078
|
-
token: '
|
|
2810
|
+
const routesReader = {
|
|
2811
|
+
id: 'key_routes',
|
|
2812
|
+
orgId: 'org_routes',
|
|
2813
|
+
scopes: ['routes:read'],
|
|
2814
|
+
token: 'secret_routes_reader',
|
|
2079
2815
|
} satisfies TestApp.kvStore.Key
|
|
2080
2816
|
|
|
2081
|
-
const
|
|
2082
|
-
id: '
|
|
2083
|
-
orgId: '
|
|
2084
|
-
projectId: '
|
|
2085
|
-
scopes: ['
|
|
2086
|
-
token: '
|
|
2817
|
+
const routesProjectReader = {
|
|
2818
|
+
id: 'key_routes_project',
|
|
2819
|
+
orgId: 'org_routes',
|
|
2820
|
+
projectId: 'prj_routes',
|
|
2821
|
+
scopes: ['routes:read'],
|
|
2822
|
+
token: 'secret_routes_project',
|
|
2087
2823
|
} satisfies TestApp.kvStore.Key
|
|
2088
2824
|
|
|
2089
|
-
const
|
|
2090
|
-
id: '
|
|
2091
|
-
orgId: '
|
|
2092
|
-
scopes: ['
|
|
2093
|
-
token: '
|
|
2825
|
+
const routesForeign = {
|
|
2826
|
+
id: 'key_routes_other',
|
|
2827
|
+
orgId: 'org_routes_other',
|
|
2828
|
+
scopes: ['routes:read', 'routes:write'],
|
|
2829
|
+
token: 'secret_routes_other',
|
|
2094
2830
|
} satisfies TestApp.kvStore.Key
|
|
2095
2831
|
|
|
2096
|
-
const
|
|
2097
|
-
id: '
|
|
2098
|
-
orgId: '
|
|
2099
|
-
scopes: ['
|
|
2100
|
-
token: '
|
|
2832
|
+
const routesWriter = {
|
|
2833
|
+
id: 'key_routes_writer',
|
|
2834
|
+
orgId: 'org_routes',
|
|
2835
|
+
scopes: ['routes:read', 'routes:write'],
|
|
2836
|
+
token: 'secret_routes_writer',
|
|
2101
2837
|
} satisfies TestApp.kvStore.Key
|
|
2102
2838
|
|
|
2103
2839
|
function transfersApp(options: TestApp.create.Options = {}) {
|
|
2104
2840
|
return create({
|
|
2105
2841
|
...options,
|
|
2106
2842
|
auth: {
|
|
2107
|
-
keys: [TestApp.key,
|
|
2843
|
+
keys: [TestApp.key, routesReader, routesProjectReader, routesForeign, routesWriter],
|
|
2108
2844
|
},
|
|
2845
|
+
db: options.db ?? db,
|
|
2109
2846
|
defaultChainId: options.defaultChainId ?? tempoMainnet.id,
|
|
2110
2847
|
})
|
|
2111
2848
|
}
|
|
2112
2849
|
|
|
2850
|
+
function transferSubsidy(maxAmount: string): RoutesTransferSubsidy.Inventory {
|
|
2851
|
+
return {
|
|
2852
|
+
account: `0x${'77'.repeat(20)}`,
|
|
2853
|
+
async check() {
|
|
2854
|
+
return { nativeAmount: '100' }
|
|
2855
|
+
},
|
|
2856
|
+
policy: { maxAmount },
|
|
2857
|
+
}
|
|
2858
|
+
}
|
|
2859
|
+
|
|
2113
2860
|
function as(key: { token: string }) {
|
|
2114
2861
|
return { headers: { authorization: `Bearer ${key.token}` } } as const
|
|
2115
2862
|
}
|
|
2116
2863
|
|
|
2117
2864
|
let seedSecond = 0
|
|
2118
2865
|
|
|
2119
|
-
function seedTransfer(input: Partial<
|
|
2866
|
+
function seedTransfer(input: Partial<RoutesTransfer.create.Input> = {}) {
|
|
2120
2867
|
// Distinct create times keep ids strictly ordered for paging assertions.
|
|
2121
|
-
return
|
|
2122
|
-
apiKeyId:
|
|
2868
|
+
return RoutesTransfer.create(db, {
|
|
2869
|
+
apiKeyId: routesReader.id,
|
|
2123
2870
|
environment: 'production',
|
|
2124
|
-
id:
|
|
2125
|
-
orgId:
|
|
2126
|
-
snapshot:
|
|
2871
|
+
id: RoutesTransfer.generateId(new Date(Date.UTC(2026, 0, 2, 0, 0, seedSecond++))),
|
|
2872
|
+
orgId: routesReader.orgId,
|
|
2873
|
+
snapshot: TestRoutes.transferSnapshot(),
|
|
2127
2874
|
...input,
|
|
2128
2875
|
})
|
|
2129
2876
|
}
|