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
|
@@ -2,39 +2,47 @@ import { Hash, Hex } from 'ox'
|
|
|
2
2
|
|
|
3
3
|
import { tempoMainnet } from 'viem/tempo/chains'
|
|
4
4
|
|
|
5
|
-
import * as
|
|
5
|
+
import * as RoutesDepositAddresses from '../../../db/tables/routesDepositAddresses.js'
|
|
6
6
|
|
|
7
|
-
import * as
|
|
7
|
+
import * as RoutesIdempotencyTable from '../../../db/tables/routesIdempotency.js'
|
|
8
|
+
|
|
9
|
+
import * as Organizations from '../../../db/tables/organizations.js'
|
|
10
|
+
|
|
11
|
+
import * as RoutesSubsidies from '../../../db/tables/routesSubsidies.js'
|
|
12
|
+
|
|
13
|
+
import * as StripeCustomers from '../../../db/tables/stripeCustomers.js'
|
|
8
14
|
|
|
9
15
|
import * as Cache from '../../../internal/Cache.js'
|
|
10
16
|
|
|
11
17
|
import * as Cursor from '../../../internal/Cursor.js'
|
|
12
18
|
|
|
13
|
-
import * as
|
|
19
|
+
import * as RoutesDeposit from '../../../internal/routes/Deposit.js'
|
|
14
20
|
|
|
15
|
-
import * as
|
|
21
|
+
import * as RoutesDepositAddress from '../../../internal/routes/DepositAddress.js'
|
|
16
22
|
|
|
17
|
-
import * as
|
|
23
|
+
import * as RoutesProvider from '../../../internal/routes/Provider.js'
|
|
18
24
|
|
|
19
25
|
import * as Idempotency from '../../../internal/Idempotency.js'
|
|
20
26
|
|
|
21
|
-
import * as Across from '../../../internal/
|
|
27
|
+
import * as Across from '../../../internal/routes/providers/across.js'
|
|
22
28
|
|
|
23
|
-
import * as Relay from '../../../internal/
|
|
29
|
+
import * as Relay from '../../../internal/routes/providers/relay.js'
|
|
24
30
|
|
|
25
|
-
import * as Rhino from '../../../internal/
|
|
31
|
+
import * as Rhino from '../../../internal/routes/providers/rhino.js'
|
|
26
32
|
|
|
27
|
-
import * as Squid from '../../../internal/
|
|
33
|
+
import * as Squid from '../../../internal/routes/providers/squid.js'
|
|
28
34
|
|
|
29
|
-
import * as Symbiosis from '../../../internal/
|
|
35
|
+
import * as Symbiosis from '../../../internal/routes/providers/symbiosis.js'
|
|
30
36
|
|
|
31
37
|
import type * as Log from '../../../internal/Log.js'
|
|
32
38
|
|
|
39
|
+
import * as Metrics from '../../../Metrics.js'
|
|
40
|
+
|
|
33
41
|
import * as TestApp from '../../../../test/App.js'
|
|
34
42
|
|
|
35
|
-
import * as
|
|
43
|
+
import * as TestRoutes from '../../../../test/Routes.js'
|
|
36
44
|
|
|
37
|
-
import * as
|
|
45
|
+
import * as Routes from './deposit-addresses.js'
|
|
38
46
|
|
|
39
47
|
const db = TestApp.database()
|
|
40
48
|
const relayApiKey = process.env.RELAY_API_KEY
|
|
@@ -45,7 +53,7 @@ const providers = [
|
|
|
45
53
|
integratorId: '0xdead',
|
|
46
54
|
userAddress: '0x1111111111111111111111111111111111111111',
|
|
47
55
|
}),
|
|
48
|
-
Relay.relay({ userAddresses:
|
|
56
|
+
Relay.relay({ userAddresses: TestRoutes.relayQuoteUsers }),
|
|
49
57
|
Rhino.rhino(),
|
|
50
58
|
Squid.squid({
|
|
51
59
|
integratorId: 'squid-integrator-id',
|
|
@@ -54,7 +62,7 @@ const providers = [
|
|
|
54
62
|
Symbiosis.symbiosis({ userAddress: '0x1111111111111111111111111111111111111111' }),
|
|
55
63
|
] as const
|
|
56
64
|
|
|
57
|
-
beforeAll(() =>
|
|
65
|
+
beforeAll(() => TestRoutes.publish(db))
|
|
58
66
|
|
|
59
67
|
function create(options: TestApp.create.Options = {}) {
|
|
60
68
|
return TestApp.create({ ...options, db })
|
|
@@ -80,21 +88,21 @@ function dereference(spec: ComponentSpec, schema: JsonSchema): JsonSchema {
|
|
|
80
88
|
return spec.components.schemas[name]!
|
|
81
89
|
}
|
|
82
90
|
|
|
83
|
-
test('publishes generator-ready
|
|
91
|
+
test('publishes generator-ready route deposit contracts', async () => {
|
|
84
92
|
const spec = await (await create({ auth: false }).request('/openapi.json')).json()
|
|
85
93
|
const depositAddressPath = Object.keys(spec.paths).find(
|
|
86
|
-
(path) => path.includes('/v1/
|
|
94
|
+
(path) => path.includes('/v1/routes/deposit-addresses/{') && !path.endsWith('/reconcile'),
|
|
87
95
|
)!
|
|
88
96
|
const depositPath = Object.keys(spec.paths).find((path) =>
|
|
89
|
-
path.includes('/v1/
|
|
97
|
+
path.includes('/v1/routes/deposits/{'),
|
|
90
98
|
)!
|
|
91
99
|
const reconcilePath = Object.keys(spec.paths).find((path) => path.endsWith('/reconcile'))!
|
|
92
100
|
const operations = {
|
|
93
|
-
createAddress: spec.paths['/v1/
|
|
101
|
+
createAddress: spec.paths['/v1/routes/deposit-addresses'].post,
|
|
94
102
|
getAddress: spec.paths[depositAddressPath].get,
|
|
95
103
|
getDeposit: spec.paths[depositPath].get,
|
|
96
|
-
listAddresses: spec.paths['/v1/
|
|
97
|
-
listDeposits: spec.paths['/v1/
|
|
104
|
+
listAddresses: spec.paths['/v1/routes/deposit-addresses'].get,
|
|
105
|
+
listDeposits: spec.paths['/v1/routes/deposits'].get,
|
|
98
106
|
reconcileAddress: spec.paths[reconcilePath].post,
|
|
99
107
|
}
|
|
100
108
|
const summarize = (operation: (typeof operations)[keyof typeof operations]) => ({
|
|
@@ -115,47 +123,47 @@ test('publishes generator-ready funding deposit contracts', async () => {
|
|
|
115
123
|
|
|
116
124
|
expect({
|
|
117
125
|
components: [
|
|
118
|
-
'
|
|
119
|
-
'
|
|
120
|
-
'
|
|
121
|
-
'
|
|
122
|
-
'
|
|
123
|
-
'
|
|
124
|
-
'
|
|
125
|
-
'
|
|
126
|
+
'CreateRoutesDepositAddressRequest',
|
|
127
|
+
'CreateRoutesDepositAddressResponse',
|
|
128
|
+
'CreatedRoutesDepositAddress',
|
|
129
|
+
'RoutesDeposit',
|
|
130
|
+
'RoutesDepositAddress',
|
|
131
|
+
'RoutesDepositAddressList',
|
|
132
|
+
'RoutesDepositList',
|
|
133
|
+
'RoutesDepositStatusReason',
|
|
126
134
|
].filter((name) => spec.components.schemas[name]),
|
|
127
135
|
formats: {
|
|
128
|
-
addressCreatedAt: spec.components.schemas.
|
|
129
|
-
addressUpdatedAt: spec.components.schemas.
|
|
130
|
-
depositCreatedAt: spec.components.schemas.
|
|
131
|
-
depositUpdatedAt: spec.components.schemas.
|
|
136
|
+
addressCreatedAt: spec.components.schemas.RoutesDepositAddress.properties.createdAt.format,
|
|
137
|
+
addressUpdatedAt: spec.components.schemas.RoutesDepositAddress.properties.updatedAt.format,
|
|
138
|
+
depositCreatedAt: spec.components.schemas.RoutesDeposit.properties.createdAt.format,
|
|
139
|
+
depositUpdatedAt: spec.components.schemas.RoutesDeposit.properties.updatedAt.format,
|
|
132
140
|
},
|
|
133
141
|
models: {
|
|
134
142
|
address: {
|
|
135
|
-
destinationChain: spec.components.schemas.
|
|
136
|
-
destinationToken: spec.components.schemas.
|
|
137
|
-
provider: spec.components.schemas.
|
|
138
|
-
sourceChain: spec.components.schemas.
|
|
139
|
-
sourceToken: spec.components.schemas.
|
|
143
|
+
destinationChain: spec.components.schemas.RoutesDepositAddress.properties.destinationChain,
|
|
144
|
+
destinationToken: spec.components.schemas.RoutesDepositAddress.properties.destinationToken,
|
|
145
|
+
provider: spec.components.schemas.RoutesDepositAddress.properties.provider,
|
|
146
|
+
sourceChain: spec.components.schemas.RoutesDepositAddress.properties.sourceChain,
|
|
147
|
+
sourceToken: spec.components.schemas.RoutesDepositAddress.properties.sourceToken,
|
|
140
148
|
},
|
|
141
|
-
addressList: spec.components.schemas.
|
|
142
|
-
createResponse: spec.components.schemas.
|
|
149
|
+
addressList: spec.components.schemas.RoutesDepositAddressList.properties.data.items,
|
|
150
|
+
createResponse: spec.components.schemas.CreateRoutesDepositAddressResponse.anyOf,
|
|
143
151
|
createdAddress: {
|
|
144
152
|
feeToken: dereference(
|
|
145
153
|
spec,
|
|
146
|
-
spec.components.schemas.
|
|
154
|
+
spec.components.schemas.CreatedRoutesDepositAddress.properties.fees.items,
|
|
147
155
|
).properties!['token'],
|
|
148
|
-
quote: spec.components.schemas.
|
|
156
|
+
quote: spec.components.schemas.CreatedRoutesDepositAddress.properties.quote,
|
|
149
157
|
},
|
|
150
158
|
deposit: {
|
|
151
|
-
destinationChain: spec.components.schemas.
|
|
152
|
-
destinationToken: spec.components.schemas.
|
|
153
|
-
provider: spec.components.schemas.
|
|
154
|
-
sourceChain: spec.components.schemas.
|
|
155
|
-
sourceToken: spec.components.schemas.
|
|
156
|
-
statusReason: spec.components.schemas.
|
|
159
|
+
destinationChain: spec.components.schemas.RoutesDeposit.properties.destinationChain,
|
|
160
|
+
destinationToken: spec.components.schemas.RoutesDeposit.properties.destinationToken,
|
|
161
|
+
provider: spec.components.schemas.RoutesDeposit.properties.provider,
|
|
162
|
+
sourceChain: spec.components.schemas.RoutesDeposit.properties.sourceChain,
|
|
163
|
+
sourceToken: spec.components.schemas.RoutesDeposit.properties.sourceToken,
|
|
164
|
+
statusReason: spec.components.schemas.RoutesDeposit.properties.statusReason,
|
|
157
165
|
},
|
|
158
|
-
depositList: spec.components.schemas.
|
|
166
|
+
depositList: spec.components.schemas.RoutesDepositList.properties.data.items,
|
|
159
167
|
},
|
|
160
168
|
operations: {
|
|
161
169
|
createAddress: summarize(operations.createAddress),
|
|
@@ -167,19 +175,19 @@ test('publishes generator-ready funding deposit contracts', async () => {
|
|
|
167
175
|
},
|
|
168
176
|
sharedErrorCodes: {
|
|
169
177
|
addressNotActive:
|
|
170
|
-
spec.components.schemas.
|
|
178
|
+
spec.components.schemas.RoutesDepositAddressNotActiveError.properties.error.properties.code
|
|
171
179
|
.enum,
|
|
172
180
|
addressNotAvailable:
|
|
173
181
|
spec.components.schemas.DepositAddressNotAvailableError.properties.error.properties.code
|
|
174
182
|
.enum,
|
|
175
183
|
addressNotFound:
|
|
176
|
-
spec.components.schemas.
|
|
184
|
+
spec.components.schemas.RoutesDepositAddressNotFoundError.properties.error.properties.code
|
|
177
185
|
.enum,
|
|
178
186
|
createInvalid:
|
|
179
187
|
spec.components.schemas.ApiKeyMalformedOrBodyInvalidOrIdempotencyKeyRequiredError.properties
|
|
180
188
|
.error.properties.code.enum,
|
|
181
189
|
depositNotFound:
|
|
182
|
-
spec.components.schemas.
|
|
190
|
+
spec.components.schemas.RoutesDepositNotFoundError.properties.error.properties.code.enum,
|
|
183
191
|
idempotencyConflict:
|
|
184
192
|
spec.components.schemas.IdempotencyConflictOrIdempotencyInProgressError.properties.error
|
|
185
193
|
.properties.code.enum,
|
|
@@ -191,18 +199,22 @@ test('publishes generator-ready funding deposit contracts', async () => {
|
|
|
191
199
|
queryInvalid:
|
|
192
200
|
spec.components.schemas.ApiKeyMalformedOrQueryInvalidError.properties.error.properties.code
|
|
193
201
|
.enum,
|
|
202
|
+
subsidyRejected:
|
|
203
|
+
spec.components.schemas.CreateRoutesDepositAddressForbiddenError.properties.error.properties
|
|
204
|
+
.code.enum,
|
|
194
205
|
},
|
|
206
|
+
statusReasons: spec.components.schemas.RoutesDepositStatusReason.properties.code.enum,
|
|
195
207
|
}).toMatchInlineSnapshot(`
|
|
196
208
|
{
|
|
197
209
|
"components": [
|
|
198
|
-
"
|
|
199
|
-
"
|
|
200
|
-
"
|
|
201
|
-
"
|
|
202
|
-
"
|
|
203
|
-
"
|
|
204
|
-
"
|
|
205
|
-
"
|
|
210
|
+
"CreateRoutesDepositAddressRequest",
|
|
211
|
+
"CreateRoutesDepositAddressResponse",
|
|
212
|
+
"CreatedRoutesDepositAddress",
|
|
213
|
+
"RoutesDeposit",
|
|
214
|
+
"RoutesDepositAddress",
|
|
215
|
+
"RoutesDepositAddressList",
|
|
216
|
+
"RoutesDepositList",
|
|
217
|
+
"RoutesDepositStatusReason",
|
|
206
218
|
],
|
|
207
219
|
"formats": {
|
|
208
220
|
"addressCreatedAt": "date-time",
|
|
@@ -213,62 +225,62 @@ test('publishes generator-ready funding deposit contracts', async () => {
|
|
|
213
225
|
"models": {
|
|
214
226
|
"address": {
|
|
215
227
|
"destinationChain": {
|
|
216
|
-
"$ref": "#/components/schemas/
|
|
228
|
+
"$ref": "#/components/schemas/RoutesChain",
|
|
217
229
|
},
|
|
218
230
|
"destinationToken": {
|
|
219
|
-
"$ref": "#/components/schemas/
|
|
231
|
+
"$ref": "#/components/schemas/RoutesToken",
|
|
220
232
|
},
|
|
221
233
|
"provider": {
|
|
222
|
-
"$ref": "#/components/schemas/
|
|
234
|
+
"$ref": "#/components/schemas/RoutesProvider",
|
|
223
235
|
},
|
|
224
236
|
"sourceChain": {
|
|
225
|
-
"$ref": "#/components/schemas/
|
|
237
|
+
"$ref": "#/components/schemas/RoutesChain",
|
|
226
238
|
},
|
|
227
239
|
"sourceToken": {
|
|
228
|
-
"$ref": "#/components/schemas/
|
|
240
|
+
"$ref": "#/components/schemas/RoutesToken",
|
|
229
241
|
},
|
|
230
242
|
},
|
|
231
243
|
"addressList": {
|
|
232
|
-
"$ref": "#/components/schemas/
|
|
244
|
+
"$ref": "#/components/schemas/RoutesDepositAddress",
|
|
233
245
|
},
|
|
234
246
|
"createResponse": [
|
|
235
247
|
{
|
|
236
|
-
"$ref": "#/components/schemas/
|
|
248
|
+
"$ref": "#/components/schemas/CreatedRoutesDepositAddress",
|
|
237
249
|
},
|
|
238
250
|
{
|
|
239
|
-
"$ref": "#/components/schemas/
|
|
251
|
+
"$ref": "#/components/schemas/RoutesDepositAddress",
|
|
240
252
|
},
|
|
241
253
|
],
|
|
242
254
|
"createdAddress": {
|
|
243
255
|
"feeToken": {
|
|
244
|
-
"$ref": "#/components/schemas/
|
|
256
|
+
"$ref": "#/components/schemas/RoutesToken",
|
|
245
257
|
},
|
|
246
258
|
"quote": {
|
|
247
|
-
"$ref": "#/components/schemas/
|
|
259
|
+
"$ref": "#/components/schemas/RoutesQuoteDetails",
|
|
248
260
|
},
|
|
249
261
|
},
|
|
250
262
|
"deposit": {
|
|
251
263
|
"destinationChain": {
|
|
252
|
-
"$ref": "#/components/schemas/
|
|
264
|
+
"$ref": "#/components/schemas/RoutesChain",
|
|
253
265
|
},
|
|
254
266
|
"destinationToken": {
|
|
255
|
-
"$ref": "#/components/schemas/
|
|
267
|
+
"$ref": "#/components/schemas/RoutesToken",
|
|
256
268
|
},
|
|
257
269
|
"provider": {
|
|
258
|
-
"$ref": "#/components/schemas/
|
|
270
|
+
"$ref": "#/components/schemas/RoutesProvider",
|
|
259
271
|
},
|
|
260
272
|
"sourceChain": {
|
|
261
|
-
"$ref": "#/components/schemas/
|
|
273
|
+
"$ref": "#/components/schemas/RoutesChain",
|
|
262
274
|
},
|
|
263
275
|
"sourceToken": {
|
|
264
|
-
"$ref": "#/components/schemas/
|
|
276
|
+
"$ref": "#/components/schemas/RoutesToken",
|
|
265
277
|
},
|
|
266
278
|
"statusReason": {
|
|
267
|
-
"$ref": "#/components/schemas/
|
|
279
|
+
"$ref": "#/components/schemas/RoutesDepositStatusReason",
|
|
268
280
|
},
|
|
269
281
|
},
|
|
270
282
|
"depositList": {
|
|
271
|
-
"$ref": "#/components/schemas/
|
|
283
|
+
"$ref": "#/components/schemas/RoutesDeposit",
|
|
272
284
|
},
|
|
273
285
|
},
|
|
274
286
|
"operations": {
|
|
@@ -281,7 +293,7 @@ test('publishes generator-ready funding deposit contracts', async () => {
|
|
|
281
293
|
"$ref": "#/components/schemas/AuthenticationError",
|
|
282
294
|
},
|
|
283
295
|
"403": {
|
|
284
|
-
"$ref": "#/components/schemas/
|
|
296
|
+
"$ref": "#/components/schemas/CreateRoutesDepositAddressForbiddenError",
|
|
285
297
|
},
|
|
286
298
|
"404": {
|
|
287
299
|
"$ref": "#/components/schemas/DepositAddressNotAvailableError",
|
|
@@ -296,12 +308,12 @@ test('publishes generator-ready funding deposit contracts', async () => {
|
|
|
296
308
|
},
|
|
297
309
|
"504": "#/components/responses/RequestTimeout",
|
|
298
310
|
},
|
|
299
|
-
"operationId": "
|
|
311
|
+
"operationId": "createRoutesDepositAddress",
|
|
300
312
|
"request": {
|
|
301
|
-
"$ref": "#/components/schemas/
|
|
313
|
+
"$ref": "#/components/schemas/CreateRoutesDepositAddressRequest",
|
|
302
314
|
},
|
|
303
315
|
"response": {
|
|
304
|
-
"$ref": "#/components/schemas/
|
|
316
|
+
"$ref": "#/components/schemas/CreateRoutesDepositAddressResponse",
|
|
305
317
|
},
|
|
306
318
|
},
|
|
307
319
|
"getAddress": {
|
|
@@ -316,7 +328,7 @@ test('publishes generator-ready funding deposit contracts', async () => {
|
|
|
316
328
|
"$ref": "#/components/schemas/ForbiddenError",
|
|
317
329
|
},
|
|
318
330
|
"404": {
|
|
319
|
-
"$ref": "#/components/schemas/
|
|
331
|
+
"$ref": "#/components/schemas/RoutesDepositAddressNotFoundError",
|
|
320
332
|
},
|
|
321
333
|
"429": "#/components/responses/RateLimited",
|
|
322
334
|
"500": "#/components/responses/InternalError",
|
|
@@ -325,10 +337,10 @@ test('publishes generator-ready funding deposit contracts', async () => {
|
|
|
325
337
|
},
|
|
326
338
|
"504": "#/components/responses/RequestTimeout",
|
|
327
339
|
},
|
|
328
|
-
"operationId": "
|
|
340
|
+
"operationId": "getRoutesDepositAddress",
|
|
329
341
|
"request": undefined,
|
|
330
342
|
"response": {
|
|
331
|
-
"$ref": "#/components/schemas/
|
|
343
|
+
"$ref": "#/components/schemas/RoutesDepositAddress",
|
|
332
344
|
},
|
|
333
345
|
},
|
|
334
346
|
"getDeposit": {
|
|
@@ -343,7 +355,7 @@ test('publishes generator-ready funding deposit contracts', async () => {
|
|
|
343
355
|
"$ref": "#/components/schemas/ForbiddenError",
|
|
344
356
|
},
|
|
345
357
|
"404": {
|
|
346
|
-
"$ref": "#/components/schemas/
|
|
358
|
+
"$ref": "#/components/schemas/RoutesDepositNotFoundError",
|
|
347
359
|
},
|
|
348
360
|
"429": "#/components/responses/RateLimited",
|
|
349
361
|
"500": "#/components/responses/InternalError",
|
|
@@ -352,10 +364,10 @@ test('publishes generator-ready funding deposit contracts', async () => {
|
|
|
352
364
|
},
|
|
353
365
|
"504": "#/components/responses/RequestTimeout",
|
|
354
366
|
},
|
|
355
|
-
"operationId": "
|
|
367
|
+
"operationId": "getRoutesDeposit",
|
|
356
368
|
"request": undefined,
|
|
357
369
|
"response": {
|
|
358
|
-
"$ref": "#/components/schemas/
|
|
370
|
+
"$ref": "#/components/schemas/RoutesDeposit",
|
|
359
371
|
},
|
|
360
372
|
},
|
|
361
373
|
"listAddresses": {
|
|
@@ -376,10 +388,10 @@ test('publishes generator-ready funding deposit contracts', async () => {
|
|
|
376
388
|
},
|
|
377
389
|
"504": "#/components/responses/RequestTimeout",
|
|
378
390
|
},
|
|
379
|
-
"operationId": "
|
|
391
|
+
"operationId": "listRoutesDepositAddresses",
|
|
380
392
|
"request": undefined,
|
|
381
393
|
"response": {
|
|
382
|
-
"$ref": "#/components/schemas/
|
|
394
|
+
"$ref": "#/components/schemas/RoutesDepositAddressList",
|
|
383
395
|
},
|
|
384
396
|
},
|
|
385
397
|
"listDeposits": {
|
|
@@ -400,10 +412,10 @@ test('publishes generator-ready funding deposit contracts', async () => {
|
|
|
400
412
|
},
|
|
401
413
|
"504": "#/components/responses/RequestTimeout",
|
|
402
414
|
},
|
|
403
|
-
"operationId": "
|
|
415
|
+
"operationId": "listRoutesDeposits",
|
|
404
416
|
"request": undefined,
|
|
405
417
|
"response": {
|
|
406
|
-
"$ref": "#/components/schemas/
|
|
418
|
+
"$ref": "#/components/schemas/RoutesDepositList",
|
|
407
419
|
},
|
|
408
420
|
},
|
|
409
421
|
"reconcileAddress": {
|
|
@@ -418,10 +430,10 @@ test('publishes generator-ready funding deposit contracts', async () => {
|
|
|
418
430
|
"$ref": "#/components/schemas/ForbiddenError",
|
|
419
431
|
},
|
|
420
432
|
"404": {
|
|
421
|
-
"$ref": "#/components/schemas/
|
|
433
|
+
"$ref": "#/components/schemas/RoutesDepositAddressNotFoundError",
|
|
422
434
|
},
|
|
423
435
|
"409": {
|
|
424
|
-
"$ref": "#/components/schemas/
|
|
436
|
+
"$ref": "#/components/schemas/RoutesDepositAddressNotActiveError",
|
|
425
437
|
},
|
|
426
438
|
"429": "#/components/responses/RateLimited",
|
|
427
439
|
"500": "#/components/responses/InternalError",
|
|
@@ -433,20 +445,20 @@ test('publishes generator-ready funding deposit contracts', async () => {
|
|
|
433
445
|
},
|
|
434
446
|
"504": "#/components/responses/RequestTimeout",
|
|
435
447
|
},
|
|
436
|
-
"operationId": "
|
|
448
|
+
"operationId": "reconcileRoutesDepositAddress",
|
|
437
449
|
"request": undefined,
|
|
438
450
|
"response": undefined,
|
|
439
451
|
},
|
|
440
452
|
},
|
|
441
453
|
"sharedErrorCodes": {
|
|
442
454
|
"addressNotActive": [
|
|
443
|
-
"
|
|
455
|
+
"routes_deposit_address_not_active",
|
|
444
456
|
],
|
|
445
457
|
"addressNotAvailable": [
|
|
446
458
|
"deposit_address_not_available",
|
|
447
459
|
],
|
|
448
460
|
"addressNotFound": [
|
|
449
|
-
"
|
|
461
|
+
"routes_deposit_address_not_found",
|
|
450
462
|
],
|
|
451
463
|
"createInvalid": [
|
|
452
464
|
"api_key_malformed",
|
|
@@ -454,7 +466,7 @@ test('publishes generator-ready funding deposit contracts', async () => {
|
|
|
454
466
|
"idempotency_key_required",
|
|
455
467
|
],
|
|
456
468
|
"depositNotFound": [
|
|
457
|
-
"
|
|
469
|
+
"routes_deposit_not_found",
|
|
458
470
|
],
|
|
459
471
|
"idempotencyConflict": [
|
|
460
472
|
"idempotency_conflict",
|
|
@@ -471,18 +483,41 @@ test('publishes generator-ready funding deposit contracts', async () => {
|
|
|
471
483
|
"api_key_malformed",
|
|
472
484
|
"query_invalid",
|
|
473
485
|
],
|
|
486
|
+
"subsidyRejected": [
|
|
487
|
+
"api_key_forbidden",
|
|
488
|
+
"api_key_ip_forbidden",
|
|
489
|
+
"billing_past_due",
|
|
490
|
+
"billing_required",
|
|
491
|
+
"forbidden",
|
|
492
|
+
"routes_deposit_address_limit_exceeded",
|
|
493
|
+
"routes_subsidy_not_enabled",
|
|
494
|
+
],
|
|
474
495
|
},
|
|
496
|
+
"statusReasons": [
|
|
497
|
+
"billing_past_due",
|
|
498
|
+
"billing_required",
|
|
499
|
+
"delivery_failed",
|
|
500
|
+
"delivery_liquidity_unavailable",
|
|
501
|
+
"manual_recovery_required",
|
|
502
|
+
"refund_failed",
|
|
503
|
+
"routes_subsidy_limit_exceeded",
|
|
504
|
+
"routes_subsidy_not_enabled",
|
|
505
|
+
"source_amount_not_supported",
|
|
506
|
+
"source_token_mismatch",
|
|
507
|
+
"subsidy_balance_unavailable",
|
|
508
|
+
"subsidy_failed",
|
|
509
|
+
],
|
|
475
510
|
}
|
|
476
511
|
`)
|
|
477
512
|
})
|
|
478
513
|
|
|
479
|
-
describe('POST /
|
|
480
|
-
test('requires
|
|
514
|
+
describe('POST /routes/deposit-addresses', () => {
|
|
515
|
+
test('requires routes:write and an idempotency key', async () => {
|
|
481
516
|
const app = transfersApp({ providers: [depositAddressProvider()] })
|
|
482
517
|
expect((await postDepositAddress(app, { headers: {} })).status).toBe(401)
|
|
483
|
-
expect((await postDepositAddress(app, { key:
|
|
518
|
+
expect((await postDepositAddress(app, { key: routesReader })).status).toBe(403)
|
|
484
519
|
const response = await postDepositAddress(app, {
|
|
485
|
-
headers: { authorization: `Bearer ${
|
|
520
|
+
headers: { authorization: `Bearer ${routesWriter.token}` },
|
|
486
521
|
})
|
|
487
522
|
expect(response.status).toBe(400)
|
|
488
523
|
expect(((await response.json()) as { error: { code: string } }).error.code).toBe(
|
|
@@ -524,11 +559,289 @@ describe('POST /funding/deposit-addresses', () => {
|
|
|
524
559
|
)
|
|
525
560
|
})
|
|
526
561
|
|
|
562
|
+
test('supports a legacy organization-less API key', async () => {
|
|
563
|
+
const response = await postDepositAddress(
|
|
564
|
+
transfersApp({
|
|
565
|
+
providers: [depositAddressProvider('TNWSLbWRWwZmFR2P1EV5ba53B5by2eqUkF')],
|
|
566
|
+
}),
|
|
567
|
+
{ key: routesLegacyWriter },
|
|
568
|
+
)
|
|
569
|
+
|
|
570
|
+
expect(response.status).toBe(200)
|
|
571
|
+
expect(await Organizations.get(db, routesLegacyWriter.id)).toMatchObject({
|
|
572
|
+
id: routesLegacyWriter.id,
|
|
573
|
+
userId: null,
|
|
574
|
+
})
|
|
575
|
+
})
|
|
576
|
+
|
|
577
|
+
test('rejects a missing policy, records its bounded reason, and releases the claim', async () => {
|
|
578
|
+
await Organizations.upsert(db, {
|
|
579
|
+
id: routesSubsidyDisabledWriter.orgId,
|
|
580
|
+
name: 'Routes subsidy disabled',
|
|
581
|
+
})
|
|
582
|
+
const counts: Parameters<Metrics.Metrics['count']>[] = []
|
|
583
|
+
const metrics = Metrics.from({
|
|
584
|
+
count(name, value, tags) {
|
|
585
|
+
counts.push([name, value, tags])
|
|
586
|
+
},
|
|
587
|
+
flush() {},
|
|
588
|
+
gauge() {},
|
|
589
|
+
histogram() {},
|
|
590
|
+
})
|
|
591
|
+
const app = transfersApp({
|
|
592
|
+
metrics,
|
|
593
|
+
providers: [depositAddressProvider('TFvF6WzyeRKMM8NcbddxL88mZXTeuUWA8Z')],
|
|
594
|
+
})
|
|
595
|
+
const body = { ...depositAddressBody, subsidize: true }
|
|
596
|
+
const idempotencyKey = nextDepositAddressKey()
|
|
597
|
+
const rejected = await postDepositAddress(app, {
|
|
598
|
+
body,
|
|
599
|
+
idempotencyKey,
|
|
600
|
+
key: routesSubsidyDisabledWriter,
|
|
601
|
+
})
|
|
602
|
+
|
|
603
|
+
expect({ body: await rejected.json(), status: rejected.status }).toMatchInlineSnapshot(
|
|
604
|
+
{
|
|
605
|
+
body: { requestId: expect.any(String) },
|
|
606
|
+
},
|
|
607
|
+
`
|
|
608
|
+
{
|
|
609
|
+
"body": {
|
|
610
|
+
"error": {
|
|
611
|
+
"code": "routes_subsidy_not_enabled",
|
|
612
|
+
"message": "Routes subsidies are not enabled for this organization.",
|
|
613
|
+
},
|
|
614
|
+
"requestId": Any<String>,
|
|
615
|
+
},
|
|
616
|
+
"status": 403,
|
|
617
|
+
}
|
|
618
|
+
`,
|
|
619
|
+
)
|
|
620
|
+
expect(counts.find(([name]) => name === 'routes_subsidy_request_rejection_count')).toEqual([
|
|
621
|
+
'routes_subsidy_request_rejection_count',
|
|
622
|
+
1,
|
|
623
|
+
{
|
|
624
|
+
reason: 'routes_subsidy_not_enabled',
|
|
625
|
+
routes_environment: 'production',
|
|
626
|
+
},
|
|
627
|
+
])
|
|
628
|
+
|
|
629
|
+
await enableRoutesSubsidy(routesSubsidyDisabledWriter, 'active')
|
|
630
|
+
expect(
|
|
631
|
+
(
|
|
632
|
+
await postDepositAddress(app, {
|
|
633
|
+
body,
|
|
634
|
+
idempotencyKey,
|
|
635
|
+
key: routesSubsidyDisabledWriter,
|
|
636
|
+
})
|
|
637
|
+
).status,
|
|
638
|
+
).toBe(200)
|
|
639
|
+
})
|
|
640
|
+
|
|
641
|
+
test('requires active production billing for an enabled policy', async () => {
|
|
642
|
+
await enableRoutesSubsidy(routesSubsidyBillingWriter)
|
|
643
|
+
await enableRoutesSubsidy(routesSubsidyPastDueWriter, 'past_due')
|
|
644
|
+
const app = transfersApp({ providers: [depositAddressProvider()] })
|
|
645
|
+
|
|
646
|
+
const required = await postDepositAddress(app, {
|
|
647
|
+
body: { ...depositAddressBody, subsidize: true },
|
|
648
|
+
key: routesSubsidyBillingWriter,
|
|
649
|
+
})
|
|
650
|
+
const pastDue = await postDepositAddress(app, {
|
|
651
|
+
body: { ...depositAddressBody, subsidize: true },
|
|
652
|
+
key: routesSubsidyPastDueWriter,
|
|
653
|
+
})
|
|
654
|
+
|
|
655
|
+
expect([
|
|
656
|
+
{ body: await required.json(), status: required.status },
|
|
657
|
+
{ body: await pastDue.json(), status: pastDue.status },
|
|
658
|
+
]).toMatchInlineSnapshot(
|
|
659
|
+
[{ body: { requestId: expect.any(String) } }, { body: { requestId: expect.any(String) } }],
|
|
660
|
+
`
|
|
661
|
+
[
|
|
662
|
+
{
|
|
663
|
+
"body": {
|
|
664
|
+
"error": {
|
|
665
|
+
"code": "billing_required",
|
|
666
|
+
"message": "Billing required.",
|
|
667
|
+
},
|
|
668
|
+
"requestId": Any<String>,
|
|
669
|
+
},
|
|
670
|
+
"status": 403,
|
|
671
|
+
},
|
|
672
|
+
{
|
|
673
|
+
"body": {
|
|
674
|
+
"error": {
|
|
675
|
+
"code": "billing_past_due",
|
|
676
|
+
"message": "Billing past due.",
|
|
677
|
+
},
|
|
678
|
+
"requestId": Any<String>,
|
|
679
|
+
},
|
|
680
|
+
"status": 403,
|
|
681
|
+
},
|
|
682
|
+
]
|
|
683
|
+
`,
|
|
684
|
+
)
|
|
685
|
+
})
|
|
686
|
+
|
|
687
|
+
test('replays a completed subsidy after policy and billing change', async () => {
|
|
688
|
+
await enableRoutesSubsidy(routesSubsidyReplayWriter, 'active')
|
|
689
|
+
const app = transfersApp({
|
|
690
|
+
providers: [depositAddressProvider('TG1YyTqihYBVjbzaoEm5gUdiZDNwHndhRg')],
|
|
691
|
+
})
|
|
692
|
+
const body = { ...depositAddressBody, subsidize: true }
|
|
693
|
+
const idempotencyKey = nextDepositAddressKey()
|
|
694
|
+
const first = await postDepositAddress(app, {
|
|
695
|
+
body,
|
|
696
|
+
idempotencyKey,
|
|
697
|
+
key: routesSubsidyReplayWriter,
|
|
698
|
+
})
|
|
699
|
+
const firstBody = await first.json()
|
|
700
|
+
await RoutesSubsidies.removeOrganization(db, routesSubsidyReplayWriter.orgId)
|
|
701
|
+
await StripeCustomers.setStatus(db, routesSubsidyReplayWriter.orgId, 'past_due')
|
|
702
|
+
const replay = await postDepositAddress(app, {
|
|
703
|
+
body,
|
|
704
|
+
idempotencyKey,
|
|
705
|
+
key: routesSubsidyReplayWriter,
|
|
706
|
+
})
|
|
707
|
+
|
|
708
|
+
expect({ body: await replay.json(), status: replay.status }).toEqual({ body: firstBody, status: 200 }) // prettier-ignore
|
|
709
|
+
})
|
|
710
|
+
|
|
711
|
+
test('preserves a subsidized claim after an ambiguous provider failure', async () => {
|
|
712
|
+
await enableRoutesSubsidy(routesSubsidyReplayWriter, 'active')
|
|
713
|
+
const app = transfersApp({
|
|
714
|
+
providers: [
|
|
715
|
+
depositAddressProvider(undefined, () => {
|
|
716
|
+
throw new Error('connection closed after dispatch')
|
|
717
|
+
}),
|
|
718
|
+
],
|
|
719
|
+
})
|
|
720
|
+
const body = {
|
|
721
|
+
...depositAddressBody,
|
|
722
|
+
recipient: `0x${'22'.repeat(20)}`,
|
|
723
|
+
subsidize: true,
|
|
724
|
+
}
|
|
725
|
+
const idempotencyKey = nextDepositAddressKey()
|
|
726
|
+
const first = await postDepositAddress(app, {
|
|
727
|
+
body,
|
|
728
|
+
idempotencyKey,
|
|
729
|
+
key: routesSubsidyReplayWriter,
|
|
730
|
+
})
|
|
731
|
+
const retry = await postDepositAddress(app, {
|
|
732
|
+
body,
|
|
733
|
+
idempotencyKey,
|
|
734
|
+
key: routesSubsidyReplayWriter,
|
|
735
|
+
})
|
|
736
|
+
|
|
737
|
+
expect([first.status, retry.status]).toEqual([502, 409])
|
|
738
|
+
await expect(
|
|
739
|
+
db.kysely
|
|
740
|
+
.selectFrom('routes_idempotency_requests')
|
|
741
|
+
.select(['irrevocable', 'status'])
|
|
742
|
+
.where('apiKeyId', '=', routesSubsidyReplayWriter.id)
|
|
743
|
+
.where('keyHash', '=', Idempotency.inputHash(idempotencyKey))
|
|
744
|
+
.executeTakeFirstOrThrow(),
|
|
745
|
+
).resolves.toEqual({ irrevocable: true, status: 'pending' })
|
|
746
|
+
})
|
|
747
|
+
|
|
748
|
+
test('resumes an expired provisioned subsidy without replaying stale quote terms', async () => {
|
|
749
|
+
await Organizations.upsert(db, {
|
|
750
|
+
id: routesSubsidyResumeWriter.orgId,
|
|
751
|
+
name: 'Routes subsidy resume',
|
|
752
|
+
})
|
|
753
|
+
const histograms: Parameters<Metrics.Metrics['histogram']>[] = []
|
|
754
|
+
const metrics = Metrics.from({
|
|
755
|
+
count() {},
|
|
756
|
+
flush() {},
|
|
757
|
+
gauge() {},
|
|
758
|
+
histogram(name, value, tags) {
|
|
759
|
+
histograms.push([name, value, tags])
|
|
760
|
+
},
|
|
761
|
+
})
|
|
762
|
+
const body = { ...depositAddressBody, subsidize: true }
|
|
763
|
+
const idempotencyKey = nextDepositAddressKey()
|
|
764
|
+
const identity = {
|
|
765
|
+
apiKeyId: routesSubsidyResumeWriter.id,
|
|
766
|
+
keyHash: Idempotency.inputHash(idempotencyKey),
|
|
767
|
+
requestHash: Idempotency.inputHash({
|
|
768
|
+
body,
|
|
769
|
+
endpoint: 'POST /v1/routes/deposit-addresses',
|
|
770
|
+
}),
|
|
771
|
+
}
|
|
772
|
+
const claim = await RoutesIdempotencyTable.claim(db, {
|
|
773
|
+
...identity,
|
|
774
|
+
irrevocable: true,
|
|
775
|
+
operation: RoutesIdempotencyTable.operations.depositAddress,
|
|
776
|
+
orgId: routesSubsidyResumeWriter.orgId,
|
|
777
|
+
ttlMs: 60_000,
|
|
778
|
+
})
|
|
779
|
+
if (claim.type !== 'claimed') throw new Error('Expected a fresh idempotency claim.')
|
|
780
|
+
const snapshot = TestRoutes.depositAddressSnapshot({
|
|
781
|
+
address: 'TG6rrQgTkf3e85cYzqtD2q8fYuJDdM99Rx',
|
|
782
|
+
subsidize: true,
|
|
783
|
+
})
|
|
784
|
+
await RoutesIdempotencyTable.checkpoint(db, {
|
|
785
|
+
apiKeyId: identity.apiKeyId,
|
|
786
|
+
createdAt: claim.createdAt,
|
|
787
|
+
keyHash: identity.keyHash,
|
|
788
|
+
replayTtlMs: 86_400_000,
|
|
789
|
+
response: JSON.stringify({
|
|
790
|
+
candidate: {
|
|
791
|
+
destinationChain: snapshot.destinationChain,
|
|
792
|
+
destinationToken: snapshot.destinationToken,
|
|
793
|
+
sourceChain: snapshot.sourceChain,
|
|
794
|
+
sourceToken: snapshot.sourceToken,
|
|
795
|
+
},
|
|
796
|
+
provider: snapshot.provider,
|
|
797
|
+
recipient: snapshot.recipient,
|
|
798
|
+
refundAddress: snapshot.refundAddress,
|
|
799
|
+
result: {
|
|
800
|
+
address: snapshot.address,
|
|
801
|
+
correlation: { requestId: 'relay_resume_request' },
|
|
802
|
+
destinationAmount: '1000000',
|
|
803
|
+
destinationAmountMin: '1000000',
|
|
804
|
+
fees: [],
|
|
805
|
+
sampledAt: '2026-08-04T00:00:00.000Z',
|
|
806
|
+
},
|
|
807
|
+
}),
|
|
808
|
+
})
|
|
809
|
+
await db.kysely
|
|
810
|
+
.updateTable('routes_idempotency_requests')
|
|
811
|
+
.set({ expiresAt: new Date(0).toISOString() })
|
|
812
|
+
.where('apiKeyId', '=', identity.apiKeyId)
|
|
813
|
+
.where('keyHash', '=', identity.keyHash)
|
|
814
|
+
.execute()
|
|
815
|
+
|
|
816
|
+
const response = await postDepositAddress(transfersApp({ metrics, providers: [] }), {
|
|
817
|
+
body,
|
|
818
|
+
idempotencyKey,
|
|
819
|
+
key: routesSubsidyResumeWriter,
|
|
820
|
+
})
|
|
821
|
+
|
|
822
|
+
expect(response.status).toBe(200)
|
|
823
|
+
const responseBody = await TestApp.json(
|
|
824
|
+
response,
|
|
825
|
+
Routes.schema.createRoutesDepositAddress.Response,
|
|
826
|
+
)
|
|
827
|
+
expect(responseBody.subsidize).toBe(true)
|
|
828
|
+
expect(responseBody).not.toHaveProperty('quote')
|
|
829
|
+
expect(
|
|
830
|
+
histograms.filter(
|
|
831
|
+
([name]) =>
|
|
832
|
+
name.startsWith('routes_customer_') ||
|
|
833
|
+
name.startsWith('routes_tempo_provider_fee_') ||
|
|
834
|
+
name === 'routes_selection_delta_bps',
|
|
835
|
+
),
|
|
836
|
+
).toEqual([])
|
|
837
|
+
})
|
|
838
|
+
|
|
527
839
|
test('creates a reusable address and persists private provider correlation', async () => {
|
|
528
|
-
|
|
529
|
-
|
|
840
|
+
await Organizations.upsert(db, { id: routesWriter.orgId, name: 'Routes' })
|
|
841
|
+
let seen: RoutesProvider.createDepositAddress.Parameters | undefined
|
|
842
|
+
const registered: RoutesDepositAddress.Public[] = []
|
|
530
843
|
const app = transfersApp({
|
|
531
|
-
|
|
844
|
+
routes: {
|
|
532
845
|
registerDepositAddress: async (address) => {
|
|
533
846
|
registered.push(address)
|
|
534
847
|
},
|
|
@@ -544,7 +857,7 @@ describe('POST /funding/deposit-addresses', () => {
|
|
|
544
857
|
})
|
|
545
858
|
expect(response.status).toBe(200)
|
|
546
859
|
expect(response.headers.get('cache-control')).toBe('no-store')
|
|
547
|
-
const body = await TestApp.json(response,
|
|
860
|
+
const body = await TestApp.json(response, Routes.schema.createRoutesDepositAddress.Response)
|
|
548
861
|
expect(body).toMatchObject({
|
|
549
862
|
address: 'TBXSw8fM4jpQkGc6zZjsVABFpVN7UvXPdV',
|
|
550
863
|
destinationToken: { symbol: 'USDT0' },
|
|
@@ -559,7 +872,7 @@ describe('POST /funding/deposit-addresses', () => {
|
|
|
559
872
|
recipient: depositAddressBody.recipient,
|
|
560
873
|
refundAddress: depositAddressBody.refundAddress,
|
|
561
874
|
})
|
|
562
|
-
const record = await
|
|
875
|
+
const record = await RoutesDepositAddresses.get(db, body.id)
|
|
563
876
|
expect(record).toMatchObject({
|
|
564
877
|
deliveryStrategy: 'provider',
|
|
565
878
|
providerOutputToken: body.destinationToken,
|
|
@@ -655,7 +968,7 @@ describe('POST /funding/deposit-addresses', () => {
|
|
|
655
968
|
sourceToken: identifier.sourceToken,
|
|
656
969
|
},
|
|
657
970
|
})
|
|
658
|
-
const body = await TestApp.json(response,
|
|
971
|
+
const body = await TestApp.json(response, Routes.schema.createRoutesDepositAddress.Response)
|
|
659
972
|
results.push({
|
|
660
973
|
destinationToken: body.destinationToken.symbol,
|
|
661
974
|
name: identifier.name,
|
|
@@ -700,14 +1013,14 @@ describe('POST /funding/deposit-addresses', () => {
|
|
|
700
1013
|
})
|
|
701
1014
|
const first = await TestApp.json(
|
|
702
1015
|
await postDepositAddress(app, { body, idempotencyKey: nextDepositAddressKey() }),
|
|
703
|
-
|
|
1016
|
+
Routes.schema.createRoutesDepositAddress.Response,
|
|
704
1017
|
)
|
|
705
1018
|
const second = await TestApp.json(
|
|
706
1019
|
await postDepositAddress(app, {
|
|
707
1020
|
body: { ...body, amount: '200000000' },
|
|
708
1021
|
idempotencyKey: nextDepositAddressKey(),
|
|
709
1022
|
}),
|
|
710
|
-
|
|
1023
|
+
Routes.schema.createRoutesDepositAddress.Response,
|
|
711
1024
|
)
|
|
712
1025
|
if (!('sourceAmount' in first)) throw new Error('Expected newly provisioned terms.')
|
|
713
1026
|
|
|
@@ -725,7 +1038,7 @@ describe('POST /funding/deposit-addresses', () => {
|
|
|
725
1038
|
},
|
|
726
1039
|
`
|
|
727
1040
|
{
|
|
728
|
-
"calls":
|
|
1041
|
+
"calls": 1,
|
|
729
1042
|
"firstHasQuote": true,
|
|
730
1043
|
"firstId": Any<String>,
|
|
731
1044
|
"firstSourceAmount": "100000000",
|
|
@@ -738,7 +1051,8 @@ describe('POST /funding/deposit-addresses', () => {
|
|
|
738
1051
|
})
|
|
739
1052
|
|
|
740
1053
|
test('stores subsidized addresses as a separate reusable identity', async () => {
|
|
741
|
-
|
|
1054
|
+
await enableRoutesSubsidy(routesSubsidyWriter, 'active')
|
|
1055
|
+
const inputs: RoutesProvider.createDepositAddress.Parameters[] = []
|
|
742
1056
|
const app = transfersApp({
|
|
743
1057
|
providers: [
|
|
744
1058
|
withCreateDepositAddress('relay', async (input) => {
|
|
@@ -761,12 +1075,15 @@ describe('POST /funding/deposit-addresses', () => {
|
|
|
761
1075
|
sourceToken: '0xfde4c96c8593536e31f229ea8f37b2ada2699bb2',
|
|
762
1076
|
}
|
|
763
1077
|
const standard = await TestApp.json(
|
|
764
|
-
await postDepositAddress(app, { body }),
|
|
765
|
-
|
|
1078
|
+
await postDepositAddress(app, { body, key: routesSubsidyWriter }),
|
|
1079
|
+
Routes.schema.createRoutesDepositAddress.Response,
|
|
766
1080
|
)
|
|
767
1081
|
const subsidized = await TestApp.json(
|
|
768
|
-
await postDepositAddress(app, {
|
|
769
|
-
|
|
1082
|
+
await postDepositAddress(app, {
|
|
1083
|
+
body: { ...body, subsidize: true },
|
|
1084
|
+
key: routesSubsidyWriter,
|
|
1085
|
+
}),
|
|
1086
|
+
Routes.schema.createRoutesDepositAddress.Response,
|
|
770
1087
|
)
|
|
771
1088
|
|
|
772
1089
|
expect({
|
|
@@ -787,8 +1104,37 @@ describe('POST /funding/deposit-addresses', () => {
|
|
|
787
1104
|
`)
|
|
788
1105
|
})
|
|
789
1106
|
|
|
1107
|
+
test('reuses a subsidized address across API keys in one organization', async () => {
|
|
1108
|
+
await enableRoutesSubsidy(routesSubsidyWriter, 'active')
|
|
1109
|
+
let calls = 0
|
|
1110
|
+
const app = transfersApp({
|
|
1111
|
+
providers: [
|
|
1112
|
+
depositAddressProvider(`0x${'34'.repeat(20)}`, () => {
|
|
1113
|
+
calls += 1
|
|
1114
|
+
}),
|
|
1115
|
+
],
|
|
1116
|
+
})
|
|
1117
|
+
const body = {
|
|
1118
|
+
...depositAddressBody,
|
|
1119
|
+
refundAddress: `0x${'35'.repeat(20)}`,
|
|
1120
|
+
sourceChain: 'base',
|
|
1121
|
+
sourceToken: '0xfde4c96c8593536e31f229ea8f37b2ada2699bb2',
|
|
1122
|
+
subsidize: true,
|
|
1123
|
+
}
|
|
1124
|
+
const first = await TestApp.json(
|
|
1125
|
+
await postDepositAddress(app, { body, key: routesSubsidyWriter }),
|
|
1126
|
+
Routes.schema.createRoutesDepositAddress.Response,
|
|
1127
|
+
)
|
|
1128
|
+
const second = await TestApp.json(
|
|
1129
|
+
await postDepositAddress(app, { body, key: routesSubsidyWriterSecond }),
|
|
1130
|
+
Routes.schema.createRoutesDepositAddress.Response,
|
|
1131
|
+
)
|
|
1132
|
+
|
|
1133
|
+
expect({ calls, reused: first.id === second.id }).toEqual({ calls: 1, reused: true })
|
|
1134
|
+
})
|
|
1135
|
+
|
|
790
1136
|
test('normalizes EVM accounts before provisioning and matching', async () => {
|
|
791
|
-
const inputs:
|
|
1137
|
+
const inputs: RoutesProvider.createDepositAddress.Parameters[] = []
|
|
792
1138
|
const recipient = '0xABcdEFABcdEFabcdEfAbCdefabcdeFABcDEFabCD'
|
|
793
1139
|
const refundAddress = '0x1234567890AbcdEF1234567890aBcdef12345678'
|
|
794
1140
|
const body = {
|
|
@@ -807,7 +1153,7 @@ describe('POST /funding/deposit-addresses', () => {
|
|
|
807
1153
|
})
|
|
808
1154
|
const first = await TestApp.json(
|
|
809
1155
|
await postDepositAddress(app, { body, idempotencyKey: nextDepositAddressKey() }),
|
|
810
|
-
|
|
1156
|
+
Routes.schema.createRoutesDepositAddress.Response,
|
|
811
1157
|
)
|
|
812
1158
|
const second = await TestApp.json(
|
|
813
1159
|
await postDepositAddress(app, {
|
|
@@ -818,7 +1164,7 @@ describe('POST /funding/deposit-addresses', () => {
|
|
|
818
1164
|
},
|
|
819
1165
|
idempotencyKey: nextDepositAddressKey(),
|
|
820
1166
|
}),
|
|
821
|
-
|
|
1167
|
+
Routes.schema.createRoutesDepositAddress.Response,
|
|
822
1168
|
)
|
|
823
1169
|
|
|
824
1170
|
expect({
|
|
@@ -837,10 +1183,6 @@ describe('POST /funding/deposit-addresses', () => {
|
|
|
837
1183
|
"recipient": "0xABcdEFABcdEFabcdEfAbCdefabcdeFABcDEFabCD",
|
|
838
1184
|
"refundAddress": "0x1234567890AbcdEF1234567890aBcdef12345678",
|
|
839
1185
|
},
|
|
840
|
-
{
|
|
841
|
-
"recipient": "0xABcdEFABcdEFabcdEfAbCdefabcdeFABcDEFabCD",
|
|
842
|
-
"refundAddress": "0x1234567890AbcdEF1234567890aBcdef12345678",
|
|
843
|
-
},
|
|
844
1186
|
],
|
|
845
1187
|
"reused": true,
|
|
846
1188
|
"second": {
|
|
@@ -860,7 +1202,7 @@ describe('POST /funding/deposit-addresses', () => {
|
|
|
860
1202
|
}),
|
|
861
1203
|
{ body, idempotencyKey: nextDepositAddressKey() },
|
|
862
1204
|
),
|
|
863
|
-
|
|
1205
|
+
Routes.schema.createRoutesDepositAddress.Response,
|
|
864
1206
|
)
|
|
865
1207
|
|
|
866
1208
|
let calls = 0
|
|
@@ -876,7 +1218,7 @@ describe('POST /funding/deposit-addresses', () => {
|
|
|
876
1218
|
body: { ...body, amount: '200000000' },
|
|
877
1219
|
idempotencyKey,
|
|
878
1220
|
})
|
|
879
|
-
const second = await TestApp.json(response,
|
|
1221
|
+
const second = await TestApp.json(response, Routes.schema.createRoutesDepositAddress.Response)
|
|
880
1222
|
|
|
881
1223
|
expect({
|
|
882
1224
|
address: second.address,
|
|
@@ -891,7 +1233,7 @@ describe('POST /funding/deposit-addresses', () => {
|
|
|
891
1233
|
`
|
|
892
1234
|
{
|
|
893
1235
|
"address": Any<String>,
|
|
894
|
-
"calls":
|
|
1236
|
+
"calls": 0,
|
|
895
1237
|
"hasQuote": false,
|
|
896
1238
|
"reused": true,
|
|
897
1239
|
"status": 200,
|
|
@@ -905,10 +1247,118 @@ describe('POST /funding/deposit-addresses', () => {
|
|
|
905
1247
|
body: { ...body, amount: '200000000' },
|
|
906
1248
|
idempotencyKey,
|
|
907
1249
|
}),
|
|
908
|
-
|
|
1250
|
+
Routes.schema.createRoutesDepositAddress.Response,
|
|
909
1251
|
),
|
|
910
1252
|
).toEqual(second)
|
|
911
|
-
expect(calls).toBe(
|
|
1253
|
+
expect(calls).toBe(0)
|
|
1254
|
+
})
|
|
1255
|
+
|
|
1256
|
+
test('retains the provider checkpoint when address persistence fails', async () => {
|
|
1257
|
+
const address = 'TKJebW6SdoJhgkKU13BeKCbrMzT6HeQhJ6'
|
|
1258
|
+
const body = { ...depositAddressBody, recipient: `0x${'66'.repeat(20)}` }
|
|
1259
|
+
const counts: Parameters<Metrics.Metrics['count']>[] = []
|
|
1260
|
+
const histograms: Parameters<Metrics.Metrics['histogram']>[] = []
|
|
1261
|
+
const metrics = Metrics.from({
|
|
1262
|
+
count(name, value, tags) {
|
|
1263
|
+
counts.push([name, value, tags])
|
|
1264
|
+
},
|
|
1265
|
+
flush() {},
|
|
1266
|
+
gauge() {},
|
|
1267
|
+
histogram(name, value, tags) {
|
|
1268
|
+
histograms.push([name, value, tags])
|
|
1269
|
+
},
|
|
1270
|
+
})
|
|
1271
|
+
await db.kysely.deleteFrom('routes_deposit_addresses').where('address', '=', address).execute()
|
|
1272
|
+
await seedDepositAddress({
|
|
1273
|
+
orgId: routesForeignWriter.orgId,
|
|
1274
|
+
snapshot: TestRoutes.depositAddressSnapshot({
|
|
1275
|
+
address,
|
|
1276
|
+
provider: { id: 'relay', name: 'Relay' },
|
|
1277
|
+
recipient: `0x${'33'.repeat(20)}`,
|
|
1278
|
+
}),
|
|
1279
|
+
})
|
|
1280
|
+
const idempotencyKey = nextDepositAddressKey()
|
|
1281
|
+
let calls = 0
|
|
1282
|
+
const app = transfersApp({
|
|
1283
|
+
metrics,
|
|
1284
|
+
providers: [
|
|
1285
|
+
depositAddressProvider(address, () => {
|
|
1286
|
+
calls += 1
|
|
1287
|
+
}),
|
|
1288
|
+
],
|
|
1289
|
+
})
|
|
1290
|
+
const response = await postDepositAddress(app, { body, idempotencyKey })
|
|
1291
|
+
|
|
1292
|
+
expect(response.status).toBe(502)
|
|
1293
|
+
await expect(
|
|
1294
|
+
db.kysely
|
|
1295
|
+
.selectFrom('routes_idempotency_requests')
|
|
1296
|
+
.select(['response', 'status'])
|
|
1297
|
+
.where('apiKeyId', '=', routesWriter.id)
|
|
1298
|
+
.where('keyHash', '=', Idempotency.inputHash(idempotencyKey))
|
|
1299
|
+
.executeTakeFirstOrThrow(),
|
|
1300
|
+
).resolves.toEqual({ response: expect.any(String), status: 'provisioned' })
|
|
1301
|
+
|
|
1302
|
+
await db.kysely
|
|
1303
|
+
.deleteFrom('routes_deposit_addresses')
|
|
1304
|
+
.where('orgId', '=', routesForeignWriter.orgId)
|
|
1305
|
+
.where('address', '=', address)
|
|
1306
|
+
.execute()
|
|
1307
|
+
const recoveredIdempotencyKey = nextDepositAddressKey()
|
|
1308
|
+
const recovered = await postDepositAddress(app, {
|
|
1309
|
+
body: { ...body, amount: '200000000' },
|
|
1310
|
+
idempotencyKey: recoveredIdempotencyKey,
|
|
1311
|
+
key: routesWriterSecond,
|
|
1312
|
+
})
|
|
1313
|
+
expect({ calls, status: recovered.status }).toEqual({ calls: 1, status: 200 })
|
|
1314
|
+
const recoveredBody = await TestApp.json(
|
|
1315
|
+
recovered,
|
|
1316
|
+
Routes.schema.createRoutesDepositAddress.Response,
|
|
1317
|
+
)
|
|
1318
|
+
expect(recoveredBody).toMatchObject({
|
|
1319
|
+
address,
|
|
1320
|
+
})
|
|
1321
|
+
expect(recoveredBody).not.toHaveProperty('quote')
|
|
1322
|
+
expect(counts.filter(([name]) => name === 'routes_resource_transition_count')).toEqual([
|
|
1323
|
+
[
|
|
1324
|
+
'routes_resource_transition_count',
|
|
1325
|
+
1,
|
|
1326
|
+
{
|
|
1327
|
+
from_status: 'none',
|
|
1328
|
+
method: 'deposit_address',
|
|
1329
|
+
provider: 'relay',
|
|
1330
|
+
reason: 'none',
|
|
1331
|
+
resource: 'deposit_address',
|
|
1332
|
+
routes_environment: 'production',
|
|
1333
|
+
to_status: 'active',
|
|
1334
|
+
},
|
|
1335
|
+
],
|
|
1336
|
+
])
|
|
1337
|
+
expect(
|
|
1338
|
+
histograms.filter(
|
|
1339
|
+
([name]) =>
|
|
1340
|
+
name.startsWith('routes_customer_') ||
|
|
1341
|
+
name.startsWith('routes_tempo_provider_fee_') ||
|
|
1342
|
+
name === 'routes_selection_delta_bps',
|
|
1343
|
+
),
|
|
1344
|
+
).toEqual([])
|
|
1345
|
+
const original = await postDepositAddress(app, { body, idempotencyKey })
|
|
1346
|
+
expect(
|
|
1347
|
+
await TestApp.json(original, Routes.schema.createRoutesDepositAddress.Response),
|
|
1348
|
+
).toMatchObject({ sourceAmount: { baseUnits: '100000000' } })
|
|
1349
|
+
await expect(
|
|
1350
|
+
db.kysely
|
|
1351
|
+
.selectFrom('routes_idempotency_requests')
|
|
1352
|
+
.select('status')
|
|
1353
|
+
.where('apiKeyId', 'in', [routesWriter.id, routesWriterSecond.id])
|
|
1354
|
+
.where('keyHash', 'in', [
|
|
1355
|
+
Idempotency.inputHash(idempotencyKey),
|
|
1356
|
+
Idempotency.inputHash(recoveredIdempotencyKey),
|
|
1357
|
+
])
|
|
1358
|
+
.where('operation', '=', RoutesIdempotencyTable.operations.depositAddress)
|
|
1359
|
+
.orderBy('apiKeyId')
|
|
1360
|
+
.execute(),
|
|
1361
|
+
).resolves.toEqual([{ status: 'completed' }, { status: 'completed' }])
|
|
912
1362
|
})
|
|
913
1363
|
|
|
914
1364
|
test('rejects a refund address from another chain', async () => {
|
|
@@ -969,12 +1419,12 @@ describe('POST /funding/deposit-addresses', () => {
|
|
|
969
1419
|
}
|
|
970
1420
|
const idempotencyKey = nextDepositAddressKey()
|
|
971
1421
|
const first = await postDepositAddress(app, { body: requestBody, idempotencyKey })
|
|
972
|
-
const response = await TestApp.json(first,
|
|
1422
|
+
const response = await TestApp.json(first, Routes.schema.createRoutesDepositAddress.Response)
|
|
973
1423
|
const { subsidize: _, ...legacy } = response
|
|
974
1424
|
await db.kysely
|
|
975
|
-
.updateTable('
|
|
1425
|
+
.updateTable('routes_idempotency_requests')
|
|
976
1426
|
.set({ response: JSON.stringify(legacy) })
|
|
977
|
-
.where('apiKeyId', '=',
|
|
1427
|
+
.where('apiKeyId', '=', routesWriter.id)
|
|
978
1428
|
.where('keyHash', '=', Idempotency.inputHash(idempotencyKey))
|
|
979
1429
|
.returningAll()
|
|
980
1430
|
.executeTakeFirstOrThrow()
|
|
@@ -982,7 +1432,7 @@ describe('POST /funding/deposit-addresses', () => {
|
|
|
982
1432
|
const replay = await postDepositAddress(app, { body: requestBody, idempotencyKey })
|
|
983
1433
|
const response_replay = await TestApp.json(
|
|
984
1434
|
replay,
|
|
985
|
-
|
|
1435
|
+
Routes.schema.createRoutesDepositAddress.Response,
|
|
986
1436
|
)
|
|
987
1437
|
|
|
988
1438
|
expect({ status: replay.status, subsidize: response_replay.subsidize }).toMatchInlineSnapshot(`
|
|
@@ -995,12 +1445,15 @@ describe('POST /funding/deposit-addresses', () => {
|
|
|
995
1445
|
|
|
996
1446
|
test('preserves the idempotency fingerprint when subsidize is omitted', async () => {
|
|
997
1447
|
const idempotencyKey = nextDepositAddressKey()
|
|
998
|
-
await
|
|
999
|
-
apiKeyId:
|
|
1448
|
+
await RoutesIdempotencyTable.claim(db, {
|
|
1449
|
+
apiKeyId: routesWriter.id,
|
|
1450
|
+
irrevocable: false,
|
|
1000
1451
|
keyHash: Idempotency.inputHash(idempotencyKey),
|
|
1452
|
+
operation: RoutesIdempotencyTable.operations.depositAddress,
|
|
1453
|
+
orgId: routesWriter.orgId,
|
|
1001
1454
|
requestHash: Idempotency.inputHash({
|
|
1002
1455
|
body: depositAddressBody,
|
|
1003
|
-
endpoint: 'POST /v1/
|
|
1456
|
+
endpoint: 'POST /v1/routes/deposit-addresses',
|
|
1004
1457
|
}),
|
|
1005
1458
|
ttlMs: 60_000,
|
|
1006
1459
|
})
|
|
@@ -1016,7 +1469,7 @@ describe('POST /funding/deposit-addresses', () => {
|
|
|
1016
1469
|
"body": {
|
|
1017
1470
|
"error": {
|
|
1018
1471
|
"code": "idempotency_in_progress",
|
|
1019
|
-
"message": "An equivalent
|
|
1472
|
+
"message": "An equivalent route deposit address creation is still running.",
|
|
1020
1473
|
},
|
|
1021
1474
|
"requestId": Any<String>,
|
|
1022
1475
|
},
|
|
@@ -1028,9 +1481,12 @@ describe('POST /funding/deposit-addresses', () => {
|
|
|
1028
1481
|
|
|
1029
1482
|
test('includes the creation endpoint in the idempotency fingerprint', async () => {
|
|
1030
1483
|
const idempotencyKey = nextDepositAddressKey()
|
|
1031
|
-
await
|
|
1032
|
-
apiKeyId:
|
|
1484
|
+
await RoutesIdempotencyTable.claim(db, {
|
|
1485
|
+
apiKeyId: routesWriter.id,
|
|
1486
|
+
irrevocable: false,
|
|
1033
1487
|
keyHash: Idempotency.inputHash(idempotencyKey),
|
|
1488
|
+
operation: RoutesIdempotencyTable.operations.depositAddress,
|
|
1489
|
+
orgId: routesWriter.orgId,
|
|
1034
1490
|
requestHash: Idempotency.inputHash(depositAddressBody),
|
|
1035
1491
|
ttlMs: 60_000,
|
|
1036
1492
|
})
|
|
@@ -1081,19 +1537,355 @@ describe('POST /funding/deposit-addresses', () => {
|
|
|
1081
1537
|
status: 502,
|
|
1082
1538
|
})
|
|
1083
1539
|
})
|
|
1540
|
+
|
|
1541
|
+
test('caps new addresses before provisioning while allowing reusable matches', async () => {
|
|
1542
|
+
await Organizations.upsert(db, { id: routesLimitWriter.orgId, name: 'Routes limit' })
|
|
1543
|
+
await seedDepositAddress({
|
|
1544
|
+
orgId: routesLimitWriter.orgId,
|
|
1545
|
+
snapshot: TestRoutes.depositAddressSnapshot({
|
|
1546
|
+
address: 'limit-existing-address',
|
|
1547
|
+
provider: { id: 'relay', name: 'Relay' },
|
|
1548
|
+
recipient: depositAddressBody.recipient,
|
|
1549
|
+
}),
|
|
1550
|
+
})
|
|
1551
|
+
for (let index = 0; index < RoutesDepositAddress.maximumPerCreator - 1; index++)
|
|
1552
|
+
await seedDepositAddress({
|
|
1553
|
+
orgId: routesLimitWriter.orgId,
|
|
1554
|
+
snapshot: TestRoutes.depositAddressSnapshot({
|
|
1555
|
+
address: `limit-address-${index}`,
|
|
1556
|
+
provider: { id: 'relay', name: 'Relay' },
|
|
1557
|
+
recipient: `0x${index.toString(16).padStart(40, '0')}`,
|
|
1558
|
+
}),
|
|
1559
|
+
})
|
|
1560
|
+
const counts: Parameters<Metrics.Metrics['count']>[] = []
|
|
1561
|
+
const metrics = Metrics.from({
|
|
1562
|
+
count(name, value, tags) {
|
|
1563
|
+
counts.push([name, value, tags])
|
|
1564
|
+
},
|
|
1565
|
+
flush() {},
|
|
1566
|
+
gauge() {},
|
|
1567
|
+
histogram() {},
|
|
1568
|
+
})
|
|
1569
|
+
let provisions = 0
|
|
1570
|
+
const app = transfersApp({
|
|
1571
|
+
metrics,
|
|
1572
|
+
providers: [
|
|
1573
|
+
depositAddressProvider(undefined, () => {
|
|
1574
|
+
provisions++
|
|
1575
|
+
}),
|
|
1576
|
+
],
|
|
1577
|
+
})
|
|
1578
|
+
const response = await postDepositAddress(app, {
|
|
1579
|
+
body: { ...depositAddressBody, recipient: `0x${'22'.repeat(20)}` },
|
|
1580
|
+
key: routesLimitWriter,
|
|
1581
|
+
})
|
|
1582
|
+
|
|
1583
|
+
expect({
|
|
1584
|
+
body: await response.json(),
|
|
1585
|
+
metric: counts.find(([name]) => name === 'routes_deposit_address_limit_rejection_count'),
|
|
1586
|
+
provisions,
|
|
1587
|
+
status: response.status,
|
|
1588
|
+
}).toMatchInlineSnapshot(
|
|
1589
|
+
{ body: { requestId: expect.any(String) } },
|
|
1590
|
+
`
|
|
1591
|
+
{
|
|
1592
|
+
"body": {
|
|
1593
|
+
"error": {
|
|
1594
|
+
"code": "routes_deposit_address_limit_exceeded",
|
|
1595
|
+
"message": "Route deposit address limit reached (100).",
|
|
1596
|
+
},
|
|
1597
|
+
"requestId": Any<String>,
|
|
1598
|
+
},
|
|
1599
|
+
"metric": [
|
|
1600
|
+
"routes_deposit_address_limit_rejection_count",
|
|
1601
|
+
1,
|
|
1602
|
+
{
|
|
1603
|
+
"routes_environment": "production",
|
|
1604
|
+
},
|
|
1605
|
+
],
|
|
1606
|
+
"provisions": 0,
|
|
1607
|
+
"status": 403,
|
|
1608
|
+
}
|
|
1609
|
+
`,
|
|
1610
|
+
)
|
|
1611
|
+
const reused = await postDepositAddress(app, { key: routesLimitWriter })
|
|
1612
|
+
expect(reused.status).toBe(200)
|
|
1613
|
+
expect(provisions).toBe(0)
|
|
1614
|
+
expect(await RoutesDepositAddresses.countByOrganization(db, routesLimitWriter.orgId)).toBe(
|
|
1615
|
+
RoutesDepositAddress.maximumPerCreator,
|
|
1616
|
+
)
|
|
1617
|
+
|
|
1618
|
+
const recoveryBody = {
|
|
1619
|
+
...depositAddressBody,
|
|
1620
|
+
recipient: `0x${'33'.repeat(20)}`,
|
|
1621
|
+
subsidize: true,
|
|
1622
|
+
}
|
|
1623
|
+
const recoverySourceKey = nextDepositAddressKey()
|
|
1624
|
+
const recoveryRetryKey = nextDepositAddressKey()
|
|
1625
|
+
const recoveryIdentity = {
|
|
1626
|
+
apiKeyId: routesLimitWriter.id,
|
|
1627
|
+
keyHash: Idempotency.inputHash(recoverySourceKey),
|
|
1628
|
+
requestHash: Idempotency.inputHash({
|
|
1629
|
+
body: recoveryBody,
|
|
1630
|
+
endpoint: 'POST /v1/routes/deposit-addresses',
|
|
1631
|
+
}),
|
|
1632
|
+
}
|
|
1633
|
+
const recoveryClaim = await RoutesIdempotencyTable.claim(db, {
|
|
1634
|
+
...recoveryIdentity,
|
|
1635
|
+
irrevocable: true,
|
|
1636
|
+
operation: RoutesIdempotencyTable.operations.depositAddress,
|
|
1637
|
+
orgId: routesLimitWriter.orgId,
|
|
1638
|
+
ttlMs: 60_000,
|
|
1639
|
+
})
|
|
1640
|
+
if (recoveryClaim.type !== 'claimed') throw new Error('Expected a recovery claim.')
|
|
1641
|
+
const recoverySnapshot = TestRoutes.depositAddressSnapshot({
|
|
1642
|
+
address: 'TPnd4mS1qPSySdshZ9BuS2mGtWuxBq4uc5',
|
|
1643
|
+
recipient: recoveryBody.recipient,
|
|
1644
|
+
subsidize: true,
|
|
1645
|
+
})
|
|
1646
|
+
await RoutesIdempotencyTable.checkpoint(db, {
|
|
1647
|
+
apiKeyId: recoveryIdentity.apiKeyId,
|
|
1648
|
+
createdAt: recoveryClaim.createdAt,
|
|
1649
|
+
keyHash: recoveryIdentity.keyHash,
|
|
1650
|
+
replayTtlMs: 86_400_000,
|
|
1651
|
+
response: JSON.stringify({
|
|
1652
|
+
candidate: {
|
|
1653
|
+
destinationChain: recoverySnapshot.destinationChain,
|
|
1654
|
+
destinationToken: recoverySnapshot.destinationToken,
|
|
1655
|
+
sourceChain: recoverySnapshot.sourceChain,
|
|
1656
|
+
sourceToken: recoverySnapshot.sourceToken,
|
|
1657
|
+
},
|
|
1658
|
+
provider: recoverySnapshot.provider,
|
|
1659
|
+
recipient: recoverySnapshot.recipient,
|
|
1660
|
+
refundAddress: recoverySnapshot.refundAddress,
|
|
1661
|
+
result: {
|
|
1662
|
+
address: recoverySnapshot.address,
|
|
1663
|
+
correlation: { requestId: 'relay_limit_recovery' },
|
|
1664
|
+
destinationAmount: '1000000',
|
|
1665
|
+
destinationAmountMin: '1000000',
|
|
1666
|
+
fees: [],
|
|
1667
|
+
sampledAt: '2026-09-04T00:00:00.000Z',
|
|
1668
|
+
},
|
|
1669
|
+
}),
|
|
1670
|
+
})
|
|
1671
|
+
|
|
1672
|
+
const recovered = await postDepositAddress(transfersApp({ providers: [] }), {
|
|
1673
|
+
body: recoveryBody,
|
|
1674
|
+
idempotencyKey: recoveryRetryKey,
|
|
1675
|
+
key: routesLimitWriterSecond,
|
|
1676
|
+
})
|
|
1677
|
+
expect(recovered.status).toBe(200)
|
|
1678
|
+
expect(await RoutesDepositAddresses.countByOrganization(db, routesLimitWriter.orgId)).toBe(
|
|
1679
|
+
RoutesDepositAddress.maximumPerCreator + 1,
|
|
1680
|
+
)
|
|
1681
|
+
await expect(
|
|
1682
|
+
db.kysely
|
|
1683
|
+
.selectFrom('routes_idempotency_requests')
|
|
1684
|
+
.select('status')
|
|
1685
|
+
.where('keyHash', 'in', [recoveryIdentity.keyHash, Idempotency.inputHash(recoveryRetryKey)])
|
|
1686
|
+
.orderBy('apiKeyId')
|
|
1687
|
+
.execute(),
|
|
1688
|
+
).resolves.toEqual([{ status: 'completed' }, { status: 'completed' }])
|
|
1689
|
+
})
|
|
1690
|
+
|
|
1691
|
+
test('reserves the final address slot before provider provisioning', async () => {
|
|
1692
|
+
await Organizations.upsert(db, { id: routesRaceWriter.orgId, name: 'Routes race' })
|
|
1693
|
+
for (let index = 0; index < RoutesDepositAddress.maximumPerCreator - 1; index++)
|
|
1694
|
+
await seedDepositAddress({
|
|
1695
|
+
orgId: routesRaceWriter.orgId,
|
|
1696
|
+
snapshot: TestRoutes.depositAddressSnapshot({
|
|
1697
|
+
provider: { id: `relay_race_${index}`, name: 'Relay' },
|
|
1698
|
+
recipient: `0x${index.toString(16).padStart(40, '0')}`,
|
|
1699
|
+
}),
|
|
1700
|
+
})
|
|
1701
|
+
const entered = Promise.withResolvers<void>()
|
|
1702
|
+
const release = Promise.withResolvers<void>()
|
|
1703
|
+
let provisions = 0
|
|
1704
|
+
const app = transfersApp({
|
|
1705
|
+
providers: [
|
|
1706
|
+
depositAddressProvider('TRXcKoEvHr6Y38VMcDYGBEYKznvH3XUX4g', async () => {
|
|
1707
|
+
provisions++
|
|
1708
|
+
entered.resolve()
|
|
1709
|
+
await release.promise
|
|
1710
|
+
}),
|
|
1711
|
+
],
|
|
1712
|
+
})
|
|
1713
|
+
const first = postDepositAddress(app, { key: routesRaceWriter })
|
|
1714
|
+
await entered.promise
|
|
1715
|
+
|
|
1716
|
+
const rejected = await postDepositAddress(app, {
|
|
1717
|
+
body: { ...depositAddressBody, recipient: `0x${'99'.repeat(20)}` },
|
|
1718
|
+
key: routesRaceWriter,
|
|
1719
|
+
})
|
|
1720
|
+
expect(rejected.status).toBe(403)
|
|
1721
|
+
expect(provisions).toBe(1)
|
|
1722
|
+
|
|
1723
|
+
release.resolve()
|
|
1724
|
+
expect((await first).status).toBe(200)
|
|
1725
|
+
expect(await RoutesDepositAddresses.countByOrganization(db, routesRaceWriter.orgId)).toBe(
|
|
1726
|
+
RoutesDepositAddress.maximumPerCreator,
|
|
1727
|
+
)
|
|
1728
|
+
await db.kysely
|
|
1729
|
+
.deleteFrom('routes_deposit_addresses')
|
|
1730
|
+
.where('orgId', '=', routesRaceWriter.orgId)
|
|
1731
|
+
.execute()
|
|
1732
|
+
})
|
|
1733
|
+
|
|
1734
|
+
test('joins concurrent reusable-match provisioning across idempotency keys', async () => {
|
|
1735
|
+
await Organizations.upsert(db, { id: routesRaceWriter.orgId, name: 'Routes match race' })
|
|
1736
|
+
const entered = Promise.withResolvers<void>()
|
|
1737
|
+
const release = Promise.withResolvers<void>()
|
|
1738
|
+
let provisions = 0
|
|
1739
|
+
const app = transfersApp({
|
|
1740
|
+
providers: [
|
|
1741
|
+
depositAddressProvider('TT5rFsXYCrnzdE2q1WdR9F2SuVY59A4hoM', async () => {
|
|
1742
|
+
provisions++
|
|
1743
|
+
entered.resolve()
|
|
1744
|
+
await release.promise
|
|
1745
|
+
}),
|
|
1746
|
+
],
|
|
1747
|
+
})
|
|
1748
|
+
const first = postDepositAddress(app, {
|
|
1749
|
+
idempotencyKey: 'routes_match_race_first',
|
|
1750
|
+
key: routesRaceWriter,
|
|
1751
|
+
})
|
|
1752
|
+
await entered.promise
|
|
1753
|
+
|
|
1754
|
+
const joined = await postDepositAddress(app, {
|
|
1755
|
+
body: { ...depositAddressBody, amount: '200000000' },
|
|
1756
|
+
idempotencyKey: 'routes_match_race_second',
|
|
1757
|
+
key: routesRaceWriter,
|
|
1758
|
+
})
|
|
1759
|
+
expect({ body: await joined.json(), provisions, status: joined.status }).toMatchInlineSnapshot(
|
|
1760
|
+
{ body: { requestId: expect.any(String) } },
|
|
1761
|
+
`
|
|
1762
|
+
{
|
|
1763
|
+
"body": {
|
|
1764
|
+
"error": {
|
|
1765
|
+
"code": "idempotency_in_progress",
|
|
1766
|
+
"message": "An equivalent route deposit address creation is still running.",
|
|
1767
|
+
},
|
|
1768
|
+
"requestId": Any<String>,
|
|
1769
|
+
},
|
|
1770
|
+
"provisions": 1,
|
|
1771
|
+
"status": 409,
|
|
1772
|
+
}
|
|
1773
|
+
`,
|
|
1774
|
+
)
|
|
1775
|
+
|
|
1776
|
+
release.resolve()
|
|
1777
|
+
expect((await first).status).toBe(200)
|
|
1778
|
+
const retried = await postDepositAddress(app, {
|
|
1779
|
+
body: { ...depositAddressBody, amount: '200000000' },
|
|
1780
|
+
idempotencyKey: 'routes_match_race_second',
|
|
1781
|
+
key: routesRaceWriter,
|
|
1782
|
+
})
|
|
1783
|
+
expect(retried.status).toBe(200)
|
|
1784
|
+
expect(provisions).toBe(1)
|
|
1785
|
+
})
|
|
1786
|
+
|
|
1787
|
+
test('shares the final address slot across sibling organizations', async () => {
|
|
1788
|
+
const userId = 'usr_routes_owner_race'
|
|
1789
|
+
await Organizations.create(db, {
|
|
1790
|
+
id: routesOwnerRaceWriter.orgId,
|
|
1791
|
+
name: 'Routes owner race',
|
|
1792
|
+
userId,
|
|
1793
|
+
})
|
|
1794
|
+
await Organizations.create(db, {
|
|
1795
|
+
id: routesOwnerRaceSiblingWriter.orgId,
|
|
1796
|
+
name: 'Routes owner race sibling',
|
|
1797
|
+
userId,
|
|
1798
|
+
})
|
|
1799
|
+
for (let index = 0; index < RoutesDepositAddress.maximumPerCreator - 1; index++)
|
|
1800
|
+
await seedDepositAddress({
|
|
1801
|
+
orgId: routesOwnerRaceWriter.orgId,
|
|
1802
|
+
snapshot: TestRoutes.depositAddressSnapshot({
|
|
1803
|
+
provider: { id: `relay_owner_race_${index}`, name: 'Relay' },
|
|
1804
|
+
recipient: `0x${index.toString(16).padStart(40, '0')}`,
|
|
1805
|
+
}),
|
|
1806
|
+
})
|
|
1807
|
+
const entered = Promise.withResolvers<void>()
|
|
1808
|
+
const release = Promise.withResolvers<void>()
|
|
1809
|
+
let provisions = 0
|
|
1810
|
+
const app = transfersApp({
|
|
1811
|
+
providers: [
|
|
1812
|
+
depositAddressProvider('TUe6BwpA7sVTDKaJQoia7FWZpC9sK8WM2t', async () => {
|
|
1813
|
+
provisions++
|
|
1814
|
+
entered.resolve()
|
|
1815
|
+
await release.promise
|
|
1816
|
+
}),
|
|
1817
|
+
],
|
|
1818
|
+
})
|
|
1819
|
+
const first = postDepositAddress(app, { key: routesOwnerRaceSiblingWriter })
|
|
1820
|
+
await entered.promise
|
|
1821
|
+
|
|
1822
|
+
const rejected = await postDepositAddress(app, { key: routesOwnerRaceWriter })
|
|
1823
|
+
expect(rejected.status).toBe(403)
|
|
1824
|
+
expect(provisions).toBe(1)
|
|
1825
|
+
|
|
1826
|
+
release.resolve()
|
|
1827
|
+
expect((await first).status).toBe(200)
|
|
1828
|
+
expect(
|
|
1829
|
+
(await RoutesDepositAddresses.countByOrganization(db, routesOwnerRaceWriter.orgId)) +
|
|
1830
|
+
(await RoutesDepositAddresses.countByOrganization(db, routesOwnerRaceSiblingWriter.orgId)),
|
|
1831
|
+
).toBe(RoutesDepositAddress.maximumPerCreator)
|
|
1832
|
+
|
|
1833
|
+
expect(await Organizations.deleteOrganization(db, routesOwnerRaceWriter.orgId)).toBe(true)
|
|
1834
|
+
await Organizations.create(db, {
|
|
1835
|
+
id: routesOwnerRaceReplacementWriter.orgId,
|
|
1836
|
+
name: 'Routes owner race replacement',
|
|
1837
|
+
userId,
|
|
1838
|
+
})
|
|
1839
|
+
const replacement = await postDepositAddress(app, {
|
|
1840
|
+
key: routesOwnerRaceReplacementWriter,
|
|
1841
|
+
})
|
|
1842
|
+
expect(replacement.status).toBe(403)
|
|
1843
|
+
expect(provisions).toBe(1)
|
|
1844
|
+
})
|
|
1845
|
+
|
|
1846
|
+
test('fences organization deletion while subsidized provider provisioning is in flight', async () => {
|
|
1847
|
+
await enableRoutesSubsidy(routesSubsidyRaceWriter, 'active')
|
|
1848
|
+
const entered = Promise.withResolvers<void>()
|
|
1849
|
+
const release = Promise.withResolvers<void>()
|
|
1850
|
+
const app = transfersApp({
|
|
1851
|
+
providers: [
|
|
1852
|
+
depositAddressProvider('TWCL826n2tBuoR7mp6oj5FzgitmfWSwCGZ', async () => {
|
|
1853
|
+
entered.resolve()
|
|
1854
|
+
await release.promise
|
|
1855
|
+
}),
|
|
1856
|
+
],
|
|
1857
|
+
})
|
|
1858
|
+
const creation = postDepositAddress(app, {
|
|
1859
|
+
body: { ...depositAddressBody, subsidize: true },
|
|
1860
|
+
key: routesSubsidyRaceWriter,
|
|
1861
|
+
})
|
|
1862
|
+
await entered.promise
|
|
1863
|
+
|
|
1864
|
+
await expect(
|
|
1865
|
+
Organizations.deleteOrganization(db, routesSubsidyRaceWriter.orgId),
|
|
1866
|
+
).rejects.toThrow(Organizations.IrrevocableDepositAddressError)
|
|
1867
|
+
expect(await Organizations.get(db, routesSubsidyRaceWriter.orgId)).toBeDefined()
|
|
1868
|
+
|
|
1869
|
+
release.resolve()
|
|
1870
|
+
expect((await creation).status).toBe(200)
|
|
1871
|
+
})
|
|
1084
1872
|
})
|
|
1085
1873
|
|
|
1086
|
-
describe('POST /webhooks/
|
|
1874
|
+
describe('POST /webhooks/routes/relay', () => {
|
|
1087
1875
|
test('authenticates and enqueues a bounded reconciliation hint', async () => {
|
|
1088
1876
|
const secret = 'relay-webhook-secret'
|
|
1089
1877
|
const address = await seedDepositAddress({
|
|
1090
|
-
snapshot:
|
|
1878
|
+
snapshot: TestRoutes.depositAddressSnapshot({
|
|
1091
1879
|
provider: { id: 'relay', name: 'Relay' },
|
|
1092
1880
|
recipient: `0x${'99'.repeat(20)}`,
|
|
1093
1881
|
}),
|
|
1094
1882
|
})
|
|
1095
|
-
const dispatched:
|
|
1883
|
+
const dispatched: RoutesProvider.Webhook.receive.Dispatchable[] = []
|
|
1884
|
+
const entries: Log.Entry[] = []
|
|
1096
1885
|
const app = transfersApp({
|
|
1886
|
+
logger: (entry) => {
|
|
1887
|
+
entries.push(entry)
|
|
1888
|
+
},
|
|
1097
1889
|
providers: [
|
|
1098
1890
|
Relay.relay({
|
|
1099
1891
|
apiKey: secret,
|
|
@@ -1121,7 +1913,7 @@ describe('POST /webhooks/funding/relay', () => {
|
|
|
1121
1913
|
Hex.fromString(secret),
|
|
1122
1914
|
Hex.fromString(`${timestamp}.${body}`),
|
|
1123
1915
|
).slice(2)
|
|
1124
|
-
const response = await app.request('/webhooks/
|
|
1916
|
+
const response = await app.request('/webhooks/routes/relay', {
|
|
1125
1917
|
body,
|
|
1126
1918
|
headers: {
|
|
1127
1919
|
'x-signature-sha256': signature,
|
|
@@ -1130,8 +1922,13 @@ describe('POST /webhooks/funding/relay', () => {
|
|
|
1130
1922
|
method: 'POST',
|
|
1131
1923
|
})
|
|
1132
1924
|
|
|
1133
|
-
expect({
|
|
1925
|
+
expect({
|
|
1926
|
+
attempt: entries.at(-1)?.routesProviderAttempts?.[0],
|
|
1927
|
+
dispatched,
|
|
1928
|
+
status: response.status,
|
|
1929
|
+
}).toMatchInlineSnapshot(
|
|
1134
1930
|
{
|
|
1931
|
+
attempt: { durationMs: expect.any(Number) },
|
|
1135
1932
|
dispatched: [
|
|
1136
1933
|
{
|
|
1137
1934
|
webhookTiming: {
|
|
@@ -1145,12 +1942,18 @@ describe('POST /webhooks/funding/relay', () => {
|
|
|
1145
1942
|
},
|
|
1146
1943
|
`
|
|
1147
1944
|
{
|
|
1945
|
+
"attempt": {
|
|
1946
|
+
"durationMs": Any<Number>,
|
|
1947
|
+
"id": "relay",
|
|
1948
|
+
"operation": "receiveWebhook",
|
|
1949
|
+
"outcome": "success",
|
|
1950
|
+
},
|
|
1148
1951
|
"dispatched": [
|
|
1149
1952
|
{
|
|
1150
1953
|
"addressId": "${address.id}",
|
|
1151
1954
|
"requestId": "relay-child-request",
|
|
1152
1955
|
"trigger": "webhook",
|
|
1153
|
-
"type": "
|
|
1956
|
+
"type": "routes:deposit-address:reconcile",
|
|
1154
1957
|
"webhookTiming": {
|
|
1155
1958
|
"enqueuedAt": Any<String>,
|
|
1156
1959
|
"providerStatus": "pending",
|
|
@@ -1175,16 +1978,46 @@ describe('POST /webhooks/funding/relay', () => {
|
|
|
1175
1978
|
}),
|
|
1176
1979
|
],
|
|
1177
1980
|
})
|
|
1178
|
-
const response = await app.request('/webhooks/
|
|
1981
|
+
const response = await app.request('/webhooks/routes/relay', {
|
|
1179
1982
|
body: '{}',
|
|
1180
1983
|
method: 'POST',
|
|
1181
1984
|
})
|
|
1182
1985
|
|
|
1183
1986
|
expect(response.status).toMatchInlineSnapshot('401')
|
|
1184
1987
|
})
|
|
1988
|
+
|
|
1989
|
+
test('rejects oversized events before signature verification', async () => {
|
|
1990
|
+
const app = transfersApp({
|
|
1991
|
+
providers: [
|
|
1992
|
+
Relay.relay({
|
|
1993
|
+
apiKey: 'relay-webhook-secret',
|
|
1994
|
+
webhook: { db, dispatch: async () => {} },
|
|
1995
|
+
}),
|
|
1996
|
+
],
|
|
1997
|
+
})
|
|
1998
|
+
const response = await app.request('/webhooks/routes/relay', {
|
|
1999
|
+
body: 'x'.repeat(64 * 1_024 + 1),
|
|
2000
|
+
headers: {
|
|
2001
|
+
'x-signature-sha256': 'a'.repeat(64),
|
|
2002
|
+
'x-signature-timestamp': String(Date.now()),
|
|
2003
|
+
},
|
|
2004
|
+
method: 'POST',
|
|
2005
|
+
})
|
|
2006
|
+
|
|
2007
|
+
expect(response.status).toMatchInlineSnapshot('413')
|
|
2008
|
+
})
|
|
2009
|
+
|
|
2010
|
+
test('rejects unknown providers before reading oversized events', async () => {
|
|
2011
|
+
const response = await transfersApp().request('/webhooks/routes/unknown', {
|
|
2012
|
+
body: 'x'.repeat(64 * 1_024 + 1),
|
|
2013
|
+
method: 'POST',
|
|
2014
|
+
})
|
|
2015
|
+
|
|
2016
|
+
expect(response.status).toMatchInlineSnapshot('404')
|
|
2017
|
+
})
|
|
1185
2018
|
})
|
|
1186
2019
|
|
|
1187
|
-
describe.skipIf(!relayApiKey)('POST /
|
|
2020
|
+
describe.skipIf(!relayApiKey)('POST /routes/deposit-addresses (relay)', () => {
|
|
1188
2021
|
test('provisions and persists a reusable address through Relay', async () => {
|
|
1189
2022
|
const app = transfersApp({
|
|
1190
2023
|
providers: [Relay.relay({ apiKey: relayApiKey })],
|
|
@@ -1194,96 +2027,14 @@ describe.skipIf(!relayApiKey)('POST /funding/deposit-addresses (relay)', () => {
|
|
|
1194
2027
|
})
|
|
1195
2028
|
|
|
1196
2029
|
expect(response.status).toBe(200)
|
|
1197
|
-
const body = await TestApp.json(response,
|
|
1198
|
-
expect(body).
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
},
|
|
1206
|
-
destinationAmountMin: {
|
|
1207
|
-
baseUnits: expect.any(String),
|
|
1208
|
-
formatted: expect.any(String),
|
|
1209
|
-
},
|
|
1210
|
-
fees: expect.any(Array),
|
|
1211
|
-
id: expect.any(String),
|
|
1212
|
-
quote: { sampledAt: expect.any(String) },
|
|
1213
|
-
updatedAt: expect.any(String),
|
|
1214
|
-
},
|
|
1215
|
-
`
|
|
1216
|
-
{
|
|
1217
|
-
"address": Any<String>,
|
|
1218
|
-
"createdAt": Any<String>,
|
|
1219
|
-
"destinationAmount": {
|
|
1220
|
-
"baseUnits": Any<String>,
|
|
1221
|
-
"currency": "USD",
|
|
1222
|
-
"decimals": 6,
|
|
1223
|
-
"formatted": Any<String>,
|
|
1224
|
-
},
|
|
1225
|
-
"destinationAmountMin": {
|
|
1226
|
-
"baseUnits": Any<String>,
|
|
1227
|
-
"currency": "USD",
|
|
1228
|
-
"decimals": 6,
|
|
1229
|
-
"formatted": Any<String>,
|
|
1230
|
-
},
|
|
1231
|
-
"destinationChain": {
|
|
1232
|
-
"addressFormat": "hex",
|
|
1233
|
-
"id": "eip155:4217",
|
|
1234
|
-
"kind": "evm",
|
|
1235
|
-
"name": "Tempo",
|
|
1236
|
-
},
|
|
1237
|
-
"destinationToken": {
|
|
1238
|
-
"address": "0x20c00000000000000000000014f22ca97301eb73",
|
|
1239
|
-
"currency": "USD",
|
|
1240
|
-
"decimals": 6,
|
|
1241
|
-
"name": "USDT0",
|
|
1242
|
-
"standard": "TIP-20",
|
|
1243
|
-
"symbol": "USDT0",
|
|
1244
|
-
"tokenKey": "eip155:4217/erc20:0x20c00000000000000000000014f22ca97301eb73",
|
|
1245
|
-
"verified": true,
|
|
1246
|
-
},
|
|
1247
|
-
"fees": Any<Array>,
|
|
1248
|
-
"id": Any<String>,
|
|
1249
|
-
"provider": {
|
|
1250
|
-
"id": "relay",
|
|
1251
|
-
"name": "Relay",
|
|
1252
|
-
},
|
|
1253
|
-
"quote": {
|
|
1254
|
-
"sampledAt": Any<String>,
|
|
1255
|
-
},
|
|
1256
|
-
"recipient": "0x7777777777777777777777777777777777777777",
|
|
1257
|
-
"refundAddress": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
|
|
1258
|
-
"sourceAmount": {
|
|
1259
|
-
"baseUnits": "100000000",
|
|
1260
|
-
"currency": "USD",
|
|
1261
|
-
"decimals": 6,
|
|
1262
|
-
"formatted": "100",
|
|
1263
|
-
},
|
|
1264
|
-
"sourceChain": {
|
|
1265
|
-
"addressFormat": "base58check",
|
|
1266
|
-
"id": "tron:0x2b6653dc",
|
|
1267
|
-
"kind": "tron",
|
|
1268
|
-
"name": "Tron",
|
|
1269
|
-
},
|
|
1270
|
-
"sourceToken": {
|
|
1271
|
-
"address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
|
|
1272
|
-
"currency": "USD",
|
|
1273
|
-
"decimals": 6,
|
|
1274
|
-
"name": "Tether USD",
|
|
1275
|
-
"standard": "TRC-20",
|
|
1276
|
-
"symbol": "USDT",
|
|
1277
|
-
"tokenKey": "tron:0x2b6653dc/trc20:TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
|
|
1278
|
-
"verified": true,
|
|
1279
|
-
},
|
|
1280
|
-
"status": "active",
|
|
1281
|
-
"subsidize": false,
|
|
1282
|
-
"updatedAt": Any<String>,
|
|
1283
|
-
}
|
|
1284
|
-
`,
|
|
1285
|
-
)
|
|
1286
|
-
const record = await FundingDepositAddresses.get(db, body.id)
|
|
2030
|
+
const body = await TestApp.json(response, Routes.schema.createRoutesDepositAddress.Response)
|
|
2031
|
+
expect(body).toMatchObject({
|
|
2032
|
+
address: expect.any(String),
|
|
2033
|
+
id: expect.any(String),
|
|
2034
|
+
provider: { id: 'relay' },
|
|
2035
|
+
status: 'active',
|
|
2036
|
+
})
|
|
2037
|
+
const record = await RoutesDepositAddresses.get(db, body.id)
|
|
1287
2038
|
expect(record).toMatchInlineSnapshot(
|
|
1288
2039
|
{
|
|
1289
2040
|
address: expect.any(String),
|
|
@@ -1293,20 +2044,21 @@ describe.skipIf(!relayApiKey)('POST /funding/deposit-addresses (relay)', () => {
|
|
|
1293
2044
|
providerRequestIds: [expect.any(String)],
|
|
1294
2045
|
providerState: expect.any(Object),
|
|
1295
2046
|
snapshot: { address: expect.any(String) },
|
|
2047
|
+
statusUpdatedAt: expect.any(String),
|
|
1296
2048
|
updatedAt: expect.any(String),
|
|
1297
2049
|
},
|
|
1298
2050
|
`
|
|
1299
2051
|
{
|
|
1300
2052
|
"address": Any<String>,
|
|
1301
|
-
"apiKeyId": "key_funding_writer",
|
|
1302
2053
|
"createdAt": Any<String>,
|
|
2054
|
+
"creatorUserId": null,
|
|
1303
2055
|
"deliveryStrategy": "provider",
|
|
1304
2056
|
"destinationTokenKey": "eip155:4217/erc20:0x20c00000000000000000000014f22ca97301eb73",
|
|
1305
2057
|
"environment": "production",
|
|
1306
2058
|
"id": Any<String>,
|
|
1307
2059
|
"lastPolledAt": null,
|
|
1308
2060
|
"nextPollAt": Any<String>,
|
|
1309
|
-
"orgId": "
|
|
2061
|
+
"orgId": "org_routes",
|
|
1310
2062
|
"pollFailureCount": 0,
|
|
1311
2063
|
"pollLeaseUntil": null,
|
|
1312
2064
|
"pollLeaseVersion": 0,
|
|
@@ -1373,6 +2125,7 @@ describe.skipIf(!relayApiKey)('POST /funding/deposit-addresses (relay)', () => {
|
|
|
1373
2125
|
"sourceChainId": "tron:0x2b6653dc",
|
|
1374
2126
|
"sourceTokenKey": "tron:0x2b6653dc/trc20:TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
|
|
1375
2127
|
"status": "active",
|
|
2128
|
+
"statusUpdatedAt": Any<String>,
|
|
1376
2129
|
"subsidize": false,
|
|
1377
2130
|
"updatedAt": Any<String>,
|
|
1378
2131
|
"version": 1,
|
|
@@ -1382,32 +2135,32 @@ describe.skipIf(!relayApiKey)('POST /funding/deposit-addresses (relay)', () => {
|
|
|
1382
2135
|
})
|
|
1383
2136
|
})
|
|
1384
2137
|
|
|
1385
|
-
describe('GET /
|
|
2138
|
+
describe('GET /routes/deposit-addresses', () => {
|
|
1386
2139
|
test('pages organization addresses and narrows project-attributed keys', async () => {
|
|
1387
2140
|
const app = transfersApp()
|
|
1388
|
-
const first = await seedDepositAddress({ orgId:
|
|
1389
|
-
const second = await seedDepositAddress({ orgId:
|
|
1390
|
-
const third = await seedDepositAddress({ orgId:
|
|
2141
|
+
const first = await seedDepositAddress({ orgId: routesAddressListReader.orgId })
|
|
2142
|
+
const second = await seedDepositAddress({ orgId: routesAddressListReader.orgId })
|
|
2143
|
+
const third = await seedDepositAddress({ orgId: routesAddressListReader.orgId })
|
|
1391
2144
|
const project = await seedDepositAddress({
|
|
1392
|
-
orgId:
|
|
1393
|
-
projectId:
|
|
2145
|
+
orgId: routesAddressListReader.orgId,
|
|
2146
|
+
projectId: routesAddressListProjectReader.projectId,
|
|
1394
2147
|
})
|
|
1395
2148
|
const sibling = await seedDepositAddress({
|
|
1396
|
-
orgId:
|
|
1397
|
-
projectId: '
|
|
2149
|
+
orgId: routesAddressListReader.orgId,
|
|
2150
|
+
projectId: 'prj_routes_address_list_sibling',
|
|
1398
2151
|
})
|
|
1399
|
-
const sixth = await seedDepositAddress({ orgId:
|
|
1400
|
-
await seedDepositAddress({ orgId:
|
|
2152
|
+
const sixth = await seedDepositAddress({ orgId: routesAddressListReader.orgId })
|
|
2153
|
+
await seedDepositAddress({ orgId: routesForeign.orgId })
|
|
1401
2154
|
await seedDepositAddress({
|
|
1402
2155
|
environment: 'sandbox',
|
|
1403
|
-
orgId:
|
|
2156
|
+
orgId: routesAddressListReader.orgId,
|
|
1404
2157
|
})
|
|
1405
2158
|
|
|
1406
|
-
const path = '/v1/
|
|
2159
|
+
const path = '/v1/routes/deposit-addresses'
|
|
1407
2160
|
expect((await app.request(path)).status).toBe(401)
|
|
1408
2161
|
expect((await app.request(path, as(TestApp.key))).status).toBe(403)
|
|
1409
2162
|
|
|
1410
|
-
const response = await app.request(`${path}?limit=5`, as(
|
|
2163
|
+
const response = await app.request(`${path}?limit=5`, as(routesAddressListReader))
|
|
1411
2164
|
expect(response.status).toBe(200)
|
|
1412
2165
|
expect({
|
|
1413
2166
|
cacheControl: response.headers.get('cache-control'),
|
|
@@ -1418,7 +2171,7 @@ describe('GET /funding/deposit-addresses', () => {
|
|
|
1418
2171
|
etag: null,
|
|
1419
2172
|
vary: 'Accept-Encoding, Authorization, Tempo-API-Key, X-API-Key',
|
|
1420
2173
|
})
|
|
1421
|
-
const body = await TestApp.json(response,
|
|
2174
|
+
const body = await TestApp.json(response, Routes.schema.listRoutesDepositAddresses.Response)
|
|
1422
2175
|
expect(body.data.map((address) => address.id)).toEqual([
|
|
1423
2176
|
sixth.id,
|
|
1424
2177
|
sibling.id,
|
|
@@ -1429,29 +2182,29 @@ describe('GET /funding/deposit-addresses', () => {
|
|
|
1429
2182
|
expect(body.nextCursor).toBe(Cursor.encode([second.createdAt, second.id]))
|
|
1430
2183
|
|
|
1431
2184
|
const next = await TestApp.json(
|
|
1432
|
-
await app.request(`${path}?limit=5&cursor=${body.nextCursor}`, as(
|
|
1433
|
-
|
|
2185
|
+
await app.request(`${path}?limit=5&cursor=${body.nextCursor}`, as(routesAddressListReader)),
|
|
2186
|
+
Routes.schema.listRoutesDepositAddresses.Response,
|
|
1434
2187
|
)
|
|
1435
2188
|
expect(next.data.map((address) => address.id)).toEqual([first.id])
|
|
1436
2189
|
expect(next.nextCursor).toBeNull()
|
|
1437
2190
|
|
|
1438
2191
|
const projectBody = await TestApp.json(
|
|
1439
|
-
await app.request(path, as(
|
|
1440
|
-
|
|
2192
|
+
await app.request(path, as(routesAddressListProjectReader)),
|
|
2193
|
+
Routes.schema.listRoutesDepositAddresses.Response,
|
|
1441
2194
|
)
|
|
1442
2195
|
expect(projectBody.data.map((address) => address.id)).toEqual([project.id])
|
|
1443
2196
|
})
|
|
1444
2197
|
})
|
|
1445
2198
|
|
|
1446
|
-
describe('GET /
|
|
1447
|
-
test('requires
|
|
2199
|
+
describe('GET /routes/deposit-addresses/:id', () => {
|
|
2200
|
+
test('requires routes:read and returns the owned address', async () => {
|
|
1448
2201
|
const app = transfersApp()
|
|
1449
2202
|
const record = await seedDepositAddress()
|
|
1450
|
-
const path = `/v1/
|
|
2203
|
+
const path = `/v1/routes/deposit-addresses/${record.id}`
|
|
1451
2204
|
expect((await app.request(path)).status).toBe(401)
|
|
1452
2205
|
expect((await app.request(path, as(TestApp.key))).status).toBe(403)
|
|
1453
2206
|
|
|
1454
|
-
const response = await app.request(path, as(
|
|
2207
|
+
const response = await app.request(path, as(routesReader))
|
|
1455
2208
|
expect(response.status).toBe(200)
|
|
1456
2209
|
expect({
|
|
1457
2210
|
cacheControl: response.headers.get('cache-control'),
|
|
@@ -1465,8 +2218,8 @@ describe('GET /funding/deposit-addresses/:id', () => {
|
|
|
1465
2218
|
expect(response.headers.get('vary')).toBe(
|
|
1466
2219
|
'Accept-Encoding, Authorization, Tempo-API-Key, X-API-Key',
|
|
1467
2220
|
)
|
|
1468
|
-
const body = await TestApp.json(response,
|
|
1469
|
-
expect(body).toEqual(
|
|
2221
|
+
const body = await TestApp.json(response, Routes.schema.getRoutesDepositAddress.Response)
|
|
2222
|
+
expect(body).toEqual(RoutesDepositAddress.toPublic(record))
|
|
1470
2223
|
expect(body).not.toHaveProperty('providerOutputToken')
|
|
1471
2224
|
expect(body).not.toHaveProperty('providerRequestIds')
|
|
1472
2225
|
})
|
|
@@ -1474,40 +2227,40 @@ describe('GET /funding/deposit-addresses/:id', () => {
|
|
|
1474
2227
|
test('hides foreign, project-inaccessible, and absent addresses', async () => {
|
|
1475
2228
|
const app = transfersApp()
|
|
1476
2229
|
const record = await seedDepositAddress()
|
|
1477
|
-
const path = `/v1/
|
|
2230
|
+
const path = `/v1/routes/deposit-addresses/${record.id}`
|
|
1478
2231
|
|
|
1479
|
-
for (const key of [
|
|
2232
|
+
for (const key of [routesForeign, routesProjectReader]) {
|
|
1480
2233
|
const response = await app.request(path, as(key))
|
|
1481
2234
|
expect(response.status).toBe(404)
|
|
1482
2235
|
expect(((await response.json()) as { error: { code: string } }).error.code).toBe(
|
|
1483
|
-
'
|
|
2236
|
+
'routes_deposit_address_not_found',
|
|
1484
2237
|
)
|
|
1485
2238
|
}
|
|
1486
2239
|
|
|
1487
2240
|
const absent = await app.request(
|
|
1488
|
-
'/v1/
|
|
1489
|
-
as(
|
|
2241
|
+
'/v1/routes/deposit-addresses/rda_000000000000000_000000000000000000000000',
|
|
2242
|
+
as(routesReader),
|
|
1490
2243
|
)
|
|
1491
2244
|
expect(absent.status).toBe(404)
|
|
1492
2245
|
})
|
|
1493
2246
|
})
|
|
1494
2247
|
|
|
1495
|
-
describe('POST /
|
|
1496
|
-
test('requires
|
|
1497
|
-
const dispatched:
|
|
2248
|
+
describe('POST /routes/deposit-addresses/:id/reconcile', () => {
|
|
2249
|
+
test('requires routes:write and queues the owned active address', async () => {
|
|
2250
|
+
const dispatched: RoutesProvider.Webhook.receive.Dispatchable[] = []
|
|
1498
2251
|
const app = transfersApp({
|
|
1499
|
-
|
|
2252
|
+
routes: {
|
|
1500
2253
|
dispatchDepositReconciliation: async (message) => {
|
|
1501
2254
|
dispatched.push(message)
|
|
1502
2255
|
},
|
|
1503
2256
|
},
|
|
1504
2257
|
})
|
|
1505
2258
|
const record = await seedDepositAddress()
|
|
1506
|
-
const path = `/v1/
|
|
2259
|
+
const path = `/v1/routes/deposit-addresses/${record.id}/reconcile`
|
|
1507
2260
|
expect((await app.request(path, { method: 'POST' })).status).toBe(401)
|
|
1508
|
-
expect((await app.request(path, { ...as(
|
|
2261
|
+
expect((await app.request(path, { ...as(routesReader), method: 'POST' })).status).toBe(403)
|
|
1509
2262
|
|
|
1510
|
-
const response = await app.request(path, { ...as(
|
|
2263
|
+
const response = await app.request(path, { ...as(routesWriter), method: 'POST' })
|
|
1511
2264
|
expect({
|
|
1512
2265
|
body: await response.text(),
|
|
1513
2266
|
cacheControl: response.headers.get('cache-control'),
|
|
@@ -1527,60 +2280,60 @@ describe('POST /funding/deposit-addresses/:id/reconcile', () => {
|
|
|
1527
2280
|
{
|
|
1528
2281
|
"addressId": "${record.id}",
|
|
1529
2282
|
"trigger": "manual",
|
|
1530
|
-
"type": "
|
|
2283
|
+
"type": "routes:deposit-address:reconcile",
|
|
1531
2284
|
},
|
|
1532
2285
|
],
|
|
1533
2286
|
"rateLimit": {
|
|
1534
2287
|
"limit": "10",
|
|
1535
2288
|
"remaining": "9",
|
|
1536
|
-
"scope": "
|
|
2289
|
+
"scope": "routes:write",
|
|
1537
2290
|
},
|
|
1538
2291
|
"status": 202,
|
|
1539
2292
|
"vary": "Accept-Encoding, Authorization, Tempo-API-Key",
|
|
1540
2293
|
}
|
|
1541
2294
|
`)
|
|
1542
|
-
expect(await
|
|
2295
|
+
expect(await RoutesDepositAddresses.get(db, record.id)).toEqual(record)
|
|
1543
2296
|
})
|
|
1544
2297
|
|
|
1545
2298
|
test('hides foreign, project-inaccessible, and absent addresses', async () => {
|
|
1546
|
-
const dispatched:
|
|
2299
|
+
const dispatched: RoutesProvider.Webhook.receive.Dispatchable[] = []
|
|
1547
2300
|
const app = transfersApp({
|
|
1548
|
-
|
|
2301
|
+
routes: {
|
|
1549
2302
|
dispatchDepositReconciliation: async (message) => {
|
|
1550
2303
|
dispatched.push(message)
|
|
1551
2304
|
},
|
|
1552
2305
|
},
|
|
1553
2306
|
})
|
|
1554
2307
|
const record = await seedDepositAddress()
|
|
1555
|
-
const path = `/v1/
|
|
2308
|
+
const path = `/v1/routes/deposit-addresses/${record.id}/reconcile`
|
|
1556
2309
|
|
|
1557
|
-
for (const key of [
|
|
2310
|
+
for (const key of [routesForeignWriter, routesProjectWriter]) {
|
|
1558
2311
|
const response = await app.request(path, { ...as(key), method: 'POST' })
|
|
1559
2312
|
expect(response.status).toBe(404)
|
|
1560
2313
|
expect(((await response.json()) as { error: { code: string } }).error.code).toBe(
|
|
1561
|
-
'
|
|
2314
|
+
'routes_deposit_address_not_found',
|
|
1562
2315
|
)
|
|
1563
2316
|
}
|
|
1564
2317
|
|
|
1565
2318
|
const absent = await app.request(
|
|
1566
|
-
'/v1/
|
|
1567
|
-
{ ...as(
|
|
2319
|
+
'/v1/routes/deposit-addresses/rda_000000000000000_000000000000000000000000/reconcile',
|
|
2320
|
+
{ ...as(routesWriter), method: 'POST' },
|
|
1568
2321
|
)
|
|
1569
2322
|
expect(absent.status).toBe(404)
|
|
1570
2323
|
expect(dispatched).toEqual([])
|
|
1571
2324
|
})
|
|
1572
2325
|
|
|
1573
2326
|
test('rejects inactive addresses and unavailable reconciliation', async () => {
|
|
1574
|
-
const dispatched:
|
|
2327
|
+
const dispatched: RoutesProvider.Webhook.receive.Dispatchable[] = []
|
|
1575
2328
|
const configured = transfersApp({
|
|
1576
|
-
|
|
2329
|
+
routes: {
|
|
1577
2330
|
dispatchDepositReconciliation: async (message) => {
|
|
1578
2331
|
dispatched.push(message)
|
|
1579
2332
|
},
|
|
1580
2333
|
},
|
|
1581
2334
|
})
|
|
1582
2335
|
const record = await seedDepositAddress()
|
|
1583
|
-
const transition = await
|
|
2336
|
+
const transition = await RoutesDepositAddress.transition(db, {
|
|
1584
2337
|
expectedVersion: record.version,
|
|
1585
2338
|
id: record.id,
|
|
1586
2339
|
status: 'action-required',
|
|
@@ -1588,18 +2341,18 @@ describe('POST /funding/deposit-addresses/:id/reconcile', () => {
|
|
|
1588
2341
|
expect(transition.type).toBe('applied')
|
|
1589
2342
|
|
|
1590
2343
|
const inactive = await configured.request(
|
|
1591
|
-
`/v1/
|
|
1592
|
-
{ ...as(
|
|
2344
|
+
`/v1/routes/deposit-addresses/${record.id}/reconcile`,
|
|
2345
|
+
{ ...as(routesWriter), method: 'POST' },
|
|
1593
2346
|
)
|
|
1594
2347
|
expect({
|
|
1595
2348
|
code: ((await inactive.json()) as { error: { code: string } }).error.code,
|
|
1596
2349
|
status: inactive.status,
|
|
1597
|
-
}).toEqual({ code: '
|
|
2350
|
+
}).toEqual({ code: 'routes_deposit_address_not_active', status: 409 })
|
|
1598
2351
|
|
|
1599
2352
|
const active = await seedDepositAddress()
|
|
1600
2353
|
const unavailable = await transfersApp().request(
|
|
1601
|
-
`/v1/
|
|
1602
|
-
{ ...as(
|
|
2354
|
+
`/v1/routes/deposit-addresses/${active.id}/reconcile`,
|
|
2355
|
+
{ ...as(routesWriter), method: 'POST' },
|
|
1603
2356
|
)
|
|
1604
2357
|
expect({
|
|
1605
2358
|
code: ((await unavailable.json()) as { error: { code: string } }).error.code,
|
|
@@ -1610,15 +2363,15 @@ describe('POST /funding/deposit-addresses/:id/reconcile', () => {
|
|
|
1610
2363
|
|
|
1611
2364
|
test('returns an upstream error when the queue rejects the message', async () => {
|
|
1612
2365
|
const app = transfersApp({
|
|
1613
|
-
|
|
2366
|
+
routes: {
|
|
1614
2367
|
dispatchDepositReconciliation: async () => {
|
|
1615
2368
|
throw new Error('queue unavailable')
|
|
1616
2369
|
},
|
|
1617
2370
|
},
|
|
1618
2371
|
})
|
|
1619
2372
|
const record = await seedDepositAddress()
|
|
1620
|
-
const response = await app.request(`/v1/
|
|
1621
|
-
...as(
|
|
2373
|
+
const response = await app.request(`/v1/routes/deposit-addresses/${record.id}/reconcile`, {
|
|
2374
|
+
...as(routesWriter),
|
|
1622
2375
|
method: 'POST',
|
|
1623
2376
|
})
|
|
1624
2377
|
|
|
@@ -1629,11 +2382,11 @@ describe('POST /funding/deposit-addresses/:id/reconcile', () => {
|
|
|
1629
2382
|
})
|
|
1630
2383
|
})
|
|
1631
2384
|
|
|
1632
|
-
describe('GET /
|
|
2385
|
+
describe('GET /routes/deposits?depositAddress', () => {
|
|
1633
2386
|
test('pages deposits newest-first under an owned address', async () => {
|
|
1634
2387
|
const app = transfersApp()
|
|
1635
2388
|
const address = await seedDepositAddress({
|
|
1636
|
-
snapshot:
|
|
2389
|
+
snapshot: TestRoutes.depositAddressSnapshot({
|
|
1637
2390
|
address: 'TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE',
|
|
1638
2391
|
provider: { id: 'relay_list_deposit_address', name: 'Relay' },
|
|
1639
2392
|
recipient: `0x${'41'.repeat(20)}`,
|
|
@@ -1647,8 +2400,8 @@ describe('GET /funding/deposits?depositAddress', () => {
|
|
|
1647
2400
|
const sixth = await seedDeposit(address)
|
|
1648
2401
|
|
|
1649
2402
|
const response = await app.request(
|
|
1650
|
-
`/v1/
|
|
1651
|
-
as(
|
|
2403
|
+
`/v1/routes/deposits?depositAddress=${address.address}&limit=5`,
|
|
2404
|
+
as(routesReader),
|
|
1652
2405
|
)
|
|
1653
2406
|
expect(response.status).toBe(200)
|
|
1654
2407
|
expect({
|
|
@@ -1660,7 +2413,7 @@ describe('GET /funding/deposits?depositAddress', () => {
|
|
|
1660
2413
|
"etag": null,
|
|
1661
2414
|
}
|
|
1662
2415
|
`)
|
|
1663
|
-
const body = await TestApp.json(response,
|
|
2416
|
+
const body = await TestApp.json(response, Routes.schema.listRoutesDeposits.Response)
|
|
1664
2417
|
expect(body.data.map((deposit) => deposit.id)).toEqual([
|
|
1665
2418
|
sixth.id,
|
|
1666
2419
|
fifth.id,
|
|
@@ -1672,10 +2425,10 @@ describe('GET /funding/deposits?depositAddress', () => {
|
|
|
1672
2425
|
|
|
1673
2426
|
const next = await TestApp.json(
|
|
1674
2427
|
await app.request(
|
|
1675
|
-
`/v1/
|
|
1676
|
-
as(
|
|
2428
|
+
`/v1/routes/deposits?depositAddress=${address.address}&limit=5&cursor=${body.nextCursor}`,
|
|
2429
|
+
as(routesReader),
|
|
1677
2430
|
),
|
|
1678
|
-
|
|
2431
|
+
Routes.schema.listRoutesDeposits.Response,
|
|
1679
2432
|
)
|
|
1680
2433
|
expect(next.data.map((deposit) => deposit.id)).toEqual([first.id])
|
|
1681
2434
|
expect(next.nextCursor).toBeNull()
|
|
@@ -1684,14 +2437,14 @@ describe('GET /funding/deposits?depositAddress', () => {
|
|
|
1684
2437
|
test('returns a provider-observed deposit before source verification', async () => {
|
|
1685
2438
|
const app = transfersApp()
|
|
1686
2439
|
const address = await seedDepositAddress({
|
|
1687
|
-
snapshot:
|
|
2440
|
+
snapshot: TestRoutes.depositAddressSnapshot({
|
|
1688
2441
|
address: 'TF17BgPaZYbz8oxbjhriubPDsA7ArKoLX3',
|
|
1689
2442
|
provider: { id: 'relay_observed', name: 'Relay' },
|
|
1690
2443
|
recipient: `0x${'31'.repeat(20)}`,
|
|
1691
2444
|
}),
|
|
1692
2445
|
})
|
|
1693
2446
|
const sourceTransactionHash = `0x${'ab'.repeat(32)}`
|
|
1694
|
-
await
|
|
2447
|
+
await RoutesDeposit.create(db, {
|
|
1695
2448
|
now: new Date('2026-01-04T00:00:00.000Z'),
|
|
1696
2449
|
providerRequestId: 'relay-observed-request',
|
|
1697
2450
|
snapshot: {
|
|
@@ -1709,11 +2462,11 @@ describe('GET /funding/deposits?depositAddress', () => {
|
|
|
1709
2462
|
})
|
|
1710
2463
|
|
|
1711
2464
|
const response = await app.request(
|
|
1712
|
-
`/v1/
|
|
1713
|
-
as(
|
|
2465
|
+
`/v1/routes/deposits?depositAddress=${address.address}`,
|
|
2466
|
+
as(routesReader),
|
|
1714
2467
|
)
|
|
1715
2468
|
expect(response.status).toBe(200)
|
|
1716
|
-
const body = await TestApp.json(response,
|
|
2469
|
+
const body = await TestApp.json(response, Routes.schema.listRoutesDeposits.Response)
|
|
1717
2470
|
expect(body).toMatchInlineSnapshot(
|
|
1718
2471
|
{
|
|
1719
2472
|
data: [
|
|
@@ -1786,8 +2539,8 @@ describe('GET /funding/deposits?depositAddress', () => {
|
|
|
1786
2539
|
test('hides a foreign deposit address', async () => {
|
|
1787
2540
|
const app = transfersApp()
|
|
1788
2541
|
const address = await seedDepositAddress({
|
|
1789
|
-
orgId:
|
|
1790
|
-
snapshot:
|
|
2542
|
+
orgId: routesForeign.orgId,
|
|
2543
|
+
snapshot: TestRoutes.depositAddressSnapshot({
|
|
1791
2544
|
address: 'TWd4WrZ9wn84f5x1hZhL4DHvk738ns5jwb',
|
|
1792
2545
|
provider: { id: 'relay_foreign_deposit_address', name: 'Relay' },
|
|
1793
2546
|
recipient: `0x${'42'.repeat(20)}`,
|
|
@@ -1795,50 +2548,50 @@ describe('GET /funding/deposits?depositAddress', () => {
|
|
|
1795
2548
|
})
|
|
1796
2549
|
await seedDeposit(address)
|
|
1797
2550
|
const response = await app.request(
|
|
1798
|
-
`/v1/
|
|
1799
|
-
as(
|
|
2551
|
+
`/v1/routes/deposits?depositAddress=${address.address}`,
|
|
2552
|
+
as(routesReader),
|
|
1800
2553
|
)
|
|
1801
2554
|
expect(response.status).toBe(200)
|
|
1802
|
-
expect(await TestApp.json(response,
|
|
2555
|
+
expect(await TestApp.json(response, Routes.schema.listRoutesDeposits.Response)).toEqual({
|
|
1803
2556
|
data: [],
|
|
1804
2557
|
nextCursor: null,
|
|
1805
2558
|
})
|
|
1806
2559
|
})
|
|
1807
2560
|
})
|
|
1808
2561
|
|
|
1809
|
-
describe('GET /
|
|
2562
|
+
describe('GET /routes/deposits', () => {
|
|
1810
2563
|
test('pages organization deposits and narrows project-attributed keys', async () => {
|
|
1811
2564
|
const app = transfersApp()
|
|
1812
|
-
const firstAddress = await seedDepositAddress({ orgId:
|
|
1813
|
-
const secondAddress = await seedDepositAddress({ orgId:
|
|
1814
|
-
const thirdAddress = await seedDepositAddress({ orgId:
|
|
2565
|
+
const firstAddress = await seedDepositAddress({ orgId: routesDepositListReader.orgId })
|
|
2566
|
+
const secondAddress = await seedDepositAddress({ orgId: routesDepositListReader.orgId })
|
|
2567
|
+
const thirdAddress = await seedDepositAddress({ orgId: routesDepositListReader.orgId })
|
|
1815
2568
|
const projectAddress = await seedDepositAddress({
|
|
1816
|
-
orgId:
|
|
1817
|
-
projectId:
|
|
2569
|
+
orgId: routesDepositListReader.orgId,
|
|
2570
|
+
projectId: routesDepositListProjectReader.projectId,
|
|
1818
2571
|
})
|
|
1819
2572
|
const siblingAddress = await seedDepositAddress({
|
|
1820
|
-
orgId:
|
|
1821
|
-
projectId: '
|
|
2573
|
+
orgId: routesDepositListReader.orgId,
|
|
2574
|
+
projectId: 'prj_routes_deposit_list_sibling',
|
|
1822
2575
|
})
|
|
1823
|
-
const sixthAddress = await seedDepositAddress({ orgId:
|
|
2576
|
+
const sixthAddress = await seedDepositAddress({ orgId: routesDepositListReader.orgId })
|
|
1824
2577
|
const first = await seedDeposit(firstAddress)
|
|
1825
2578
|
const second = await seedDeposit(secondAddress)
|
|
1826
2579
|
const third = await seedDeposit(thirdAddress)
|
|
1827
2580
|
const project = await seedDeposit(projectAddress)
|
|
1828
2581
|
const sibling = await seedDeposit(siblingAddress)
|
|
1829
2582
|
const sixth = await seedDeposit(sixthAddress)
|
|
1830
|
-
const foreignAddress = await seedDepositAddress({ orgId:
|
|
2583
|
+
const foreignAddress = await seedDepositAddress({ orgId: routesForeign.orgId })
|
|
1831
2584
|
await seedDeposit(foreignAddress)
|
|
1832
2585
|
const sandboxAddress = await seedDepositAddress({
|
|
1833
2586
|
environment: 'sandbox',
|
|
1834
|
-
orgId:
|
|
2587
|
+
orgId: routesDepositListReader.orgId,
|
|
1835
2588
|
})
|
|
1836
2589
|
await seedDeposit(sandboxAddress)
|
|
1837
2590
|
|
|
1838
|
-
const path = '/v1/
|
|
1839
|
-
const response = await app.request(`${path}?limit=5`, as(
|
|
2591
|
+
const path = '/v1/routes/deposits'
|
|
2592
|
+
const response = await app.request(`${path}?limit=5`, as(routesDepositListReader))
|
|
1840
2593
|
expect(response.status).toBe(200)
|
|
1841
|
-
const body = await TestApp.json(response,
|
|
2594
|
+
const body = await TestApp.json(response, Routes.schema.listRoutesDeposits.Response)
|
|
1842
2595
|
expect(body.data.map((deposit) => deposit.id)).toEqual([
|
|
1843
2596
|
sixth.id,
|
|
1844
2597
|
sibling.id,
|
|
@@ -1849,47 +2602,47 @@ describe('GET /funding/deposits', () => {
|
|
|
1849
2602
|
expect(body.nextCursor).toBe(Cursor.encode([second.createdAt, second.id]))
|
|
1850
2603
|
|
|
1851
2604
|
const next = await TestApp.json(
|
|
1852
|
-
await app.request(`${path}?limit=5&cursor=${body.nextCursor}`, as(
|
|
1853
|
-
|
|
2605
|
+
await app.request(`${path}?limit=5&cursor=${body.nextCursor}`, as(routesDepositListReader)),
|
|
2606
|
+
Routes.schema.listRoutesDeposits.Response,
|
|
1854
2607
|
)
|
|
1855
2608
|
expect(next.data.map((deposit) => deposit.id)).toEqual([first.id])
|
|
1856
2609
|
expect(next.nextCursor).toBeNull()
|
|
1857
2610
|
|
|
1858
2611
|
const projectBody = await TestApp.json(
|
|
1859
|
-
await app.request(path, as(
|
|
1860
|
-
|
|
2612
|
+
await app.request(path, as(routesDepositListProjectReader)),
|
|
2613
|
+
Routes.schema.listRoutesDeposits.Response,
|
|
1861
2614
|
)
|
|
1862
2615
|
expect(projectBody.data.map((deposit) => deposit.id)).toEqual([project.id])
|
|
1863
2616
|
})
|
|
1864
2617
|
})
|
|
1865
2618
|
|
|
1866
|
-
describe('GET /
|
|
1867
|
-
test('requires
|
|
2619
|
+
describe('GET /routes/deposits?recipient', () => {
|
|
2620
|
+
test('requires routes:read and pages recipient deposits across addresses', async () => {
|
|
1868
2621
|
const app = transfersApp()
|
|
1869
2622
|
const recipient = '0xABcdEFABcdEFabcdEfAbCdefabcdeFABcDEFabCD'
|
|
1870
|
-
const path = `/v1/
|
|
2623
|
+
const path = `/v1/routes/deposits?recipient=${recipient.toLowerCase()}`
|
|
1871
2624
|
expect((await app.request(path)).status).toBe(401)
|
|
1872
2625
|
expect((await app.request(path, as(TestApp.key))).status).toBe(403)
|
|
1873
2626
|
expect(
|
|
1874
|
-
(await app.request('/v1/
|
|
2627
|
+
(await app.request('/v1/routes/deposits?depositAddress=', as(routesReader))).status,
|
|
1875
2628
|
).toBe(400)
|
|
1876
2629
|
expect(
|
|
1877
2630
|
(
|
|
1878
2631
|
await app.request(
|
|
1879
2632
|
`${path}&depositAddress=TJRabPrwbZy45sbavfcjinPJC18kjpRTv8`,
|
|
1880
|
-
as(
|
|
2633
|
+
as(routesReader),
|
|
1881
2634
|
)
|
|
1882
2635
|
).status,
|
|
1883
2636
|
).toBe(200)
|
|
1884
2637
|
|
|
1885
2638
|
const firstAddress = await seedDepositAddress({
|
|
1886
|
-
snapshot:
|
|
2639
|
+
snapshot: TestRoutes.depositAddressSnapshot({
|
|
1887
2640
|
provider: { id: 'relay_account_first', name: 'Relay' },
|
|
1888
2641
|
recipient,
|
|
1889
2642
|
}),
|
|
1890
2643
|
})
|
|
1891
2644
|
const secondAddress = await seedDepositAddress({
|
|
1892
|
-
snapshot:
|
|
2645
|
+
snapshot: TestRoutes.depositAddressSnapshot({
|
|
1893
2646
|
provider: { id: 'relay_account_second', name: 'Relay' },
|
|
1894
2647
|
recipient,
|
|
1895
2648
|
subsidize: true,
|
|
@@ -1904,15 +2657,15 @@ describe('GET /funding/deposits?recipient', () => {
|
|
|
1904
2657
|
const unrelatedAddress = await seedDepositAddress()
|
|
1905
2658
|
await seedDeposit(unrelatedAddress)
|
|
1906
2659
|
const foreignAddress = await seedDepositAddress({
|
|
1907
|
-
orgId:
|
|
1908
|
-
snapshot:
|
|
2660
|
+
orgId: routesForeign.orgId,
|
|
2661
|
+
snapshot: TestRoutes.depositAddressSnapshot({
|
|
1909
2662
|
provider: { id: 'relay_account_foreign', name: 'Relay' },
|
|
1910
2663
|
recipient,
|
|
1911
2664
|
}),
|
|
1912
2665
|
})
|
|
1913
2666
|
await seedDeposit(foreignAddress)
|
|
1914
2667
|
|
|
1915
|
-
const response = await app.request(`${path}&limit=5`, as(
|
|
2668
|
+
const response = await app.request(`${path}&limit=5`, as(routesReader))
|
|
1916
2669
|
expect(response.status).toBe(200)
|
|
1917
2670
|
expect({
|
|
1918
2671
|
cacheControl: response.headers.get('cache-control'),
|
|
@@ -1925,7 +2678,7 @@ describe('GET /funding/deposits?recipient', () => {
|
|
|
1925
2678
|
"vary": "Accept-Encoding, Authorization, Tempo-API-Key",
|
|
1926
2679
|
}
|
|
1927
2680
|
`)
|
|
1928
|
-
const body = await TestApp.json(response,
|
|
2681
|
+
const body = await TestApp.json(response, Routes.schema.listRoutesDeposits.Response)
|
|
1929
2682
|
expect(body.data.map((deposit) => deposit.id)).toEqual([
|
|
1930
2683
|
sixth.id,
|
|
1931
2684
|
fifth.id,
|
|
@@ -1936,8 +2689,8 @@ describe('GET /funding/deposits?recipient', () => {
|
|
|
1936
2689
|
expect(body.nextCursor).toBe(Cursor.encode([second.createdAt, second.id]))
|
|
1937
2690
|
|
|
1938
2691
|
const next = await TestApp.json(
|
|
1939
|
-
await app.request(`${path}&limit=5&cursor=${body.nextCursor}`, as(
|
|
1940
|
-
|
|
2692
|
+
await app.request(`${path}&limit=5&cursor=${body.nextCursor}`, as(routesReader)),
|
|
2693
|
+
Routes.schema.listRoutesDeposits.Response,
|
|
1941
2694
|
)
|
|
1942
2695
|
expect(next.data.map((deposit) => deposit.id)).toEqual([first.id])
|
|
1943
2696
|
expect(next.nextCursor).toBeNull()
|
|
@@ -1947,15 +2700,15 @@ describe('GET /funding/deposits?recipient', () => {
|
|
|
1947
2700
|
const app = transfersApp()
|
|
1948
2701
|
const recipient = `0x${'ab'.repeat(20)}`
|
|
1949
2702
|
const projectAddress = await seedDepositAddress({
|
|
1950
|
-
projectId:
|
|
1951
|
-
snapshot:
|
|
2703
|
+
projectId: routesProjectReader.projectId,
|
|
2704
|
+
snapshot: TestRoutes.depositAddressSnapshot({
|
|
1952
2705
|
provider: { id: 'relay_account_project', name: 'Relay' },
|
|
1953
2706
|
recipient,
|
|
1954
2707
|
}),
|
|
1955
2708
|
})
|
|
1956
2709
|
const siblingAddress = await seedDepositAddress({
|
|
1957
|
-
projectId: '
|
|
1958
|
-
snapshot:
|
|
2710
|
+
projectId: 'prj_routes_other',
|
|
2711
|
+
snapshot: TestRoutes.depositAddressSnapshot({
|
|
1959
2712
|
provider: { id: 'relay_account_sibling', name: 'Relay' },
|
|
1960
2713
|
recipient,
|
|
1961
2714
|
}),
|
|
@@ -1964,27 +2717,27 @@ describe('GET /funding/deposits?recipient', () => {
|
|
|
1964
2717
|
await seedDeposit(siblingAddress)
|
|
1965
2718
|
|
|
1966
2719
|
const body = await TestApp.json(
|
|
1967
|
-
await app.request(`/v1/
|
|
1968
|
-
|
|
2720
|
+
await app.request(`/v1/routes/deposits?recipient=${recipient}`, as(routesProjectReader)),
|
|
2721
|
+
Routes.schema.listRoutesDeposits.Response,
|
|
1969
2722
|
)
|
|
1970
2723
|
expect(body.data.map((deposit) => deposit.id)).toEqual([projectDeposit.id])
|
|
1971
2724
|
})
|
|
1972
2725
|
})
|
|
1973
2726
|
|
|
1974
|
-
describe('GET /
|
|
2727
|
+
describe('GET /routes/deposits?filters', () => {
|
|
1975
2728
|
test('AND-combines canonical aliases and includes the matching count', async () => {
|
|
1976
2729
|
const app = transfersApp()
|
|
1977
|
-
const snapshot =
|
|
2730
|
+
const snapshot = TestRoutes.depositAddressSnapshot({
|
|
1978
2731
|
address: 'TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE',
|
|
1979
2732
|
})
|
|
1980
2733
|
const address = await seedDepositAddress({
|
|
1981
|
-
orgId:
|
|
2734
|
+
orgId: routesDepositFilterReader.orgId,
|
|
1982
2735
|
snapshot,
|
|
1983
2736
|
})
|
|
1984
2737
|
const deposit = await seedDeposit(address)
|
|
1985
2738
|
const unrelatedAddress = await seedDepositAddress({
|
|
1986
|
-
orgId:
|
|
1987
|
-
snapshot:
|
|
2739
|
+
orgId: routesDepositFilterReader.orgId,
|
|
2740
|
+
snapshot: TestRoutes.depositAddressSnapshot({
|
|
1988
2741
|
provider: { id: 'relay_unrelated', name: 'Relay' },
|
|
1989
2742
|
recipient: `0x${'22'.repeat(20)}`,
|
|
1990
2743
|
}),
|
|
@@ -2002,21 +2755,21 @@ describe('GET /funding/deposits?filters', () => {
|
|
|
2002
2755
|
})
|
|
2003
2756
|
|
|
2004
2757
|
const body = await TestApp.json(
|
|
2005
|
-
await app.request(`/v1/
|
|
2006
|
-
|
|
2758
|
+
await app.request(`/v1/routes/deposits?${query}`, as(routesDepositFilterReader)),
|
|
2759
|
+
Routes.schema.listRoutesDeposits.Response,
|
|
2007
2760
|
)
|
|
2008
2761
|
expect(body).toEqual({
|
|
2009
|
-
data: [
|
|
2762
|
+
data: [RoutesDeposit.toPublic(deposit)],
|
|
2010
2763
|
meta: { totalCount: 1, totalCountCapped: false },
|
|
2011
2764
|
nextCursor: null,
|
|
2012
2765
|
})
|
|
2013
2766
|
|
|
2014
2767
|
const empty = await TestApp.json(
|
|
2015
2768
|
await app.request(
|
|
2016
|
-
'/v1/
|
|
2017
|
-
as(
|
|
2769
|
+
'/v1/routes/deposits?sourceToken=unknown&include=totalCount',
|
|
2770
|
+
as(routesDepositFilterReader),
|
|
2018
2771
|
),
|
|
2019
|
-
|
|
2772
|
+
Routes.schema.listRoutesDeposits.Response,
|
|
2020
2773
|
)
|
|
2021
2774
|
expect(empty).toEqual({
|
|
2022
2775
|
data: [],
|
|
@@ -2026,7 +2779,7 @@ describe('GET /funding/deposits?filters', () => {
|
|
|
2026
2779
|
})
|
|
2027
2780
|
})
|
|
2028
2781
|
|
|
2029
|
-
describe('GET /
|
|
2782
|
+
describe('GET /routes/deposits/:id', () => {
|
|
2030
2783
|
test('returns the owned deposit without private reconciliation state', async () => {
|
|
2031
2784
|
const app = transfersApp()
|
|
2032
2785
|
const address = await seedDepositAddress()
|
|
@@ -2034,11 +2787,11 @@ describe('GET /funding/deposits/:id', () => {
|
|
|
2034
2787
|
providerRequestIds: ['relay-private'],
|
|
2035
2788
|
providerState: { request: 'private' },
|
|
2036
2789
|
})
|
|
2037
|
-
const response = await app.request(`/v1/
|
|
2790
|
+
const response = await app.request(`/v1/routes/deposits/${record.id}`, as(routesReader))
|
|
2038
2791
|
expect(response.status).toBe(200)
|
|
2039
2792
|
expect(response.headers.get('cache-control')).toBe(Cache.policies.state)
|
|
2040
|
-
const body = await TestApp.json(response,
|
|
2041
|
-
expect(body).toEqual(
|
|
2793
|
+
const body = await TestApp.json(response, Routes.schema.getRoutesDeposit.Response)
|
|
2794
|
+
expect(body).toEqual(RoutesDeposit.toPublic(record))
|
|
2042
2795
|
expect(body).not.toHaveProperty('providerRequestIds')
|
|
2043
2796
|
expect(body).not.toHaveProperty('providerState')
|
|
2044
2797
|
})
|
|
@@ -2047,14 +2800,14 @@ describe('GET /funding/deposits/:id', () => {
|
|
|
2047
2800
|
const app = transfersApp()
|
|
2048
2801
|
const address = await seedDepositAddress()
|
|
2049
2802
|
const record = await seedDeposit(address)
|
|
2050
|
-
expect(
|
|
2051
|
-
|
|
2052
|
-
)
|
|
2803
|
+
expect((await app.request(`/v1/routes/deposits/${record.id}`, as(routesForeign))).status).toBe(
|
|
2804
|
+
404,
|
|
2805
|
+
)
|
|
2053
2806
|
expect(
|
|
2054
2807
|
(
|
|
2055
2808
|
await app.request(
|
|
2056
|
-
'/v1/
|
|
2057
|
-
as(
|
|
2809
|
+
'/v1/routes/deposits/rdp_000000000000000_000000000000000000000000',
|
|
2810
|
+
as(routesReader),
|
|
2058
2811
|
)
|
|
2059
2812
|
).status,
|
|
2060
2813
|
).toBe(404)
|
|
@@ -2073,7 +2826,7 @@ const depositAddressBody = {
|
|
|
2073
2826
|
let depositAddressIdempotencySequence = 0
|
|
2074
2827
|
|
|
2075
2828
|
function nextDepositAddressKey() {
|
|
2076
|
-
return `
|
|
2829
|
+
return `routes_deposit_address_${depositAddressIdempotencySequence++}`
|
|
2077
2830
|
}
|
|
2078
2831
|
|
|
2079
2832
|
function postDepositAddress(
|
|
@@ -2085,10 +2838,10 @@ function postDepositAddress(
|
|
|
2085
2838
|
key?: { token: string } | undefined
|
|
2086
2839
|
} = {},
|
|
2087
2840
|
) {
|
|
2088
|
-
return app.request('/v1/
|
|
2841
|
+
return app.request('/v1/routes/deposit-addresses', {
|
|
2089
2842
|
body: JSON.stringify(options.body ?? depositAddressBody),
|
|
2090
2843
|
headers: options.headers ?? {
|
|
2091
|
-
authorization: `Bearer ${(options.key ??
|
|
2844
|
+
authorization: `Bearer ${(options.key ?? routesWriter).token}`,
|
|
2092
2845
|
'content-type': 'application/json',
|
|
2093
2846
|
'idempotency-key': options.idempotencyKey ?? nextDepositAddressKey(),
|
|
2094
2847
|
},
|
|
@@ -2097,20 +2850,22 @@ function postDepositAddress(
|
|
|
2097
2850
|
}
|
|
2098
2851
|
|
|
2099
2852
|
function withCreateDepositAddress(
|
|
2100
|
-
id:
|
|
2101
|
-
createDepositAddress: NonNullable<
|
|
2853
|
+
id: RoutesProvider.ProviderId,
|
|
2854
|
+
createDepositAddress: NonNullable<RoutesProvider.Provider['createDepositAddress']>,
|
|
2102
2855
|
) {
|
|
2103
2856
|
const provider = providers.find((entry) => entry.id === id)
|
|
2104
2857
|
if (!provider) throw new Error(`Missing ${id} provider`)
|
|
2105
|
-
return
|
|
2858
|
+
return RoutesProvider.from({ ...provider, createDepositAddress })
|
|
2106
2859
|
}
|
|
2107
2860
|
|
|
2108
2861
|
function depositAddressProvider(
|
|
2109
2862
|
address = 'TJRabPrwbZy45sbavfcjinPJC18kjpRTv8',
|
|
2110
|
-
onCreate: (
|
|
2863
|
+
onCreate: (
|
|
2864
|
+
input: RoutesProvider.createDepositAddress.Parameters,
|
|
2865
|
+
) => void | Promise<void> = () => {},
|
|
2111
2866
|
) {
|
|
2112
2867
|
return withCreateDepositAddress('relay', async (input) => {
|
|
2113
|
-
onCreate(input)
|
|
2868
|
+
await onCreate(input)
|
|
2114
2869
|
return {
|
|
2115
2870
|
address,
|
|
2116
2871
|
correlation: {
|
|
@@ -2125,87 +2880,199 @@ function depositAddressProvider(
|
|
|
2125
2880
|
})
|
|
2126
2881
|
}
|
|
2127
2882
|
|
|
2128
|
-
const
|
|
2129
|
-
id: '
|
|
2130
|
-
orgId: '
|
|
2131
|
-
scopes: ['
|
|
2132
|
-
token: '
|
|
2883
|
+
const routesReader = {
|
|
2884
|
+
id: 'key_routes',
|
|
2885
|
+
orgId: 'org_routes',
|
|
2886
|
+
scopes: ['routes:read'],
|
|
2887
|
+
token: 'secret_routes_reader',
|
|
2888
|
+
} satisfies TestApp.kvStore.Key
|
|
2889
|
+
|
|
2890
|
+
const routesAddressListReader = {
|
|
2891
|
+
id: 'key_routes_address_list',
|
|
2892
|
+
orgId: 'org_routes_address_list',
|
|
2893
|
+
scopes: ['routes:read'],
|
|
2894
|
+
token: 'secret_routes_address_list',
|
|
2133
2895
|
} satisfies TestApp.kvStore.Key
|
|
2134
2896
|
|
|
2135
|
-
const
|
|
2136
|
-
id: '
|
|
2137
|
-
orgId:
|
|
2138
|
-
|
|
2139
|
-
|
|
2897
|
+
const routesAddressListProjectReader = {
|
|
2898
|
+
id: 'key_routes_address_list_project',
|
|
2899
|
+
orgId: routesAddressListReader.orgId,
|
|
2900
|
+
projectId: 'prj_routes_address_list',
|
|
2901
|
+
scopes: ['routes:read'],
|
|
2902
|
+
token: 'secret_routes_address_list_project',
|
|
2140
2903
|
} satisfies TestApp.kvStore.Key
|
|
2141
2904
|
|
|
2142
|
-
const
|
|
2143
|
-
id: '
|
|
2144
|
-
orgId:
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
token: 'secret_funding_address_list_project',
|
|
2905
|
+
const routesDepositListReader = {
|
|
2906
|
+
id: 'key_routes_deposit_list',
|
|
2907
|
+
orgId: 'org_routes_deposit_list',
|
|
2908
|
+
scopes: ['routes:read'],
|
|
2909
|
+
token: 'secret_routes_deposit_list',
|
|
2148
2910
|
} satisfies TestApp.kvStore.Key
|
|
2149
2911
|
|
|
2150
|
-
const
|
|
2151
|
-
id: '
|
|
2152
|
-
orgId: '
|
|
2153
|
-
scopes: ['
|
|
2154
|
-
token: '
|
|
2912
|
+
const routesDepositFilterReader = {
|
|
2913
|
+
id: 'key_routes_deposit_filter',
|
|
2914
|
+
orgId: 'org_routes_deposit_filter',
|
|
2915
|
+
scopes: ['routes:read'],
|
|
2916
|
+
token: 'secret_routes_deposit_filter',
|
|
2155
2917
|
} satisfies TestApp.kvStore.Key
|
|
2156
2918
|
|
|
2157
|
-
const
|
|
2158
|
-
id: '
|
|
2159
|
-
orgId:
|
|
2160
|
-
|
|
2161
|
-
|
|
2919
|
+
const routesDepositListProjectReader = {
|
|
2920
|
+
id: 'key_routes_deposit_list_project',
|
|
2921
|
+
orgId: routesDepositListReader.orgId,
|
|
2922
|
+
projectId: 'prj_routes_deposit_list',
|
|
2923
|
+
scopes: ['routes:read'],
|
|
2924
|
+
token: 'secret_routes_deposit_list_project',
|
|
2162
2925
|
} satisfies TestApp.kvStore.Key
|
|
2163
2926
|
|
|
2164
|
-
const
|
|
2165
|
-
id: '
|
|
2166
|
-
orgId:
|
|
2167
|
-
projectId: '
|
|
2168
|
-
scopes: ['
|
|
2169
|
-
token: '
|
|
2927
|
+
const routesProjectReader = {
|
|
2928
|
+
id: 'key_routes_project',
|
|
2929
|
+
orgId: 'org_routes',
|
|
2930
|
+
projectId: 'prj_routes',
|
|
2931
|
+
scopes: ['routes:read'],
|
|
2932
|
+
token: 'secret_routes_project',
|
|
2170
2933
|
} satisfies TestApp.kvStore.Key
|
|
2171
2934
|
|
|
2172
|
-
const
|
|
2173
|
-
id: '
|
|
2174
|
-
orgId: '
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
token: 'secret_funding_project',
|
|
2935
|
+
const routesForeign = {
|
|
2936
|
+
id: 'key_routes_other',
|
|
2937
|
+
orgId: 'org_routes_other',
|
|
2938
|
+
scopes: ['routes:read'],
|
|
2939
|
+
token: 'secret_routes_other',
|
|
2178
2940
|
} satisfies TestApp.kvStore.Key
|
|
2179
2941
|
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2942
|
+
/** Key with routes write access in a different organization. */
|
|
2943
|
+
const routesForeignWriter = {
|
|
2944
|
+
id: 'key_routes_other_writer',
|
|
2945
|
+
orgId: routesForeign.orgId,
|
|
2946
|
+
scopes: ['routes:write'],
|
|
2947
|
+
token: 'secret_routes_other_writer',
|
|
2185
2948
|
} satisfies TestApp.kvStore.Key
|
|
2186
2949
|
|
|
2187
|
-
/**
|
|
2188
|
-
const
|
|
2189
|
-
id: '
|
|
2190
|
-
orgId:
|
|
2191
|
-
|
|
2192
|
-
|
|
2950
|
+
/** Project-attributed routes writer in the owning organization. */
|
|
2951
|
+
const routesProjectWriter = {
|
|
2952
|
+
id: 'key_routes_project_writer',
|
|
2953
|
+
orgId: routesReader.orgId,
|
|
2954
|
+
projectId: routesProjectReader.projectId,
|
|
2955
|
+
scopes: ['routes:write'],
|
|
2956
|
+
token: 'secret_routes_project_writer',
|
|
2193
2957
|
} satisfies TestApp.kvStore.Key
|
|
2194
2958
|
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
scopes: ['funding:write'],
|
|
2201
|
-
token: 'secret_funding_project_writer',
|
|
2959
|
+
const routesSubsidyBillingWriter = {
|
|
2960
|
+
id: 'key_routes_subsidy_billing',
|
|
2961
|
+
orgId: 'org_routes_subsidy_billing',
|
|
2962
|
+
scopes: ['routes:write'],
|
|
2963
|
+
token: 'secret_routes_subsidy_billing',
|
|
2202
2964
|
} satisfies TestApp.kvStore.Key
|
|
2203
2965
|
|
|
2204
|
-
const
|
|
2205
|
-
id: '
|
|
2206
|
-
orgId: '
|
|
2207
|
-
scopes: ['
|
|
2208
|
-
token: '
|
|
2966
|
+
const routesSubsidyDisabledWriter = {
|
|
2967
|
+
id: 'key_routes_subsidy_disabled',
|
|
2968
|
+
orgId: 'org_routes_subsidy_disabled',
|
|
2969
|
+
scopes: ['routes:write'],
|
|
2970
|
+
token: 'secret_routes_subsidy_disabled',
|
|
2971
|
+
} satisfies TestApp.kvStore.Key
|
|
2972
|
+
|
|
2973
|
+
const routesSubsidyPastDueWriter = {
|
|
2974
|
+
id: 'key_routes_subsidy_past_due',
|
|
2975
|
+
orgId: 'org_routes_subsidy_past_due',
|
|
2976
|
+
scopes: ['routes:write'],
|
|
2977
|
+
token: 'secret_routes_subsidy_past_due',
|
|
2978
|
+
} satisfies TestApp.kvStore.Key
|
|
2979
|
+
|
|
2980
|
+
const routesSubsidyReplayWriter = {
|
|
2981
|
+
id: 'key_routes_subsidy_replay',
|
|
2982
|
+
orgId: 'org_routes_subsidy_replay',
|
|
2983
|
+
scopes: ['routes:write'],
|
|
2984
|
+
token: 'secret_routes_subsidy_replay',
|
|
2985
|
+
} satisfies TestApp.kvStore.Key
|
|
2986
|
+
|
|
2987
|
+
const routesSubsidyResumeWriter = {
|
|
2988
|
+
id: 'key_routes_subsidy_resume',
|
|
2989
|
+
orgId: 'org_routes_subsidy_resume',
|
|
2990
|
+
scopes: ['routes:write'],
|
|
2991
|
+
token: 'secret_routes_subsidy_resume',
|
|
2992
|
+
} satisfies TestApp.kvStore.Key
|
|
2993
|
+
|
|
2994
|
+
const routesSubsidyWriter = {
|
|
2995
|
+
id: 'key_routes_subsidy',
|
|
2996
|
+
orgId: 'org_routes_subsidy',
|
|
2997
|
+
scopes: ['routes:write'],
|
|
2998
|
+
token: 'secret_routes_subsidy',
|
|
2999
|
+
} satisfies TestApp.kvStore.Key
|
|
3000
|
+
|
|
3001
|
+
const routesSubsidyWriterSecond = {
|
|
3002
|
+
id: 'key_routes_subsidy_second',
|
|
3003
|
+
orgId: routesSubsidyWriter.orgId,
|
|
3004
|
+
scopes: ['routes:write'],
|
|
3005
|
+
token: 'secret_routes_subsidy_second',
|
|
3006
|
+
} satisfies TestApp.kvStore.Key
|
|
3007
|
+
|
|
3008
|
+
const routesWriter = {
|
|
3009
|
+
id: 'key_routes_writer',
|
|
3010
|
+
orgId: 'org_routes',
|
|
3011
|
+
scopes: ['routes:read', 'routes:write'],
|
|
3012
|
+
token: 'secret_routes_writer',
|
|
3013
|
+
} satisfies TestApp.kvStore.Key
|
|
3014
|
+
|
|
3015
|
+
const routesWriterSecond = {
|
|
3016
|
+
id: 'key_routes_writer_second',
|
|
3017
|
+
orgId: routesWriter.orgId,
|
|
3018
|
+
scopes: ['routes:read', 'routes:write'],
|
|
3019
|
+
token: 'secret_routes_writer_second',
|
|
3020
|
+
} satisfies TestApp.kvStore.Key
|
|
3021
|
+
|
|
3022
|
+
const routesLimitWriter = {
|
|
3023
|
+
id: 'key_routes_limit_writer',
|
|
3024
|
+
orgId: 'org_routes_limit',
|
|
3025
|
+
scopes: ['routes:write'],
|
|
3026
|
+
token: 'secret_routes_limit_writer',
|
|
3027
|
+
} satisfies TestApp.kvStore.Key
|
|
3028
|
+
|
|
3029
|
+
const routesLimitWriterSecond = {
|
|
3030
|
+
id: 'key_routes_limit_writer_second',
|
|
3031
|
+
orgId: routesLimitWriter.orgId,
|
|
3032
|
+
scopes: ['routes:write'],
|
|
3033
|
+
token: 'secret_routes_limit_writer_second',
|
|
3034
|
+
} satisfies TestApp.kvStore.Key
|
|
3035
|
+
|
|
3036
|
+
const routesLegacyWriter = {
|
|
3037
|
+
id: 'key_routes_legacy_writer',
|
|
3038
|
+
orgId: 'key_routes_legacy_writer',
|
|
3039
|
+
scopes: ['routes:write'],
|
|
3040
|
+
token: 'secret_routes_legacy_writer',
|
|
3041
|
+
} satisfies TestApp.kvStore.Key
|
|
3042
|
+
|
|
3043
|
+
const routesRaceWriter = {
|
|
3044
|
+
id: 'key_routes_race_writer',
|
|
3045
|
+
orgId: 'org_routes_race',
|
|
3046
|
+
scopes: ['routes:write'],
|
|
3047
|
+
token: 'secret_routes_race_writer',
|
|
3048
|
+
} satisfies TestApp.kvStore.Key
|
|
3049
|
+
|
|
3050
|
+
const routesOwnerRaceWriter = {
|
|
3051
|
+
id: 'key_routes_owner_race_writer',
|
|
3052
|
+
orgId: 'org_routes_owner_race',
|
|
3053
|
+
scopes: ['routes:write'],
|
|
3054
|
+
token: 'secret_routes_owner_race_writer',
|
|
3055
|
+
} satisfies TestApp.kvStore.Key
|
|
3056
|
+
|
|
3057
|
+
const routesOwnerRaceSiblingWriter = {
|
|
3058
|
+
id: 'key_routes_owner_race_sibling_writer',
|
|
3059
|
+
orgId: 'org_routes_owner_race_sibling',
|
|
3060
|
+
scopes: ['routes:write'],
|
|
3061
|
+
token: 'secret_routes_owner_race_sibling_writer',
|
|
3062
|
+
} satisfies TestApp.kvStore.Key
|
|
3063
|
+
|
|
3064
|
+
const routesOwnerRaceReplacementWriter = {
|
|
3065
|
+
id: 'key_routes_owner_race_replacement_writer',
|
|
3066
|
+
orgId: 'org_routes_owner_race_replacement',
|
|
3067
|
+
scopes: ['routes:write'],
|
|
3068
|
+
token: 'secret_routes_owner_race_replacement_writer',
|
|
3069
|
+
} satisfies TestApp.kvStore.Key
|
|
3070
|
+
|
|
3071
|
+
const routesSubsidyRaceWriter = {
|
|
3072
|
+
id: 'key_routes_subsidy_race_writer',
|
|
3073
|
+
orgId: 'org_routes_subsidy_race',
|
|
3074
|
+
scopes: ['routes:write'],
|
|
3075
|
+
token: 'secret_routes_subsidy_race_writer',
|
|
2209
3076
|
} satisfies TestApp.kvStore.Key
|
|
2210
3077
|
|
|
2211
3078
|
function transfersApp(options: TestApp.create.Options = {}) {
|
|
@@ -2214,41 +3081,74 @@ function transfersApp(options: TestApp.create.Options = {}) {
|
|
|
2214
3081
|
auth: {
|
|
2215
3082
|
keys: [
|
|
2216
3083
|
TestApp.key,
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
3084
|
+
routesAddressListProjectReader,
|
|
3085
|
+
routesAddressListReader,
|
|
3086
|
+
routesDepositFilterReader,
|
|
3087
|
+
routesDepositListProjectReader,
|
|
3088
|
+
routesDepositListReader,
|
|
3089
|
+
routesForeign,
|
|
3090
|
+
routesForeignWriter,
|
|
3091
|
+
routesProjectReader,
|
|
3092
|
+
routesProjectWriter,
|
|
3093
|
+
routesReader,
|
|
3094
|
+
routesLegacyWriter,
|
|
3095
|
+
routesLimitWriter,
|
|
3096
|
+
routesLimitWriterSecond,
|
|
3097
|
+
routesOwnerRaceReplacementWriter,
|
|
3098
|
+
routesOwnerRaceSiblingWriter,
|
|
3099
|
+
routesOwnerRaceWriter,
|
|
3100
|
+
routesRaceWriter,
|
|
3101
|
+
routesSubsidyBillingWriter,
|
|
3102
|
+
routesSubsidyDisabledWriter,
|
|
3103
|
+
routesSubsidyPastDueWriter,
|
|
3104
|
+
routesSubsidyRaceWriter,
|
|
3105
|
+
routesSubsidyReplayWriter,
|
|
3106
|
+
routesSubsidyResumeWriter,
|
|
3107
|
+
routesSubsidyWriter,
|
|
3108
|
+
routesSubsidyWriterSecond,
|
|
3109
|
+
routesWriter,
|
|
3110
|
+
routesWriterSecond,
|
|
2228
3111
|
],
|
|
2229
3112
|
},
|
|
2230
3113
|
defaultChainId: options.defaultChainId ?? tempoMainnet.id,
|
|
2231
3114
|
})
|
|
2232
3115
|
}
|
|
2233
3116
|
|
|
3117
|
+
async function enableRoutesSubsidy(
|
|
3118
|
+
key: TestApp.kvStore.Key,
|
|
3119
|
+
billingStatus?: StripeCustomers.Status,
|
|
3120
|
+
) {
|
|
3121
|
+
await Organizations.upsert(db, { id: key.orgId, name: key.orgId })
|
|
3122
|
+
await RoutesSubsidies.upsertOrganization(db, {
|
|
3123
|
+
frequency: 'tx',
|
|
3124
|
+
maxAmount: '5',
|
|
3125
|
+
orgId: key.orgId,
|
|
3126
|
+
})
|
|
3127
|
+
if (!billingStatus) return
|
|
3128
|
+
await StripeCustomers.create(db, {
|
|
3129
|
+
orgId: key.orgId,
|
|
3130
|
+
stripeCustomerId: `cus_${key.id}`,
|
|
3131
|
+
})
|
|
3132
|
+
await StripeCustomers.setStatus(db, key.orgId, billingStatus)
|
|
3133
|
+
}
|
|
3134
|
+
|
|
2234
3135
|
function as(key: { token: string }) {
|
|
2235
3136
|
return { headers: { authorization: `Bearer ${key.token}` } } as const
|
|
2236
3137
|
}
|
|
2237
3138
|
|
|
2238
3139
|
let seedDepositAddressSecond = 0
|
|
2239
3140
|
|
|
2240
|
-
function seedDepositAddress(input: Partial<
|
|
3141
|
+
function seedDepositAddress(input: Partial<RoutesDepositAddress.create.Input> = {}) {
|
|
2241
3142
|
const index = seedDepositAddressSecond++
|
|
2242
3143
|
const now = new Date(Date.UTC(2026, 0, 3, 0, 0, index))
|
|
2243
|
-
return
|
|
2244
|
-
apiKeyId: fundingReader.id,
|
|
3144
|
+
return RoutesDepositAddress.create(db, {
|
|
2245
3145
|
deliveryStrategy: 'provider',
|
|
2246
3146
|
environment: 'production',
|
|
2247
|
-
id:
|
|
3147
|
+
id: RoutesDepositAddress.generateId(now),
|
|
2248
3148
|
now,
|
|
2249
|
-
orgId:
|
|
2250
|
-
providerOutputToken:
|
|
2251
|
-
snapshot:
|
|
3149
|
+
orgId: routesReader.orgId,
|
|
3150
|
+
providerOutputToken: TestRoutes.providerOutputToken(),
|
|
3151
|
+
snapshot: TestRoutes.depositAddressSnapshot({
|
|
2252
3152
|
provider: { id: `relay_route_${index}`, name: 'Relay' },
|
|
2253
3153
|
recipient: `0x${index.toString(16).padStart(40, '0')}`,
|
|
2254
3154
|
}),
|
|
@@ -2260,15 +3160,15 @@ let seedDepositSecond = 0
|
|
|
2260
3160
|
|
|
2261
3161
|
function seedDeposit(
|
|
2262
3162
|
address: Awaited<ReturnType<typeof seedDepositAddress>>,
|
|
2263
|
-
input: Partial<
|
|
3163
|
+
input: Partial<RoutesDeposit.create.Input> = {},
|
|
2264
3164
|
) {
|
|
2265
3165
|
const index = seedDepositSecond++
|
|
2266
3166
|
const now = new Date(Date.UTC(2026, 0, 4, 0, 0, index))
|
|
2267
3167
|
const sourceTransactionHash = index.toString(16).padStart(64, '0')
|
|
2268
|
-
return
|
|
3168
|
+
return RoutesDeposit.create(db, {
|
|
2269
3169
|
now,
|
|
2270
3170
|
providerRequestId: `relay_request_${index}`,
|
|
2271
|
-
snapshot:
|
|
3171
|
+
snapshot: TestRoutes.depositSnapshot(address.id, {
|
|
2272
3172
|
provider: address.snapshot.provider,
|
|
2273
3173
|
sourceTransactionHashes: [sourceTransactionHash],
|
|
2274
3174
|
}),
|