tapimo 0.12.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/App.d.ts +11333 -9563
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js +39 -3
- package/dist/App.js.map +1 -1
- package/dist/Scope.d.ts +2 -0
- package/dist/Scope.d.ts.map +1 -1
- package/dist/Scope.js +17 -0
- package/dist/Scope.js.map +1 -1
- package/dist/Webhooks.js +2 -2
- package/dist/Webhooks.js.map +1 -1
- package/dist/admin/App.d.ts +1064 -924
- package/dist/admin/App.d.ts.map +1 -1
- package/dist/admin/apps/api-keys.d.ts +80 -0
- package/dist/admin/apps/api-keys.d.ts.map +1 -1
- package/dist/admin/apps/api-keys.js +54 -0
- package/dist/admin/apps/api-keys.js.map +1 -1
- package/dist/admin/apps/earn-vaults.d.ts +63 -15
- package/dist/admin/apps/earn-vaults.d.ts.map +1 -1
- package/dist/admin/apps/earn-vaults.js +2 -1
- package/dist/admin/apps/earn-vaults.js.map +1 -1
- package/dist/admin/apps/organizations.d.ts +92 -3
- package/dist/admin/apps/organizations.d.ts.map +1 -1
- package/dist/admin/apps/organizations.js +69 -7
- package/dist/admin/apps/organizations.js.map +1 -1
- package/dist/admin/apps/verified-tokens.d.ts +7 -7
- package/dist/admin/ui.generated.d.ts +1 -1
- package/dist/admin/ui.generated.d.ts.map +1 -1
- package/dist/admin/ui.generated.js +151 -151
- package/dist/admin/ui.generated.js.map +1 -1
- package/dist/apps/Zones.d.ts +28 -28
- package/dist/apps/Zones.js +7 -7
- package/dist/apps/data/App.d.ts +2909 -2523
- package/dist/apps/data/App.d.ts.map +1 -1
- package/dist/apps/data/App.js +26 -21
- package/dist/apps/data/App.js.map +1 -1
- package/dist/apps/data/ZoneSelection.d.ts +8 -8
- package/dist/apps/data/ZoneSelection.d.ts.map +1 -1
- package/dist/apps/data/ZoneSelection.js +1 -1
- package/dist/apps/data/ZoneSelection.js.map +1 -1
- package/dist/apps/data/routes/activities.d.ts +588 -584
- package/dist/apps/data/routes/activities.d.ts.map +1 -1
- package/dist/apps/data/routes/activities.js +1561 -1239
- package/dist/apps/data/routes/activities.js.map +1 -1
- package/dist/apps/data/routes/addresses.d.ts +22 -22
- package/dist/apps/data/routes/balances.d.ts +26 -26
- package/dist/apps/data/routes/balances.d.ts.map +1 -1
- package/dist/apps/data/routes/balances.js +43 -16
- package/dist/apps/data/routes/balances.js.map +1 -1
- package/dist/apps/data/routes/blocks.d.ts +44 -44
- package/dist/apps/data/routes/blocks.d.ts.map +1 -1
- package/dist/apps/data/routes/blocks.js +21 -11
- package/dist/apps/data/routes/blocks.js.map +1 -1
- package/dist/apps/data/routes/coingecko.d.ts +3 -3
- package/dist/apps/data/routes/earn.d.ts +201 -25
- package/dist/apps/data/routes/earn.d.ts.map +1 -1
- package/dist/apps/data/routes/earn.js +434 -75
- package/dist/apps/data/routes/earn.js.map +1 -1
- package/dist/apps/data/routes/exchanges.d.ts +160 -145
- package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
- package/dist/apps/data/routes/exchanges.js +180 -114
- package/dist/apps/data/routes/exchanges.js.map +1 -1
- package/dist/apps/data/routes/fee-amm.d.ts +2 -2
- package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
- package/dist/apps/data/routes/fee-amm.js +18 -19
- package/dist/apps/data/routes/fee-amm.js.map +1 -1
- package/dist/apps/data/routes/receipts.d.ts +155 -55
- package/dist/apps/data/routes/receipts.d.ts.map +1 -1
- package/dist/apps/data/routes/receipts.js +28 -10
- package/dist/apps/data/routes/receipts.js.map +1 -1
- package/dist/apps/data/routes/tokenlist.d.ts +13 -13
- package/dist/apps/data/routes/tokens.d.ts +5 -5
- package/dist/apps/data/routes/tokens.d.ts.map +1 -1
- package/dist/apps/data/routes/tokens.js +51 -20
- package/dist/apps/data/routes/tokens.js.map +1 -1
- package/dist/apps/data/routes/transactions.d.ts +7 -2
- package/dist/apps/data/routes/transactions.d.ts.map +1 -1
- package/dist/apps/data/routes/transactions.js +37 -17
- package/dist/apps/data/routes/transactions.js.map +1 -1
- package/dist/apps/data/routes/transfers.d.ts +13 -13
- package/dist/apps/data/routes/transfers.d.ts.map +1 -1
- package/dist/apps/data/routes/transfers.js +18 -12
- package/dist/apps/data/routes/transfers.js.map +1 -1
- package/dist/apps/data/routes/valuation.d.ts +31 -31
- package/dist/apps/data/routes/valuation.d.ts.map +1 -1
- package/dist/apps/data/routes/valuation.js +12 -7
- package/dist/apps/data/routes/valuation.js.map +1 -1
- package/dist/apps/data/routes/verified-tokens.d.ts +8 -8
- package/dist/apps/data/routes/webhooks.d.ts +816 -113
- package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
- package/dist/apps/data/routes/webhooks.js +47 -5
- package/dist/apps/data/routes/webhooks.js.map +1 -1
- package/dist/apps/data/routes/zones.d.ts +14 -14
- package/dist/apps/data/routes/zones.js +1 -1
- package/dist/apps/funding/App.d.ts +466 -44
- package/dist/apps/funding/App.d.ts.map +1 -1
- package/dist/apps/funding/App.js +1 -1
- package/dist/apps/funding/App.js.map +1 -1
- package/dist/apps/funding/routes/deposit-addresses.d.ts +17 -17
- package/dist/apps/funding/routes/deposit-addresses.d.ts.map +1 -1
- package/dist/apps/funding/routes/deposit-addresses.js +17 -12
- package/dist/apps/funding/routes/deposit-addresses.js.map +1 -1
- package/dist/apps/funding/routes/transfers.d.ts +650 -57
- package/dist/apps/funding/routes/transfers.d.ts.map +1 -1
- package/dist/apps/funding/routes/transfers.js +238 -24
- package/dist/apps/funding/routes/transfers.js.map +1 -1
- package/dist/apps/management/App.d.ts +5120 -4152
- package/dist/apps/management/App.d.ts.map +1 -1
- package/dist/apps/management/Billing.d.ts +1 -1
- package/dist/apps/management/Billing.d.ts.map +1 -1
- package/dist/apps/management/Billing.js +17 -1
- package/dist/apps/management/Billing.js.map +1 -1
- package/dist/apps/management/routes/api-keys.d.ts +632 -81
- package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
- package/dist/apps/management/routes/api-keys.js +236 -4
- package/dist/apps/management/routes/api-keys.js.map +1 -1
- package/dist/apps/management/routes/billing.d.ts +76 -76
- package/dist/apps/management/routes/faucet.d.ts +6 -6
- package/dist/apps/management/routes/invitations.d.ts +24 -24
- package/dist/apps/management/routes/invite-links.d.ts +4 -4
- package/dist/apps/management/routes/members.d.ts +16 -16
- package/dist/apps/management/routes/orgs.d.ts +20 -20
- package/dist/apps/management/routes/projects.d.ts +4 -4
- package/dist/apps/management/routes/usage.d.ts +8 -8
- package/dist/apps/management/routes/verified-token-requests.d.ts +17 -17
- package/dist/apps/management/routes/webhooks.d.ts +675 -25
- package/dist/apps/management/routes/webhooks.d.ts.map +1 -1
- package/dist/apps/management/routes/webhooks.js +21 -21
- package/dist/apps/management/routes/webhooks.js.map +1 -1
- package/dist/apps/relay/App.d.ts.map +1 -1
- package/dist/apps/relay/App.js +115 -23
- package/dist/apps/relay/App.js.map +1 -1
- package/dist/apps/relay/Sponsorships.d.ts.map +1 -1
- package/dist/apps/relay/Sponsorships.js +27 -1
- package/dist/apps/relay/Sponsorships.js.map +1 -1
- package/dist/db/Db.d.ts.map +1 -1
- package/dist/db/Db.js +34 -1
- package/dist/db/Db.js.map +1 -1
- package/dist/db/Schema.d.ts +11 -5
- package/dist/db/Schema.d.ts.map +1 -1
- package/dist/db/Schema.js +21 -3
- package/dist/db/Schema.js.map +1 -1
- package/dist/db/tables/fundingCatalog.d.ts +4 -2
- package/dist/db/tables/fundingCatalog.d.ts.map +1 -1
- package/dist/db/tables/fundingCatalog.js +5 -1
- package/dist/db/tables/fundingCatalog.js.map +1 -1
- package/dist/db/tables/fundingTransferTransactions.d.ts +38 -0
- package/dist/db/tables/fundingTransferTransactions.d.ts.map +1 -1
- package/dist/db/tables/fundingTransferTransactions.js +44 -3
- package/dist/db/tables/fundingTransferTransactions.js.map +1 -1
- package/dist/db/tables/fundingTransfers.d.ts +17 -0
- package/dist/db/tables/fundingTransfers.d.ts.map +1 -1
- package/dist/db/tables/fundingTransfers.js +21 -0
- package/dist/db/tables/fundingTransfers.js.map +1 -1
- package/dist/db/tables/organizations.d.ts +24 -0
- package/dist/db/tables/organizations.d.ts.map +1 -1
- package/dist/db/tables/organizations.js +27 -0
- package/dist/db/tables/organizations.js.map +1 -1
- package/dist/db/tables/projects.d.ts +25 -1
- package/dist/db/tables/projects.d.ts.map +1 -1
- package/dist/db/tables/projects.js +26 -0
- package/dist/db/tables/projects.js.map +1 -1
- package/dist/db/tables/sponsoredTransactions.d.ts +44 -0
- package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
- package/dist/db/tables/sponsoredTransactions.js +146 -13
- package/dist/db/tables/sponsoredTransactions.js.map +1 -1
- package/dist/db/tables/webhookSubscriptions.d.ts +10 -6
- package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
- package/dist/db/tables/webhookSubscriptions.js +9 -6
- package/dist/db/tables/webhookSubscriptions.js.map +1 -1
- package/dist/handlers/internal/utils.d.ts.map +1 -1
- package/dist/handlers/internal/utils.js +9 -0
- package/dist/handlers/internal/utils.js.map +1 -1
- package/dist/internal/Auth.d.ts +3 -1
- package/dist/internal/Auth.d.ts.map +1 -1
- package/dist/internal/Auth.js +6 -3
- package/dist/internal/Auth.js.map +1 -1
- package/dist/internal/EarnVaults.d.ts +3 -3
- package/dist/internal/EarnVaults.js +5 -5
- package/dist/internal/EarnVaults.js.map +1 -1
- package/dist/internal/Fetch.d.ts +23 -0
- package/dist/internal/Fetch.d.ts.map +1 -0
- package/dist/internal/Fetch.js +26 -0
- package/dist/internal/Fetch.js.map +1 -0
- package/dist/internal/Log.d.ts +4 -2
- package/dist/internal/Log.d.ts.map +1 -1
- package/dist/internal/Log.js +16 -3
- package/dist/internal/Log.js.map +1 -1
- package/dist/internal/OpenApi.d.ts +5 -3
- package/dist/internal/OpenApi.d.ts.map +1 -1
- package/dist/internal/OpenApi.js +13 -3
- package/dist/internal/OpenApi.js.map +1 -1
- package/dist/internal/Response.d.ts +1 -1
- package/dist/internal/Response.d.ts.map +1 -1
- package/dist/internal/Schema.d.ts +6 -3
- package/dist/internal/Schema.d.ts.map +1 -1
- package/dist/internal/Schema.js +8 -2
- package/dist/internal/Schema.js.map +1 -1
- package/dist/internal/Store.d.ts +16 -3
- package/dist/internal/Store.d.ts.map +1 -1
- package/dist/internal/Store.js +82 -16
- package/dist/internal/Store.js.map +1 -1
- package/dist/internal/Tidx.d.ts.map +1 -1
- package/dist/internal/Tidx.js +7 -2
- package/dist/internal/Tidx.js.map +1 -1
- package/dist/internal/Timeout.d.ts +36 -0
- package/dist/internal/Timeout.d.ts.map +1 -0
- package/dist/internal/Timeout.js +37 -0
- package/dist/internal/Timeout.js.map +1 -0
- package/dist/internal/Timing.d.ts +9 -0
- package/dist/internal/Timing.d.ts.map +1 -1
- package/dist/internal/Timing.js +7 -0
- package/dist/internal/Timing.js.map +1 -1
- package/dist/internal/Viem.d.ts +16 -1
- package/dist/internal/Viem.d.ts.map +1 -1
- package/dist/internal/Viem.js +12 -2
- package/dist/internal/Viem.js.map +1 -1
- package/dist/internal/WebhookDestination.d.ts.map +1 -1
- package/dist/internal/WebhookDestination.js +3 -0
- package/dist/internal/WebhookDestination.js.map +1 -1
- package/dist/internal/funding/Action.d.ts +9 -0
- package/dist/internal/funding/Action.d.ts.map +1 -1
- package/dist/internal/funding/Action.js +16 -8
- package/dist/internal/funding/Action.js.map +1 -1
- package/dist/internal/funding/Catalog.d.ts +9 -2
- package/dist/internal/funding/Catalog.d.ts.map +1 -1
- package/dist/internal/funding/Catalog.js +19 -8
- package/dist/internal/funding/Catalog.js.map +1 -1
- package/dist/internal/funding/DepositWebhook.d.ts.map +1 -1
- package/dist/internal/funding/DepositWebhook.js +2 -1
- package/dist/internal/funding/DepositWebhook.js.map +1 -1
- package/dist/internal/funding/Evidence.d.ts.map +1 -1
- package/dist/internal/funding/Evidence.js +2 -10
- package/dist/internal/funding/Evidence.js.map +1 -1
- package/dist/internal/funding/Provider.d.ts +108 -13
- package/dist/internal/funding/Provider.d.ts.map +1 -1
- package/dist/internal/funding/Provider.js +34 -8
- package/dist/internal/funding/Provider.js.map +1 -1
- package/dist/internal/funding/SourceObservation.d.ts.map +1 -1
- package/dist/internal/funding/SourceObservation.js +5 -7
- package/dist/internal/funding/SourceObservation.js.map +1 -1
- package/dist/internal/funding/Transfer.d.ts +114 -18
- package/dist/internal/funding/Transfer.d.ts.map +1 -1
- package/dist/internal/funding/Transfer.js +185 -55
- package/dist/internal/funding/Transfer.js.map +1 -1
- package/dist/internal/funding/TransferReconciliation.d.ts +52 -0
- package/dist/internal/funding/TransferReconciliation.d.ts.map +1 -0
- package/dist/internal/funding/TransferReconciliation.js +192 -0
- package/dist/internal/funding/TransferReconciliation.js.map +1 -0
- package/dist/internal/funding/TransferWebhook.d.ts +21 -0
- package/dist/internal/funding/TransferWebhook.d.ts.map +1 -0
- package/dist/internal/funding/TransferWebhook.js +43 -0
- package/dist/internal/funding/TransferWebhook.js.map +1 -0
- package/dist/internal/funding/index.d.ts +1 -0
- package/dist/internal/funding/index.d.ts.map +1 -1
- package/dist/internal/funding/index.js +1 -0
- package/dist/internal/funding/index.js.map +1 -1
- package/dist/internal/funding/providers/relay.d.ts.map +1 -1
- package/dist/internal/funding/providers/relay.js +3 -12
- package/dist/internal/funding/providers/relay.js.map +1 -1
- package/dist/internal/funding/providers/stargate.d.ts +127 -9
- package/dist/internal/funding/providers/stargate.d.ts.map +1 -1
- package/dist/internal/funding/providers/stargate.js +548 -112
- package/dist/internal/funding/providers/stargate.js.map +1 -1
- package/dist/internal/index.d.ts +1 -0
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +1 -0
- package/dist/internal/index.js.map +1 -1
- package/dist/internal/webhookDestinations/slack.d.ts.map +1 -1
- package/dist/internal/webhookDestinations/slack.js +16 -0
- package/dist/internal/webhookDestinations/slack.js.map +1 -1
- package/package.json +2 -2
- package/src/App.test.ts +100 -0
- package/src/App.ts +43 -3
- package/src/Client.test-d.ts +129 -2
- package/src/Scope.test.ts +20 -0
- package/src/Scope.ts +16 -0
- package/src/Webhooks.ts +2 -2
- package/src/admin/apps/api-keys.test.ts +75 -0
- package/src/admin/apps/api-keys.ts +64 -0
- package/src/admin/apps/earn-vaults.test.ts +1 -1
- package/src/admin/apps/earn-vaults.ts +2 -1
- package/src/admin/apps/organizations.test.ts +53 -1
- package/src/admin/apps/organizations.ts +90 -5
- package/src/admin/ui/src/lib/api-keys.ts +19 -0
- package/src/admin/ui/src/lib/organizations.test.ts +112 -1
- package/src/admin/ui/src/lib/organizations.ts +55 -0
- package/src/admin/ui/src/routes/api-keys.tsx +89 -2
- package/src/admin/ui/src/routes/organizations_.$orgId.tsx +116 -0
- package/src/admin/ui.generated.ts +189 -151
- package/src/apps/Zones.test.ts +7 -7
- package/src/apps/Zones.ts +7 -7
- package/src/apps/composition.test.ts +2 -1
- package/src/apps/data/App.test.ts +41 -0
- package/src/apps/data/App.ts +30 -21
- package/src/apps/data/ZoneSelection.test.ts +2 -2
- package/src/apps/data/ZoneSelection.ts +8 -8
- package/src/apps/data/routes/activities.test.ts +1526 -12
- package/src/apps/data/routes/activities.ts +1774 -1356
- package/src/apps/data/routes/balances.ts +133 -97
- package/src/apps/data/routes/blocks.test.ts +533 -0
- package/src/apps/data/routes/blocks.ts +35 -16
- package/src/apps/data/routes/earn.test.ts +373 -16
- package/src/apps/data/routes/earn.ts +548 -79
- package/src/apps/data/routes/earn.zone-access.test.ts +6 -6
- package/src/apps/data/routes/exchanges.test.ts +740 -15
- package/src/apps/data/routes/exchanges.ts +954 -753
- package/src/apps/data/routes/fee-amm.ts +17 -18
- package/src/apps/data/routes/receipts.ts +47 -16
- package/src/apps/data/routes/tokens.test.ts +578 -0
- package/src/apps/data/routes/tokens.ts +283 -225
- package/src/apps/data/routes/transactions.ts +68 -29
- package/src/apps/data/routes/transfers.test.ts +421 -0
- package/src/apps/data/routes/transfers.ts +45 -27
- package/src/apps/data/routes/valuation.ts +94 -78
- package/src/apps/data/routes/webhooks.test.ts +21 -5
- package/src/apps/data/routes/webhooks.ts +63 -8
- package/src/apps/data/routes/zones.test.ts +2 -2
- package/src/apps/data/routes/zones.ts +1 -1
- package/src/apps/funding/App.ts +12 -2
- package/src/apps/funding/routes/deposit-addresses.test.ts +29 -7
- package/src/apps/funding/routes/deposit-addresses.ts +19 -14
- package/src/apps/funding/routes/quotes.test.ts +5 -9
- package/src/apps/funding/routes/transfers.test.ts +901 -23
- package/src/apps/funding/routes/transfers.ts +347 -64
- package/src/apps/management/Billing.ts +18 -5
- package/src/apps/management/routes/api-keys.test.ts +220 -0
- package/src/apps/management/routes/api-keys.ts +280 -3
- package/src/apps/management/routes/webhooks.test.ts +3 -3
- package/src/apps/management/routes/webhooks.ts +24 -25
- package/src/apps/relay/App.test.ts +212 -1
- package/src/apps/relay/App.ts +158 -29
- package/src/apps/relay/Sponsorships.ts +24 -1
- package/src/db/Db.ts +48 -1
- package/src/db/Schema.ts +22 -4
- package/src/db/tables/earnVaults.test.ts +9 -9
- package/src/db/tables/fundingCatalog.test.ts +16 -2
- package/src/db/tables/fundingCatalog.ts +9 -3
- package/src/db/tables/fundingTransferTransactions.test.ts +43 -0
- package/src/db/tables/fundingTransferTransactions.ts +79 -3
- package/src/db/tables/fundingTransfers.test.ts +26 -0
- package/src/db/tables/fundingTransfers.ts +36 -0
- package/src/db/tables/organizations.test.ts +41 -0
- package/src/db/tables/organizations.ts +49 -0
- package/src/db/tables/projects.test.ts +55 -0
- package/src/db/tables/projects.ts +46 -1
- package/src/db/tables/sponsoredTransactions.test.ts +338 -0
- package/src/db/tables/sponsoredTransactions.ts +197 -13
- package/src/db/tables/webhookSubscriptions.ts +18 -11
- package/src/handlers/internal/utils.test.ts +53 -0
- package/src/handlers/internal/utils.ts +15 -0
- package/src/internal/Auth.ts +12 -4
- package/src/internal/EarnVaults.capabilities.test.ts +2 -2
- package/src/internal/EarnVaults.test.ts +1 -1
- package/src/internal/EarnVaults.ts +5 -5
- package/src/internal/Fetch.test.ts +46 -0
- package/src/internal/Fetch.ts +56 -0
- package/src/internal/Log.test-d.ts +2 -0
- package/src/internal/Log.test.ts +21 -0
- package/src/internal/Log.ts +22 -5
- package/src/internal/OpenApi.ts +14 -4
- package/src/internal/Response.ts +1 -1
- package/src/internal/Schema.test.ts +2 -0
- package/src/internal/Schema.ts +12 -2
- package/src/internal/Store.test.ts +178 -0
- package/src/internal/Store.ts +104 -18
- package/src/internal/Tidx.test.ts +2 -1
- package/src/internal/Tidx.ts +7 -2
- package/src/internal/Timeout.test.ts +35 -0
- package/src/internal/Timeout.ts +73 -0
- package/src/internal/Timing.ts +16 -0
- package/src/internal/Viem.ts +39 -3
- package/src/internal/WebhookDestination.ts +3 -0
- package/src/internal/Webhooks.test.ts +45 -0
- package/src/internal/funding/Action.test.ts +41 -1
- package/src/internal/funding/Action.ts +69 -41
- package/src/internal/funding/Catalog.test.ts +34 -0
- package/src/internal/funding/Catalog.ts +28 -11
- package/src/internal/funding/DepositWebhook.ts +2 -1
- package/src/internal/funding/Evidence.ts +2 -13
- package/src/internal/funding/Provider.test.ts +73 -0
- package/src/internal/funding/Provider.ts +125 -28
- package/src/internal/funding/SourceObservation.ts +5 -9
- package/src/internal/funding/Transfer.test.ts +155 -0
- package/src/internal/funding/Transfer.ts +387 -147
- package/src/internal/funding/TransferReconciliation.test.ts +147 -0
- package/src/internal/funding/TransferReconciliation.ts +264 -0
- package/src/internal/funding/TransferWebhook.test.ts +128 -0
- package/src/internal/funding/TransferWebhook.ts +67 -0
- package/src/internal/funding/index.test.ts +1 -0
- package/src/internal/funding/index.ts +1 -0
- package/src/internal/funding/providers/index.test.ts +4 -167
- package/src/internal/funding/providers/relay.test.ts +2 -2
- package/src/internal/funding/providers/relay.ts +3 -15
- package/src/internal/funding/providers/stargate.test.ts +328 -0
- package/src/internal/funding/providers/stargate.ts +807 -135
- package/src/internal/index.test.ts +1 -0
- package/src/internal/index.ts +1 -0
- package/src/internal/webhookDestinations/slack.ts +15 -0
|
@@ -2,11 +2,15 @@ import * as z from 'zod/mini'
|
|
|
2
2
|
|
|
3
3
|
import type * as Db from '../../db/Db.js'
|
|
4
4
|
import * as FundingTransferEvents from '../../db/tables/fundingTransferEvents.js'
|
|
5
|
+
import * as FundingTransferTransactions from '../../db/tables/fundingTransferTransactions.js'
|
|
5
6
|
import * as FundingTransfers from '../../db/tables/fundingTransfers.js'
|
|
6
7
|
import * as Id from '../Id.js'
|
|
8
|
+
import * as OpenApi from '../OpenApi.js'
|
|
7
9
|
import * as Schema from '../Schema.js'
|
|
10
|
+
import type * as Webhooks from '../Webhooks.js'
|
|
8
11
|
import * as Action from './Action.js'
|
|
9
12
|
import * as Provider from './Provider.js'
|
|
13
|
+
import * as TransferWebhook from './TransferWebhook.js'
|
|
10
14
|
|
|
11
15
|
/** Public funding transfer statuses, in the order documented by the API. */
|
|
12
16
|
export const statuses = [
|
|
@@ -60,7 +64,7 @@ const transitions: Record<Status, readonly Status[]> = {
|
|
|
60
64
|
'awaiting-source': ['action-required', 'expired', 'processing'],
|
|
61
65
|
completed: [],
|
|
62
66
|
expired: [],
|
|
63
|
-
processing: ['action-required', 'completed', 'refunding'],
|
|
67
|
+
processing: ['action-required', 'awaiting-source', 'completed', 'refunding'],
|
|
64
68
|
refunded: [],
|
|
65
69
|
refunding: ['action-required', 'refunded'],
|
|
66
70
|
}
|
|
@@ -91,22 +95,25 @@ export namespace schema {
|
|
|
91
95
|
)
|
|
92
96
|
|
|
93
97
|
/** Customer-safe explanation of a status that needs context. */
|
|
94
|
-
export const StatusReason =
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
export const StatusReason = OpenApi.component(
|
|
99
|
+
z
|
|
100
|
+
.object({
|
|
101
|
+
code: z
|
|
102
|
+
.enum(statusReasonCodes)
|
|
103
|
+
.check(
|
|
104
|
+
z.describe('Stable machine-readable reason code.'),
|
|
105
|
+
z.meta({ examples: ['destination_amount_below_minimum'] }),
|
|
106
|
+
),
|
|
107
|
+
message: z.string().check(
|
|
108
|
+
z.describe('Human-readable explanation of the reason.'),
|
|
109
|
+
z.meta({
|
|
110
|
+
examples: ['The verified destination amount did not satisfy the quoted minimum.'],
|
|
111
|
+
}),
|
|
101
112
|
),
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}),
|
|
107
|
-
),
|
|
108
|
-
})
|
|
109
|
-
.check(z.describe('Why the transfer is in its current status, when context is needed.'))
|
|
113
|
+
})
|
|
114
|
+
.check(z.describe('Why the transfer is in its current status, when context is needed.')),
|
|
115
|
+
'FundingTransferStatusReason',
|
|
116
|
+
)
|
|
110
117
|
|
|
111
118
|
/** Funding method selected at creation. */
|
|
112
119
|
export const Method = z
|
|
@@ -122,39 +129,45 @@ export namespace schema {
|
|
|
122
129
|
)
|
|
123
130
|
|
|
124
131
|
/** One fee applied to the transfer. */
|
|
125
|
-
export const Fee =
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
132
|
+
export const Fee = OpenApi.component(
|
|
133
|
+
z
|
|
134
|
+
.object({
|
|
135
|
+
amount: Schema.TokenAmount,
|
|
136
|
+
side: z
|
|
137
|
+
.enum(['destination', 'source'])
|
|
138
|
+
.check(
|
|
139
|
+
z.describe('Which side of the transfer the fee is taken from.'),
|
|
140
|
+
z.meta({ examples: ['destination'] }),
|
|
141
|
+
),
|
|
142
|
+
token: Provider.schema.TokenRef,
|
|
143
|
+
type: z
|
|
144
|
+
.enum(['provider'])
|
|
145
|
+
.check(z.describe('What the fee pays for.'), z.meta({ examples: ['provider'] })),
|
|
146
|
+
})
|
|
147
|
+
.check(z.describe('One fee applied to the transfer.')),
|
|
148
|
+
'FundingTransferFee',
|
|
149
|
+
)
|
|
140
150
|
|
|
141
151
|
/** Freshness and validity window of the selected quote. */
|
|
142
|
-
export const Quote =
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
.
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
.
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
152
|
+
export const Quote = OpenApi.component(
|
|
153
|
+
z
|
|
154
|
+
.object({
|
|
155
|
+
expiresAt: z.iso
|
|
156
|
+
.datetime()
|
|
157
|
+
.check(
|
|
158
|
+
z.describe('When the quoted terms stop being executable (ISO 8601).'),
|
|
159
|
+
z.meta({ examples: ['2026-07-30T04:01:00.000Z'] }),
|
|
160
|
+
),
|
|
161
|
+
sampledAt: z.iso
|
|
162
|
+
.datetime()
|
|
163
|
+
.check(
|
|
164
|
+
z.describe('When the provider produced the quote (ISO 8601).'),
|
|
165
|
+
z.meta({ examples: ['2026-07-30T04:00:00.000Z'] }),
|
|
166
|
+
),
|
|
167
|
+
})
|
|
168
|
+
.check(z.describe('Freshness and validity window of the selected quote.')),
|
|
169
|
+
'FundingTransferQuote',
|
|
170
|
+
)
|
|
158
171
|
|
|
159
172
|
const hashesCheck = (description: string) => [
|
|
160
173
|
z.describe(description),
|
|
@@ -219,8 +232,8 @@ export namespace schema {
|
|
|
219
232
|
.check(z.describe('Quote terms and reconciled public fields of a funding transfer.'))
|
|
220
233
|
|
|
221
234
|
const fundingTransferFields = {
|
|
222
|
-
createdAt: z
|
|
223
|
-
.
|
|
235
|
+
createdAt: z.iso
|
|
236
|
+
.datetime()
|
|
224
237
|
.check(
|
|
225
238
|
z.describe('When the transfer was created (ISO 8601).'),
|
|
226
239
|
z.meta({ examples: ['2026-07-30T04:00:00.000Z'] }),
|
|
@@ -253,8 +266,8 @@ export namespace schema {
|
|
|
253
266
|
sourceTransactionHashes: snapshotFields.sourceTransactionHashes,
|
|
254
267
|
status: Status,
|
|
255
268
|
statusReason: z.optional(StatusReason),
|
|
256
|
-
updatedAt: z
|
|
257
|
-
.
|
|
269
|
+
updatedAt: z.iso
|
|
270
|
+
.datetime()
|
|
258
271
|
.check(
|
|
259
272
|
z.describe('When the transfer last materially changed (ISO 8601).'),
|
|
260
273
|
z.meta({ examples: ['2026-07-30T04:00:20.000Z'] }),
|
|
@@ -270,73 +283,86 @@ export namespace schema {
|
|
|
270
283
|
}
|
|
271
284
|
|
|
272
285
|
/** A funding transfer as returned by reads. Reads never include `action`. */
|
|
273
|
-
export const FundingTransfer =
|
|
274
|
-
.object(fundingTransferFields)
|
|
275
|
-
|
|
286
|
+
export const FundingTransfer = OpenApi.component(
|
|
287
|
+
z.object(fundingTransferFields).check(z.describe('One durable funding transfer.')),
|
|
288
|
+
'FundingTransfer',
|
|
289
|
+
)
|
|
276
290
|
|
|
277
291
|
/** A created funding transfer: the read shape plus the executable action. */
|
|
278
|
-
export const CreatedFundingTransfer =
|
|
279
|
-
|
|
280
|
-
|
|
292
|
+
export const CreatedFundingTransfer = OpenApi.component(
|
|
293
|
+
z
|
|
294
|
+
.object({ action: Action.schema.Action, ...fundingTransferFields })
|
|
295
|
+
.check(z.describe('The created funding transfer, including its one-time executable action.')),
|
|
296
|
+
'CreatedFundingTransfer',
|
|
297
|
+
)
|
|
281
298
|
|
|
282
299
|
/** Request body accepted by funding transfer creation. */
|
|
283
|
-
export const CreateRequest =
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
z.regex(/^[1-9]\d*$/),
|
|
289
|
-
z.describe('Amount in base units of the token the mode fixes.'),
|
|
290
|
-
z.meta({ examples: ['1000000'] }),
|
|
291
|
-
),
|
|
292
|
-
destinationToken: z
|
|
293
|
-
.string()
|
|
294
|
-
.check(
|
|
295
|
-
z.minLength(1),
|
|
296
|
-
z.describe('Tempo destination token symbol, contract address, or token key.'),
|
|
297
|
-
z.meta({ examples: ['pathusd'] }),
|
|
298
|
-
),
|
|
299
|
-
mode: Mode,
|
|
300
|
-
recipient: z
|
|
301
|
-
.string()
|
|
302
|
-
.check(
|
|
303
|
-
z.regex(/^0x[0-9a-fA-F]{40}$/),
|
|
304
|
-
z.describe('Final beneficiary of the transfer.'),
|
|
305
|
-
z.meta({ examples: [`0x${'11'.repeat(20)}`] }),
|
|
306
|
-
),
|
|
307
|
-
sender: z
|
|
308
|
-
.string()
|
|
309
|
-
.check(
|
|
310
|
-
z.regex(/^0x[0-9a-fA-F]{40}$/),
|
|
311
|
-
z.describe('Source-chain account that signs the funding action.'),
|
|
312
|
-
z.meta({ examples: [`0x${'22'.repeat(20)}`] }),
|
|
313
|
-
),
|
|
314
|
-
slippageBps: z.optional(
|
|
315
|
-
z
|
|
316
|
-
.number()
|
|
300
|
+
export const CreateRequest = OpenApi.component(
|
|
301
|
+
z
|
|
302
|
+
.strictObject({
|
|
303
|
+
amount: z
|
|
304
|
+
.string()
|
|
317
305
|
.check(
|
|
318
|
-
z.
|
|
319
|
-
z.
|
|
320
|
-
z.
|
|
321
|
-
z.describe('Maximum acceptable slippage in basis points.'),
|
|
322
|
-
z.meta({ examples: [50] }),
|
|
306
|
+
z.regex(/^[1-9]\d*$/),
|
|
307
|
+
z.describe('Amount in base units of the token the mode fixes.'),
|
|
308
|
+
z.meta({ examples: ['1000000'] }),
|
|
323
309
|
),
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
310
|
+
destinationToken: z
|
|
311
|
+
.string()
|
|
312
|
+
.check(
|
|
313
|
+
z.minLength(1),
|
|
314
|
+
z.describe('Tempo destination token symbol, contract address, or token key.'),
|
|
315
|
+
z.meta({ examples: ['pathusd'] }),
|
|
316
|
+
),
|
|
317
|
+
mode: Mode,
|
|
318
|
+
provider: z
|
|
319
|
+
.optional(z.string().check(z.minLength(1)))
|
|
320
|
+
.check(
|
|
321
|
+
z.describe('Funding provider ID. Omit to select the best available provider.'),
|
|
322
|
+
z.meta({ examples: ['relay'] }),
|
|
323
|
+
),
|
|
324
|
+
recipient: z
|
|
325
|
+
.string()
|
|
326
|
+
.check(
|
|
327
|
+
z.regex(/^0x[0-9a-fA-F]{40}$/),
|
|
328
|
+
z.describe('Final beneficiary of the transfer.'),
|
|
329
|
+
z.meta({ examples: [`0x${'11'.repeat(20)}`] }),
|
|
330
|
+
),
|
|
331
|
+
sender: z
|
|
332
|
+
.string()
|
|
333
|
+
.check(
|
|
334
|
+
z.regex(/^0x[0-9a-fA-F]{40}$/),
|
|
335
|
+
z.describe('Source-chain account that signs the funding action.'),
|
|
336
|
+
z.meta({ examples: [`0x${'22'.repeat(20)}`] }),
|
|
337
|
+
),
|
|
338
|
+
slippageBps: z.optional(
|
|
339
|
+
z
|
|
340
|
+
.number()
|
|
341
|
+
.check(
|
|
342
|
+
z.int(),
|
|
343
|
+
z.gte(0),
|
|
344
|
+
z.lte(10_000),
|
|
345
|
+
z.describe('Maximum acceptable slippage in basis points.'),
|
|
346
|
+
z.meta({ examples: [50] }),
|
|
347
|
+
),
|
|
337
348
|
),
|
|
338
|
-
|
|
339
|
-
|
|
349
|
+
sourceChain: z
|
|
350
|
+
.string()
|
|
351
|
+
.check(
|
|
352
|
+
z.describe('Source chain CAIP-2 id, slug, or alias.'),
|
|
353
|
+
z.meta({ examples: ['base', 'eip155:8453'] }),
|
|
354
|
+
),
|
|
355
|
+
sourceToken: z
|
|
356
|
+
.string()
|
|
357
|
+
.check(
|
|
358
|
+
z.minLength(1),
|
|
359
|
+
z.describe('Source token symbol, contract address, or token key.'),
|
|
360
|
+
z.meta({ examples: ['usdc'] }),
|
|
361
|
+
),
|
|
362
|
+
})
|
|
363
|
+
.check(z.describe('Funding transfer creation request.')),
|
|
364
|
+
'CreateFundingTransferRequest',
|
|
365
|
+
)
|
|
340
366
|
}
|
|
341
367
|
|
|
342
368
|
/** Stored public snapshot of a funding transfer (see {@link schema.Snapshot}). */
|
|
@@ -360,12 +386,22 @@ export const transactionRoles = ['destination', 'refund', 'source'] as const
|
|
|
360
386
|
/** Role of a verified transaction reference on a transfer. */
|
|
361
387
|
export type TransactionRole = (typeof transactionRoles)[number]
|
|
362
388
|
|
|
389
|
+
/** Bounded private provider state retained for transfer reconciliation. */
|
|
390
|
+
export type ProviderState = Record<string, unknown>
|
|
391
|
+
|
|
392
|
+
type Staged = {
|
|
393
|
+
/** Funding transfer record committed with the webhook obligations. */
|
|
394
|
+
record: FundingTransfers.Record
|
|
395
|
+
/** Webhook queue references committed with the transfer. */
|
|
396
|
+
references: Webhooks.QueueReference[]
|
|
397
|
+
}
|
|
398
|
+
|
|
363
399
|
/**
|
|
364
400
|
* Creates a durable funding transfer: the row plus its version-1 event commit
|
|
365
401
|
* in one transaction, so every stored version has an immutable public record.
|
|
366
402
|
*/
|
|
367
403
|
export async function create(db: Db.Db, input: create.Input): Promise<FundingTransfers.Record> {
|
|
368
|
-
return db.transaction((tx) => createIn(tx, input))
|
|
404
|
+
return db.transaction(async (tx) => (await createIn(tx, input)).record)
|
|
369
405
|
}
|
|
370
406
|
|
|
371
407
|
/**
|
|
@@ -373,7 +409,7 @@ export async function create(db: Db.Db, input: create.Input): Promise<FundingTra
|
|
|
373
409
|
* transaction, for writes that must commit atomically with sibling state
|
|
374
410
|
* (idempotency completion).
|
|
375
411
|
*/
|
|
376
|
-
export async function createIn(tx: Db.Db, input: create.Input): Promise<
|
|
412
|
+
export async function createIn(tx: Db.Db, input: create.Input): Promise<createIn.Result> {
|
|
377
413
|
const now = new Date()
|
|
378
414
|
const snapshot = parseSnapshot(input.snapshot)
|
|
379
415
|
const record: FundingTransfers.Record = {
|
|
@@ -395,14 +431,22 @@ export async function createIn(tx: Db.Db, input: create.Input): Promise<FundingT
|
|
|
395
431
|
version: 1,
|
|
396
432
|
}
|
|
397
433
|
const created = await FundingTransfers.insert(tx, record)
|
|
398
|
-
await FundingTransferEvents.insert(tx, {
|
|
434
|
+
const event = await FundingTransferEvents.insert(tx, {
|
|
399
435
|
createdAt: record.createdAt,
|
|
400
436
|
snapshot: toPublic(created),
|
|
401
437
|
status: created.status,
|
|
402
438
|
transferId: created.id,
|
|
403
439
|
version: created.version,
|
|
404
440
|
})
|
|
405
|
-
|
|
441
|
+
const { references } = await TransferWebhook.stage(tx, {
|
|
442
|
+
changes: [{ event, record: created }],
|
|
443
|
+
})
|
|
444
|
+
return { record: created, references }
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
export declare namespace createIn {
|
|
448
|
+
/** Created transfer and webhook queue references committed with it. */
|
|
449
|
+
type Result = Staged
|
|
406
450
|
}
|
|
407
451
|
|
|
408
452
|
export declare namespace create {
|
|
@@ -419,12 +463,193 @@ export declare namespace create {
|
|
|
419
463
|
/** Attributed project id, when the creating key is project-attributed. */
|
|
420
464
|
projectId?: string | undefined
|
|
421
465
|
/** Private provider correlation retained for reconciliation. */
|
|
422
|
-
providerState?:
|
|
466
|
+
providerState?: ProviderState | undefined
|
|
423
467
|
/** The public snapshot captured from the selected quote. */
|
|
424
468
|
snapshot: Snapshot
|
|
425
469
|
}
|
|
426
470
|
}
|
|
427
471
|
|
|
472
|
+
/** Atomically assigns one verified source transaction and starts reconciliation. */
|
|
473
|
+
export async function registerSourceTransaction(
|
|
474
|
+
db: Db.Db,
|
|
475
|
+
options: registerSourceTransaction.Options,
|
|
476
|
+
): Promise<registerSourceTransaction.Result> {
|
|
477
|
+
return db.transaction(async (tx) => {
|
|
478
|
+
const current = await FundingTransfers.getForUpdate(tx, options.id)
|
|
479
|
+
if (!current) return { type: 'not_found' }
|
|
480
|
+
|
|
481
|
+
const existing = await FundingTransferTransactions.getSource(tx, {
|
|
482
|
+
chainId: options.chainId,
|
|
483
|
+
transactionRef: options.transactionHash,
|
|
484
|
+
})
|
|
485
|
+
if (existing) {
|
|
486
|
+
if (existing.transferId !== current.id) return { current, type: 'conflict' }
|
|
487
|
+
if (current.status !== 'processing' && current.status !== 'completed')
|
|
488
|
+
return { current, type: 'invalid' }
|
|
489
|
+
return { record: current, type: 'replayed' }
|
|
490
|
+
}
|
|
491
|
+
if (current.status !== 'awaiting-source') return { current, type: 'invalid' }
|
|
492
|
+
|
|
493
|
+
const claimed = await FundingTransferTransactions.claimSource(tx, {
|
|
494
|
+
chainId: options.chainId,
|
|
495
|
+
createdAt: new Date().toISOString(),
|
|
496
|
+
role: 'source',
|
|
497
|
+
transactionRef: options.transactionHash,
|
|
498
|
+
transferId: options.id,
|
|
499
|
+
})
|
|
500
|
+
if (claimed.type === 'conflict') return { current, type: 'conflict' }
|
|
501
|
+
if (claimed.type === 'replayed') return { record: current, type: 'replayed' }
|
|
502
|
+
|
|
503
|
+
const result = await transitionIn(tx, {
|
|
504
|
+
current,
|
|
505
|
+
expectedVersion: current.version,
|
|
506
|
+
id: current.id,
|
|
507
|
+
providerState: { ...current.providerState, ...options.providerState },
|
|
508
|
+
snapshot: {
|
|
509
|
+
...current.snapshot,
|
|
510
|
+
sourceTransactionHashes: [claimed.record.transactionRef],
|
|
511
|
+
},
|
|
512
|
+
status: 'processing',
|
|
513
|
+
})
|
|
514
|
+
if (result.type !== 'applied') throw new AtomicTransitionError()
|
|
515
|
+
return { record: result.record, references: result.references, type: 'registered' }
|
|
516
|
+
})
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
export declare namespace registerSourceTransaction {
|
|
520
|
+
/** Verified source evidence and private provider correlation. */
|
|
521
|
+
type Options = {
|
|
522
|
+
/** Source chain CAIP-2 id. */
|
|
523
|
+
chainId: string
|
|
524
|
+
/** Transfer id (`ftr_…`). */
|
|
525
|
+
id: string
|
|
526
|
+
/** Private state added for destination reconciliation. */
|
|
527
|
+
providerState: ProviderState
|
|
528
|
+
/** Verified source transaction hash. */
|
|
529
|
+
transactionHash: string
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
/** Source transaction registration outcome. */
|
|
533
|
+
type Result =
|
|
534
|
+
| { current: FundingTransfers.Record; type: 'conflict' }
|
|
535
|
+
| { current: FundingTransfers.Record; type: 'invalid' }
|
|
536
|
+
| (Staged & { type: 'registered' })
|
|
537
|
+
| { record: FundingTransfers.Record; type: 'replayed' }
|
|
538
|
+
| { type: 'not_found' }
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/** Atomically removes invalidated source evidence and accepts a replacement. */
|
|
542
|
+
export async function reopenSourceTransaction(
|
|
543
|
+
db: Db.Db,
|
|
544
|
+
options: reopenSourceTransaction.Options,
|
|
545
|
+
): Promise<reopenSourceTransaction.Result> {
|
|
546
|
+
return db.transaction(async (tx) => {
|
|
547
|
+
const current = await FundingTransfers.getForUpdate(tx, options.id)
|
|
548
|
+
if (!current) return { type: 'not_found' }
|
|
549
|
+
if (current.status !== 'processing') return { current, type: 'invalid' }
|
|
550
|
+
|
|
551
|
+
const removed = await FundingTransferTransactions.removeSource(tx, {
|
|
552
|
+
chainId: options.chainId,
|
|
553
|
+
transactionHash: options.transactionHash,
|
|
554
|
+
transferId: current.id,
|
|
555
|
+
})
|
|
556
|
+
if (!removed) return { current, type: 'invalid' }
|
|
557
|
+
const { sourceTransactionHashes: _sourceTransactionHashes, ...snapshot } = current.snapshot
|
|
558
|
+
const result = await transitionIn(tx, {
|
|
559
|
+
current,
|
|
560
|
+
expectedVersion: current.version,
|
|
561
|
+
id: current.id,
|
|
562
|
+
providerState: options.providerState,
|
|
563
|
+
snapshot,
|
|
564
|
+
status: 'awaiting-source',
|
|
565
|
+
})
|
|
566
|
+
if (result.type !== 'applied') throw new AtomicTransitionError()
|
|
567
|
+
return { record: result.record, references: result.references, type: 'reopened' }
|
|
568
|
+
})
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
export declare namespace reopenSourceTransaction {
|
|
572
|
+
/** Source evidence to remove after it disappears from the canonical chain. */
|
|
573
|
+
type Options = {
|
|
574
|
+
/** Source chain CAIP-2 id. */
|
|
575
|
+
chainId: string
|
|
576
|
+
/** Transfer id (`ftr_…`). */
|
|
577
|
+
id: string
|
|
578
|
+
/** Private provider state retained while awaiting replacement evidence. */
|
|
579
|
+
providerState: ProviderState
|
|
580
|
+
/** Invalidated source transaction hash. */
|
|
581
|
+
transactionHash: string
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/** Source transaction reopening outcome. */
|
|
585
|
+
type Result =
|
|
586
|
+
| { current: FundingTransfers.Record; type: 'invalid' }
|
|
587
|
+
| (Staged & { type: 'reopened' })
|
|
588
|
+
| { type: 'not_found' }
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/** Atomically records a verified destination transaction and completes a transfer. */
|
|
592
|
+
export async function complete(db: Db.Db, options: complete.Options): Promise<complete.Result> {
|
|
593
|
+
return db.transaction(async (tx) => {
|
|
594
|
+
const current = await FundingTransfers.getForUpdate(tx, options.id)
|
|
595
|
+
if (!current) return { type: 'not_found' }
|
|
596
|
+
if (current.status === 'completed') {
|
|
597
|
+
const transactions = await FundingTransferTransactions.listByTransfer(tx, current.id)
|
|
598
|
+
const existing = transactions.some(
|
|
599
|
+
(transaction) =>
|
|
600
|
+
transaction.chainId === options.chainId &&
|
|
601
|
+
transaction.role === 'destination' &&
|
|
602
|
+
transaction.transactionRef === options.transactionHash.toLowerCase(),
|
|
603
|
+
)
|
|
604
|
+
return existing ? { record: current, type: 'replayed' } : { current, type: 'invalid' }
|
|
605
|
+
}
|
|
606
|
+
if (current.status !== 'processing') return { current, type: 'invalid' }
|
|
607
|
+
|
|
608
|
+
const transaction = await FundingTransferTransactions.insert(tx, {
|
|
609
|
+
chainId: options.chainId,
|
|
610
|
+
createdAt: new Date().toISOString(),
|
|
611
|
+
role: 'destination',
|
|
612
|
+
transactionRef: options.transactionHash,
|
|
613
|
+
transferId: options.id,
|
|
614
|
+
})
|
|
615
|
+
if (!transaction) throw new AtomicTransitionError()
|
|
616
|
+
const result = await transitionIn(tx, {
|
|
617
|
+
current,
|
|
618
|
+
expectedVersion: current.version,
|
|
619
|
+
id: current.id,
|
|
620
|
+
snapshot: {
|
|
621
|
+
...current.snapshot,
|
|
622
|
+
destinationAmount: options.destinationAmount,
|
|
623
|
+
destinationTransactionHashes: [transaction.transactionRef],
|
|
624
|
+
},
|
|
625
|
+
status: 'completed',
|
|
626
|
+
})
|
|
627
|
+
if (result.type !== 'applied') throw new AtomicTransitionError()
|
|
628
|
+
return { record: result.record, references: result.references, type: 'completed' }
|
|
629
|
+
})
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
export declare namespace complete {
|
|
633
|
+
/** Verified destination evidence for one processing transfer. */
|
|
634
|
+
type Options = {
|
|
635
|
+
/** Destination chain CAIP-2 id. */
|
|
636
|
+
chainId: string
|
|
637
|
+
/** Exact verified destination amount. */
|
|
638
|
+
destinationAmount: NonNullable<Snapshot['destinationAmount']>
|
|
639
|
+
/** Transfer id (`ftr_…`). */
|
|
640
|
+
id: string
|
|
641
|
+
/** Verified destination transaction hash. */
|
|
642
|
+
transactionHash: string
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
/** Transfer completion outcome. */
|
|
646
|
+
type Result =
|
|
647
|
+
| { current: FundingTransfers.Record; type: 'invalid' }
|
|
648
|
+
| (Staged & { type: 'completed' })
|
|
649
|
+
| { record: FundingTransfers.Record; type: 'replayed' }
|
|
650
|
+
| { type: 'not_found' }
|
|
651
|
+
}
|
|
652
|
+
|
|
428
653
|
/**
|
|
429
654
|
* Applies a version-guarded material change: a status transition, a snapshot
|
|
430
655
|
* update, or both. The row update and its immutable event commit in one
|
|
@@ -434,39 +659,48 @@ export declare namespace create {
|
|
|
434
659
|
export async function transition(
|
|
435
660
|
db: Db.Db,
|
|
436
661
|
options: transition.Options,
|
|
662
|
+
): Promise<transition.Result> {
|
|
663
|
+
return db.transaction((tx) => transitionIn(tx, options))
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
async function transitionIn(
|
|
667
|
+
tx: Db.Db,
|
|
668
|
+
options: transition.Options & { current?: FundingTransfers.Record | undefined },
|
|
437
669
|
): Promise<transition.Result> {
|
|
438
670
|
const now = new Date()
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
671
|
+
const current = options.current ?? (await FundingTransfers.get(tx, options.id))
|
|
672
|
+
if (!current) return { type: 'not_found' }
|
|
673
|
+
if (current.version !== options.expectedVersion) return { current, type: 'stale' }
|
|
674
|
+
const status = options.status ?? current.status
|
|
675
|
+
if (status !== current.status && !canTransition(current.status, status))
|
|
676
|
+
return { current, type: 'invalid' }
|
|
677
|
+
|
|
678
|
+
const updated = await FundingTransfers.update(tx, {
|
|
679
|
+
expectedVersion: options.expectedVersion,
|
|
680
|
+
id: options.id,
|
|
681
|
+
providerState:
|
|
682
|
+
options.providerState === undefined ? current.providerState : options.providerState,
|
|
683
|
+
snapshot: options.snapshot === undefined ? current.snapshot : parseSnapshot(options.snapshot),
|
|
684
|
+
status,
|
|
685
|
+
statusReason: options.statusReason ?? (status === current.status ? current.statusReason : null),
|
|
686
|
+
updatedAt: now.toISOString(),
|
|
687
|
+
version: current.version + 1,
|
|
688
|
+
})
|
|
689
|
+
if (!updated) {
|
|
690
|
+
const latest = await FundingTransfers.get(tx, options.id)
|
|
691
|
+
return latest ? { current: latest, type: 'stale' } : { type: 'not_found' }
|
|
692
|
+
}
|
|
693
|
+
const event = await FundingTransferEvents.insert(tx, {
|
|
694
|
+
createdAt: updated.updatedAt,
|
|
695
|
+
snapshot: toPublic(updated),
|
|
696
|
+
status: updated.status,
|
|
697
|
+
transferId: updated.id,
|
|
698
|
+
version: updated.version,
|
|
699
|
+
})
|
|
700
|
+
const { references } = await TransferWebhook.stage(tx, {
|
|
701
|
+
changes: [{ event, record: updated }],
|
|
469
702
|
})
|
|
703
|
+
return { record: updated, references, type: 'applied' }
|
|
470
704
|
}
|
|
471
705
|
|
|
472
706
|
export declare namespace transition {
|
|
@@ -476,6 +710,8 @@ export declare namespace transition {
|
|
|
476
710
|
expectedVersion: number
|
|
477
711
|
/** Transfer id (`ftr_…`). */
|
|
478
712
|
id: string
|
|
713
|
+
/** Replacement private provider state; omitted keeps the stored value. */
|
|
714
|
+
providerState?: ProviderState | null | undefined
|
|
479
715
|
/** Replacement public snapshot; omitted keeps the stored snapshot. */
|
|
480
716
|
snapshot?: Snapshot | undefined
|
|
481
717
|
/** New status; omitted keeps the current status (snapshot-only change). */
|
|
@@ -486,7 +722,7 @@ export declare namespace transition {
|
|
|
486
722
|
|
|
487
723
|
/** Outcome of a guarded transition. */
|
|
488
724
|
type Result =
|
|
489
|
-
|
|
|
725
|
+
| (Staged & { type: 'applied' })
|
|
490
726
|
| { current: FundingTransfers.Record; type: 'invalid' }
|
|
491
727
|
| { current: FundingTransfers.Record; type: 'stale' }
|
|
492
728
|
| { type: 'not_found' }
|
|
@@ -520,3 +756,7 @@ function parseSnapshot(snapshot: Snapshot): Snapshot {
|
|
|
520
756
|
},
|
|
521
757
|
}
|
|
522
758
|
}
|
|
759
|
+
|
|
760
|
+
class AtomicTransitionError extends Error {
|
|
761
|
+
override name = 'Funding.Transfer.AtomicTransitionError'
|
|
762
|
+
}
|