tapimo 0.15.1 → 0.18.1
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 +137 -0
- package/dist/ApiKey.d.ts +1 -0
- package/dist/ApiKey.d.ts.map +1 -1
- package/dist/ApiKey.js +4 -2
- package/dist/ApiKey.js.map +1 -1
- package/dist/ApiKeys.d.ts +37 -11
- package/dist/ApiKeys.d.ts.map +1 -1
- package/dist/ApiKeys.js +163 -10
- package/dist/ApiKeys.js.map +1 -1
- package/dist/App.d.ts +13085 -11974
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js +46 -15
- package/dist/App.js.map +1 -1
- package/dist/Scope.d.ts +1 -1
- package/dist/Scope.d.ts.map +1 -1
- package/dist/Scope.js +1 -1
- package/dist/Scope.js.map +1 -1
- package/dist/admin/App.d.ts +893 -191
- package/dist/admin/App.d.ts.map +1 -1
- package/dist/admin/App.js +5 -1
- package/dist/admin/App.js.map +1 -1
- package/dist/admin/apps/api-keys.d.ts +70 -70
- package/dist/admin/apps/api-keys.d.ts.map +1 -1
- package/dist/admin/apps/api-keys.js +8 -3
- package/dist/admin/apps/api-keys.js.map +1 -1
- package/dist/admin/apps/earn-vaults.d.ts +66 -27
- package/dist/admin/apps/earn-vaults.d.ts.map +1 -1
- package/dist/admin/apps/earn-vaults.js +36 -7
- package/dist/admin/apps/earn-vaults.js.map +1 -1
- package/dist/admin/apps/organizations.d.ts +25 -25
- package/dist/admin/apps/organizations.d.ts.map +1 -1
- package/dist/admin/apps/organizations.js +5 -4
- package/dist/admin/apps/organizations.js.map +1 -1
- package/dist/admin/apps/route-policies.d.ts +632 -0
- package/dist/admin/apps/route-policies.d.ts.map +1 -0
- package/dist/admin/apps/route-policies.js +257 -0
- package/dist/admin/apps/route-policies.js.map +1 -0
- package/dist/admin/apps/routes-support.js +39 -3
- package/dist/admin/apps/routes-support.js.map +1 -1
- package/dist/admin/apps/routes.d.ts +529 -76
- package/dist/admin/apps/routes.d.ts.map +1 -1
- package/dist/admin/apps/routes.js +82 -1
- package/dist/admin/apps/routes.js.map +1 -1
- package/dist/admin/apps/verified-tokens.d.ts +157 -157
- package/dist/admin/index.d.ts +0 -1
- package/dist/admin/index.d.ts.map +1 -1
- package/dist/admin/index.js +0 -1
- package/dist/admin/index.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 +205 -201
- package/dist/admin/ui.generated.js.map +1 -1
- package/dist/analytics/Analytics.d.ts.map +1 -1
- package/dist/analytics/Analytics.js +65 -1
- package/dist/analytics/Analytics.js.map +1 -1
- package/dist/analytics/tables/requestEvents.d.ts +1 -1
- package/dist/analytics/tables/requestEvents.d.ts.map +1 -1
- package/dist/analytics/tables/requestEvents.js +58 -59
- package/dist/analytics/tables/requestEvents.js.map +1 -1
- package/dist/apps/data/App.d.ts +2709 -2670
- package/dist/apps/data/App.d.ts.map +1 -1
- package/dist/apps/data/routes/activities.d.ts +357 -357
- package/dist/apps/data/routes/activities.d.ts.map +1 -1
- package/dist/apps/data/routes/activities.js +50 -0
- package/dist/apps/data/routes/activities.js.map +1 -1
- package/dist/apps/data/routes/addresses.d.ts +248 -248
- package/dist/apps/data/routes/balances.d.ts +22 -22
- package/dist/apps/data/routes/balances.d.ts.map +1 -1
- package/dist/apps/data/routes/balances.js +5 -7
- package/dist/apps/data/routes/balances.js.map +1 -1
- package/dist/apps/data/routes/blocks.d.ts +125 -125
- package/dist/apps/data/routes/coingecko.d.ts +54 -54
- package/dist/apps/data/routes/earn.d.ts +103 -12
- package/dist/apps/data/routes/earn.d.ts.map +1 -1
- package/dist/apps/data/routes/earn.js +456 -220
- package/dist/apps/data/routes/earn.js.map +1 -1
- package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
- package/dist/apps/data/routes/exchanges.js +267 -97
- package/dist/apps/data/routes/exchanges.js.map +1 -1
- package/dist/apps/data/routes/fee-amm.d.ts +109 -127
- package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
- package/dist/apps/data/routes/fee-amm.js +83 -54
- package/dist/apps/data/routes/fee-amm.js.map +1 -1
- package/dist/apps/data/routes/indexer.d.ts +43 -43
- package/dist/apps/data/routes/receipts.d.ts +235 -235
- package/dist/apps/data/routes/rpc.d.ts +30 -30
- package/dist/apps/data/routes/tokens.d.ts.map +1 -1
- package/dist/apps/data/routes/tokens.js +11 -6
- package/dist/apps/data/routes/tokens.js.map +1 -1
- package/dist/apps/data/routes/transactions.d.ts +2 -0
- package/dist/apps/data/routes/transactions.d.ts.map +1 -1
- package/dist/apps/data/routes/transactions.js +30 -22
- package/dist/apps/data/routes/transactions.js.map +1 -1
- package/dist/apps/data/routes/transfers.d.ts +77 -77
- package/dist/apps/data/routes/valuation.d.ts +32 -32
- package/dist/apps/data/routes/verified-tokens.d.ts +86 -86
- package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
- package/dist/apps/data/routes/webhooks.js +1 -1
- package/dist/apps/data/routes/webhooks.js.map +1 -1
- package/dist/apps/data/routes/zones.d.ts +31 -31
- package/dist/apps/management/App.d.ts +2909 -2064
- package/dist/apps/management/App.d.ts.map +1 -1
- package/dist/apps/management/App.js +2 -0
- package/dist/apps/management/App.js.map +1 -1
- package/dist/apps/management/Billing.d.ts +2 -4
- package/dist/apps/management/Billing.d.ts.map +1 -1
- package/dist/apps/management/Billing.js +65 -26
- package/dist/apps/management/Billing.js.map +1 -1
- package/dist/apps/management/routes/api-keys.d.ts +257 -245
- package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
- package/dist/apps/management/routes/api-keys.js +70 -11
- package/dist/apps/management/routes/api-keys.js.map +1 -1
- package/dist/apps/management/routes/billing.d.ts +84 -84
- package/dist/apps/management/routes/cli.d.ts +912 -0
- package/dist/apps/management/routes/cli.d.ts.map +1 -0
- package/dist/apps/management/routes/cli.js +416 -0
- package/dist/apps/management/routes/cli.js.map +1 -0
- package/dist/apps/management/routes/faucet.d.ts +8 -8
- package/dist/apps/management/routes/invitations.d.ts +138 -138
- package/dist/apps/management/routes/invite-links.d.ts +172 -172
- package/dist/apps/management/routes/members.d.ts +16 -16
- package/dist/apps/management/routes/orgs.d.ts +104 -104
- package/dist/apps/management/routes/orgs.d.ts.map +1 -1
- package/dist/apps/management/routes/orgs.js +8 -2
- package/dist/apps/management/routes/orgs.js.map +1 -1
- package/dist/apps/management/routes/projects.d.ts +125 -125
- package/dist/apps/management/routes/usage.d.ts +8 -8
- package/dist/apps/management/routes/verified-token-requests.d.ts +86 -86
- package/dist/apps/management/routes/webhooks.d.ts +485 -485
- package/dist/apps/mpp/App.d.ts +44 -44
- package/dist/apps/mpp/internal/Policy.d.ts.map +1 -1
- package/dist/apps/mpp/internal/Policy.js +4 -2
- package/dist/apps/mpp/internal/Policy.js.map +1 -1
- package/dist/apps/mpp/internal/Sponsorship.d.ts.map +1 -1
- package/dist/apps/mpp/internal/Sponsorship.js +6 -4
- package/dist/apps/mpp/internal/Sponsorship.js.map +1 -1
- package/dist/apps/relay/App.d.ts +8 -0
- package/dist/apps/relay/App.d.ts.map +1 -1
- package/dist/apps/relay/App.js +16 -4
- package/dist/apps/relay/App.js.map +1 -1
- package/dist/apps/relay/Sponsorships.d.ts +4 -6
- package/dist/apps/relay/Sponsorships.d.ts.map +1 -1
- package/dist/apps/relay/Sponsorships.js +71 -60
- package/dist/apps/relay/Sponsorships.js.map +1 -1
- package/dist/apps/routes/Access.d.ts +53 -0
- package/dist/apps/routes/Access.d.ts.map +1 -1
- package/dist/apps/routes/Access.js +121 -0
- package/dist/apps/routes/Access.js.map +1 -1
- package/dist/apps/routes/App.d.ts +397 -158
- package/dist/apps/routes/App.d.ts.map +1 -1
- package/dist/apps/routes/App.js.map +1 -1
- package/dist/apps/routes/routes/chains.d.ts +25 -25
- package/dist/apps/routes/routes/deposit-addresses.d.ts +169 -61
- package/dist/apps/routes/routes/deposit-addresses.d.ts.map +1 -1
- package/dist/apps/routes/routes/deposit-addresses.js +217 -32
- package/dist/apps/routes/routes/deposit-addresses.js.map +1 -1
- package/dist/apps/routes/routes/quotes.d.ts +171 -81
- package/dist/apps/routes/routes/quotes.d.ts.map +1 -1
- package/dist/apps/routes/routes/quotes.js +101 -27
- package/dist/apps/routes/routes/quotes.js.map +1 -1
- package/dist/apps/routes/routes/transfers.d.ts +532 -480
- package/dist/apps/routes/routes/transfers.d.ts.map +1 -1
- package/dist/apps/routes/routes/transfers.js +182 -37
- package/dist/apps/routes/routes/transfers.js.map +1 -1
- package/dist/cli/ApiKeys.d.ts +120 -0
- package/dist/cli/ApiKeys.d.ts.map +1 -0
- package/dist/cli/ApiKeys.js +138 -0
- package/dist/cli/ApiKeys.js.map +1 -0
- package/dist/cli/Cli.d.ts +92 -34
- package/dist/cli/Cli.d.ts.map +1 -1
- package/dist/cli/Cli.js +188 -11
- package/dist/cli/Cli.js.map +1 -1
- package/dist/cli/Credentials.d.ts +95 -0
- package/dist/cli/Credentials.d.ts.map +1 -0
- package/dist/cli/Credentials.js +110 -0
- package/dist/cli/Credentials.js.map +1 -0
- package/dist/cli/Spec.d.ts +59 -0
- package/dist/cli/Spec.d.ts.map +1 -0
- package/dist/cli/Spec.js +77 -0
- package/dist/cli/Spec.js.map +1 -0
- package/dist/cli/bin.js +5 -1
- package/dist/cli/bin.js.map +1 -1
- package/dist/cli/commands/admin.d.ts +5 -5
- package/dist/cli/commands/admin.d.ts.map +1 -1
- package/dist/cli/commands/auth.d.ts +73 -0
- package/dist/cli/commands/auth.d.ts.map +1 -0
- package/dist/cli/commands/auth.js +204 -0
- package/dist/cli/commands/auth.js.map +1 -0
- package/dist/cli/commands/keys.d.ts +17 -0
- package/dist/cli/commands/keys.d.ts.map +1 -0
- package/dist/cli/commands/keys.js +109 -0
- package/dist/cli/commands/keys.js.map +1 -0
- package/dist/cloudflare.d.ts +27 -2
- package/dist/cloudflare.d.ts.map +1 -1
- package/dist/cloudflare.js +144 -17
- package/dist/cloudflare.js.map +1 -1
- package/dist/db/Db.d.ts +23 -0
- package/dist/db/Db.d.ts.map +1 -1
- package/dist/db/Db.js +413 -1
- package/dist/db/Db.js.map +1 -1
- package/dist/db/Schema.d.ts +44 -1
- package/dist/db/Schema.d.ts.map +1 -1
- package/dist/db/Schema.js +56 -3
- package/dist/db/Schema.js.map +1 -1
- package/dist/db/tables/apiKeyAdmissions.d.ts +28 -2
- package/dist/db/tables/apiKeyAdmissions.d.ts.map +1 -1
- package/dist/db/tables/apiKeyAdmissions.js +65 -9
- package/dist/db/tables/apiKeyAdmissions.js.map +1 -1
- package/dist/db/tables/apiKeyOwnerTombstones.d.ts +2 -0
- package/dist/db/tables/apiKeyOwnerTombstones.d.ts.map +1 -1
- package/dist/db/tables/apiKeyOwnerTombstones.js +2 -2
- package/dist/db/tables/apiKeyOwnerTombstones.js.map +1 -1
- package/dist/db/tables/authAccounts.d.ts.map +1 -1
- package/dist/db/tables/authAccounts.js +1 -0
- package/dist/db/tables/authAccounts.js.map +1 -1
- package/dist/db/tables/earnVaults.d.ts +5 -1
- package/dist/db/tables/earnVaults.d.ts.map +1 -1
- package/dist/db/tables/earnVaults.js +12 -1
- package/dist/db/tables/earnVaults.js.map +1 -1
- package/dist/db/tables/organizations.d.ts +4 -2
- package/dist/db/tables/organizations.d.ts.map +1 -1
- package/dist/db/tables/organizations.js +8 -34
- package/dist/db/tables/organizations.js.map +1 -1
- package/dist/db/tables/requestUsage.d.ts +5 -1
- package/dist/db/tables/requestUsage.d.ts.map +1 -1
- package/dist/db/tables/requestUsage.js +10 -2
- package/dist/db/tables/requestUsage.js.map +1 -1
- package/dist/db/tables/rewardEligibilityAssociations.d.ts +13 -0
- package/dist/db/tables/rewardEligibilityAssociations.d.ts.map +1 -1
- package/dist/db/tables/rewardEligibilityAssociations.js +11 -0
- package/dist/db/tables/rewardEligibilityAssociations.js.map +1 -1
- package/dist/db/tables/rewardRuns.d.ts.map +1 -1
- package/dist/db/tables/rewardRuns.js +4 -0
- package/dist/db/tables/rewardRuns.js.map +1 -1
- package/dist/db/tables/rewardTransactionAttempts.d.ts.map +1 -1
- package/dist/db/tables/rewardTransactionAttempts.js +2 -0
- package/dist/db/tables/rewardTransactionAttempts.js.map +1 -1
- package/dist/db/tables/routesDepositAddresses.d.ts +29 -0
- package/dist/db/tables/routesDepositAddresses.d.ts.map +1 -1
- package/dist/db/tables/routesDepositAddresses.js +84 -31
- package/dist/db/tables/routesDepositAddresses.js.map +1 -1
- package/dist/db/tables/routesDeposits.d.ts.map +1 -1
- package/dist/db/tables/routesDeposits.js +31 -21
- package/dist/db/tables/routesDeposits.js.map +1 -1
- package/dist/db/tables/routesIdempotency.d.ts.map +1 -1
- package/dist/db/tables/routesIdempotency.js +2 -0
- package/dist/db/tables/routesIdempotency.js.map +1 -1
- package/dist/db/tables/routesPolicies.d.ts +58 -0
- package/dist/db/tables/routesPolicies.d.ts.map +1 -0
- package/dist/db/tables/routesPolicies.js +198 -0
- package/dist/db/tables/routesPolicies.js.map +1 -0
- package/dist/db/tables/routesTransferSubsidies.d.ts +22 -0
- package/dist/db/tables/routesTransferSubsidies.d.ts.map +1 -1
- package/dist/db/tables/routesTransferSubsidies.js +41 -0
- package/dist/db/tables/routesTransferSubsidies.js.map +1 -1
- package/dist/db/tables/routesTransferSubsidyNonces.d.ts.map +1 -1
- package/dist/db/tables/routesTransferSubsidyNonces.js +12 -4
- package/dist/db/tables/routesTransferSubsidyNonces.js.map +1 -1
- package/dist/db/tables/routesTransfers.d.ts +26 -1
- package/dist/db/tables/routesTransfers.d.ts.map +1 -1
- package/dist/db/tables/routesTransfers.js +36 -6
- package/dist/db/tables/routesTransfers.js.map +1 -1
- package/dist/db/tables/sponsoredTransactions.d.ts +45 -13
- package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
- package/dist/db/tables/sponsoredTransactions.js +144 -33
- package/dist/db/tables/sponsoredTransactions.js.map +1 -1
- package/dist/db/tables/users.d.ts +2 -0
- package/dist/db/tables/users.d.ts.map +1 -1
- package/dist/db/tables/users.js +11 -0
- package/dist/db/tables/users.js.map +1 -1
- package/dist/handlers/internal/multisig.d.ts +1 -1
- package/dist/handlers/internal/multisig.d.ts.map +1 -1
- package/dist/handlers/internal/multisig.js +3 -2
- package/dist/handlers/internal/multisig.js.map +1 -1
- package/dist/handlers/relay.d.ts +2 -0
- package/dist/handlers/relay.d.ts.map +1 -1
- package/dist/handlers/relay.js +34 -15
- package/dist/handlers/relay.js.map +1 -1
- package/dist/internal/Auth.d.ts +57 -6
- package/dist/internal/Auth.d.ts.map +1 -1
- package/dist/internal/Auth.js +182 -78
- package/dist/internal/Auth.js.map +1 -1
- package/dist/internal/BetterAuth.d.ts +22 -0
- package/dist/internal/BetterAuth.d.ts.map +1 -1
- package/dist/internal/BetterAuth.js +17 -14
- package/dist/internal/BetterAuth.js.map +1 -1
- package/dist/internal/Cache.d.ts +5 -0
- package/dist/internal/Cache.d.ts.map +1 -1
- package/dist/internal/Cache.js +3 -1
- package/dist/internal/Cache.js.map +1 -1
- package/dist/internal/CliAuth.d.ts +243 -0
- package/dist/internal/CliAuth.d.ts.map +1 -0
- package/dist/internal/CliAuth.js +249 -0
- package/dist/internal/CliAuth.js.map +1 -0
- package/dist/internal/EarnSharePrices.d.ts +1 -1
- package/dist/internal/EarnSharePrices.d.ts.map +1 -1
- package/dist/internal/EarnSharePrices.js +7 -3
- package/dist/internal/EarnSharePrices.js.map +1 -1
- package/dist/internal/EarnVaults.d.ts +47 -0
- package/dist/internal/EarnVaults.d.ts.map +1 -1
- package/dist/internal/EarnVaults.js +188 -4
- package/dist/internal/EarnVaults.js.map +1 -1
- package/dist/internal/EarnWithdrawals.d.ts +73 -0
- package/dist/internal/EarnWithdrawals.d.ts.map +1 -0
- package/dist/internal/EarnWithdrawals.js +189 -0
- package/dist/internal/EarnWithdrawals.js.map +1 -0
- package/dist/internal/ExecutionContext.d.ts +21 -0
- package/dist/internal/ExecutionContext.d.ts.map +1 -0
- package/dist/internal/ExecutionContext.js +16 -0
- package/dist/internal/ExecutionContext.js.map +1 -0
- package/dist/internal/Log.d.ts +7 -3
- package/dist/internal/Log.d.ts.map +1 -1
- package/dist/internal/Log.js +163 -130
- package/dist/internal/Log.js.map +1 -1
- package/dist/internal/MetricSink.d.ts.map +1 -1
- package/dist/internal/MetricSink.js +26 -1
- package/dist/internal/MetricSink.js.map +1 -1
- package/dist/internal/RateLimit.d.ts +67 -0
- package/dist/internal/RateLimit.d.ts.map +1 -1
- package/dist/internal/RateLimit.js +174 -27
- package/dist/internal/RateLimit.js.map +1 -1
- package/dist/internal/Store.d.ts +6 -0
- package/dist/internal/Store.d.ts.map +1 -1
- package/dist/internal/Store.js +4 -5
- package/dist/internal/Store.js.map +1 -1
- package/dist/internal/Timing.d.ts +6 -0
- package/dist/internal/Timing.d.ts.map +1 -1
- package/dist/internal/Timing.js +21 -1
- package/dist/internal/Timing.js.map +1 -1
- package/dist/internal/Tron.d.ts +124 -0
- package/dist/internal/Tron.d.ts.map +1 -0
- package/dist/internal/Tron.js +202 -0
- package/dist/internal/Tron.js.map +1 -0
- package/dist/internal/Viem.d.ts +4 -0
- package/dist/internal/Viem.d.ts.map +1 -1
- package/dist/internal/Viem.js +25 -6
- package/dist/internal/Viem.js.map +1 -1
- package/dist/internal/rewards/Read.d.ts +2 -2
- package/dist/internal/rewards/Read.d.ts.map +1 -1
- package/dist/internal/rewards/Read.js +11 -2
- package/dist/internal/rewards/Read.js.map +1 -1
- package/dist/internal/routes/Action.d.ts +27 -0
- package/dist/internal/routes/Action.d.ts.map +1 -1
- package/dist/internal/routes/Action.js +49 -1
- package/dist/internal/routes/Action.js.map +1 -1
- package/dist/internal/routes/Chain.d.ts +2 -0
- package/dist/internal/routes/Chain.d.ts.map +1 -1
- package/dist/internal/routes/Chain.js +4 -0
- package/dist/internal/routes/Chain.js.map +1 -1
- package/dist/internal/routes/DepositAddress.d.ts.map +1 -1
- package/dist/internal/routes/DepositAddress.js +5 -0
- package/dist/internal/routes/DepositAddress.js.map +1 -1
- package/dist/internal/routes/Evidence.d.ts.map +1 -1
- package/dist/internal/routes/Evidence.js +6 -2
- package/dist/internal/routes/Evidence.js.map +1 -1
- package/dist/internal/routes/EvmTransferSettlement.d.ts +17 -0
- package/dist/internal/routes/EvmTransferSettlement.d.ts.map +1 -0
- package/dist/internal/routes/EvmTransferSettlement.js +196 -0
- package/dist/internal/routes/EvmTransferSettlement.js.map +1 -0
- package/dist/internal/routes/Policy.d.ts +161 -0
- package/dist/internal/routes/Policy.d.ts.map +1 -0
- package/dist/internal/routes/Policy.js +249 -0
- package/dist/internal/routes/Policy.js.map +1 -0
- package/dist/internal/routes/Provider.d.ts +66 -3
- package/dist/internal/routes/Provider.d.ts.map +1 -1
- package/dist/internal/routes/Provider.js +106 -27
- package/dist/internal/routes/Provider.js.map +1 -1
- package/dist/internal/routes/Quota.d.ts +57 -0
- package/dist/internal/routes/Quota.d.ts.map +1 -0
- package/dist/internal/routes/Quota.js +144 -0
- package/dist/internal/routes/Quota.js.map +1 -0
- package/dist/internal/routes/Reconciliation.d.ts.map +1 -1
- package/dist/internal/routes/Reconciliation.js +163 -47
- package/dist/internal/routes/Reconciliation.js.map +1 -1
- package/dist/internal/routes/SolanaTransferSettlement.d.ts +12 -0
- package/dist/internal/routes/SolanaTransferSettlement.d.ts.map +1 -0
- package/dist/internal/routes/SolanaTransferSettlement.js +220 -0
- package/dist/internal/routes/SolanaTransferSettlement.js.map +1 -0
- package/dist/internal/routes/SolanaTransferSubsidy.d.ts +172 -0
- package/dist/internal/routes/SolanaTransferSubsidy.d.ts.map +1 -0
- package/dist/internal/routes/SolanaTransferSubsidy.js +564 -0
- package/dist/internal/routes/SolanaTransferSubsidy.js.map +1 -0
- package/dist/internal/routes/Subsidy.d.ts +2 -2
- package/dist/internal/routes/Subsidy.d.ts.map +1 -1
- package/dist/internal/routes/Subsidy.js +2 -2
- package/dist/internal/routes/Subsidy.js.map +1 -1
- package/dist/internal/routes/Transfer.d.ts +229 -1
- package/dist/internal/routes/Transfer.d.ts.map +1 -1
- package/dist/internal/routes/Transfer.js +644 -7
- package/dist/internal/routes/Transfer.js.map +1 -1
- package/dist/internal/routes/TransferReconciliation.d.ts +6 -0
- package/dist/internal/routes/TransferReconciliation.d.ts.map +1 -1
- package/dist/internal/routes/TransferReconciliation.js +83 -159
- package/dist/internal/routes/TransferReconciliation.js.map +1 -1
- package/dist/internal/routes/TransferSettlement.d.ts +45 -0
- package/dist/internal/routes/TransferSettlement.d.ts.map +1 -0
- package/dist/internal/routes/TransferSettlement.js +2 -0
- package/dist/internal/routes/TransferSettlement.js.map +1 -0
- package/dist/internal/routes/TransferSubsidy.d.ts +23 -8
- package/dist/internal/routes/TransferSubsidy.d.ts.map +1 -1
- package/dist/internal/routes/TransferSubsidy.js +64 -5
- package/dist/internal/routes/TransferSubsidy.js.map +1 -1
- package/dist/internal/routes/TronTransferSettlement.d.ts +12 -0
- package/dist/internal/routes/TronTransferSettlement.d.ts.map +1 -0
- package/dist/internal/routes/TronTransferSettlement.js +201 -0
- package/dist/internal/routes/TronTransferSettlement.js.map +1 -0
- package/dist/internal/routes/TronTransferSubsidy.d.ts +174 -0
- package/dist/internal/routes/TronTransferSubsidy.d.ts.map +1 -0
- package/dist/internal/routes/TronTransferSubsidy.js +439 -0
- package/dist/internal/routes/TronTransferSubsidy.js.map +1 -0
- package/dist/internal/routes/index.d.ts +3 -0
- package/dist/internal/routes/index.d.ts.map +1 -1
- package/dist/internal/routes/index.js +3 -0
- package/dist/internal/routes/index.js.map +1 -1
- package/dist/internal/routes/providers/across.d.ts +3 -0
- package/dist/internal/routes/providers/across.d.ts.map +1 -1
- package/dist/internal/routes/providers/across.js +11 -0
- package/dist/internal/routes/providers/across.js.map +1 -1
- package/dist/internal/routes/providers/legacyMesh.d.ts +29 -0
- package/dist/internal/routes/providers/legacyMesh.d.ts.map +1 -0
- package/dist/internal/routes/providers/legacyMesh.js +474 -0
- package/dist/internal/routes/providers/legacyMesh.js.map +1 -0
- package/dist/internal/routes/providers/legacyMeshDelivery.d.ts +59 -0
- package/dist/internal/routes/providers/legacyMeshDelivery.d.ts.map +1 -0
- package/dist/internal/routes/providers/legacyMeshDelivery.js +229 -0
- package/dist/internal/routes/providers/legacyMeshDelivery.js.map +1 -0
- package/dist/internal/routes/providers/legacyMeshOutbound.d.ts +19 -0
- package/dist/internal/routes/providers/legacyMeshOutbound.d.ts.map +1 -0
- package/dist/internal/routes/providers/legacyMeshOutbound.js +457 -0
- package/dist/internal/routes/providers/legacyMeshOutbound.js.map +1 -0
- package/dist/internal/routes/providers/legacyMeshOutboundDelivery.d.ts +123 -0
- package/dist/internal/routes/providers/legacyMeshOutboundDelivery.d.ts.map +1 -0
- package/dist/internal/routes/providers/legacyMeshOutboundDelivery.js +333 -0
- package/dist/internal/routes/providers/legacyMeshOutboundDelivery.js.map +1 -0
- package/dist/internal/routes/providers/propAmm.d.ts +70 -0
- package/dist/internal/routes/providers/propAmm.d.ts.map +1 -0
- package/dist/internal/routes/providers/propAmm.js +524 -0
- package/dist/internal/routes/providers/propAmm.js.map +1 -0
- package/dist/internal/routes/providers/relay.d.ts +3 -0
- package/dist/internal/routes/providers/relay.d.ts.map +1 -1
- package/dist/internal/routes/providers/relay.js +352 -41
- package/dist/internal/routes/providers/relay.js.map +1 -1
- package/dist/internal/routes/providers/rhino.d.ts +3 -0
- package/dist/internal/routes/providers/rhino.d.ts.map +1 -1
- package/dist/internal/routes/providers/rhino.js +11 -0
- package/dist/internal/routes/providers/rhino.js.map +1 -1
- package/dist/internal/routes/providers/squid.d.ts +3 -0
- package/dist/internal/routes/providers/squid.d.ts.map +1 -1
- package/dist/internal/routes/providers/squid.js +19 -0
- package/dist/internal/routes/providers/squid.js.map +1 -1
- package/dist/internal/routes/providers/stargate.d.ts.map +1 -1
- package/dist/internal/routes/providers/stargate.js +22 -9
- package/dist/internal/routes/providers/stargate.js.map +1 -1
- package/dist/internal/routes/providers/symbiosis.d.ts.map +1 -1
- package/dist/internal/routes/providers/symbiosis.js +13 -17
- package/dist/internal/routes/providers/symbiosis.js.map +1 -1
- package/dist/providers/index.d.ts +14 -0
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +6 -0
- package/dist/providers/index.js.map +1 -1
- package/package.json +16 -6
- package/src/ApiKey.ts +7 -3
- package/src/ApiKeys.test.ts +652 -8
- package/src/ApiKeys.ts +191 -11
- package/src/App.test.ts +405 -18
- package/src/App.ts +51 -15
- package/src/Client.test-d.ts +157 -10
- package/src/Client.test.ts +4 -4
- package/src/Scope.ts +1 -2
- package/src/admin/App.ts +11 -5
- package/src/admin/apps/api-keys.test.ts +98 -2
- package/src/admin/apps/api-keys.ts +21 -12
- package/src/admin/apps/earn-vaults.test.ts +76 -7
- package/src/admin/apps/earn-vaults.ts +47 -8
- package/src/admin/apps/organizations.test.ts +147 -31
- package/src/admin/apps/organizations.ts +5 -4
- package/src/admin/apps/route-policies.test.ts +220 -0
- package/src/admin/apps/route-policies.ts +322 -0
- package/src/admin/apps/routes-support.test.ts +107 -2
- package/src/admin/apps/routes-support.ts +43 -3
- package/src/admin/apps/routes.test.ts +150 -0
- package/src/admin/apps/routes.ts +97 -1
- package/src/admin/apps/scopes.test.ts +1 -1
- package/src/admin/index.ts +0 -1
- package/src/admin/ui/plugin.ts +2 -1
- package/src/admin/ui/src/components/Dialog.tsx +1 -1
- package/src/admin/ui/src/components/EarnVaultForm.tsx +45 -0
- package/src/admin/ui/src/components/RoutePicker.tsx +79 -0
- package/src/admin/ui/src/lib/earn-vaults.ts +1 -1
- package/src/admin/ui/src/lib/route-policies.test.ts +452 -0
- package/src/admin/ui/src/lib/route-policies.ts +232 -0
- package/src/admin/ui/src/lib/routes.ts +34 -0
- package/src/admin/ui/src/routeTree.gen.ts +21 -0
- package/src/admin/ui/src/routes/api-keys.tsx +21 -2
- package/src/admin/ui/src/routes/early-access.tsx +1 -0
- package/src/admin/ui/src/routes/earn.vaults.tsx +1 -0
- package/src/admin/ui/src/routes/earn.vaults_.$vaultId.edit.tsx +22 -0
- package/src/admin/ui/src/routes/earn.vaults_.new.tsx +10 -0
- package/src/admin/ui/src/routes/organizations.tsx +1 -0
- package/src/admin/ui/src/routes/organizations_.$orgId.tsx +18 -3
- package/src/admin/ui/src/routes/route-policies.tsx +678 -0
- package/src/admin/ui/src/routes/routes.tsx +85 -2
- package/src/admin/ui/src/routes/routes_.support.tsx +6 -22
- package/src/admin/ui/src/routes/subsidies.tsx +1 -0
- package/src/admin/ui/src/routes/verified-tokens.tsx +1 -0
- package/src/admin/ui.generated.ts +258 -202
- package/src/analytics/Analytics.test.ts +4 -50
- package/src/analytics/Analytics.ts +65 -1
- package/src/analytics/tables/requestEvents.test.ts +402 -1
- package/src/analytics/tables/requestEvents.ts +62 -93
- package/src/apps/data/routes/activities.test.ts +315 -14
- package/src/apps/data/routes/activities.ts +60 -0
- package/src/apps/data/routes/balances.ts +5 -7
- package/src/apps/data/routes/earn.bench.ts +18 -0
- package/src/apps/data/routes/earn.local.test.ts +507 -0
- package/src/apps/data/routes/earn.test.ts +405 -127
- package/src/apps/data/routes/earn.ts +660 -270
- package/src/apps/data/routes/exchanges.bench.ts +3 -1
- package/src/apps/data/routes/exchanges.test.ts +166 -2
- package/src/apps/data/routes/exchanges.ts +308 -101
- package/src/apps/data/routes/fee-amm.test.ts +134 -2
- package/src/apps/data/routes/fee-amm.ts +122 -60
- package/src/apps/data/routes/receipts.test.ts +21 -18
- package/src/apps/data/routes/rpc.test.ts +2 -2
- package/src/apps/data/routes/tokens.provenance.test.ts +157 -0
- package/src/apps/data/routes/tokens.test.ts +4 -4
- package/src/apps/data/routes/tokens.ts +11 -6
- package/src/apps/data/routes/transactions.test.ts +29 -0
- package/src/apps/data/routes/transactions.ts +33 -22
- package/src/apps/data/routes/webhooks.test.ts +12 -3
- package/src/apps/data/routes/webhooks.ts +2 -1
- package/src/apps/management/App.ts +4 -0
- package/src/apps/management/Billing.test.ts +253 -27
- package/src/apps/management/Billing.ts +83 -29
- package/src/apps/management/routes/api-keys.test.ts +1 -1
- package/src/apps/management/routes/api-keys.ts +85 -11
- package/src/apps/management/routes/billing.test.ts +68 -4
- package/src/apps/management/routes/cli.test.ts +370 -0
- package/src/apps/management/routes/cli.ts +533 -0
- package/src/apps/management/routes/me.test.ts +14 -4
- package/src/apps/management/routes/orgs.test.ts +108 -4
- package/src/apps/management/routes/orgs.ts +7 -2
- package/src/apps/management/routes/usage.test.ts +2 -2
- package/src/apps/mpp/internal/Policy.test.ts +51 -4
- package/src/apps/mpp/internal/Policy.ts +6 -2
- package/src/apps/mpp/internal/Sponsorship.test.ts +29 -0
- package/src/apps/mpp/internal/Sponsorship.ts +6 -4
- package/src/apps/relay/App.test.ts +85 -1
- package/src/apps/relay/App.ts +28 -4
- package/src/apps/relay/Sponsorships.test.ts +97 -1
- package/src/apps/relay/Sponsorships.ts +77 -66
- package/src/apps/routes/Access.test.ts +319 -0
- package/src/apps/routes/Access.ts +147 -0
- package/src/apps/routes/App.ts +10 -0
- package/src/apps/routes/routes/chains.test.ts +3 -2
- package/src/apps/routes/routes/deposit-addresses.test.ts +978 -34
- package/src/apps/routes/routes/deposit-addresses.ts +243 -32
- package/src/apps/routes/routes/propAmm.local.test.ts +951 -0
- package/src/apps/routes/routes/quotes.test.ts +81 -8
- package/src/apps/routes/routes/quotes.ts +109 -27
- package/src/apps/routes/routes/transfers.test.ts +252 -15
- package/src/apps/routes/routes/transfers.ts +212 -33
- package/src/cli/ApiKeys.test.ts +265 -0
- package/src/cli/ApiKeys.ts +189 -0
- package/src/cli/Cli.test.ts +188 -0
- package/src/cli/Cli.ts +280 -12
- package/src/cli/Credentials.test.ts +122 -0
- package/src/cli/Credentials.ts +144 -0
- package/src/cli/Spec.test.ts +133 -0
- package/src/cli/Spec.ts +132 -0
- package/src/cli/bin.test.ts +49 -0
- package/src/cli/bin.ts +5 -1
- package/src/cli/commands/auth.test.ts +138 -0
- package/src/cli/commands/auth.ts +254 -0
- package/src/cli/commands/keys.test.ts +68 -0
- package/src/cli/commands/keys.ts +125 -0
- package/src/cloudflare.ts +184 -36
- package/src/db/Db.test.ts +877 -0
- package/src/db/Db.ts +498 -1
- package/src/db/Schema.ts +75 -4
- package/src/db/tables/apiKeyAdmissions.test.ts +57 -0
- package/src/db/tables/apiKeyAdmissions.ts +101 -11
- package/src/db/tables/apiKeyOwnerTombstones.ts +2 -2
- package/src/db/tables/authAccounts.test.ts +30 -0
- package/src/db/tables/authAccounts.ts +1 -0
- package/src/db/tables/earnVaults.test.ts +34 -0
- package/src/db/tables/earnVaults.ts +17 -2
- package/src/db/tables/organizations.test.ts +148 -84
- package/src/db/tables/organizations.ts +11 -43
- package/src/db/tables/requestUsage.ts +13 -2
- package/src/db/tables/rewardCampaigns.test.ts +163 -0
- package/src/db/tables/rewardEligibilityAssociations.test.ts +14 -0
- package/src/db/tables/rewardEligibilityAssociations.ts +24 -0
- package/src/db/tables/rewardRuns.ts +4 -0
- package/src/db/tables/rewardTransactionAttempts.ts +2 -0
- package/src/db/tables/routesDepositAddresses.test.ts +263 -0
- package/src/db/tables/routesDepositAddresses.ts +118 -34
- package/src/db/tables/routesDeposits.test.ts +66 -5
- package/src/db/tables/routesDeposits.ts +47 -26
- package/src/db/tables/routesIdempotency.test.ts +80 -0
- package/src/db/tables/routesIdempotency.ts +2 -0
- package/src/db/tables/routesPolicies.test.ts +143 -0
- package/src/db/tables/routesPolicies.ts +251 -0
- package/src/db/tables/routesTransferSubsidies.ts +64 -0
- package/src/db/tables/routesTransferSubsidyNonces.ts +16 -4
- package/src/db/tables/routesTransfers.test.ts +183 -2
- package/src/db/tables/routesTransfers.ts +65 -6
- package/src/db/tables/sponsoredTransactions.test.ts +351 -76
- package/src/db/tables/sponsoredTransactions.ts +182 -38
- package/src/db/tables/users.test.ts +51 -0
- package/src/db/tables/users.ts +12 -0
- package/src/handlers/internal/multisig.store.test.ts +120 -0
- package/src/handlers/internal/multisig.test.ts +389 -0
- package/src/handlers/internal/multisig.ts +13 -10
- package/src/handlers/relay.test.ts +259 -83
- package/src/handlers/relay.ts +36 -17
- package/src/internal/Auth.test.ts +291 -8
- package/src/internal/Auth.ts +227 -96
- package/src/internal/BetterAuth.test.ts +58 -22
- package/src/internal/BetterAuth.ts +23 -17
- package/src/internal/Cache.ts +3 -1
- package/src/internal/CliAuth.test.ts +279 -0
- package/src/internal/CliAuth.ts +319 -0
- package/src/internal/EarnSharePrices.test.ts +25 -0
- package/src/internal/EarnSharePrices.ts +9 -2
- package/src/internal/EarnVaults.test.ts +67 -0
- package/src/internal/EarnVaults.ts +299 -4
- package/src/internal/EarnWithdrawals.test.ts +315 -0
- package/src/internal/EarnWithdrawals.ts +266 -0
- package/src/internal/ExecutionContext.ts +31 -0
- package/src/internal/Log.test.ts +210 -0
- package/src/internal/Log.ts +180 -142
- package/src/internal/MetricSink.test.ts +190 -15
- package/src/internal/MetricSink.ts +27 -1
- package/src/internal/RateLimit.test.ts +144 -8
- package/src/internal/RateLimit.ts +254 -26
- package/src/internal/Store.ts +4 -5
- package/src/internal/Timing.test.ts +32 -0
- package/src/internal/Timing.ts +20 -1
- package/src/internal/Tron.test-d.ts +22 -0
- package/src/internal/Tron.test.ts +94 -0
- package/src/internal/Tron.ts +289 -0
- package/src/internal/Viem.rpc.test.ts +76 -0
- package/src/internal/Viem.ts +29 -6
- package/src/internal/rewards/Read.test.ts +109 -0
- package/src/internal/rewards/Read.ts +13 -4
- package/src/internal/routes/Action.test.ts +70 -0
- package/src/internal/routes/Action.ts +76 -1
- package/src/internal/routes/Chain.test.ts +18 -0
- package/src/internal/routes/Chain.ts +5 -0
- package/src/internal/routes/DepositAddress.ts +5 -0
- package/src/internal/routes/Evidence.test.ts +64 -0
- package/src/internal/routes/Evidence.ts +11 -3
- package/src/internal/routes/EvmTransferSettlement.ts +213 -0
- package/src/internal/routes/Policy.test.ts +316 -0
- package/src/internal/routes/Policy.ts +399 -0
- package/src/internal/routes/Provider.test.ts +103 -2
- package/src/internal/routes/Provider.ts +149 -27
- package/src/internal/routes/Quota.test.ts +149 -0
- package/src/internal/routes/Quota.ts +226 -0
- package/src/internal/routes/Reconciliation.local.test.ts +285 -0
- package/src/internal/routes/Reconciliation.test.ts +371 -13
- package/src/internal/routes/Reconciliation.ts +193 -42
- package/src/internal/routes/SolanaTransferSettlement.ts +232 -0
- package/src/internal/routes/SolanaTransferSubsidy.test.ts +471 -0
- package/src/internal/routes/SolanaTransferSubsidy.ts +760 -0
- package/src/internal/routes/SourceObservation.test.ts +221 -0
- package/src/internal/routes/Subsidy.local.test.ts +46 -0
- package/src/internal/routes/Subsidy.ts +4 -2
- package/src/internal/routes/Transfer.solana.test.ts +389 -0
- package/src/internal/routes/Transfer.test.ts +130 -1
- package/src/internal/routes/Transfer.tron.test.ts +172 -0
- package/src/internal/routes/Transfer.ts +866 -8
- package/src/internal/routes/TransferReconciliation.test.ts +26 -4
- package/src/internal/routes/TransferReconciliation.ts +91 -166
- package/src/internal/routes/TransferSettlement.ts +48 -0
- package/src/internal/routes/TransferSubsidy.local.test.ts +143 -0
- package/src/internal/routes/TransferSubsidy.test.ts +34 -4
- package/src/internal/routes/TransferSubsidy.ts +87 -12
- package/src/internal/routes/TronTransferSettlement.ts +212 -0
- package/src/internal/routes/TronTransferSubsidy.test.ts +109 -0
- package/src/internal/routes/TronTransferSubsidy.ts +619 -0
- package/src/internal/routes/index.test.ts +3 -0
- package/src/internal/routes/index.ts +3 -0
- package/src/internal/routes/providers/across.ts +13 -0
- package/src/internal/routes/providers/index.test.ts +141 -0
- package/src/internal/routes/providers/legacyMesh.test.ts +484 -0
- package/src/internal/routes/providers/legacyMesh.ts +633 -0
- package/src/internal/routes/providers/legacyMeshDelivery.test.ts +306 -0
- package/src/internal/routes/providers/legacyMeshDelivery.ts +320 -0
- package/src/internal/routes/providers/legacyMeshOutbound.test.ts +401 -0
- package/src/internal/routes/providers/legacyMeshOutbound.ts +566 -0
- package/src/internal/routes/providers/legacyMeshOutboundDelivery.ts +473 -0
- package/src/internal/routes/providers/propAmm.ts +640 -0
- package/src/internal/routes/providers/relay.test.ts +1263 -41
- package/src/internal/routes/providers/relay.ts +423 -38
- package/src/internal/routes/providers/rhino.ts +14 -1
- package/src/internal/routes/providers/squid.ts +21 -0
- package/src/internal/routes/providers/stargate.test.ts +105 -1
- package/src/internal/routes/providers/stargate.ts +22 -9
- package/src/internal/routes/providers/symbiosis.ts +13 -47
- package/src/providers/index.test.ts +2 -0
- package/src/providers/index.ts +18 -0
- package/dist/admin/Access.d.ts +0 -39
- package/dist/admin/Access.d.ts.map +0 -1
- package/dist/admin/Access.js +0 -73
- package/dist/admin/Access.js.map +0 -1
- package/src/admin/Access.test.ts +0 -130
- package/src/admin/Access.ts +0 -85
|
@@ -53,7 +53,9 @@ export async function finalize(db: Db.Db, options: finalize.Options): Promise<fi
|
|
|
53
53
|
// here only the TTL can settle them.
|
|
54
54
|
if (row.transactionHash === null) {
|
|
55
55
|
if (Date.parse(row.createdAt) + pendingTtlMs <= now().getTime()) {
|
|
56
|
-
await SponsoredTransactions.fail(db, row.id, now().toISOString()
|
|
56
|
+
await SponsoredTransactions.fail(db, row.id, now().toISOString(), {
|
|
57
|
+
transactionHash: row.transactionHash,
|
|
58
|
+
})
|
|
57
59
|
result.failed++
|
|
58
60
|
} else result.pending++
|
|
59
61
|
continue
|
|
@@ -70,7 +72,9 @@ export async function finalize(db: Db.Db, options: finalize.Options): Promise<fi
|
|
|
70
72
|
else {
|
|
71
73
|
result.errors++
|
|
72
74
|
if (Date.parse(row.createdAt) + receiptErrorTtlMs <= now().getTime()) {
|
|
73
|
-
await SponsoredTransactions.fail(db, row.id, now().toISOString()
|
|
75
|
+
await SponsoredTransactions.fail(db, row.id, now().toISOString(), {
|
|
76
|
+
transactionHash: row.transactionHash,
|
|
77
|
+
})
|
|
74
78
|
result.failed++
|
|
75
79
|
} else result.pending++
|
|
76
80
|
continue
|
|
@@ -83,10 +87,13 @@ export async function finalize(db: Db.Db, options: finalize.Options): Promise<fi
|
|
|
83
87
|
await SponsoredTransactions.finalize(db, row.id, {
|
|
84
88
|
feeAmount: feeAmount.toString(),
|
|
85
89
|
finalizedAt: now().toISOString(),
|
|
90
|
+
transactionHash: row.transactionHash,
|
|
86
91
|
})
|
|
87
92
|
result.finalized++
|
|
88
93
|
} else if (Date.parse(row.createdAt) + pendingTtlMs <= now().getTime()) {
|
|
89
|
-
await SponsoredTransactions.fail(db, row.id, now().toISOString()
|
|
94
|
+
await SponsoredTransactions.fail(db, row.id, now().toISOString(), {
|
|
95
|
+
transactionHash: row.transactionHash,
|
|
96
|
+
})
|
|
90
97
|
result.failed++
|
|
91
98
|
} else result.pending++
|
|
92
99
|
}
|
|
@@ -123,11 +130,9 @@ export declare namespace finalize {
|
|
|
123
130
|
}
|
|
124
131
|
|
|
125
132
|
/**
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
* matching intents' hashes so the receipt pass can finalize them. Query or
|
|
130
|
-
* candidate errors leave intents for the next pass.
|
|
133
|
+
* Reconciles pending fill intents and recently failed sponsorships against
|
|
134
|
+
* on-chain fee-payer sign payloads. Matches update their transaction hashes;
|
|
135
|
+
* errors leave sponsorships for the next pass.
|
|
131
136
|
*
|
|
132
137
|
* @param db - The database holding `sponsored_transactions`.
|
|
133
138
|
* @param options - Reconciliation options.
|
|
@@ -147,74 +152,80 @@ export async function reconcile(db: Db.Db, options: reconcile.Options): Promise<
|
|
|
147
152
|
const failedSince = new Date(Date.now() - failedIntentTtlMs).toISOString()
|
|
148
153
|
// Old failed intents must not move the active scan behind its candidate cap.
|
|
149
154
|
const [intents, recoveryWindows] = await Promise.all([
|
|
150
|
-
SponsoredTransactions.
|
|
155
|
+
SponsoredTransactions.listReconciliationCandidates(db, { limit: batchSize }),
|
|
151
156
|
SponsoredTransactions.listRecoveryWindows(db, { failedSince }),
|
|
152
157
|
])
|
|
153
158
|
const result = { errors: 0, matched: 0, scanned: 0 }
|
|
154
159
|
if (intents.length === 0 && recoveryWindows.length === 0) return result
|
|
155
160
|
|
|
156
|
-
const groups =
|
|
157
|
-
|
|
158
|
-
|
|
161
|
+
const groups = [
|
|
162
|
+
new Map<number, SponsoredTransactions.Record[]>(),
|
|
163
|
+
new Map<number, SponsoredTransactions.Record[]>(),
|
|
164
|
+
]
|
|
165
|
+
for (const intent of intents) {
|
|
166
|
+
const group = groups[intent.transactionHash === null ? 0 : 1]!
|
|
167
|
+
group.set(intent.chainId, [...(group.get(intent.chainId) ?? []), intent])
|
|
168
|
+
}
|
|
159
169
|
|
|
160
|
-
for (const
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
170
|
+
for (const group of groups)
|
|
171
|
+
for (const [chainId, rows] of group) {
|
|
172
|
+
if (candidateCap <= 0) continue
|
|
173
|
+
const bySignPayload = new Map(rows.map((row) => [row.signPayload, row]))
|
|
174
|
+
const since = formatTidxTimestamp(
|
|
175
|
+
Math.min(...rows.map((row) => Date.parse(row.createdAt))) - skewMs,
|
|
176
|
+
)
|
|
166
177
|
|
|
167
|
-
|
|
168
|
-
try {
|
|
169
|
-
// Dynamic filter values; the tidx client's query type wants literals.
|
|
170
|
-
const fetched = await getTidx(chainId).fetch({
|
|
171
|
-
chainId,
|
|
172
|
-
query:
|
|
173
|
-
`SELECT hash, "from" FROM txs WHERE fee_payer = '${feePayer.toLowerCase()}' AND block_timestamp >= '${since}' ORDER BY block_timestamp ASC LIMIT ${candidateCap}` as string,
|
|
174
|
-
})
|
|
175
|
-
candidates = fetched.rows
|
|
176
|
-
} catch {
|
|
177
|
-
// Indexer outage must not fail intents; retry on the next pass.
|
|
178
|
-
result.errors++
|
|
179
|
-
continue
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
for (const candidate of candidates) {
|
|
183
|
-
if (bySignPayload.size === 0) break
|
|
184
|
-
const hash = candidate['hash'] as Hex.Hex | undefined
|
|
185
|
-
const sender = candidate['from'] as Address | undefined
|
|
186
|
-
if (!hash || !sender) continue
|
|
187
|
-
result.scanned++
|
|
178
|
+
let candidates: readonly globalThis.Record<string, unknown>[]
|
|
188
179
|
try {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
180
|
+
// Dynamic filter values; the tidx client's query type wants literals.
|
|
181
|
+
const fetched = await getTidx(chainId).fetch({
|
|
182
|
+
chainId,
|
|
183
|
+
query:
|
|
184
|
+
`SELECT hash, "from" FROM txs WHERE fee_payer = '${feePayer.toLowerCase()}' AND block_timestamp >= '${since}' ORDER BY block_timestamp ASC LIMIT ${candidateCap}` as string,
|
|
185
|
+
})
|
|
186
|
+
candidates = fetched.rows
|
|
187
|
+
} catch {
|
|
188
|
+
// Indexer outage must not fail sponsorships; retry on the next pass.
|
|
189
|
+
result.errors++
|
|
190
|
+
continue
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
for (const candidate of candidates) {
|
|
194
|
+
if (bySignPayload.size === 0) break
|
|
195
|
+
const hash = candidate['hash'] as Hex.Hex | undefined
|
|
196
|
+
const sender = candidate['from'] as Address | undefined
|
|
197
|
+
if (!hash || !sender) continue
|
|
198
|
+
result.scanned++
|
|
199
|
+
try {
|
|
200
|
+
const serialized = await getRawTransaction(getClient(chainId), hash)
|
|
201
|
+
if (!serialized) {
|
|
202
|
+
result.errors++
|
|
203
|
+
continue
|
|
204
|
+
}
|
|
205
|
+
if (!serialized.startsWith(TxEnvelopeTempo.serializedType)) continue
|
|
206
|
+
const signPayload = TxEnvelopeTempo.getFeePayerSignPayload(
|
|
207
|
+
TxEnvelopeTempo.deserialize(serialized as TxEnvelopeTempo.Serialized),
|
|
208
|
+
{ sender },
|
|
209
|
+
)
|
|
210
|
+
const intent = bySignPayload.get(signPayload)
|
|
211
|
+
if (!intent) continue
|
|
212
|
+
await SponsoredTransactions.assignTransactionHash(
|
|
213
|
+
db,
|
|
214
|
+
intent.id,
|
|
215
|
+
hash,
|
|
216
|
+
await options.limitFor?.(intent),
|
|
217
|
+
)
|
|
218
|
+
bySignPayload.delete(signPayload)
|
|
219
|
+
result.matched++
|
|
220
|
+
} catch (error) {
|
|
221
|
+
// Spend-limit enforcement is an expected policy refusal; dependency,
|
|
222
|
+
// lookup, and malformed-envelope failures remain operational errors.
|
|
223
|
+
if (!(error instanceof SponsoredTransactions.PeriodSpendLimitError)) result.errors++
|
|
193
224
|
}
|
|
194
|
-
if (!serialized.startsWith(TxEnvelopeTempo.serializedType)) continue
|
|
195
|
-
const signPayload = TxEnvelopeTempo.getFeePayerSignPayload(
|
|
196
|
-
TxEnvelopeTempo.deserialize(serialized as TxEnvelopeTempo.Serialized),
|
|
197
|
-
{ sender },
|
|
198
|
-
)
|
|
199
|
-
const intent = bySignPayload.get(signPayload)
|
|
200
|
-
if (!intent) continue
|
|
201
|
-
await SponsoredTransactions.assignTransactionHash(
|
|
202
|
-
db,
|
|
203
|
-
intent.id,
|
|
204
|
-
hash,
|
|
205
|
-
await options.limitFor?.(intent),
|
|
206
|
-
)
|
|
207
|
-
bySignPayload.delete(signPayload)
|
|
208
|
-
result.matched++
|
|
209
|
-
} catch (error) {
|
|
210
|
-
// Spend-limit enforcement is an expected policy refusal; dependency,
|
|
211
|
-
// lookup, and malformed-envelope failures remain operational errors.
|
|
212
|
-
if (!(error instanceof SponsoredTransactions.PeriodSpendLimitError)) result.errors++
|
|
213
225
|
}
|
|
226
|
+
// A truncated active scan cannot prove that the remaining sponsorships were never mined.
|
|
227
|
+
if (candidates.length === candidateCap && bySignPayload.size > 0) result.errors++
|
|
214
228
|
}
|
|
215
|
-
// A truncated active scan cannot prove that the remaining intents were never mined.
|
|
216
|
-
if (candidates.length === candidateCap && bySignPayload.size > 0) result.errors++
|
|
217
|
-
}
|
|
218
229
|
|
|
219
230
|
const feePayer_lower = feePayer.toLowerCase() as Address
|
|
220
231
|
for (const window of recoveryWindows) {
|
|
@@ -353,7 +364,7 @@ export async function reconcile(db: Db.Db, options: reconcile.Options): Promise<
|
|
|
353
364
|
export declare namespace reconcile {
|
|
354
365
|
/** Options for {@link reconcile}. */
|
|
355
366
|
type Options = {
|
|
356
|
-
/** Maximum
|
|
367
|
+
/** Maximum pending sponsorships per transaction-hash state considered per pass. @default 100 */
|
|
357
368
|
batchSize?: number | undefined
|
|
358
369
|
/** Maximum candidates per chain in each active or recovery scan. @default 500 */
|
|
359
370
|
candidateCap?: number | undefined
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import * as TestApp from '../../../test/App.js'
|
|
2
|
+
import * as TestRoutes from '../../../test/Routes.js'
|
|
3
|
+
import * as ApiKeys from '../../ApiKeys.js'
|
|
4
|
+
import * as Organizations from '../../db/tables/organizations.js'
|
|
5
|
+
import * as Projects from '../../db/tables/projects.js'
|
|
6
|
+
import * as RoutesPolicies from '../../db/tables/routesPolicies.js'
|
|
7
|
+
import * as StripeCustomers from '../../db/tables/stripeCustomers.js'
|
|
8
|
+
import * as Auth from '../../internal/Auth.js'
|
|
9
|
+
import * as OpenApi from '../../internal/OpenApi.js'
|
|
10
|
+
import * as Store from '../../internal/Store.js'
|
|
11
|
+
import * as Policy from '../../internal/routes/Policy.js'
|
|
12
|
+
import * as Relay from '../../internal/routes/providers/relay.js'
|
|
13
|
+
import * as Access from './Access.js'
|
|
14
|
+
|
|
15
|
+
const route = {
|
|
16
|
+
sourceChainId: 'eip155:8453',
|
|
17
|
+
sourceTokenId: 'USDC',
|
|
18
|
+
destinationChainId: 'eip155:4217',
|
|
19
|
+
destinationTokenId: 'USDC.e',
|
|
20
|
+
providerId: 'relay',
|
|
21
|
+
} satisfies Policy.Rule
|
|
22
|
+
|
|
23
|
+
describe('filterCatalog', () => {
|
|
24
|
+
test('allows a per-route enable through a disabled legacy gate', () => {
|
|
25
|
+
const catalogRoute = TestRoutes.snapshot.routes.find((item) => item.providerId === 'relay')!
|
|
26
|
+
const input = context({ terms: [{ ...Policy.fromRoute(catalogRoute), subsidyEnabled: true }] })
|
|
27
|
+
input.layers[0] = { access: null, subsidyRoutes: null }
|
|
28
|
+
const filtered = Access.filterCatalog(TestRoutes.snapshot, input, true)
|
|
29
|
+
|
|
30
|
+
expect(filtered.routes.map((item) => item.providerId)).toContain('relay')
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
test('keeps the legacy not-enabled error when no catalog route is enabled', () => {
|
|
34
|
+
const input = context({ subsidyEnabled: false })
|
|
35
|
+
expect(() => Access.filterCatalog(TestRoutes.snapshot, input, true)).toThrowError(
|
|
36
|
+
expect.objectContaining({
|
|
37
|
+
code: 'routes_subsidy_not_enabled',
|
|
38
|
+
message:
|
|
39
|
+
'Route subsidies are not enabled for this request. Contact Tempo to enable them, or use an API key from an organization with subsidies enabled.',
|
|
40
|
+
}),
|
|
41
|
+
)
|
|
42
|
+
})
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
describe('commitment', () => {
|
|
46
|
+
test('allows Tempo-paid production without customer billing and clamps the expense cap', async () => {
|
|
47
|
+
const db = TestApp.database()
|
|
48
|
+
const result = await Access.commitment(
|
|
49
|
+
db,
|
|
50
|
+
context({ subsidyPayer: 'tempo', maxAmount: '12.345678' }),
|
|
51
|
+
route,
|
|
52
|
+
'10.25',
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
expect(result).toEqual({
|
|
56
|
+
maxAmount: '10.25',
|
|
57
|
+
scope: { apiKeyId: 'key_policy', environment: 'production', orgId: 'org_policy' },
|
|
58
|
+
subsidyPayer: 'tempo',
|
|
59
|
+
versions: [1, 2],
|
|
60
|
+
})
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
test('pins inherited terms for a route enabled over legacy false', async () => {
|
|
64
|
+
const input = context({
|
|
65
|
+
terms: [{ ...route, subsidyEnabled: true, subsidyPayer: 'tempo', maxAmount: '3' }],
|
|
66
|
+
})
|
|
67
|
+
input.layers[0] = { access: null, subsidyRoutes: null }
|
|
68
|
+
|
|
69
|
+
await expect(Access.commitment(TestApp.database(), input, route, '9')).resolves.toMatchObject({
|
|
70
|
+
maxAmount: '3',
|
|
71
|
+
subsidyPayer: 'tempo',
|
|
72
|
+
versions: [1, 2],
|
|
73
|
+
})
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
test('requires active billing for enterprise-paid production', async () => {
|
|
77
|
+
const db = TestApp.database()
|
|
78
|
+
await Organizations.create(db, { id: 'org_policy', name: 'Policy' })
|
|
79
|
+
const input = context({ subsidyPayer: 'enterprise', maxAmount: '5' })
|
|
80
|
+
|
|
81
|
+
await expect(Access.commitment(db, input, route, '9')).rejects.toMatchObject({
|
|
82
|
+
code: 'billing_required',
|
|
83
|
+
})
|
|
84
|
+
await StripeCustomers.create(db, { orgId: 'org_policy', stripeCustomerId: 'cus_policy' })
|
|
85
|
+
await StripeCustomers.setStatus(db, 'org_policy', 'active')
|
|
86
|
+
await expect(Access.commitment(db, input, route, '9')).resolves.toMatchObject({
|
|
87
|
+
maxAmount: '5',
|
|
88
|
+
subsidyPayer: 'enterprise',
|
|
89
|
+
})
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
test.each<[string, Policy.Overrides, Access.PolicyError['code']]>([
|
|
93
|
+
['inaccessible', { access: [] }, 'routes_not_allowed'],
|
|
94
|
+
['suspended', {}, 'routes_suspended'],
|
|
95
|
+
['ineligible', { terms: [{ ...route, subsidyEligible: false }] }, 'routes_subsidy_not_allowed'],
|
|
96
|
+
['globally disabled', { subsidyEnabled: false }, 'routes_subsidy_not_enabled'],
|
|
97
|
+
])('rejects an %s route before creating a commitment', async (_name, policy, code) => {
|
|
98
|
+
const input = context(policy)
|
|
99
|
+
if (_name === 'suspended') input.layers[0] = { ...input.layers[0], suspended: true }
|
|
100
|
+
await expect(Access.commitment(TestApp.database(), input, route, '9')).rejects.toMatchObject({
|
|
101
|
+
code,
|
|
102
|
+
})
|
|
103
|
+
})
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
describe('assertPolicy', () => {
|
|
107
|
+
test.each(['organization', 'project'] as const)(
|
|
108
|
+
'rejects inherited-policy acceptance after %s reassignment without a key override',
|
|
109
|
+
async (kind) => {
|
|
110
|
+
const db = TestApp.database()
|
|
111
|
+
const state = Store.memory()
|
|
112
|
+
const org = await Organizations.create(db, { name: 'Original owner' })
|
|
113
|
+
const project =
|
|
114
|
+
kind === 'project'
|
|
115
|
+
? await Projects.create(db, { orgId: org.id, name: 'Original project' })
|
|
116
|
+
: undefined
|
|
117
|
+
const parent = {
|
|
118
|
+
environment: 'production',
|
|
119
|
+
orgId: org.id,
|
|
120
|
+
...(project ? { projectId: project.id } : {}),
|
|
121
|
+
} as const
|
|
122
|
+
await RoutesPolicies.save(db, {
|
|
123
|
+
scope: parent,
|
|
124
|
+
version: 0,
|
|
125
|
+
policy: { access: null, subsidyEnabled: true, subsidyPayer: 'tempo', maxAmount: '1' },
|
|
126
|
+
})
|
|
127
|
+
const { record } = await ApiKeys.mintBounded(db, state, {
|
|
128
|
+
...parent,
|
|
129
|
+
scopes: ['routes:write'],
|
|
130
|
+
})
|
|
131
|
+
const scope = { ...parent, apiKeyId: record.id }
|
|
132
|
+
const loaded = await RoutesPolicies.load(db, scope)
|
|
133
|
+
const pending = {
|
|
134
|
+
scope,
|
|
135
|
+
layers: loaded.layers.map((layer) => layer.policy),
|
|
136
|
+
legacy: loaded.legacy,
|
|
137
|
+
versions: loaded.layers.map((layer) => layer.version),
|
|
138
|
+
}
|
|
139
|
+
expect(await RoutesPolicies.get(db, scope)).toBeUndefined()
|
|
140
|
+
await expect(
|
|
141
|
+
db.transaction((tx) => Access.assertPolicy(tx, pending)),
|
|
142
|
+
).resolves.toBeUndefined()
|
|
143
|
+
|
|
144
|
+
const destination =
|
|
145
|
+
kind === 'organization'
|
|
146
|
+
? { orgId: (await Organizations.create(db, { name: 'New owner' })).id }
|
|
147
|
+
: { projectId: (await Projects.create(db, { orgId: org.id, name: 'New project' })).id }
|
|
148
|
+
const moved = await ApiKeys.updateBounded(db, state, record.id, destination)
|
|
149
|
+
expect(moved).toMatchObject({ ...destination, scopes: ['routes:write'] })
|
|
150
|
+
// No explicit key policy existed, so clearing it cannot invalidate these versions.
|
|
151
|
+
expect(await RoutesPolicies.load(db, scope)).toEqual(loaded)
|
|
152
|
+
await expect(db.transaction((tx) => Access.assertPolicy(tx, pending))).rejects.toMatchObject({
|
|
153
|
+
code: 'route_policy_changed',
|
|
154
|
+
})
|
|
155
|
+
},
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
test.each([
|
|
159
|
+
['revision', { maxAmount: '2' }],
|
|
160
|
+
['suspension', { maxAmount: '1', suspended: true }],
|
|
161
|
+
] as const)(
|
|
162
|
+
'detects a concurrent %s after taking the organization lock',
|
|
163
|
+
async (_name, policy) => {
|
|
164
|
+
const db = TestApp.database()
|
|
165
|
+
await Organizations.create(db, { id: 'org_assert', name: 'Assert' })
|
|
166
|
+
const scope = {
|
|
167
|
+
...(_name === 'revision' ? { apiKeyId: 'key_assert' } : {}),
|
|
168
|
+
environment: 'production',
|
|
169
|
+
orgId: 'org_assert',
|
|
170
|
+
} as const
|
|
171
|
+
await RoutesPolicies.save(db, {
|
|
172
|
+
policy: { maxAmount: '1' },
|
|
173
|
+
scope,
|
|
174
|
+
version: 0,
|
|
175
|
+
})
|
|
176
|
+
const loaded = await RoutesPolicies.load(db, scope)
|
|
177
|
+
const stale = {
|
|
178
|
+
scope,
|
|
179
|
+
layers: loaded.layers.map((layer) => layer.policy),
|
|
180
|
+
legacy: loaded.legacy,
|
|
181
|
+
versions: loaded.layers.map((layer) => layer.version),
|
|
182
|
+
}
|
|
183
|
+
await RoutesPolicies.save(db, { policy, scope, version: 1 })
|
|
184
|
+
|
|
185
|
+
await expect(db.transaction((tx) => Access.assertPolicy(tx, stale))).rejects.toMatchObject({
|
|
186
|
+
code: 'route_policy_changed',
|
|
187
|
+
})
|
|
188
|
+
},
|
|
189
|
+
)
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
describe('loadPolicy', () => {
|
|
193
|
+
test('keeps missing organization policies in legacy mode until the first environment-specific save', async () => {
|
|
194
|
+
const db = TestApp.database()
|
|
195
|
+
const org = await Organizations.create(db, { name: 'Legacy policies' })
|
|
196
|
+
const keys = (['production', 'sandbox'] as const).map((environment) => ({
|
|
197
|
+
id: `key_legacy_${environment}`,
|
|
198
|
+
orgId: org.id,
|
|
199
|
+
environment,
|
|
200
|
+
token: `secret_legacy_${environment}`,
|
|
201
|
+
scopes: ['routes:read'],
|
|
202
|
+
}))
|
|
203
|
+
const app = TestApp.create({ db, auth: { keys } }).get(
|
|
204
|
+
'/policy',
|
|
205
|
+
Auth.policy({ apiKey: { scopes: ['routes:read'] } }),
|
|
206
|
+
OpenApi.describeRoute({ hide: true }),
|
|
207
|
+
async (c) => {
|
|
208
|
+
const loaded = (await Access.loadPolicy(c))!
|
|
209
|
+
return c.json({
|
|
210
|
+
access: Policy.resolve(loaded).access,
|
|
211
|
+
legacy: Access.isLegacy(loaded),
|
|
212
|
+
routes: Access.filterCatalog(TestRoutes.snapshot, loaded, false).routes.length,
|
|
213
|
+
})
|
|
214
|
+
},
|
|
215
|
+
)
|
|
216
|
+
const read = async (index: number) =>
|
|
217
|
+
(
|
|
218
|
+
await app.request('/policy', {
|
|
219
|
+
headers: { authorization: `Bearer ${keys[index]!.token}` },
|
|
220
|
+
})
|
|
221
|
+
).json()
|
|
222
|
+
expect(await read(0)).toEqual({
|
|
223
|
+
access: null,
|
|
224
|
+
legacy: true,
|
|
225
|
+
routes: TestRoutes.snapshot.routes.length,
|
|
226
|
+
})
|
|
227
|
+
// A child can explicitly narrow legacy access without changing another key/environment.
|
|
228
|
+
await RoutesPolicies.save(db, {
|
|
229
|
+
scope: { orgId: org.id, environment: 'production', apiKeyId: keys[0]!.id },
|
|
230
|
+
policy: { access: [] },
|
|
231
|
+
version: 0,
|
|
232
|
+
})
|
|
233
|
+
expect(await read(0)).toEqual({ access: [], legacy: false, routes: 0 })
|
|
234
|
+
expect(await read(1)).toEqual({
|
|
235
|
+
access: null,
|
|
236
|
+
legacy: true,
|
|
237
|
+
routes: TestRoutes.snapshot.routes.length,
|
|
238
|
+
})
|
|
239
|
+
await RoutesPolicies.save(db, {
|
|
240
|
+
scope: { orgId: org.id, environment: 'sandbox' },
|
|
241
|
+
policy: {},
|
|
242
|
+
version: 0,
|
|
243
|
+
})
|
|
244
|
+
expect(await read(1)).toEqual({ access: [], legacy: false, routes: 0 })
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
test('enforces key access and organization suspension through composed creation and quote routes', async () => {
|
|
248
|
+
const db = TestApp.database()
|
|
249
|
+
const key = {
|
|
250
|
+
id: 'key_runtime_policy',
|
|
251
|
+
orgId: 'org_runtime_policy',
|
|
252
|
+
token: 'secret_runtime_policy',
|
|
253
|
+
scopes: ['routes:write', 'data:read'],
|
|
254
|
+
}
|
|
255
|
+
const scope = { apiKeyId: key.id, orgId: key.orgId, environment: 'production' } as const
|
|
256
|
+
await Organizations.create(db, { id: key.orgId, name: 'Policy runtime' })
|
|
257
|
+
await TestRoutes.publish(db)
|
|
258
|
+
const app = TestApp.create({
|
|
259
|
+
db,
|
|
260
|
+
defaultChainId: 4217,
|
|
261
|
+
auth: { keys: [key] },
|
|
262
|
+
providers: [Relay.relay()],
|
|
263
|
+
})
|
|
264
|
+
const headers = {
|
|
265
|
+
'Tempo-API-Key': key.token,
|
|
266
|
+
'Content-Type': 'application/json',
|
|
267
|
+
'Idempotency-Key': 'policy-request',
|
|
268
|
+
}
|
|
269
|
+
const body = {
|
|
270
|
+
amount: '1000000',
|
|
271
|
+
sourceChain: 'eip155:8453',
|
|
272
|
+
sourceToken: 'usdc',
|
|
273
|
+
destinationToken: 'usdce',
|
|
274
|
+
recipient: `0x${'11'.repeat(20)}`,
|
|
275
|
+
}
|
|
276
|
+
await RoutesPolicies.save(db, { scope, version: 0, policy: { access: [] } })
|
|
277
|
+
const quote = await app.request(
|
|
278
|
+
'/v1/routes/quotes?sourceChain=base&sourceToken=usdc&destinationToken=usdce&sourceAmount=1000000',
|
|
279
|
+
{ headers },
|
|
280
|
+
)
|
|
281
|
+
expect({ status: quote.status, body: await quote.json() }).toMatchObject({
|
|
282
|
+
status: 400,
|
|
283
|
+
body: { error: { code: 'route_unavailable' } },
|
|
284
|
+
})
|
|
285
|
+
const denied = await app.request('/v1/routes/deposit-addresses', {
|
|
286
|
+
method: 'POST',
|
|
287
|
+
headers,
|
|
288
|
+
body: JSON.stringify({ ...body, refundAddress: `0x${'22'.repeat(20)}` }),
|
|
289
|
+
})
|
|
290
|
+
expect({ status: denied.status, body: await denied.json() }).toMatchObject({
|
|
291
|
+
status: 403,
|
|
292
|
+
body: { error: { code: 'routes_not_allowed' } },
|
|
293
|
+
})
|
|
294
|
+
await RoutesPolicies.save(db, {
|
|
295
|
+
scope: { orgId: key.orgId, environment: 'production' },
|
|
296
|
+
version: 0,
|
|
297
|
+
policy: { suspended: true },
|
|
298
|
+
})
|
|
299
|
+
await RoutesPolicies.save(db, { scope, version: 1, policy: { access: null } })
|
|
300
|
+
const suspended = await app.request('/v1/routes/transfers', {
|
|
301
|
+
method: 'POST',
|
|
302
|
+
headers,
|
|
303
|
+
body: JSON.stringify({ ...body, mode: 'exactSource', sender: `0x${'22'.repeat(20)}` }),
|
|
304
|
+
})
|
|
305
|
+
expect({ status: suspended.status, body: await suspended.json() }).toMatchObject({
|
|
306
|
+
status: 403,
|
|
307
|
+
body: { error: { code: 'routes_suspended' } },
|
|
308
|
+
})
|
|
309
|
+
})
|
|
310
|
+
})
|
|
311
|
+
|
|
312
|
+
function context(keyPolicy: Policy.Overrides): Access.PolicyContext {
|
|
313
|
+
return {
|
|
314
|
+
scope: { apiKeyId: 'key_policy', environment: 'production', orgId: 'org_policy' },
|
|
315
|
+
layers: [{ access: null, subsidyEnabled: true, subsidyRoutes: null }, keyPolicy],
|
|
316
|
+
legacy: { subsidyEnabled: false, maxAmount: '0', subsidyPayer: 'enterprise' },
|
|
317
|
+
versions: [1, 2],
|
|
318
|
+
}
|
|
319
|
+
}
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import type { Context } from 'hono'
|
|
2
|
+
import { Value } from 'ox'
|
|
2
3
|
|
|
3
4
|
import type * as App from '../../App.js'
|
|
5
|
+
import * as Db from '../../db/Db.js'
|
|
6
|
+
import * as ApiKeyAdmissions from '../../db/tables/apiKeyAdmissions.js'
|
|
7
|
+
import * as RoutesPolicies from '../../db/tables/routesPolicies.js'
|
|
8
|
+
import * as RoutesSubsidies from '../../db/tables/routesSubsidies.js'
|
|
9
|
+
import * as StripeCustomers from '../../db/tables/stripeCustomers.js'
|
|
4
10
|
import type * as RoutesTransfers from '../../db/tables/routesTransfers.js'
|
|
5
11
|
import * as Auth from '../../internal/Auth.js'
|
|
6
12
|
import * as Response from '../../internal/Response.js'
|
|
13
|
+
import * as Policy from '../../internal/routes/Policy.js'
|
|
14
|
+
import type * as Catalog from '../../internal/routes/Catalog.js'
|
|
7
15
|
|
|
8
16
|
/** Returns the routes owner encoded by an API-key principal. */
|
|
9
17
|
export function owner(c: Context<App.Environment>): RoutesTransfers.Owner | null {
|
|
@@ -24,3 +32,142 @@ export function unauthorized(c: Context<App.Environment>) {
|
|
|
24
32
|
status: 401,
|
|
25
33
|
})
|
|
26
34
|
}
|
|
35
|
+
|
|
36
|
+
/** Request-local authoritative policy context. Public quotes have no context. */
|
|
37
|
+
export type PolicyContext = {
|
|
38
|
+
scope: Policy.Scope
|
|
39
|
+
layers: Policy.Overrides[]
|
|
40
|
+
legacy: Policy.Legacy
|
|
41
|
+
defaultAccess?: null
|
|
42
|
+
versions: number[]
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Reads grants from the primary database, never the API-key KV/cache. */
|
|
46
|
+
export async function loadPolicy(c: Context<App.Environment>): Promise<PolicyContext | undefined> {
|
|
47
|
+
const principal = Auth.getPrincipal(c)
|
|
48
|
+
if (principal?.type !== 'api_key') return undefined
|
|
49
|
+
const scope: Policy.Scope = {
|
|
50
|
+
apiKeyId: principal.id,
|
|
51
|
+
environment: principal.environment,
|
|
52
|
+
orgId: principal.orgId,
|
|
53
|
+
...(principal.projectId === undefined ? {} : { projectId: principal.projectId }),
|
|
54
|
+
}
|
|
55
|
+
const loaded = await RoutesPolicies.load(Db.get(c.get('db')), scope)
|
|
56
|
+
return {
|
|
57
|
+
scope,
|
|
58
|
+
...(loaded.layers[0]?.version === 0 ? { defaultAccess: null } : {}),
|
|
59
|
+
layers: loaded.layers.map((layer) => layer.policy),
|
|
60
|
+
legacy: loaded.legacy,
|
|
61
|
+
versions: loaded.layers.map((layer) => layer.version),
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** No saved policy in this scope chain: retain the original subsidy/provisioning contract. */
|
|
66
|
+
export function isLegacy(context: PolicyContext): boolean {
|
|
67
|
+
return context.versions.every((version) => version === 0)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Applies independent access and subsidy gates before provider selection. */
|
|
71
|
+
export function filterCatalog(
|
|
72
|
+
catalog: Catalog.Snapshot,
|
|
73
|
+
context: PolicyContext,
|
|
74
|
+
subsidize: boolean,
|
|
75
|
+
): Catalog.Snapshot {
|
|
76
|
+
if (isLegacy(context)) return catalog
|
|
77
|
+
const effective = Policy.resolve(context)
|
|
78
|
+
if (effective.suspended) throw new PolicyError('routes_suspended')
|
|
79
|
+
if (
|
|
80
|
+
subsidize &&
|
|
81
|
+
!catalog.routes.some(
|
|
82
|
+
(route) => Policy.resolve({ ...context, route: Policy.fromRoute(route) }).subsidyEnabled,
|
|
83
|
+
)
|
|
84
|
+
)
|
|
85
|
+
throw new PolicyError('routes_subsidy_not_enabled')
|
|
86
|
+
return Policy.filter(catalog, { ...context, subsidize })
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Checks financial eligibility and pins a platform-bounded expense ceiling. */
|
|
90
|
+
export async function commitment(
|
|
91
|
+
db: Db.Db,
|
|
92
|
+
context: PolicyContext,
|
|
93
|
+
route: Policy.Rule,
|
|
94
|
+
platformMaxAmount: string,
|
|
95
|
+
): Promise<Policy.Commitment> {
|
|
96
|
+
const effective = Policy.resolve({ ...context, route })
|
|
97
|
+
if (effective.suspended) throw new PolicyError('routes_suspended')
|
|
98
|
+
if (!Policy.allows(effective.access, route)) throw new PolicyError('routes_not_allowed')
|
|
99
|
+
if (!effective.subsidyEnabled) throw new PolicyError('routes_subsidy_not_enabled')
|
|
100
|
+
if (!effective.subsidyEligible) throw new PolicyError('routes_subsidy_not_allowed')
|
|
101
|
+
if (context.scope.environment === 'production' && effective.subsidyPayer === 'enterprise') {
|
|
102
|
+
const billing = await StripeCustomers.get(db, context.scope.orgId)
|
|
103
|
+
if (billing?.status === 'past_due') throw new PolicyError('billing_past_due')
|
|
104
|
+
if (billing?.status !== 'active') throw new PolicyError('billing_required')
|
|
105
|
+
}
|
|
106
|
+
const limit = Value.from(effective.maxAmount, 6)
|
|
107
|
+
const platformLimit = Value.from(platformMaxAmount, 6)
|
|
108
|
+
return {
|
|
109
|
+
maxAmount: Value.format(limit < platformLimit ? limit : platformLimit, 6),
|
|
110
|
+
scope: context.scope,
|
|
111
|
+
subsidyPayer: effective.subsidyPayer,
|
|
112
|
+
versions: context.versions,
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Serializes acceptance against admin changes; call inside the resource transaction. */
|
|
117
|
+
export async function assertPolicy(db: Db.Db, context: PolicyContext): Promise<void> {
|
|
118
|
+
await RoutesSubsidies.lockOrganization(db, context.scope.orgId)
|
|
119
|
+
// Reassignment takes this organization lock even when no key override exists.
|
|
120
|
+
// Policy versions alone cannot fence requests authenticated under the old owner.
|
|
121
|
+
if (
|
|
122
|
+
context.scope.apiKeyId !== undefined &&
|
|
123
|
+
!(await ApiKeyAdmissions.matches(db, {
|
|
124
|
+
id: context.scope.apiKeyId,
|
|
125
|
+
orgId: context.scope.orgId,
|
|
126
|
+
projectId: context.scope.projectId,
|
|
127
|
+
}))
|
|
128
|
+
)
|
|
129
|
+
throw new PolicyError('route_policy_changed')
|
|
130
|
+
const current = await RoutesPolicies.load(db, context.scope)
|
|
131
|
+
if (
|
|
132
|
+
JSON.stringify(current.layers.map((layer) => layer.version)) !==
|
|
133
|
+
JSON.stringify(context.versions) ||
|
|
134
|
+
JSON.stringify(current.legacy) !== JSON.stringify(context.legacy)
|
|
135
|
+
)
|
|
136
|
+
throw new PolicyError('route_policy_changed')
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** Emits a bounded denial metric and a customer-safe response. */
|
|
140
|
+
export function policyError(c: Context<App.Environment>, cause: PolicyError) {
|
|
141
|
+
c.get('metrics')?.count('routes_policy_denial_count', 1, { reason: cause.code })
|
|
142
|
+
if (cause.code === 'route_policy_changed')
|
|
143
|
+
return Response.error(c, {
|
|
144
|
+
code: cause.code,
|
|
145
|
+
message: messages[cause.code],
|
|
146
|
+
status: 409,
|
|
147
|
+
})
|
|
148
|
+
return Response.error(c, {
|
|
149
|
+
code: cause.code,
|
|
150
|
+
message: messages[cause.code],
|
|
151
|
+
status: 403,
|
|
152
|
+
})
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const messages = {
|
|
156
|
+
billing_past_due: 'Billing past due.',
|
|
157
|
+
billing_required:
|
|
158
|
+
'Active billing is required for enterprise-paid route subsidies. Set up billing for this organization, then retry.',
|
|
159
|
+
route_policy_changed: 'Route policy changed during creation. Retry the request.',
|
|
160
|
+
routes_not_allowed: 'This route is not permitted by your access policy.',
|
|
161
|
+
routes_subsidy_not_allowed: 'This route is not eligible for the requested subsidy.',
|
|
162
|
+
routes_subsidy_not_enabled:
|
|
163
|
+
'Route subsidies are not enabled for this request. Contact Tempo to enable them, or use an API key from an organization with subsidies enabled.',
|
|
164
|
+
routes_suspended: 'New route instructions are suspended for this organization and environment.',
|
|
165
|
+
} as const
|
|
166
|
+
|
|
167
|
+
/** A policy denial, distinct from provider unavailability. */
|
|
168
|
+
export class PolicyError extends Error {
|
|
169
|
+
override name = 'Routes.Access.PolicyError'
|
|
170
|
+
constructor(public code: keyof typeof messages) {
|
|
171
|
+
super(messages[code])
|
|
172
|
+
}
|
|
173
|
+
}
|