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
|
@@ -0,0 +1,760 @@
|
|
|
1
|
+
import { ed25519 } from '@noble/curves/ed25519'
|
|
2
|
+
import {
|
|
3
|
+
findAssociatedTokenPda,
|
|
4
|
+
getTokenDecoder,
|
|
5
|
+
getTransferCheckedInstruction,
|
|
6
|
+
TOKEN_PROGRAM_ADDRESS,
|
|
7
|
+
} from '@solana-program/token'
|
|
8
|
+
import {
|
|
9
|
+
address,
|
|
10
|
+
appendTransactionMessageInstruction,
|
|
11
|
+
blockhash,
|
|
12
|
+
compileTransaction,
|
|
13
|
+
createTransactionMessage,
|
|
14
|
+
decompileTransactionMessage,
|
|
15
|
+
getCompiledTransactionMessageDecoder,
|
|
16
|
+
getTransactionDecoder,
|
|
17
|
+
getTransactionEncoder,
|
|
18
|
+
setTransactionMessageFeePayer,
|
|
19
|
+
setTransactionMessageLifetimeUsingBlockhash,
|
|
20
|
+
} from '@solana/kit'
|
|
21
|
+
import { Base58 } from 'ox'
|
|
22
|
+
|
|
23
|
+
import type * as Chain from './Chain.js'
|
|
24
|
+
|
|
25
|
+
const mainnet = 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp'
|
|
26
|
+
const usdcMint = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'
|
|
27
|
+
const recoverySlotWindow = 256
|
|
28
|
+
const signingBlockMargin = 64
|
|
29
|
+
|
|
30
|
+
/** An immutable Solana transaction prepared before requesting a Horcrux signature. */
|
|
31
|
+
export type Prepared = {
|
|
32
|
+
/** Horcrux wallet public key. */
|
|
33
|
+
account: string
|
|
34
|
+
/** Destination token quantity in base units. */
|
|
35
|
+
amount: string
|
|
36
|
+
/** Destination chain identifier. */
|
|
37
|
+
chainId: string
|
|
38
|
+
/** Derived recipient USDC token account. */
|
|
39
|
+
destination: string
|
|
40
|
+
/** Last block height at which Solana accepts the transaction. */
|
|
41
|
+
lastValidBlockHeight: number
|
|
42
|
+
/** Native SOL fee reserved in lamports. */
|
|
43
|
+
nativeAmount: string
|
|
44
|
+
/** Finalized slot that supplied the transaction blockhash. */
|
|
45
|
+
originSlot: number
|
|
46
|
+
/** Recipient wallet public key. */
|
|
47
|
+
recipient: string
|
|
48
|
+
/** Exact body sent to Horcrux on signing retries. */
|
|
49
|
+
request: { network: 'solana:mainnet-beta'; transaction: string }
|
|
50
|
+
/** Derived subsidy wallet USDC token account. */
|
|
51
|
+
source: string
|
|
52
|
+
/** Destination token mint. */
|
|
53
|
+
token: string
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** A Horcrux-signed transaction persisted before broadcast. */
|
|
57
|
+
export type Signed = Prepared & {
|
|
58
|
+
/** First Solana signature, used as the transaction identifier. */
|
|
59
|
+
hash: string
|
|
60
|
+
/** Canonical signed transaction in standard base64. */
|
|
61
|
+
transaction: string
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Read-only Solana destination subsidy inventory checker. */
|
|
65
|
+
export type Inventory = {
|
|
66
|
+
/** Horcrux wallet public key. */
|
|
67
|
+
account: string
|
|
68
|
+
/** Checks USDC and SOL capacity including unsettled commitments. */
|
|
69
|
+
check(options: create.CheckOptions): Promise<{ nativeAmount: string }>
|
|
70
|
+
/** Operational maximum destination subsidy. */
|
|
71
|
+
policy: { maxAmount: string }
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Prepares, signs, broadcasts, and verifies Solana destination subsidies. */
|
|
75
|
+
export type Settler = Inventory & {
|
|
76
|
+
/** Broadcasts the persisted signed transaction. */
|
|
77
|
+
broadcast(options: { chain: Chain.Chain; signed: Signed }): Promise<void>
|
|
78
|
+
/** Checks whether a prepared blockhash is too close to expiry to sign safely. */
|
|
79
|
+
expiring(options: { chain: Chain.Chain; prepared: Prepared }): Promise<boolean>
|
|
80
|
+
/** Constructs an unsigned transfer without contacting Horcrux. */
|
|
81
|
+
prepare(options: create.CheckOptions): Promise<Prepared>
|
|
82
|
+
/** Signs an immutable request through Horcrux. */
|
|
83
|
+
sign(options: { idempotencyKey: string; prepared: Prepared }): Promise<Signed>
|
|
84
|
+
/** Reads finalized execution for the exact signed transaction. */
|
|
85
|
+
status(
|
|
86
|
+
options: create.StatusOptions,
|
|
87
|
+
): Promise<'ambiguous' | 'expired' | 'pending' | 'reverted' | 'success'>
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Validates prepared subsidy state restored from durable storage. */
|
|
91
|
+
export function readPrepared(value: unknown): Prepared | undefined {
|
|
92
|
+
if (typeof value === 'string') {
|
|
93
|
+
try {
|
|
94
|
+
value = JSON.parse(value)
|
|
95
|
+
} catch {
|
|
96
|
+
return undefined
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (!isObject(value) || !isObject(value['request'])) return undefined
|
|
100
|
+
const request = value['request']
|
|
101
|
+
if (
|
|
102
|
+
typeof value['account'] !== 'string' ||
|
|
103
|
+
typeof value['amount'] !== 'string' ||
|
|
104
|
+
!/^[1-9]\d*$/.test(value['amount']) ||
|
|
105
|
+
value['chainId'] !== mainnet ||
|
|
106
|
+
typeof value['destination'] !== 'string' ||
|
|
107
|
+
typeof value['lastValidBlockHeight'] !== 'number' ||
|
|
108
|
+
!Number.isSafeInteger(value['lastValidBlockHeight']) ||
|
|
109
|
+
value['lastValidBlockHeight'] <= 0 ||
|
|
110
|
+
typeof value['nativeAmount'] !== 'string' ||
|
|
111
|
+
!/^[1-9]\d*$/.test(value['nativeAmount']) ||
|
|
112
|
+
typeof value['originSlot'] !== 'number' ||
|
|
113
|
+
!Number.isSafeInteger(value['originSlot']) ||
|
|
114
|
+
value['originSlot'] <= 0 ||
|
|
115
|
+
typeof value['recipient'] !== 'string' ||
|
|
116
|
+
typeof value['source'] !== 'string' ||
|
|
117
|
+
value['token'] !== usdcMint ||
|
|
118
|
+
request['network'] !== 'solana:mainnet-beta' ||
|
|
119
|
+
typeof request['transaction'] !== 'string'
|
|
120
|
+
)
|
|
121
|
+
return undefined
|
|
122
|
+
try {
|
|
123
|
+
const account = address(value['account'])
|
|
124
|
+
address(value['recipient'])
|
|
125
|
+
const source = address(value['source'])
|
|
126
|
+
const destination = address(value['destination'])
|
|
127
|
+
const raw = Buffer.from(request['transaction'], 'base64')
|
|
128
|
+
if (raw.toString('base64') !== request['transaction']) return undefined
|
|
129
|
+
const tx = getTransactionDecoder().decode(raw)
|
|
130
|
+
const compiled = getCompiledTransactionMessageDecoder().decode(tx.messageBytes)
|
|
131
|
+
if (compiled.version !== 'legacy') return undefined
|
|
132
|
+
const message = decompileTransactionMessage(compiled)
|
|
133
|
+
if (!('blockhash' in message.lifetimeConstraint)) return undefined
|
|
134
|
+
if (Object.keys(tx.signatures).length !== 1 || tx.signatures[account] !== null) return undefined
|
|
135
|
+
const expected = unsignedTransaction({
|
|
136
|
+
account,
|
|
137
|
+
amount: BigInt(value['amount']),
|
|
138
|
+
blockhash: message.lifetimeConstraint.blockhash,
|
|
139
|
+
destination,
|
|
140
|
+
source,
|
|
141
|
+
})
|
|
142
|
+
if (!Buffer.from(getTransactionEncoder().encode(expected)).equals(raw)) return undefined
|
|
143
|
+
} catch {
|
|
144
|
+
return undefined
|
|
145
|
+
}
|
|
146
|
+
return value as Prepared
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Validates signed subsidy state restored from durable storage. */
|
|
150
|
+
export function readSigned(value: unknown): Signed | undefined {
|
|
151
|
+
const prepared = readPrepared(value)
|
|
152
|
+
if (!prepared || typeof (prepared as Signed).transaction !== 'string') return undefined
|
|
153
|
+
const signed = prepared as Signed
|
|
154
|
+
try {
|
|
155
|
+
const raw = Buffer.from(signed.transaction, 'base64')
|
|
156
|
+
if (raw.toString('base64') !== signed.transaction) return undefined
|
|
157
|
+
const tx = getTransactionDecoder().decode(raw)
|
|
158
|
+
const signature = tx.signatures[address(signed.account)]
|
|
159
|
+
const preparedTransaction = getTransactionDecoder().decode(
|
|
160
|
+
Buffer.from(prepared.request.transaction, 'base64'),
|
|
161
|
+
)
|
|
162
|
+
if (
|
|
163
|
+
typeof signed.hash !== 'string' ||
|
|
164
|
+
!signature ||
|
|
165
|
+
Object.keys(tx.signatures).length !== 1 ||
|
|
166
|
+
!Buffer.from(tx.messageBytes).equals(Buffer.from(preparedTransaction.messageBytes)) ||
|
|
167
|
+
!ed25519.verify(
|
|
168
|
+
Buffer.from(signature),
|
|
169
|
+
Buffer.from(tx.messageBytes),
|
|
170
|
+
Base58.toBytes(signed.account),
|
|
171
|
+
) ||
|
|
172
|
+
Base58.fromBytes(signature) !== signed.hash ||
|
|
173
|
+
!Buffer.from(getTransactionEncoder().encode(tx)).equals(raw)
|
|
174
|
+
)
|
|
175
|
+
return undefined
|
|
176
|
+
} catch {
|
|
177
|
+
return undefined
|
|
178
|
+
}
|
|
179
|
+
return signed
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/** Checks persisted transaction terms against freshly verified delivery. */
|
|
183
|
+
export function matchesTerms(prepared: Prepared, options: matchesTerms.Options): boolean {
|
|
184
|
+
return (
|
|
185
|
+
readPrepared(prepared) !== undefined &&
|
|
186
|
+
prepared.account === options.account &&
|
|
187
|
+
prepared.amount === options.amount.toString() &&
|
|
188
|
+
prepared.chainId === options.chainId &&
|
|
189
|
+
prepared.recipient === options.recipient &&
|
|
190
|
+
prepared.token === options.token
|
|
191
|
+
)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export declare namespace matchesTerms {
|
|
195
|
+
/** Exact terms required before a subsidy is signed or broadcast. */
|
|
196
|
+
type Options = {
|
|
197
|
+
account: string
|
|
198
|
+
amount: bigint
|
|
199
|
+
chainId: string
|
|
200
|
+
recipient: string
|
|
201
|
+
token: string
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** Creates a Solana inventory checker and Horcrux signer for one wallet. */
|
|
206
|
+
export function create(options: create.Options): Settler {
|
|
207
|
+
const account = address(options.account)
|
|
208
|
+
if (!/^[0-9a-fA-F-]{36}$/.test(options.walletId))
|
|
209
|
+
throw new ConfigurationError('Invalid Horcrux wallet ID.')
|
|
210
|
+
const horcruxUrl = new URL(options.horcrux.url)
|
|
211
|
+
if (
|
|
212
|
+
!['https:', 'http:'].includes(horcruxUrl.protocol) ||
|
|
213
|
+
(horcruxUrl.protocol === 'http:' &&
|
|
214
|
+
!['localhost', '127.0.0.1', '[::1]'].includes(horcruxUrl.hostname)) ||
|
|
215
|
+
horcruxUrl.username ||
|
|
216
|
+
horcruxUrl.password ||
|
|
217
|
+
horcruxUrl.search ||
|
|
218
|
+
horcruxUrl.hash
|
|
219
|
+
)
|
|
220
|
+
throw new ConfigurationError('Horcrux requires HTTPS or loopback HTTP.')
|
|
221
|
+
if (
|
|
222
|
+
options.horcrux.auth.type === 'none' &&
|
|
223
|
+
!['localhost', '127.0.0.1', '[::1]'].includes(horcruxUrl.hostname)
|
|
224
|
+
)
|
|
225
|
+
throw new ConfigurationError('Unauthenticated Horcrux requires loopback.')
|
|
226
|
+
|
|
227
|
+
async function rpc(chain: Chain.Chain, method: string, params: readonly unknown[]) {
|
|
228
|
+
assertChain(chain)
|
|
229
|
+
let failure: UpstreamError | undefined
|
|
230
|
+
for (const url of chain.rpcUrls) {
|
|
231
|
+
let response: Response
|
|
232
|
+
try {
|
|
233
|
+
response = await options.fetch(url, {
|
|
234
|
+
body: JSON.stringify({ id: 1, jsonrpc: '2.0', method, params }),
|
|
235
|
+
headers: { 'content-type': 'application/json' },
|
|
236
|
+
method: 'POST',
|
|
237
|
+
signal: AbortSignal.timeout(10_000),
|
|
238
|
+
})
|
|
239
|
+
} catch {
|
|
240
|
+
failure = new UpstreamError(`Solana RPC ${method} is unavailable.`)
|
|
241
|
+
continue
|
|
242
|
+
}
|
|
243
|
+
if (!response.ok) {
|
|
244
|
+
failure = new UpstreamError(`Solana RPC returned HTTP ${response.status}.`)
|
|
245
|
+
continue
|
|
246
|
+
}
|
|
247
|
+
let body: unknown
|
|
248
|
+
try {
|
|
249
|
+
body = await response.json()
|
|
250
|
+
} catch {
|
|
251
|
+
failure = new UpstreamError(`Solana RPC ${method} returned an invalid response.`)
|
|
252
|
+
continue
|
|
253
|
+
}
|
|
254
|
+
if (!isObject(body)) {
|
|
255
|
+
failure = new UpstreamError(`Solana RPC ${method} returned an invalid response.`)
|
|
256
|
+
continue
|
|
257
|
+
}
|
|
258
|
+
if (body['error'] !== undefined) {
|
|
259
|
+
const cause = body['error']
|
|
260
|
+
const message =
|
|
261
|
+
isObject(cause) && typeof cause['message'] === 'string'
|
|
262
|
+
? cause['message']
|
|
263
|
+
: 'unknown error'
|
|
264
|
+
const blockhashNotFound =
|
|
265
|
+
isObject(cause) &&
|
|
266
|
+
((isObject(cause['data']) && cause['data']['err'] === 'BlockhashNotFound') ||
|
|
267
|
+
/blockhash not found/i.test(message))
|
|
268
|
+
const error = new UpstreamError(`Solana RPC ${method} failed: ${message}`)
|
|
269
|
+
// Other nodes may still serve a request when one node is unhealthy or lacks recent history.
|
|
270
|
+
if (
|
|
271
|
+
isObject(cause) &&
|
|
272
|
+
typeof cause['code'] === 'number' &&
|
|
273
|
+
([-32603, -32016, -32009, -32005, -32004].includes(cause['code']) ||
|
|
274
|
+
(method === 'sendTransaction' && cause['code'] === -32002 && blockhashNotFound))
|
|
275
|
+
) {
|
|
276
|
+
failure = error
|
|
277
|
+
continue
|
|
278
|
+
}
|
|
279
|
+
throw error
|
|
280
|
+
}
|
|
281
|
+
if (!('result' in body)) {
|
|
282
|
+
failure = new UpstreamError(`Solana RPC ${method} omitted a result.`)
|
|
283
|
+
continue
|
|
284
|
+
}
|
|
285
|
+
return body['result']
|
|
286
|
+
}
|
|
287
|
+
throw failure ?? new UpstreamError(`Solana RPC ${method} is unavailable.`)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
async function expiredStatus(chain: Chain.Chain, signed: Signed) {
|
|
291
|
+
const info = await rpc(chain, 'getEpochInfo', [{ commitment: 'finalized' }])
|
|
292
|
+
if (
|
|
293
|
+
!isObject(info) ||
|
|
294
|
+
typeof info['absoluteSlot'] !== 'number' ||
|
|
295
|
+
typeof info['blockHeight'] !== 'number' ||
|
|
296
|
+
!Number.isSafeInteger(info['absoluteSlot']) ||
|
|
297
|
+
!Number.isSafeInteger(info['blockHeight'])
|
|
298
|
+
)
|
|
299
|
+
throw new UpstreamError('Solana finalized position is unavailable.')
|
|
300
|
+
if (info['blockHeight'] <= signed.lastValidBlockHeight) return 'pending' as const
|
|
301
|
+
const endSlot = info['absoluteSlot']
|
|
302
|
+
if (endSlot < signed.originSlot) return 'ambiguous' as const
|
|
303
|
+
const first = await rpc(chain, 'getFirstAvailableBlock', [])
|
|
304
|
+
if (typeof first !== 'number' || !Number.isSafeInteger(first))
|
|
305
|
+
throw new UpstreamError('Solana block history boundary is unavailable.')
|
|
306
|
+
if (first > signed.originSlot) return 'ambiguous' as const
|
|
307
|
+
let previousSlot: number | undefined
|
|
308
|
+
let previousBlockhash: string | undefined
|
|
309
|
+
let previousHeight: number | undefined
|
|
310
|
+
for (let start = signed.originSlot; start <= endSlot; start += recoverySlotWindow) {
|
|
311
|
+
const end = Math.min(start + recoverySlotWindow - 1, endSlot)
|
|
312
|
+
const slots = await rpc(chain, 'getBlocks', [start, end, { commitment: 'finalized' }])
|
|
313
|
+
if (
|
|
314
|
+
!Array.isArray(slots) ||
|
|
315
|
+
slots.some(
|
|
316
|
+
(slot, index) =>
|
|
317
|
+
typeof slot !== 'number' ||
|
|
318
|
+
!Number.isSafeInteger(slot) ||
|
|
319
|
+
slot < start ||
|
|
320
|
+
slot > end ||
|
|
321
|
+
(index > 0 && slot <= slots[index - 1]),
|
|
322
|
+
)
|
|
323
|
+
)
|
|
324
|
+
return 'ambiguous' as const
|
|
325
|
+
for (let offset = 0; offset < slots.length; offset += 8) {
|
|
326
|
+
const batch = slots.slice(offset, offset + 8)
|
|
327
|
+
const blocks = await Promise.all(
|
|
328
|
+
batch.map((slot) =>
|
|
329
|
+
rpc(chain, 'getBlock', [
|
|
330
|
+
slot,
|
|
331
|
+
{
|
|
332
|
+
commitment: 'finalized',
|
|
333
|
+
maxSupportedTransactionVersion: 1,
|
|
334
|
+
rewards: false,
|
|
335
|
+
transactionDetails: 'signatures',
|
|
336
|
+
},
|
|
337
|
+
]),
|
|
338
|
+
),
|
|
339
|
+
)
|
|
340
|
+
for (const [index, block] of blocks.entries()) {
|
|
341
|
+
const slot = batch[index]!
|
|
342
|
+
const result = inspectFinalizedBlock({
|
|
343
|
+
block,
|
|
344
|
+
lastValidBlockHeight: signed.lastValidBlockHeight,
|
|
345
|
+
originSlot: signed.originSlot,
|
|
346
|
+
previousBlockhash,
|
|
347
|
+
previousHeight,
|
|
348
|
+
previousSlot,
|
|
349
|
+
signature: signed.hash,
|
|
350
|
+
slot,
|
|
351
|
+
})
|
|
352
|
+
if (result.type === 'ambiguous') return 'ambiguous' as const
|
|
353
|
+
previousSlot = slot
|
|
354
|
+
previousBlockhash = result.blockhash
|
|
355
|
+
previousHeight = result.blockHeight
|
|
356
|
+
if (result.type === 'found') {
|
|
357
|
+
const full = await rpc(chain, 'getBlock', [
|
|
358
|
+
slot,
|
|
359
|
+
{
|
|
360
|
+
commitment: 'finalized',
|
|
361
|
+
encoding: 'json',
|
|
362
|
+
maxSupportedTransactionVersion: 1,
|
|
363
|
+
rewards: false,
|
|
364
|
+
transactionDetails: 'full',
|
|
365
|
+
},
|
|
366
|
+
])
|
|
367
|
+
if (
|
|
368
|
+
!isObject(full) ||
|
|
369
|
+
full['blockhash'] !== result.blockhash ||
|
|
370
|
+
!Array.isArray(full['transactions'])
|
|
371
|
+
)
|
|
372
|
+
return 'ambiguous' as const
|
|
373
|
+
const entry = full['transactions'].find(
|
|
374
|
+
(value) =>
|
|
375
|
+
isObject(value) &&
|
|
376
|
+
isObject(value['transaction']) &&
|
|
377
|
+
Array.isArray(value['transaction']['signatures']) &&
|
|
378
|
+
value['transaction']['signatures'].includes(signed.hash),
|
|
379
|
+
)
|
|
380
|
+
if (!isObject(entry) || !isObject(entry['meta']) || !('err' in entry['meta']))
|
|
381
|
+
return 'ambiguous' as const
|
|
382
|
+
return entry['meta']['err'] === null ? ('success' as const) : ('reverted' as const)
|
|
383
|
+
}
|
|
384
|
+
// The first finalized block above the validity height closes the entire inclusion window.
|
|
385
|
+
if (result.type === 'expired') return 'expired' as const
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
return 'ambiguous' as const
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
async function accountsMatch(prepared: Prepared) {
|
|
393
|
+
const mint = address(prepared.token)
|
|
394
|
+
const [[source], [destination]] = await Promise.all([
|
|
395
|
+
findAssociatedTokenPda({
|
|
396
|
+
mint,
|
|
397
|
+
owner: address(prepared.account),
|
|
398
|
+
tokenProgram: TOKEN_PROGRAM_ADDRESS,
|
|
399
|
+
}),
|
|
400
|
+
findAssociatedTokenPda({
|
|
401
|
+
mint,
|
|
402
|
+
owner: address(prepared.recipient),
|
|
403
|
+
tokenProgram: TOKEN_PROGRAM_ADDRESS,
|
|
404
|
+
}),
|
|
405
|
+
])
|
|
406
|
+
return prepared.source === source && prepared.destination === destination
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
async function tokenAccount(chain: Chain.Chain, tokenAddress: string) {
|
|
410
|
+
const result = await rpc(chain, 'getAccountInfo', [
|
|
411
|
+
tokenAddress,
|
|
412
|
+
{ commitment: 'finalized', encoding: 'base64' },
|
|
413
|
+
])
|
|
414
|
+
if (!isObject(result) || !isObject(result['value'])) throw new BalanceUnavailableError()
|
|
415
|
+
const value = result['value']
|
|
416
|
+
if (
|
|
417
|
+
value['owner'] !== TOKEN_PROGRAM_ADDRESS ||
|
|
418
|
+
!Array.isArray(value['data']) ||
|
|
419
|
+
typeof value['data'][0] !== 'string' ||
|
|
420
|
+
value['data'][1] !== 'base64'
|
|
421
|
+
)
|
|
422
|
+
throw new ConfigurationError('Solana subsidy token account is invalid.')
|
|
423
|
+
return getTokenDecoder().decode(Buffer.from(value['data'][0], 'base64'))
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
async function construct(parameters: create.CheckOptions, requireDestination: boolean) {
|
|
427
|
+
assertChain(parameters.chain)
|
|
428
|
+
if (parameters.token !== usdcMint)
|
|
429
|
+
throw new ConfigurationError('Unsupported Solana subsidy token.')
|
|
430
|
+
const mint = address(parameters.token)
|
|
431
|
+
const recipient = address(parameters.recipient)
|
|
432
|
+
const [[source], [destination]] = await Promise.all([
|
|
433
|
+
findAssociatedTokenPda({ mint, owner: account, tokenProgram: TOKEN_PROGRAM_ADDRESS }),
|
|
434
|
+
findAssociatedTokenPda({ mint, owner: recipient, tokenProgram: TOKEN_PROGRAM_ADDRESS }),
|
|
435
|
+
])
|
|
436
|
+
const [sourceAccount, destinationAccount, balanceResult, latestResult] = await Promise.all([
|
|
437
|
+
tokenAccount(parameters.chain, source),
|
|
438
|
+
requireDestination ? tokenAccount(parameters.chain, destination) : Promise.resolve(undefined),
|
|
439
|
+
rpc(parameters.chain, 'getBalance', [account, { commitment: 'finalized' }]),
|
|
440
|
+
rpc(parameters.chain, 'getLatestBlockhash', [{ commitment: 'finalized' }]),
|
|
441
|
+
])
|
|
442
|
+
if (
|
|
443
|
+
!isObject(balanceResult) ||
|
|
444
|
+
typeof balanceResult['value'] !== 'number' ||
|
|
445
|
+
!isObject(latestResult) ||
|
|
446
|
+
!isObject(latestResult['value']) ||
|
|
447
|
+
typeof latestResult['value']['blockhash'] !== 'string' ||
|
|
448
|
+
typeof latestResult['value']['lastValidBlockHeight'] !== 'number' ||
|
|
449
|
+
!isObject(latestResult['context']) ||
|
|
450
|
+
typeof latestResult['context']['slot'] !== 'number' ||
|
|
451
|
+
!Number.isSafeInteger(latestResult['context']['slot']) ||
|
|
452
|
+
latestResult['context']['slot'] <= 0
|
|
453
|
+
)
|
|
454
|
+
throw new UpstreamError('Solana balance or blockhash is unavailable.')
|
|
455
|
+
const latest = latestResult['value']
|
|
456
|
+
if (
|
|
457
|
+
sourceAccount.owner !== account ||
|
|
458
|
+
sourceAccount.mint !== mint ||
|
|
459
|
+
(destinationAccount !== undefined &&
|
|
460
|
+
(destinationAccount.owner !== recipient || destinationAccount.mint !== mint))
|
|
461
|
+
)
|
|
462
|
+
throw new ConfigurationError('Solana subsidy token account terms changed.')
|
|
463
|
+
if (sourceAccount.amount < parameters.amount + parameters.reservations.tokenAmount)
|
|
464
|
+
throw new BalanceUnavailableError()
|
|
465
|
+
const tx = unsignedTransaction({
|
|
466
|
+
account,
|
|
467
|
+
amount: parameters.amount,
|
|
468
|
+
blockhash: blockhash(latest['blockhash'] as string),
|
|
469
|
+
destination,
|
|
470
|
+
source,
|
|
471
|
+
})
|
|
472
|
+
const feeResult = await rpc(parameters.chain, 'getFeeForMessage', [
|
|
473
|
+
Buffer.from(tx.messageBytes).toString('base64'),
|
|
474
|
+
{ commitment: 'finalized' },
|
|
475
|
+
])
|
|
476
|
+
if (!isObject(feeResult) || typeof feeResult['value'] !== 'number' || feeResult['value'] <= 0)
|
|
477
|
+
throw new UpstreamError('Solana fee is unavailable.')
|
|
478
|
+
const fee = feeResult['value']
|
|
479
|
+
if (BigInt(balanceResult['value']) < BigInt(fee) + parameters.reservations.nativeAmount)
|
|
480
|
+
throw new BalanceUnavailableError()
|
|
481
|
+
return {
|
|
482
|
+
destination,
|
|
483
|
+
fee,
|
|
484
|
+
latest,
|
|
485
|
+
originSlot: latestResult['context']['slot'] as number,
|
|
486
|
+
source,
|
|
487
|
+
tx,
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
return {
|
|
492
|
+
account,
|
|
493
|
+
async broadcast({ chain, signed }) {
|
|
494
|
+
if (!readSigned(signed) || signed.account !== account || !(await accountsMatch(signed)))
|
|
495
|
+
throw new ConfigurationError('Invalid signed Solana subsidy transaction.')
|
|
496
|
+
const hash = await rpc(chain, 'sendTransaction', [
|
|
497
|
+
signed.transaction,
|
|
498
|
+
{ encoding: 'base64' },
|
|
499
|
+
]).catch((cause) => {
|
|
500
|
+
if (cause instanceof Error && /already processed|duplicate signature/i.test(cause.message))
|
|
501
|
+
return signed.hash
|
|
502
|
+
throw cause
|
|
503
|
+
})
|
|
504
|
+
if (hash !== signed.hash) throw new BroadcastError('Solana returned a different signature.')
|
|
505
|
+
},
|
|
506
|
+
async check(parameters) {
|
|
507
|
+
const { fee } = await construct(parameters, false)
|
|
508
|
+
return { nativeAmount: String(fee) }
|
|
509
|
+
},
|
|
510
|
+
async expiring({ chain, prepared }) {
|
|
511
|
+
assertChain(chain)
|
|
512
|
+
if (!readPrepared(prepared) || prepared.chainId !== chain.id)
|
|
513
|
+
throw new ConfigurationError('Invalid prepared Solana subsidy transaction.')
|
|
514
|
+
const height = await rpc(chain, 'getBlockHeight', [{ commitment: 'confirmed' }])
|
|
515
|
+
if (typeof height !== 'number' || !Number.isSafeInteger(height) || height < 0)
|
|
516
|
+
throw new UpstreamError('Solana block height is unavailable.')
|
|
517
|
+
// Leave time for Horcrux signing, persistence, and the first broadcast.
|
|
518
|
+
return height + signingBlockMargin >= prepared.lastValidBlockHeight
|
|
519
|
+
},
|
|
520
|
+
policy: options.policy,
|
|
521
|
+
async prepare(parameters) {
|
|
522
|
+
const { destination, fee, latest, originSlot, source, tx } = await construct(parameters, true)
|
|
523
|
+
return {
|
|
524
|
+
account,
|
|
525
|
+
amount: parameters.amount.toString(),
|
|
526
|
+
chainId: parameters.chain.id,
|
|
527
|
+
destination,
|
|
528
|
+
lastValidBlockHeight: latest['lastValidBlockHeight'] as number,
|
|
529
|
+
nativeAmount: String(fee),
|
|
530
|
+
originSlot,
|
|
531
|
+
recipient: parameters.recipient,
|
|
532
|
+
request: {
|
|
533
|
+
network: 'solana:mainnet-beta',
|
|
534
|
+
transaction: Buffer.from(getTransactionEncoder().encode(tx)).toString('base64'),
|
|
535
|
+
},
|
|
536
|
+
source,
|
|
537
|
+
token: parameters.token,
|
|
538
|
+
}
|
|
539
|
+
},
|
|
540
|
+
async sign({ idempotencyKey, prepared }) {
|
|
541
|
+
if (!/^[\x21-\x7e]{1,256}$/.test(idempotencyKey))
|
|
542
|
+
throw new ConfigurationError('Invalid Horcrux idempotency key.')
|
|
543
|
+
if (
|
|
544
|
+
!readPrepared(prepared) ||
|
|
545
|
+
prepared.account !== account ||
|
|
546
|
+
!(await accountsMatch(prepared))
|
|
547
|
+
)
|
|
548
|
+
throw new ConfigurationError('Invalid prepared Solana subsidy transaction.')
|
|
549
|
+
const headers: Record<string, string> = {
|
|
550
|
+
'content-type': 'application/json',
|
|
551
|
+
'Idempotency-Key': idempotencyKey,
|
|
552
|
+
}
|
|
553
|
+
if (options.horcrux.auth.type === 'cloudflare-access') {
|
|
554
|
+
headers['CF-Access-Client-Id'] = options.horcrux.auth.clientId
|
|
555
|
+
headers['CF-Access-Client-Secret'] = options.horcrux.auth.clientSecret
|
|
556
|
+
}
|
|
557
|
+
const response = await options.fetch(
|
|
558
|
+
new URL(`/v1/wallets/${options.walletId}/sign`, horcruxUrl),
|
|
559
|
+
{
|
|
560
|
+
body: JSON.stringify(prepared.request),
|
|
561
|
+
headers,
|
|
562
|
+
method: 'POST',
|
|
563
|
+
redirect: 'manual',
|
|
564
|
+
signal: AbortSignal.timeout(10_000),
|
|
565
|
+
},
|
|
566
|
+
)
|
|
567
|
+
if (!response.ok) throw new SigningError(`Horcrux signing returned HTTP ${response.status}.`)
|
|
568
|
+
const result: unknown = await response.json()
|
|
569
|
+
if (!isObject(result) || typeof result['signed_transaction'] !== 'string')
|
|
570
|
+
throw new SigningError('Horcrux returned an invalid signing response.')
|
|
571
|
+
const tx = getTransactionDecoder().decode(Buffer.from(result['signed_transaction'], 'base64'))
|
|
572
|
+
const signature = tx.signatures[address(account)]
|
|
573
|
+
if (!signature) throw new SigningError('Horcrux omitted the Solana signature.')
|
|
574
|
+
const signed = {
|
|
575
|
+
...prepared,
|
|
576
|
+
hash: Base58.fromBytes(signature),
|
|
577
|
+
transaction: result['signed_transaction'],
|
|
578
|
+
}
|
|
579
|
+
if (!readSigned(signed)) throw new SigningError('Horcrux changed the Solana transaction.')
|
|
580
|
+
return signed
|
|
581
|
+
},
|
|
582
|
+
async status({ chain, recipient, signed, token }) {
|
|
583
|
+
if (
|
|
584
|
+
!readSigned(signed) ||
|
|
585
|
+
!(await accountsMatch(signed)) ||
|
|
586
|
+
!matchesTerms(signed, {
|
|
587
|
+
account,
|
|
588
|
+
amount: BigInt(signed.amount),
|
|
589
|
+
chainId: chain.id,
|
|
590
|
+
recipient,
|
|
591
|
+
token,
|
|
592
|
+
})
|
|
593
|
+
)
|
|
594
|
+
return 'reverted'
|
|
595
|
+
const result = await rpc(chain, 'getSignatureStatuses', [
|
|
596
|
+
[signed.hash],
|
|
597
|
+
{ searchTransactionHistory: true },
|
|
598
|
+
])
|
|
599
|
+
if (!isObject(result) || !Array.isArray(result['value']))
|
|
600
|
+
throw new UpstreamError('Solana signature status is unavailable.')
|
|
601
|
+
const receipt = result['value'][0]
|
|
602
|
+
if (!receipt) return expiredStatus(chain, signed)
|
|
603
|
+
if (!isObject(receipt)) throw new UpstreamError('Solana signature status is invalid.')
|
|
604
|
+
if (receipt['confirmationStatus'] !== 'finalized') return 'pending'
|
|
605
|
+
return receipt['err'] ? 'reverted' : 'success'
|
|
606
|
+
},
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
export declare namespace create {
|
|
611
|
+
/** Horcrux connection and Solana RPC dependencies. */
|
|
612
|
+
type Options = {
|
|
613
|
+
account: string
|
|
614
|
+
fetch: typeof globalThis.fetch
|
|
615
|
+
horcrux: {
|
|
616
|
+
auth: { type: 'none' } | { clientId: string; clientSecret: string; type: 'cloudflare-access' }
|
|
617
|
+
url: string
|
|
618
|
+
}
|
|
619
|
+
policy: { maxAmount: string }
|
|
620
|
+
walletId: string
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
/** Creation-time inventory request. */
|
|
624
|
+
type CheckOptions = {
|
|
625
|
+
amount: bigint
|
|
626
|
+
chain: Chain.Chain
|
|
627
|
+
recipient: string
|
|
628
|
+
reservations: { nativeAmount: bigint; tokenAmount: bigint }
|
|
629
|
+
token: string
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
/** Finalized receipt query and expected delivery. */
|
|
633
|
+
type StatusOptions = { chain: Chain.Chain; recipient: string; signed: Signed; token: string }
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
/** Checks one finalized block against the signed transaction and the preceding block. */
|
|
637
|
+
export function inspectFinalizedBlock(
|
|
638
|
+
options: inspectFinalizedBlock.Options,
|
|
639
|
+
):
|
|
640
|
+
| { type: 'ambiguous' }
|
|
641
|
+
| { blockhash: string; blockHeight: number; type: 'absent' | 'expired' | 'found' } {
|
|
642
|
+
const block = options.block
|
|
643
|
+
if (
|
|
644
|
+
!isObject(block) ||
|
|
645
|
+
typeof block['blockhash'] !== 'string' ||
|
|
646
|
+
typeof block['previousBlockhash'] !== 'string' ||
|
|
647
|
+
typeof block['parentSlot'] !== 'number' ||
|
|
648
|
+
!Number.isSafeInteger(block['parentSlot']) ||
|
|
649
|
+
typeof block['blockHeight'] !== 'number' ||
|
|
650
|
+
!Number.isSafeInteger(block['blockHeight']) ||
|
|
651
|
+
!Array.isArray(block['signatures']) ||
|
|
652
|
+
!block['signatures'].every((signature) => typeof signature === 'string') ||
|
|
653
|
+
(options.previousSlot === undefined && options.slot !== options.originSlot) ||
|
|
654
|
+
(options.previousSlot !== undefined &&
|
|
655
|
+
(block['parentSlot'] !== options.previousSlot ||
|
|
656
|
+
block['previousBlockhash'] !== options.previousBlockhash ||
|
|
657
|
+
options.previousHeight === undefined ||
|
|
658
|
+
block['blockHeight'] !== options.previousHeight + 1))
|
|
659
|
+
)
|
|
660
|
+
return { type: 'ambiguous' }
|
|
661
|
+
const blockHeight = block['blockHeight']
|
|
662
|
+
const type = (() => {
|
|
663
|
+
if (block['signatures'].includes(options.signature)) return 'found' as const
|
|
664
|
+
if (blockHeight > options.lastValidBlockHeight) return 'expired' as const
|
|
665
|
+
return 'absent' as const
|
|
666
|
+
})()
|
|
667
|
+
return {
|
|
668
|
+
blockhash: block['blockhash'],
|
|
669
|
+
blockHeight,
|
|
670
|
+
type,
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
export declare namespace inspectFinalizedBlock {
|
|
675
|
+
/** Finalized block and its expected place in a continuous chain. */
|
|
676
|
+
type Options = {
|
|
677
|
+
block: unknown
|
|
678
|
+
lastValidBlockHeight: number
|
|
679
|
+
originSlot: number
|
|
680
|
+
previousBlockhash: string | undefined
|
|
681
|
+
previousHeight: number | undefined
|
|
682
|
+
previousSlot: number | undefined
|
|
683
|
+
signature: string
|
|
684
|
+
slot: number
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
function assertChain(chain: Chain.Chain) {
|
|
689
|
+
if (chain.id !== mainnet || chain.kind !== 'solana' || chain.rpcUrls.length === 0)
|
|
690
|
+
throw new ConfigurationError('Unsupported Solana subsidy chain.')
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
function isObject(value: unknown): value is Record<string, unknown> {
|
|
694
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
function unsignedTransaction(options: unsignedTransaction.Options) {
|
|
698
|
+
const message = appendTransactionMessageInstruction(
|
|
699
|
+
getTransferCheckedInstruction({
|
|
700
|
+
amount: options.amount,
|
|
701
|
+
authority: options.account,
|
|
702
|
+
decimals: 6,
|
|
703
|
+
destination: options.destination,
|
|
704
|
+
mint: address(usdcMint),
|
|
705
|
+
source: options.source,
|
|
706
|
+
}),
|
|
707
|
+
setTransactionMessageLifetimeUsingBlockhash(
|
|
708
|
+
{ blockhash: options.blockhash, lastValidBlockHeight: 0n },
|
|
709
|
+
setTransactionMessageFeePayer(
|
|
710
|
+
options.account,
|
|
711
|
+
createTransactionMessage({ version: 'legacy' }),
|
|
712
|
+
),
|
|
713
|
+
),
|
|
714
|
+
)
|
|
715
|
+
return compileTransaction(message)
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
declare namespace unsignedTransaction {
|
|
719
|
+
type Options = {
|
|
720
|
+
account: ReturnType<typeof address>
|
|
721
|
+
amount: bigint
|
|
722
|
+
blockhash: ReturnType<typeof blockhash>
|
|
723
|
+
destination: ReturnType<typeof address>
|
|
724
|
+
source: ReturnType<typeof address>
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
/** Returns whether replaying the same signed transaction cannot succeed. */
|
|
729
|
+
export function isPermanentBroadcastError(cause: unknown): boolean {
|
|
730
|
+
if (cause instanceof BroadcastError || cause instanceof ConfigurationError) return true
|
|
731
|
+
if (!(cause instanceof Error)) return false
|
|
732
|
+
return /block height exceeded|transaction expired|custom program error|invalid account data|signature verification failed/i.test(
|
|
733
|
+
cause.message,
|
|
734
|
+
)
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
/** The subsidy wallet lacks USDC or SOL inventory. */
|
|
738
|
+
export class BalanceUnavailableError extends Error {
|
|
739
|
+
override name = 'Routes.SolanaTransferSubsidy.BalanceUnavailableError'
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
/** Solana subsidy configuration or persisted terms are invalid. */
|
|
743
|
+
export class ConfigurationError extends Error {
|
|
744
|
+
override name = 'Routes.SolanaTransferSubsidy.ConfigurationError'
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
/** Horcrux failed to return the expected Solana signature. */
|
|
748
|
+
export class SigningError extends Error {
|
|
749
|
+
override name = 'Routes.SolanaTransferSubsidy.SigningError'
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
/** Solana rejected a signed subsidy transaction. */
|
|
753
|
+
export class BroadcastError extends Error {
|
|
754
|
+
override name = 'Routes.SolanaTransferSubsidy.BroadcastError'
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
/** Solana RPC could not provide reliable inventory or fee data. */
|
|
758
|
+
export class UpstreamError extends Error {
|
|
759
|
+
override name = 'Routes.SolanaTransferSubsidy.UpstreamError'
|
|
760
|
+
}
|