tapimo 0.7.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -7
- package/dist/ApiKey.d.ts +3 -0
- package/dist/ApiKey.d.ts.map +1 -1
- package/dist/ApiKey.js +10 -0
- package/dist/ApiKey.js.map +1 -1
- package/dist/ApiKeys.d.ts +29 -8
- package/dist/ApiKeys.d.ts.map +1 -1
- package/dist/ApiKeys.js +24 -5
- package/dist/ApiKeys.js.map +1 -1
- package/dist/App.d.ts +20680 -15487
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js +250 -129
- package/dist/App.js.map +1 -1
- package/dist/Assets.d.ts +10 -0
- package/dist/Assets.d.ts.map +1 -1
- package/dist/Assets.js +17 -4
- package/dist/Assets.js.map +1 -1
- package/dist/Scope.d.ts +19 -8
- package/dist/Scope.d.ts.map +1 -1
- package/dist/Scope.js +25 -9
- package/dist/Scope.js.map +1 -1
- package/dist/Webhooks.d.ts +1 -1
- package/dist/admin/App.d.ts +667 -76
- package/dist/admin/App.d.ts.map +1 -1
- package/dist/admin/App.js +12 -2
- package/dist/admin/App.js.map +1 -1
- package/dist/admin/apps/api-keys.d.ts +107 -11
- package/dist/admin/apps/api-keys.d.ts.map +1 -1
- package/dist/admin/apps/api-keys.js +145 -32
- package/dist/admin/apps/api-keys.js.map +1 -1
- package/dist/admin/apps/earn-vaults.d.ts +1069 -0
- package/dist/admin/apps/earn-vaults.d.ts.map +1 -0
- package/dist/admin/apps/earn-vaults.js +409 -0
- package/dist/admin/apps/earn-vaults.js.map +1 -0
- package/dist/admin/apps/organizations.d.ts +2 -0
- package/dist/admin/apps/organizations.d.ts.map +1 -1
- package/dist/admin/apps/verified-tokens.d.ts +74 -74
- 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 +99 -43
- package/dist/admin/ui.generated.js.map +1 -1
- package/dist/analytics/Analytics.d.ts +4 -0
- package/dist/analytics/Analytics.d.ts.map +1 -1
- package/dist/analytics/Analytics.js +21 -2
- package/dist/analytics/Analytics.js.map +1 -1
- package/dist/analytics/tables/requestEvents.d.ts +22 -1
- package/dist/analytics/tables/requestEvents.d.ts.map +1 -1
- package/dist/analytics/tables/requestEvents.js +59 -39
- package/dist/analytics/tables/requestEvents.js.map +1 -1
- package/dist/apps/Zones.d.ts +8335 -0
- package/dist/apps/Zones.d.ts.map +1 -0
- package/dist/apps/Zones.js +38 -0
- package/dist/apps/Zones.js.map +1 -0
- package/dist/apps/data/App.d.ts +5666 -3934
- package/dist/apps/data/App.d.ts.map +1 -1
- package/dist/apps/data/App.js +90 -22
- package/dist/apps/data/App.js.map +1 -1
- package/dist/apps/data/FxOracle.d.ts +1 -1
- package/dist/apps/data/FxOracle.d.ts.map +1 -1
- package/dist/apps/data/index.d.ts +0 -1
- package/dist/apps/data/index.d.ts.map +1 -1
- package/dist/apps/data/index.js +0 -1
- package/dist/apps/data/index.js.map +1 -1
- package/dist/apps/data/routes/activities.d.ts +56 -56
- package/dist/apps/data/routes/activities.d.ts.map +1 -1
- package/dist/apps/data/routes/activities.js +130 -65
- package/dist/apps/data/routes/activities.js.map +1 -1
- package/dist/apps/data/routes/addresses.d.ts +65 -65
- package/dist/apps/data/routes/balances.d.ts +14 -14
- package/dist/apps/data/routes/balances.js +5 -5
- package/dist/apps/data/routes/balances.js.map +1 -1
- package/dist/apps/data/routes/blocks.d.ts +39 -39
- package/dist/apps/data/routes/coingecko.d.ts +54 -54
- package/dist/apps/data/routes/coingecko.d.ts.map +1 -1
- package/dist/apps/data/routes/coingecko.js +62 -35
- package/dist/apps/data/routes/coingecko.js.map +1 -1
- package/dist/apps/data/routes/earn.d.ts +2574 -0
- package/dist/apps/data/routes/earn.d.ts.map +1 -0
- package/dist/apps/data/routes/earn.js +1574 -0
- package/dist/apps/data/routes/earn.js.map +1 -0
- package/dist/apps/data/routes/exchanges.d.ts +1626 -719
- package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
- package/dist/apps/data/routes/exchanges.js +656 -193
- package/dist/apps/data/routes/exchanges.js.map +1 -1
- package/dist/apps/data/routes/fee-amm.d.ts +108 -108
- package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
- package/dist/apps/data/routes/fee-amm.js +59 -8
- package/dist/apps/data/routes/fee-amm.js.map +1 -1
- package/dist/apps/data/routes/indexer.d.ts +35 -35
- package/dist/apps/data/routes/indexer.d.ts.map +1 -1
- package/dist/apps/data/routes/indexer.js +23 -3
- package/dist/apps/data/routes/indexer.js.map +1 -1
- package/dist/apps/data/routes/receipts.d.ts +33 -33
- package/dist/apps/data/routes/receipts.d.ts.map +1 -1
- package/dist/apps/data/routes/receipts.js +11 -11
- package/dist/apps/data/routes/receipts.js.map +1 -1
- package/dist/apps/data/routes/rpc.d.ts +6 -6
- package/dist/apps/data/routes/rpc.d.ts.map +1 -1
- package/dist/apps/data/routes/rpc.js +214 -22
- package/dist/apps/data/routes/rpc.js.map +1 -1
- package/dist/apps/data/routes/tokenlist.d.ts +1 -1
- package/dist/apps/data/routes/tokenlist.d.ts.map +1 -1
- package/dist/apps/data/routes/tokenlist.js +39 -8
- package/dist/apps/data/routes/tokenlist.js.map +1 -1
- package/dist/apps/data/routes/tokens.d.ts +115 -87
- package/dist/apps/data/routes/tokens.d.ts.map +1 -1
- package/dist/apps/data/routes/tokens.js +194 -91
- package/dist/apps/data/routes/tokens.js.map +1 -1
- package/dist/apps/data/routes/transactions.d.ts +54 -54
- package/dist/apps/data/routes/transactions.d.ts.map +1 -1
- package/dist/apps/data/routes/transactions.js +78 -39
- package/dist/apps/data/routes/transactions.js.map +1 -1
- package/dist/apps/data/routes/transfers.d.ts +76 -27
- package/dist/apps/data/routes/transfers.d.ts.map +1 -1
- package/dist/apps/data/routes/transfers.js +165 -67
- package/dist/apps/data/routes/transfers.js.map +1 -1
- package/dist/apps/data/routes/valuation.d.ts +42 -42
- package/dist/apps/data/routes/valuation.js +2 -2
- package/dist/apps/data/routes/valuation.js.map +1 -1
- package/dist/apps/data/routes/verified-tokens.d.ts +36 -36
- package/dist/apps/data/routes/webhooks.d.ts +370 -368
- package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
- package/dist/apps/data/routes/webhooks.js +161 -59
- package/dist/apps/data/routes/webhooks.js.map +1 -1
- package/dist/apps/data/routes/zones.d.ts +281 -0
- package/dist/apps/data/routes/zones.d.ts.map +1 -0
- package/dist/apps/data/routes/zones.js +252 -0
- package/dist/apps/data/routes/zones.js.map +1 -0
- package/dist/apps/docs/reference.js +6 -5
- package/dist/apps/docs/reference.js.map +1 -1
- package/dist/apps/funding/Access.d.ts +16 -0
- package/dist/apps/funding/Access.d.ts.map +1 -0
- package/dist/apps/funding/Access.js +22 -0
- package/dist/apps/funding/Access.js.map +1 -0
- package/dist/apps/funding/App.d.ts +3183 -0
- package/dist/apps/funding/App.d.ts.map +1 -0
- package/dist/apps/funding/App.js +46 -0
- package/dist/apps/funding/App.js.map +1 -0
- package/dist/apps/funding/Inventory.d.ts +5 -0
- package/dist/apps/funding/Inventory.d.ts.map +1 -0
- package/dist/apps/funding/Inventory.js +25 -0
- package/dist/apps/funding/Inventory.js.map +1 -0
- package/dist/apps/funding/ProviderAttempts.d.ts +5 -0
- package/dist/apps/funding/ProviderAttempts.d.ts.map +1 -0
- package/dist/apps/funding/ProviderAttempts.js +24 -0
- package/dist/apps/funding/ProviderAttempts.js.map +1 -0
- package/dist/apps/funding/index.d.ts +2 -0
- package/dist/apps/funding/index.d.ts.map +1 -0
- package/dist/apps/funding/index.js +2 -0
- package/dist/apps/funding/index.js.map +1 -0
- package/dist/apps/funding/routes/chains.d.ts +169 -0
- package/dist/apps/funding/routes/chains.d.ts.map +1 -0
- package/dist/apps/funding/routes/chains.js +80 -0
- package/dist/apps/funding/routes/chains.js.map +1 -0
- package/dist/apps/funding/routes/deposit-addresses.d.ts +2388 -0
- package/dist/apps/funding/routes/deposit-addresses.d.ts.map +1 -0
- package/dist/apps/funding/routes/deposit-addresses.js +860 -0
- package/dist/apps/funding/routes/deposit-addresses.js.map +1 -0
- package/dist/apps/funding/routes/providers.d.ts +91 -0
- package/dist/apps/funding/routes/providers.d.ts.map +1 -0
- package/dist/apps/funding/routes/providers.js +56 -0
- package/dist/apps/funding/routes/providers.js.map +1 -0
- package/dist/apps/{data/routes/funding.d.ts → funding/routes/quotes.d.ts} +26 -396
- package/dist/apps/funding/routes/quotes.d.ts.map +1 -0
- package/dist/apps/funding/routes/quotes.js +188 -0
- package/dist/apps/funding/routes/quotes.js.map +1 -0
- package/dist/apps/funding/routes/transfers.d.ts +1999 -0
- package/dist/apps/funding/routes/transfers.d.ts.map +1 -0
- package/dist/apps/funding/routes/transfers.js +614 -0
- package/dist/apps/funding/routes/transfers.js.map +1 -0
- package/dist/apps/index.d.ts +3 -1
- package/dist/apps/index.d.ts.map +1 -1
- package/dist/apps/index.js +3 -1
- package/dist/apps/index.js.map +1 -1
- package/dist/apps/management/App.d.ts +839 -574
- package/dist/apps/management/App.d.ts.map +1 -1
- package/dist/apps/management/Billing.d.ts +8 -0
- package/dist/apps/management/Billing.d.ts.map +1 -1
- package/dist/apps/management/Billing.js +12 -0
- package/dist/apps/management/Billing.js.map +1 -1
- package/dist/apps/management/Error.d.ts +12 -0
- package/dist/apps/management/Error.d.ts.map +1 -0
- package/dist/apps/management/Error.js +10 -0
- package/dist/apps/management/Error.js.map +1 -0
- package/dist/apps/management/routes/api-keys.d.ts +296 -19
- package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
- package/dist/apps/management/routes/api-keys.js +77 -9
- package/dist/apps/management/routes/api-keys.js.map +1 -1
- package/dist/apps/management/routes/billing.d.ts +119 -119
- package/dist/apps/management/routes/faucet.d.ts +35 -35
- package/dist/apps/management/routes/invitations.d.ts +17 -17
- package/dist/apps/management/routes/invitations.d.ts.map +1 -1
- package/dist/apps/management/routes/invitations.js +4 -10
- package/dist/apps/management/routes/invitations.js.map +1 -1
- package/dist/apps/management/routes/invite-links.d.ts +38 -38
- package/dist/apps/management/routes/me.d.ts +6 -6
- package/dist/apps/management/routes/members.d.ts +69 -69
- package/dist/apps/management/routes/orgs.d.ts +16 -16
- package/dist/apps/management/routes/orgs.d.ts.map +1 -1
- package/dist/apps/management/routes/orgs.js +2 -8
- package/dist/apps/management/routes/orgs.js.map +1 -1
- package/dist/apps/management/routes/projects.d.ts +19 -19
- package/dist/apps/management/routes/scopes.d.ts +1 -1
- package/dist/apps/management/routes/scopes.js +2 -2
- package/dist/apps/management/routes/scopes.js.map +1 -1
- package/dist/apps/management/routes/usage.d.ts +72 -72
- package/dist/apps/management/routes/verified-token-requests.d.ts +18 -18
- package/dist/apps/management/routes/webhooks.d.ts +122 -122
- package/dist/apps/management/routes/webhooks.d.ts.map +1 -1
- package/dist/apps/management/routes/webhooks.js +15 -3
- package/dist/apps/management/routes/webhooks.js.map +1 -1
- package/dist/apps/mcp.d.ts +2 -3
- package/dist/apps/mcp.d.ts.map +1 -1
- package/dist/apps/mcp.js +16 -14
- package/dist/apps/mcp.js.map +1 -1
- package/dist/apps/metadata.d.ts +4 -0
- package/dist/apps/metadata.d.ts.map +1 -1
- package/dist/apps/metadata.js +10 -0
- package/dist/apps/metadata.js.map +1 -1
- package/dist/apps/mpp/App.d.ts +57 -58
- package/dist/apps/mpp/App.d.ts.map +1 -1
- package/dist/apps/mpp/App.js +192 -27
- package/dist/apps/mpp/App.js.map +1 -1
- package/dist/apps/mpp/Mpp.d.ts +0 -20
- package/dist/apps/mpp/Mpp.d.ts.map +1 -1
- package/dist/apps/mpp/Mpp.js +0 -24
- package/dist/apps/mpp/Mpp.js.map +1 -1
- package/dist/apps/mpp/internal/Adapter.d.ts +40 -0
- package/dist/apps/mpp/internal/Adapter.d.ts.map +1 -0
- package/dist/apps/mpp/internal/Adapter.js +66 -0
- package/dist/apps/mpp/internal/Adapter.js.map +1 -0
- package/dist/apps/mpp/internal/Error.d.ts +4 -0
- package/dist/apps/mpp/internal/Error.d.ts.map +1 -0
- package/dist/apps/mpp/internal/Error.js +41 -0
- package/dist/apps/mpp/internal/Error.js.map +1 -0
- package/dist/apps/mpp/internal/Idempotency.d.ts +33 -0
- package/dist/apps/mpp/internal/Idempotency.d.ts.map +1 -0
- package/dist/apps/mpp/internal/Idempotency.js +28 -0
- package/dist/apps/mpp/internal/Idempotency.js.map +1 -0
- package/dist/apps/mpp/internal/Policy.d.ts +46 -0
- package/dist/apps/mpp/internal/Policy.d.ts.map +1 -0
- package/dist/apps/mpp/internal/Policy.js +57 -0
- package/dist/apps/mpp/internal/Policy.js.map +1 -0
- package/dist/apps/mpp/internal/ScreenManager.d.ts +27 -0
- package/dist/apps/mpp/internal/ScreenManager.d.ts.map +1 -0
- package/dist/apps/mpp/internal/ScreenManager.js +18 -0
- package/dist/apps/mpp/internal/ScreenManager.js.map +1 -0
- package/dist/apps/mpp/internal/Screening.d.ts +35 -0
- package/dist/apps/mpp/internal/Screening.d.ts.map +1 -0
- package/dist/apps/mpp/internal/Screening.js +20 -0
- package/dist/apps/mpp/internal/Screening.js.map +1 -0
- package/dist/apps/mpp/internal/Sponsorship.d.ts +36 -0
- package/dist/apps/mpp/internal/Sponsorship.d.ts.map +1 -0
- package/dist/apps/mpp/internal/Sponsorship.js +103 -0
- package/dist/apps/mpp/internal/Sponsorship.js.map +1 -0
- package/dist/apps/mpp/internal/Utils.d.ts +7 -0
- package/dist/apps/mpp/internal/Utils.d.ts.map +1 -0
- package/dist/apps/mpp/internal/Utils.js +24 -0
- package/dist/apps/mpp/internal/Utils.js.map +1 -0
- package/dist/apps/relay/App.js +183 -23
- package/dist/apps/relay/App.js.map +1 -1
- package/dist/apps/relay/Sponsorships.d.ts +4 -0
- package/dist/apps/relay/Sponsorships.d.ts.map +1 -1
- package/dist/apps/relay/Sponsorships.js +15 -6
- package/dist/apps/relay/Sponsorships.js.map +1 -1
- package/dist/cloudflare.d.ts +50 -0
- package/dist/cloudflare.d.ts.map +1 -1
- package/dist/cloudflare.js +178 -0
- package/dist/cloudflare.js.map +1 -1
- package/dist/db/Db.d.ts +22 -0
- package/dist/db/Db.d.ts.map +1 -1
- package/dist/db/Db.js +379 -0
- package/dist/db/Db.js.map +1 -1
- package/dist/db/Schema.d.ts +933 -1
- package/dist/db/Schema.d.ts.map +1 -1
- package/dist/db/Schema.js +289 -1
- package/dist/db/Schema.js.map +1 -1
- package/dist/db/tables/earnVaults.d.ts +68 -0
- package/dist/db/tables/earnVaults.d.ts.map +1 -0
- package/dist/db/tables/earnVaults.js +72 -0
- package/dist/db/tables/earnVaults.js.map +1 -0
- package/dist/db/tables/fundingCatalog.d.ts +56 -0
- package/dist/db/tables/fundingCatalog.d.ts.map +1 -0
- package/dist/db/tables/fundingCatalog.js +85 -0
- package/dist/db/tables/fundingCatalog.js.map +1 -0
- package/dist/db/tables/fundingDepositAddresses.d.ts +172 -0
- package/dist/db/tables/fundingDepositAddresses.d.ts.map +1 -0
- package/dist/db/tables/fundingDepositAddresses.js +218 -0
- package/dist/db/tables/fundingDepositAddresses.js.map +1 -0
- package/dist/db/tables/fundingDepositRequestObservations.d.ts +45 -0
- package/dist/db/tables/fundingDepositRequestObservations.d.ts.map +1 -0
- package/dist/db/tables/fundingDepositRequestObservations.js +46 -0
- package/dist/db/tables/fundingDepositRequestObservations.js.map +1 -0
- package/dist/db/tables/fundingDeposits.d.ts +171 -0
- package/dist/db/tables/fundingDeposits.d.ts.map +1 -0
- package/dist/db/tables/fundingDeposits.js +182 -0
- package/dist/db/tables/fundingDeposits.js.map +1 -0
- package/dist/db/tables/fundingIdempotency.d.ts +91 -0
- package/dist/db/tables/fundingIdempotency.d.ts.map +1 -0
- package/dist/db/tables/fundingIdempotency.js +103 -0
- package/dist/db/tables/fundingIdempotency.js.map +1 -0
- package/dist/db/tables/fundingTransferEvents.d.ts +12 -0
- package/dist/db/tables/fundingTransferEvents.d.ts.map +1 -0
- package/dist/db/tables/fundingTransferEvents.js +18 -0
- package/dist/db/tables/fundingTransferEvents.js.map +1 -0
- package/dist/db/tables/fundingTransferTransactions.d.ts +15 -0
- package/dist/db/tables/fundingTransferTransactions.d.ts.map +1 -0
- package/dist/db/tables/fundingTransferTransactions.js +27 -0
- package/dist/db/tables/fundingTransferTransactions.js.map +1 -0
- package/dist/db/tables/fundingTransfers.d.ts +82 -0
- package/dist/db/tables/fundingTransfers.d.ts.map +1 -0
- package/dist/db/tables/fundingTransfers.js +89 -0
- package/dist/db/tables/fundingTransfers.js.map +1 -0
- package/dist/db/tables/organizations.d.ts +8 -0
- package/dist/db/tables/organizations.d.ts.map +1 -1
- package/dist/db/tables/organizations.js +16 -0
- package/dist/db/tables/organizations.js.map +1 -1
- package/dist/db/tables/projects.d.ts +8 -0
- package/dist/db/tables/projects.d.ts.map +1 -1
- package/dist/db/tables/projects.js +16 -0
- package/dist/db/tables/projects.js.map +1 -1
- package/dist/db/tables/requestUsage.d.ts +13 -0
- package/dist/db/tables/requestUsage.d.ts.map +1 -1
- package/dist/db/tables/requestUsage.js +16 -0
- package/dist/db/tables/requestUsage.js.map +1 -1
- package/dist/db/tables/sponsoredTransactions.d.ts +2 -2
- package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
- package/dist/db/tables/sponsoredTransactions.js +1 -1
- package/dist/db/tables/sponsoredTransactions.js.map +1 -1
- package/dist/db/tables/users.d.ts +8 -0
- package/dist/db/tables/users.d.ts.map +1 -1
- package/dist/db/tables/users.js +16 -0
- package/dist/db/tables/users.js.map +1 -1
- package/dist/db/tables/verifiedTokens.d.ts +14 -7
- package/dist/db/tables/verifiedTokens.d.ts.map +1 -1
- package/dist/db/tables/verifiedTokens.js +9 -7
- package/dist/db/tables/verifiedTokens.js.map +1 -1
- package/dist/db/tables/webhookSubscriptions.d.ts +31 -1
- package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
- package/dist/db/tables/webhookSubscriptions.js +24 -3
- package/dist/db/tables/webhookSubscriptions.js.map +1 -1
- package/dist/handlers/relay.js +108 -108
- package/dist/handlers/relay.js.map +1 -1
- package/dist/internal/Auth.d.ts +37 -11
- package/dist/internal/Auth.d.ts.map +1 -1
- package/dist/internal/Auth.js +75 -16
- package/dist/internal/Auth.js.map +1 -1
- package/dist/internal/Cache.d.ts.map +1 -1
- package/dist/internal/Cache.js +17 -11
- package/dist/internal/Cache.js.map +1 -1
- package/dist/internal/Cursor.js +1 -1
- package/dist/internal/Cursor.js.map +1 -1
- package/dist/internal/EarnRates.d.ts +89 -0
- package/dist/internal/EarnRates.d.ts.map +1 -0
- package/dist/internal/EarnRates.js +266 -0
- package/dist/internal/EarnRates.js.map +1 -0
- package/dist/internal/EarnVaults.d.ts +171 -0
- package/dist/internal/EarnVaults.d.ts.map +1 -0
- package/dist/internal/EarnVaults.js +547 -0
- package/dist/internal/EarnVaults.js.map +1 -0
- package/dist/internal/EdgeCache.d.ts +10 -3
- package/dist/internal/EdgeCache.d.ts.map +1 -1
- package/dist/internal/EdgeCache.js +43 -11
- package/dist/internal/EdgeCache.js.map +1 -1
- package/dist/internal/Id.d.ts +11 -0
- package/dist/internal/Id.d.ts.map +1 -1
- package/dist/internal/Id.js +13 -0
- package/dist/internal/Id.js.map +1 -1
- package/dist/internal/Idempotency.d.ts +83 -0
- package/dist/internal/Idempotency.d.ts.map +1 -0
- package/dist/internal/Idempotency.js +113 -0
- package/dist/internal/Idempotency.js.map +1 -0
- package/dist/internal/IpAllowlist.d.ts +15 -0
- package/dist/internal/IpAllowlist.d.ts.map +1 -0
- package/dist/internal/IpAllowlist.js +27 -0
- package/dist/internal/IpAllowlist.js.map +1 -0
- package/dist/internal/Log.d.ts +64 -9
- package/dist/internal/Log.d.ts.map +1 -1
- package/dist/internal/Log.js +29 -7
- package/dist/internal/Log.js.map +1 -1
- package/dist/internal/MetricSink.d.ts.map +1 -1
- package/dist/internal/MetricSink.js +47 -1
- package/dist/internal/MetricSink.js.map +1 -1
- package/dist/internal/OpenApi.d.ts +2 -2
- package/dist/internal/OpenApi.d.ts.map +1 -1
- package/dist/internal/OpenApi.js +4 -1
- package/dist/internal/OpenApi.js.map +1 -1
- package/dist/internal/Provider.d.ts +14 -0
- package/dist/internal/Provider.d.ts.map +1 -0
- package/dist/internal/Provider.js +5 -0
- package/dist/internal/Provider.js.map +1 -0
- package/dist/internal/Schema.d.ts +6 -1
- package/dist/internal/Schema.d.ts.map +1 -1
- package/dist/internal/Schema.js +20 -11
- package/dist/internal/Schema.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 +35 -0
- package/dist/internal/Store.js.map +1 -1
- package/dist/internal/Tidx.d.ts +49 -24
- package/dist/internal/Tidx.d.ts.map +1 -1
- package/dist/internal/Tidx.js +90 -12
- package/dist/internal/Tidx.js.map +1 -1
- package/dist/internal/Viem.d.ts +90 -65
- package/dist/internal/Viem.d.ts.map +1 -1
- package/dist/internal/Viem.js +90 -12
- package/dist/internal/Viem.js.map +1 -1
- package/dist/internal/WebhookDestination.d.ts.map +1 -1
- package/dist/internal/WebhookDestination.js +34 -28
- package/dist/internal/WebhookDestination.js.map +1 -1
- package/dist/internal/Webhooks.d.ts +9 -0
- package/dist/internal/Webhooks.d.ts.map +1 -1
- package/dist/internal/Webhooks.js +15 -10
- package/dist/internal/Webhooks.js.map +1 -1
- package/dist/internal/exchange/Provider.d.ts +219 -0
- package/dist/internal/exchange/Provider.d.ts.map +1 -0
- package/dist/internal/exchange/Provider.js +117 -0
- package/dist/internal/exchange/Provider.js.map +1 -0
- package/dist/internal/exchange/index.d.ts +2 -0
- package/dist/internal/exchange/index.d.ts.map +1 -0
- package/dist/internal/exchange/index.js +2 -0
- package/dist/internal/exchange/index.js.map +1 -0
- package/dist/internal/exchange/providers/uniswap.d.ts +57 -0
- package/dist/internal/exchange/providers/uniswap.d.ts.map +1 -0
- package/dist/internal/exchange/providers/uniswap.js +553 -0
- package/dist/internal/exchange/providers/uniswap.js.map +1 -0
- package/dist/internal/funding/Action.d.ts +55 -0
- package/dist/internal/funding/Action.d.ts.map +1 -0
- package/dist/internal/funding/Action.js +74 -0
- package/dist/internal/funding/Action.js.map +1 -0
- package/dist/internal/funding/Catalog.d.ts +107 -0
- package/dist/internal/funding/Catalog.d.ts.map +1 -0
- package/dist/internal/funding/Catalog.js +270 -0
- package/dist/internal/funding/Catalog.js.map +1 -0
- package/dist/internal/funding/Chain.d.ts +76 -0
- package/dist/internal/funding/Chain.d.ts.map +1 -0
- package/dist/internal/funding/Chain.js +38 -0
- package/dist/internal/funding/Chain.js.map +1 -0
- package/dist/internal/funding/Deposit.d.ts +408 -0
- package/dist/internal/funding/Deposit.d.ts.map +1 -0
- package/dist/internal/funding/Deposit.js +318 -0
- package/dist/internal/funding/Deposit.js.map +1 -0
- package/dist/internal/funding/DepositAddress.d.ts +345 -0
- package/dist/internal/funding/DepositAddress.d.ts.map +1 -0
- package/dist/internal/funding/DepositAddress.js +189 -0
- package/dist/internal/funding/DepositAddress.js.map +1 -0
- package/dist/internal/funding/Evidence.d.ts +48 -0
- package/dist/internal/funding/Evidence.d.ts.map +1 -0
- package/dist/internal/funding/Evidence.js +315 -0
- package/dist/internal/funding/Evidence.js.map +1 -0
- package/dist/internal/funding/Provider.d.ts +1288 -0
- package/dist/internal/funding/Provider.d.ts.map +1 -0
- package/dist/internal/funding/Provider.js +1086 -0
- package/dist/internal/funding/Provider.js.map +1 -0
- package/dist/internal/funding/Reconciliation.d.ts +127 -0
- package/dist/internal/funding/Reconciliation.d.ts.map +1 -0
- package/dist/internal/funding/Reconciliation.js +885 -0
- package/dist/internal/funding/Reconciliation.js.map +1 -0
- package/dist/internal/funding/Route.d.ts +21 -0
- package/dist/internal/funding/Route.d.ts.map +1 -0
- package/dist/internal/funding/Route.js +5 -0
- package/dist/internal/funding/Route.js.map +1 -0
- package/dist/internal/funding/SourceObservation.d.ts +108 -0
- package/dist/internal/funding/SourceObservation.d.ts.map +1 -0
- package/dist/internal/funding/SourceObservation.js +143 -0
- package/dist/internal/funding/SourceObservation.js.map +1 -0
- package/dist/internal/funding/Subsidy.d.ts +113 -0
- package/dist/internal/funding/Subsidy.d.ts.map +1 -0
- package/dist/internal/funding/Subsidy.js +138 -0
- package/dist/internal/funding/Subsidy.js.map +1 -0
- package/dist/internal/funding/Token.d.ts +41 -0
- package/dist/internal/funding/Token.d.ts.map +1 -0
- package/dist/internal/funding/Token.js +22 -0
- package/dist/internal/funding/Token.js.map +1 -0
- package/dist/internal/funding/Transfer.d.ts +643 -0
- package/dist/internal/funding/Transfer.d.ts.map +1 -0
- package/dist/internal/funding/Transfer.js +332 -0
- package/dist/internal/funding/Transfer.js.map +1 -0
- package/dist/internal/funding/index.d.ts +14 -0
- package/dist/internal/funding/index.d.ts.map +1 -0
- package/dist/internal/funding/index.js +14 -0
- package/dist/internal/funding/index.js.map +1 -0
- package/dist/internal/funding/providers/across.d.ts +21 -0
- package/dist/internal/funding/providers/across.d.ts.map +1 -0
- package/dist/internal/funding/providers/across.js +117 -0
- package/dist/internal/funding/providers/across.js.map +1 -0
- package/dist/internal/funding/providers/relay.d.ts +88 -0
- package/dist/internal/funding/providers/relay.d.ts.map +1 -0
- package/dist/internal/funding/providers/relay.js +871 -0
- package/dist/internal/funding/providers/relay.js.map +1 -0
- package/dist/internal/funding/providers/rhino.d.ts +15 -0
- package/dist/internal/funding/providers/rhino.d.ts.map +1 -0
- package/dist/internal/funding/providers/rhino.js +116 -0
- package/dist/internal/funding/providers/rhino.js.map +1 -0
- package/dist/internal/funding/providers/squid.d.ts +19 -0
- package/dist/internal/funding/providers/squid.d.ts.map +1 -0
- package/dist/internal/funding/providers/squid.js +120 -0
- package/dist/internal/funding/providers/squid.js.map +1 -0
- package/dist/internal/funding/providers/symbiosis.d.ts +20 -0
- package/dist/internal/funding/providers/symbiosis.d.ts.map +1 -0
- package/dist/internal/funding/providers/symbiosis.js +176 -0
- package/dist/internal/funding/providers/symbiosis.js.map +1 -0
- package/dist/internal/index.d.ts +5 -1
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +5 -1
- package/dist/internal/index.js.map +1 -1
- package/dist/internal/webhookDestinations/url.js +61 -57
- package/dist/internal/webhookDestinations/url.js.map +1 -1
- package/dist/providers/index.d.ts +43 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +19 -0
- package/dist/providers/index.js.map +1 -0
- package/package.json +10 -5
- package/src/ApiKey.test.ts +35 -0
- package/src/ApiKey.ts +27 -0
- package/src/ApiKeys.test.ts +40 -7
- package/src/ApiKeys.ts +46 -10
- package/src/App.test.ts +108 -15
- package/src/App.ts +296 -138
- package/src/Assets.ts +29 -4
- package/src/Client.test-d.ts +809 -37
- package/src/Scope.test.ts +19 -0
- package/src/Scope.ts +28 -11
- package/src/Webhooks.test.ts +25 -0
- package/src/Webhooks.ts +1 -1
- package/src/admin/App.test.ts +9 -2
- package/src/admin/App.ts +32 -9
- package/src/admin/apps/api-keys.test.ts +190 -22
- package/src/admin/apps/api-keys.ts +170 -28
- package/src/admin/apps/earn-vaults.test.ts +338 -0
- package/src/admin/apps/earn-vaults.ts +572 -0
- package/src/admin/apps/scopes.test.ts +16 -1
- package/src/admin/ui/plugin.ts +2 -2
- package/src/admin/ui/src/components/EarnVaultForm.tsx +137 -0
- package/src/admin/ui/src/components/MobileProfile.tsx +2 -2
- package/src/admin/ui/src/components/Page.tsx +1 -1
- package/src/admin/ui/src/components/ThemeToggle.tsx +1 -1
- package/src/admin/ui/src/lib/api-keys.ts +37 -7
- package/src/admin/ui/src/lib/client.ts +1 -1
- package/src/admin/ui/src/lib/config.ts +1 -1
- package/src/admin/ui/src/lib/early-access.ts +8 -9
- package/src/admin/ui/src/lib/earn-vaults.ts +207 -0
- package/src/admin/ui/src/lib/format.ts +13 -0
- package/src/admin/ui/src/lib/organizations.test.ts +14 -4
- package/src/admin/ui/src/lib/organizations.ts +7 -1
- package/src/admin/ui/src/lib/response.ts +22 -0
- package/src/admin/ui/src/lib/scopes.test.ts +19 -11
- package/src/admin/ui/src/lib/scopes.ts +28 -7
- package/src/admin/ui/src/lib/verified-tokens.ts +10 -9
- package/src/admin/ui/src/routeTree.gen.ts +70 -7
- package/src/admin/ui/src/router.tsx +2 -2
- package/src/admin/ui/src/routes/__root.tsx +9 -8
- package/src/admin/ui/src/routes/api-keys.tsx +475 -64
- package/src/admin/ui/src/routes/early-access.tsx +5 -12
- package/src/admin/ui/src/routes/earn.vaults.tsx +348 -0
- package/src/admin/ui/src/routes/earn.vaults_.$vaultId.edit.tsx +154 -0
- package/src/admin/ui/src/routes/earn.vaults_.new.tsx +190 -0
- package/src/admin/ui/src/routes/organizations.tsx +4 -7
- package/src/admin/ui/src/routes/organizations_.$orgId.tsx +56 -54
- package/src/admin/ui/src/routes/verified-tokens.tsx +4 -4
- package/src/admin/ui/vite.config.ts +4 -1
- package/src/admin/ui.generated.ts +113 -43
- package/src/analytics/Analytics.test.ts +69 -10
- package/src/analytics/Analytics.ts +24 -1
- package/src/analytics/tables/requestEvents.ts +79 -37
- package/src/apps/Zones.test.ts +33 -0
- package/src/apps/Zones.ts +40 -0
- package/src/apps/composition.test.ts +184 -3
- package/src/apps/data/App.test.ts +28 -23
- package/src/apps/data/App.ts +95 -36
- package/src/apps/data/FxOracle.ts +1 -1
- package/src/apps/data/index.ts +0 -1
- package/src/apps/data/routes/activities.test.ts +82 -6
- package/src/apps/data/routes/activities.ts +131 -71
- package/src/apps/data/routes/balances.test.ts +50 -37
- package/src/apps/data/routes/balances.ts +5 -5
- package/src/apps/data/routes/blocks.test.ts +2 -0
- package/src/apps/data/routes/coingecko.test.ts +22 -0
- package/src/apps/data/routes/coingecko.ts +84 -48
- package/src/apps/data/routes/earn.test.ts +1391 -0
- package/src/apps/data/routes/earn.ts +2188 -0
- package/src/apps/data/routes/exchanges.test.ts +82 -33
- package/src/apps/data/routes/exchanges.ts +842 -227
- package/src/apps/data/routes/fee-amm.test.ts +4 -6
- package/src/apps/data/routes/fee-amm.ts +69 -12
- package/src/apps/data/routes/indexer.test.ts +43 -34
- package/src/apps/data/routes/indexer.ts +21 -3
- package/src/apps/data/routes/receipts.test.ts +5 -3
- package/src/apps/data/routes/receipts.ts +13 -11
- package/src/apps/data/routes/rpc.test.ts +446 -28
- package/src/apps/data/routes/rpc.ts +245 -25
- package/src/apps/data/routes/tokenlist.ts +72 -19
- package/src/apps/data/routes/tokens.test.ts +6 -8
- package/src/apps/data/routes/tokens.ts +258 -86
- package/src/apps/data/routes/transactions.test.ts +2 -0
- package/src/apps/data/routes/transactions.ts +77 -42
- package/src/apps/data/routes/transfers.test.ts +166 -4
- package/src/apps/data/routes/transfers.ts +216 -78
- package/src/apps/data/routes/valuation.test.ts +62 -9
- package/src/apps/data/routes/valuation.ts +2 -2
- package/src/apps/data/routes/webhooks.test.ts +386 -43
- package/src/apps/data/routes/webhooks.ts +172 -71
- package/src/apps/data/routes/zones.test.ts +473 -0
- package/src/apps/data/routes/zones.ts +338 -0
- package/src/apps/docs/reference.ts +8 -6
- package/src/apps/funding/Access.ts +26 -0
- package/src/apps/funding/App.test.ts +78 -0
- package/src/apps/funding/App.ts +63 -0
- package/src/apps/funding/Inventory.ts +30 -0
- package/src/apps/funding/ProviderAttempts.ts +26 -0
- package/src/apps/funding/index.ts +1 -0
- package/src/apps/funding/routes/chains.test.ts +78 -0
- package/src/apps/funding/routes/chains.ts +101 -0
- package/src/apps/funding/routes/deposit-addresses.test.ts +1628 -0
- package/src/apps/funding/routes/deposit-addresses.ts +1015 -0
- package/src/apps/funding/routes/providers.test.ts +165 -0
- package/src/apps/funding/routes/providers.ts +73 -0
- package/src/apps/funding/routes/quotes.test.ts +511 -0
- package/src/apps/funding/routes/quotes.ts +205 -0
- package/src/apps/funding/routes/transfers.test.ts +1255 -0
- package/src/apps/funding/routes/transfers.ts +704 -0
- package/src/apps/index.ts +3 -1
- package/src/apps/management/Billing.test.ts +29 -0
- package/src/apps/management/Billing.ts +23 -0
- package/src/apps/management/Error.ts +12 -0
- package/src/apps/management/routes/api-keys.test.ts +103 -3
- package/src/apps/management/routes/api-keys.ts +98 -10
- package/src/apps/management/routes/invitations.ts +4 -11
- package/src/apps/management/routes/orgs.ts +2 -9
- package/src/apps/management/routes/scopes.test.ts +7 -2
- package/src/apps/management/routes/scopes.ts +2 -2
- package/src/apps/management/routes/webhooks.test.ts +6 -1
- package/src/apps/management/routes/webhooks.ts +15 -3
- package/src/apps/mcp.test.ts +17 -2
- package/src/apps/mcp.ts +18 -13
- package/src/apps/metadata.ts +12 -0
- package/src/apps/mpp/App.ts +276 -29
- package/src/apps/mpp/Mpp.test.ts +631 -26
- package/src/apps/mpp/Mpp.ts +0 -42
- package/src/apps/mpp/internal/Adapter.ts +108 -3
- package/src/apps/mpp/internal/Error.test.ts +33 -0
- package/src/apps/mpp/internal/Error.ts +44 -6
- package/src/apps/mpp/internal/Idempotency.test.ts +213 -0
- package/src/apps/mpp/internal/Idempotency.ts +59 -5
- package/src/apps/mpp/internal/Policy.test.ts +128 -0
- package/src/apps/mpp/internal/Policy.ts +98 -0
- package/src/apps/mpp/internal/ScreenManager.test.ts +68 -0
- package/src/apps/mpp/internal/ScreenManager.ts +41 -0
- package/src/apps/mpp/internal/Screening.ts +40 -3
- package/src/apps/mpp/internal/Sponsorship.ts +144 -0
- package/src/apps/mpp/internal/Utils.ts +30 -0
- package/src/apps/relay/App.test.ts +493 -62
- package/src/apps/relay/App.ts +233 -23
- package/src/apps/relay/Sponsorships.test.ts +49 -0
- package/src/apps/relay/Sponsorships.ts +18 -6
- package/src/cloudflare.ts +279 -0
- package/src/db/Db.ts +501 -0
- package/src/db/Schema.ts +349 -2
- package/src/db/tables/earnVaults.test.ts +185 -0
- package/src/db/tables/earnVaults.ts +151 -0
- package/src/db/tables/fundingCatalog.test.ts +108 -0
- package/src/db/tables/fundingCatalog.ts +157 -0
- package/src/db/tables/fundingDepositAddresses.test.ts +580 -0
- package/src/db/tables/fundingDepositAddresses.ts +404 -0
- package/src/db/tables/fundingDepositRequestObservations.test.ts +106 -0
- package/src/db/tables/fundingDepositRequestObservations.ts +99 -0
- package/src/db/tables/fundingDeposits.test.ts +399 -0
- package/src/db/tables/fundingDeposits.ts +373 -0
- package/src/db/tables/fundingIdempotency.test.ts +182 -0
- package/src/db/tables/fundingIdempotency.ts +180 -0
- package/src/db/tables/fundingTransferEvents.ts +28 -0
- package/src/db/tables/fundingTransferTransactions.test.ts +69 -0
- package/src/db/tables/fundingTransferTransactions.ts +37 -0
- package/src/db/tables/fundingTransfers.test.ts +89 -0
- package/src/db/tables/fundingTransfers.ts +153 -0
- package/src/db/tables/organizations.ts +16 -0
- package/src/db/tables/projects.ts +16 -0
- package/src/db/tables/requestUsage.ts +23 -0
- package/src/db/tables/sponsoredTransactions.test.ts +11 -0
- package/src/db/tables/sponsoredTransactions.ts +3 -3
- package/src/db/tables/users.ts +16 -0
- package/src/db/tables/verifiedTokens.ts +19 -14
- package/src/db/tables/webhookSubscriptions.ts +58 -3
- package/src/handlers/relay.test.ts +2 -0
- package/src/handlers/relay.ts +95 -99
- package/src/internal/Auth.test.ts +225 -5
- package/src/internal/Auth.ts +109 -20
- package/src/internal/Cache.test.ts +37 -3
- package/src/internal/Cache.ts +14 -10
- package/src/internal/Cursor.test.ts +2 -2
- package/src/internal/Cursor.ts +1 -1
- package/src/internal/EarnRates.test.ts +125 -0
- package/src/internal/EarnRates.ts +409 -0
- package/src/internal/EarnVaults.test.ts +195 -0
- package/src/internal/EarnVaults.ts +876 -0
- package/src/internal/EdgeCache.test.ts +26 -7
- package/src/internal/EdgeCache.ts +48 -9
- package/src/internal/Id.ts +14 -0
- package/src/internal/Idempotency.test.ts +109 -0
- package/src/internal/Idempotency.ts +237 -0
- package/src/internal/IpAllowlist.test.ts +52 -0
- package/src/internal/IpAllowlist.ts +39 -0
- package/src/internal/Log.test-d.ts +41 -8
- package/src/internal/Log.test.ts +196 -9
- package/src/internal/Log.ts +124 -17
- package/src/internal/MetricSink.test.ts +244 -4
- package/src/internal/MetricSink.ts +51 -1
- package/src/internal/OpenApi.ts +4 -1
- package/src/internal/Provider.test.ts +17 -0
- package/src/internal/Provider.ts +17 -0
- package/src/internal/Schema.ts +27 -17
- package/src/internal/Store.test.ts +25 -0
- package/src/internal/Store.ts +46 -0
- package/src/internal/Tidx.local.test.ts +78 -3
- package/src/internal/Tidx.test.ts +240 -18
- package/src/internal/Tidx.ts +129 -33
- package/src/internal/VerifiedTokens.test.ts +15 -0
- package/src/internal/Viem.test.ts +198 -17
- package/src/internal/Viem.ts +127 -28
- package/src/internal/WebhookDestination.ts +25 -23
- package/src/internal/Webhooks.test.ts +59 -0
- package/src/internal/Webhooks.ts +34 -10
- package/src/internal/exchange/Provider.test.ts +216 -0
- package/src/internal/exchange/Provider.ts +326 -0
- package/src/internal/exchange/index.test.ts +6 -0
- package/src/internal/exchange/index.ts +1 -0
- package/src/internal/exchange/providers/uniswap.test.ts +122 -0
- package/src/internal/exchange/providers/uniswap.ts +682 -0
- package/src/internal/funding/Action.test.ts +138 -0
- package/src/internal/funding/Action.ts +117 -0
- package/src/internal/funding/Catalog.test.ts +311 -0
- package/src/internal/funding/Catalog.ts +347 -0
- package/src/internal/funding/Chain.test.ts +79 -0
- package/src/internal/funding/Chain.ts +120 -0
- package/src/internal/funding/Deposit.test.ts +26 -0
- package/src/internal/funding/Deposit.ts +522 -0
- package/src/internal/funding/DepositAddress.test.ts +18 -0
- package/src/internal/funding/DepositAddress.ts +312 -0
- package/src/internal/funding/Evidence.test.ts +297 -0
- package/src/internal/funding/Evidence.ts +425 -0
- package/src/internal/funding/Provider.test.ts +1328 -0
- package/src/internal/funding/Provider.ts +1911 -0
- package/src/internal/funding/Reconciliation.local.test.ts +511 -0
- package/src/internal/funding/Reconciliation.test.ts +3037 -0
- package/src/internal/funding/Reconciliation.ts +1202 -0
- package/src/internal/funding/Route.test.ts +66 -0
- package/src/internal/funding/Route.ts +29 -0
- package/src/internal/funding/SourceObservation.test.ts +301 -0
- package/src/internal/funding/SourceObservation.ts +267 -0
- package/src/internal/funding/Subsidy.local.test.ts +152 -0
- package/src/internal/funding/Subsidy.test.ts +75 -0
- package/src/internal/funding/Subsidy.ts +260 -0
- package/src/internal/funding/Token.test.ts +47 -0
- package/src/internal/funding/Token.ts +59 -0
- package/src/internal/funding/Transfer.test.ts +369 -0
- package/src/internal/funding/Transfer.ts +522 -0
- package/src/internal/funding/index.test.ts +21 -0
- package/src/internal/funding/index.ts +13 -0
- package/src/internal/funding/providers/across.ts +149 -0
- package/src/{apps/data/FundingQuoteProviders.test.ts → internal/funding/providers/index.test.ts} +178 -157
- package/src/internal/funding/providers/relay.test.ts +564 -0
- package/src/internal/funding/providers/relay.ts +1060 -0
- package/src/internal/funding/providers/rhino.ts +139 -0
- package/src/internal/funding/providers/squid.ts +151 -0
- package/src/internal/funding/providers/symbiosis.ts +221 -0
- package/src/internal/index.test.ts +5 -1
- package/src/internal/index.ts +5 -1
- package/src/internal/webhookDestinations/url.ts +49 -45
- package/src/providers/index.test.ts +14 -0
- package/src/providers/index.ts +54 -0
- package/dist/apps/data/FundingQuoteProviders.d.ts +0 -174
- package/dist/apps/data/FundingQuoteProviders.d.ts.map +0 -1
- package/dist/apps/data/FundingQuoteProviders.js +0 -775
- package/dist/apps/data/FundingQuoteProviders.js.map +0 -1
- package/dist/apps/data/routes/funding.d.ts.map +0 -1
- package/dist/apps/data/routes/funding.js +0 -410
- package/dist/apps/data/routes/funding.js.map +0 -1
- package/dist/internal/FundingQuotes.d.ts +0 -864
- package/dist/internal/FundingQuotes.d.ts.map +0 -1
- package/dist/internal/FundingQuotes.js +0 -672
- package/dist/internal/FundingQuotes.js.map +0 -1
- package/src/apps/data/FundingQuoteProviders.ts +0 -1043
- package/src/apps/data/routes/funding.test.ts +0 -503
- package/src/apps/data/routes/funding.ts +0 -604
- package/src/internal/FundingQuotes.test.ts +0 -456
- package/src/internal/FundingQuotes.ts +0 -944
|
@@ -0,0 +1,2188 @@
|
|
|
1
|
+
import { type Context, Hono } from 'hono'
|
|
2
|
+
import { Value as core_Value } from 'ox'
|
|
3
|
+
import {
|
|
4
|
+
type Chain,
|
|
5
|
+
ContractFunctionExecutionError,
|
|
6
|
+
ContractFunctionRevertedError,
|
|
7
|
+
ContractFunctionZeroDataError,
|
|
8
|
+
zeroAddress,
|
|
9
|
+
} from 'viem'
|
|
10
|
+
import * as z from 'zod/mini'
|
|
11
|
+
|
|
12
|
+
import type * as App from '../../../App.js'
|
|
13
|
+
import * as Db from '../../../db/Db.js'
|
|
14
|
+
import * as core_EarnVaults from '../../../db/tables/earnVaults.js'
|
|
15
|
+
import * as Auth from '../../../internal/Auth.js'
|
|
16
|
+
import * as Cache from '../../../internal/Cache.js'
|
|
17
|
+
import * as Cursor from '../../../internal/Cursor.js'
|
|
18
|
+
import * as EarnRates from '../../../internal/EarnRates.js'
|
|
19
|
+
import * as EarnVaults from '../../../internal/EarnVaults.js'
|
|
20
|
+
import * as OpenApi from '../../../internal/OpenApi.js'
|
|
21
|
+
import * as Response from '../../../internal/Response.js'
|
|
22
|
+
import * as Schema from '../../../internal/Schema.js'
|
|
23
|
+
import * as Store from '../../../internal/Store.js'
|
|
24
|
+
import * as Tidx from '../../../internal/Tidx.js'
|
|
25
|
+
import * as Timing from '../../../internal/Timing.js'
|
|
26
|
+
import * as Ttl from '../../../internal/Ttl.js'
|
|
27
|
+
import * as Value from '../../../internal/Value.js'
|
|
28
|
+
import * as VerifiedTokens from '../../../internal/VerifiedTokens.js'
|
|
29
|
+
import * as FxOracle from '../FxOracle.js'
|
|
30
|
+
import * as Tokens from './tokens.js'
|
|
31
|
+
import * as Valuation from './valuation.js'
|
|
32
|
+
|
|
33
|
+
const deployedSignature =
|
|
34
|
+
'event EarnStackDeployed(address indexed earnVault,address indexed earnShare,address indexed earnFees,address engine,address asset,address owner,bytes32 deploymentId,address emergencyGuardian,address asyncJanitor,uint8 migrationMode,bytes32 earnShareSalt,bytes32 controlConfigHash,bytes32 feeConfigHash,bytes32 earnFeesSalt)'
|
|
35
|
+
|
|
36
|
+
const depositedSignature =
|
|
37
|
+
'event Deposited(address indexed caller,address indexed receiver,uint256 assets,uint256 earnShares)'
|
|
38
|
+
|
|
39
|
+
const redeemedSignature =
|
|
40
|
+
'event Redeemed(address indexed caller,address indexed receiver,uint256 earnShares,uint256 assets)'
|
|
41
|
+
|
|
42
|
+
const withdrewExactSignature =
|
|
43
|
+
'event WithdrewExact(address indexed caller,address indexed receiver,uint256 assets,uint256 earnSharesBurned)'
|
|
44
|
+
|
|
45
|
+
const redeemFinalizedSignature =
|
|
46
|
+
'event RedeemFinalized(bytes32 indexed requestId,address indexed receiver,uint256 earnShares,address asset,uint256 assets)'
|
|
47
|
+
|
|
48
|
+
const redeemCancelledSignature =
|
|
49
|
+
'event RedeemCancelled(bytes32 indexed requestId,address indexed receiver,uint256 earnShares)'
|
|
50
|
+
|
|
51
|
+
const redeemRequestedSignature =
|
|
52
|
+
'event RedeemRequested(bytes32 indexed requestId,address indexed requester,address indexed receiver,uint256 earnShares)'
|
|
53
|
+
|
|
54
|
+
const venueSharesDepositedSignature =
|
|
55
|
+
'event VenueSharesDeposited(address indexed caller,address indexed receiver,uint256 requestedVenueShares,uint256 receivedVenueShares,uint256 earnShares)'
|
|
56
|
+
|
|
57
|
+
const maxScannedDeployments = 250
|
|
58
|
+
const scanLimit = 50
|
|
59
|
+
|
|
60
|
+
/** Vault TVL is reported in USD only; the API exposes no denomination parameter. */
|
|
61
|
+
const tvlDenomination = 'USD'
|
|
62
|
+
|
|
63
|
+
/** `Valuation.valuationFor` floors to 6 dp, so 6 is the precision a valued amount carries. */
|
|
64
|
+
const tvlDecimals = 6
|
|
65
|
+
|
|
66
|
+
/** Returns the smallest useful live-discovery batch. */
|
|
67
|
+
export function discoveryBatchLimit(options: discoveryBatchLimit.Options): number {
|
|
68
|
+
const needed = options.limit + 1 - options.matches
|
|
69
|
+
return Math.min(options.filtered ? needed * 2 : needed, options.remaining, scanLimit)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export declare namespace discoveryBatchLimit {
|
|
73
|
+
/** Inputs controlling one discovery batch. */
|
|
74
|
+
type Options = {
|
|
75
|
+
/** Whether filters can reject resolved candidates. */
|
|
76
|
+
filtered: boolean
|
|
77
|
+
/** Requested response page size. */
|
|
78
|
+
limit: number
|
|
79
|
+
/** Compatible matches already collected. */
|
|
80
|
+
matches: number
|
|
81
|
+
/** Candidates remaining within the scan bound. */
|
|
82
|
+
remaining: number
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Zod schemas owned by the public Earn-vault resource. */
|
|
87
|
+
export namespace schema {
|
|
88
|
+
const capability = z
|
|
89
|
+
.enum([
|
|
90
|
+
'asyncRedeem',
|
|
91
|
+
'boundedRedeem',
|
|
92
|
+
'deposit',
|
|
93
|
+
'exactWithdraw',
|
|
94
|
+
'inKindDeposit',
|
|
95
|
+
'privateRouting',
|
|
96
|
+
'redeem',
|
|
97
|
+
'routerSwaps',
|
|
98
|
+
])
|
|
99
|
+
.check(z.describe('Vault capability required by the request.'))
|
|
100
|
+
|
|
101
|
+
const engineType = z
|
|
102
|
+
.enum(['erc4626', 'veda'])
|
|
103
|
+
.check(z.describe('Inferred vault engine type.'), z.meta({ examples: ['erc4626'] }))
|
|
104
|
+
|
|
105
|
+
const engine = Schema.describe(
|
|
106
|
+
z.strictObject({
|
|
107
|
+
address: Schema.Address.check(
|
|
108
|
+
z.describe('Current vault engine contract address.'),
|
|
109
|
+
z.meta({ examples: ['0xd85fc943333a6cd7c0e3391acd54fc4e572f0baf'] }),
|
|
110
|
+
),
|
|
111
|
+
type: z
|
|
112
|
+
.nullable(engineType)
|
|
113
|
+
.check(z.describe('Inferred engine type, or null when it is unknown.')),
|
|
114
|
+
venue: z
|
|
115
|
+
.nullable(
|
|
116
|
+
Schema.Address.check(
|
|
117
|
+
z.describe('Yield venue contract bound to the engine.'),
|
|
118
|
+
z.meta({ examples: ['0xa8b4f0e69cd4b0e56b676343f02acd8c3b355322'] }),
|
|
119
|
+
),
|
|
120
|
+
)
|
|
121
|
+
.check(z.describe('Yield venue, or null when the engine does not expose one.')),
|
|
122
|
+
}),
|
|
123
|
+
'Current vault engine.',
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
const include = z
|
|
127
|
+
.enum(['access', 'apy', 'capabilities', 'token.logoUri', 'tvl', 'zone'])
|
|
128
|
+
.check(z.describe('Optional vault fields to embed via `include`.'))
|
|
129
|
+
|
|
130
|
+
const includeQuery = Schema.includeQuery(
|
|
131
|
+
include,
|
|
132
|
+
'Comma-separated vault fields to include, such as `apy,tvl`.',
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
// `apy` and `tvl` need indexer and FX access, so surfaces lacking either
|
|
136
|
+
// select from this reduced set instead.
|
|
137
|
+
const baseInclude = z
|
|
138
|
+
.enum(['access', 'capabilities', 'token.logoUri', 'zone'])
|
|
139
|
+
.check(z.describe('Optional vault fields to embed via `include`.'))
|
|
140
|
+
|
|
141
|
+
const baseIncludeQuery = Schema.includeQuery(
|
|
142
|
+
baseInclude,
|
|
143
|
+
'Comma-separated vault fields to include, such as `access,zone`.',
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
const zone = z
|
|
147
|
+
.strictObject({
|
|
148
|
+
chainId: Schema.ChainId.check(
|
|
149
|
+
z.describe('Private Zone chain id.'),
|
|
150
|
+
z.meta({ examples: [421700001] }),
|
|
151
|
+
),
|
|
152
|
+
inputTokens: z
|
|
153
|
+
.array(Schema.Address)
|
|
154
|
+
.check(
|
|
155
|
+
z.describe('Tokens accepted by private deposits.'),
|
|
156
|
+
z.meta({ examples: [['0x20c000000000000000000000ff04042ee92fd449']] }),
|
|
157
|
+
),
|
|
158
|
+
name: z.string().check(z.describe('Private Zone name.'), z.meta({ examples: ['zone-e'] })),
|
|
159
|
+
outputTokens: z
|
|
160
|
+
.array(Schema.Address)
|
|
161
|
+
.check(
|
|
162
|
+
z.describe('Tokens supported by private redemptions.'),
|
|
163
|
+
z.meta({ examples: [['0x20c000000000000000000000ff04042ee92fd449']] }),
|
|
164
|
+
),
|
|
165
|
+
})
|
|
166
|
+
.check(z.describe('Private Zone route configured for a verified vault.'))
|
|
167
|
+
|
|
168
|
+
const value = z.strictObject({
|
|
169
|
+
amount: Schema.DecimalString.check(
|
|
170
|
+
z.describe('Value in base units at `decimals` precision.'),
|
|
171
|
+
z.meta({ examples: ['125288750000'] }),
|
|
172
|
+
),
|
|
173
|
+
currency: z
|
|
174
|
+
.string()
|
|
175
|
+
.check(z.describe('Display currency of this value.'), z.meta({ examples: ['USD'] })),
|
|
176
|
+
decimals: z
|
|
177
|
+
.number()
|
|
178
|
+
.check(
|
|
179
|
+
z.int(),
|
|
180
|
+
z.nonnegative(),
|
|
181
|
+
z.describe('Decimal places used to convert `amount` into `formatted`.'),
|
|
182
|
+
z.meta({ examples: [6] }),
|
|
183
|
+
),
|
|
184
|
+
formatted: z
|
|
185
|
+
.string()
|
|
186
|
+
.check(
|
|
187
|
+
z.regex(/^\d+(\.\d+)?$/),
|
|
188
|
+
z.describe('Value rendered in whole units.'),
|
|
189
|
+
z.meta({ examples: ['125288.75'] }),
|
|
190
|
+
),
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
const vault = z.strictObject({
|
|
194
|
+
access: z
|
|
195
|
+
.optional(EarnVaults.schema.Discovery.shape.access)
|
|
196
|
+
.check(z.describe('Vault share-token access, when requested.')),
|
|
197
|
+
apy: z
|
|
198
|
+
.optional(z.nullable(EarnRates.schema.Apy))
|
|
199
|
+
.check(
|
|
200
|
+
z.describe(
|
|
201
|
+
'Annualized share-price growth over the selected window, when requested via `include=apy` or by selecting `apy.window`. Null when the rate could not be measured: the vault predates the window, a boundary or historical quote is unavailable, the engine changed inside the window, or the growth is too extreme to annualize as a ratio.',
|
|
202
|
+
),
|
|
203
|
+
),
|
|
204
|
+
assetToken: Tokens.schema.Token.check(z.describe('Asset accepted by the vault.')),
|
|
205
|
+
capabilities: z
|
|
206
|
+
.optional(EarnVaults.schema.Discovery.shape.capabilities)
|
|
207
|
+
.check(z.describe('Vault capabilities, when requested.')),
|
|
208
|
+
description: z
|
|
209
|
+
.nullable(z.string())
|
|
210
|
+
.check(
|
|
211
|
+
z.describe('Curated vault description, or null when the vault is not verified.'),
|
|
212
|
+
z.meta({ examples: ['Bridge test PATHUSD deposited into Tempo Earn.'] }),
|
|
213
|
+
),
|
|
214
|
+
engine,
|
|
215
|
+
id: Schema.Address.check(
|
|
216
|
+
z.describe('Stable vault id, equal to the lowercase vault address.'),
|
|
217
|
+
z.meta({ examples: ['0xf4ae63687d6753a78e7f551d2eda1d0d31a5ea3a'] }),
|
|
218
|
+
),
|
|
219
|
+
instantLiquidity: EarnVaults.schema.Discovery.shape.instantLiquidity.check(
|
|
220
|
+
z.describe(
|
|
221
|
+
'Assets the venue would release right now, capped at the vault backing, in asset base units. Null when the engine interface cannot report a reliable number.',
|
|
222
|
+
),
|
|
223
|
+
),
|
|
224
|
+
label: z
|
|
225
|
+
.string()
|
|
226
|
+
.check(z.describe('Vault display label.'), z.meta({ examples: ['btPATHUSD Earn'] })),
|
|
227
|
+
sharePrice: z
|
|
228
|
+
.nullable(value)
|
|
229
|
+
.check(
|
|
230
|
+
z.describe(
|
|
231
|
+
'Assets returned for one whole Earn share, in the asset display currency, or null when the engine cannot quote an exit.',
|
|
232
|
+
),
|
|
233
|
+
),
|
|
234
|
+
shareToken: Tokens.schema.Token.check(z.describe('Token representing vault shares.')),
|
|
235
|
+
slug: z
|
|
236
|
+
.nullable(z.string())
|
|
237
|
+
.check(
|
|
238
|
+
z.describe('Curated URL slug, or null when the vault is not verified.'),
|
|
239
|
+
z.meta({ examples: ['btpathusd-earn-h8k2m4n6'] }),
|
|
240
|
+
),
|
|
241
|
+
state: EarnVaults.schema.Discovery.shape.state,
|
|
242
|
+
tvl: z
|
|
243
|
+
.optional(z.nullable(value))
|
|
244
|
+
.check(
|
|
245
|
+
z.describe(
|
|
246
|
+
'Total assets valued in USD, when requested via `include=tvl`, or null when the asset has no priced display currency.',
|
|
247
|
+
),
|
|
248
|
+
),
|
|
249
|
+
vaultAddress: Schema.Address.check(
|
|
250
|
+
z.describe('Earn vault contract address.'),
|
|
251
|
+
z.meta({ examples: ['0xf4ae63687d6753a78e7f551d2eda1d0d31a5ea3a'] }),
|
|
252
|
+
),
|
|
253
|
+
verified: z
|
|
254
|
+
.boolean()
|
|
255
|
+
.check(
|
|
256
|
+
z.describe('Whether this vault is in the curated Earn registry.'),
|
|
257
|
+
z.meta({ examples: [true] }),
|
|
258
|
+
),
|
|
259
|
+
zone: z
|
|
260
|
+
.optional(z.nullable(zone))
|
|
261
|
+
.check(z.describe('Curated private Zone route, when requested, or null when absent.')),
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
/** One compatible Earn vault resolved from current chain state. */
|
|
265
|
+
export const Vault = Schema.describe(vault, 'A compatible Earn vault resolved from chain state.')
|
|
266
|
+
|
|
267
|
+
/** One registry-curated Earn vault. */
|
|
268
|
+
export const VerifiedVault = Schema.describe(
|
|
269
|
+
z.extend(vault, {
|
|
270
|
+
engine: z.extend(engine, { type: engineType }),
|
|
271
|
+
slug: z
|
|
272
|
+
.string()
|
|
273
|
+
.check(
|
|
274
|
+
z.describe('Stable curated vault slug.'),
|
|
275
|
+
z.meta({ examples: ['btpathusd-earn-h8k2m4n6'] }),
|
|
276
|
+
),
|
|
277
|
+
verified: z
|
|
278
|
+
.literal(true)
|
|
279
|
+
.check(
|
|
280
|
+
z.describe('This vault is in the curated Earn registry.'),
|
|
281
|
+
z.meta({ examples: [true] }),
|
|
282
|
+
),
|
|
283
|
+
}),
|
|
284
|
+
'A registry-curated Earn vault resolved from chain state.',
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
const position = z.strictObject({
|
|
288
|
+
account: Schema.Address.check(
|
|
289
|
+
z.describe('Account whose Earn position was read.'),
|
|
290
|
+
z.meta({ examples: ['0xbe058e1c4df8a4366a387bf595b284246a93039e'] }),
|
|
291
|
+
),
|
|
292
|
+
assetAllowance: Schema.DecimalString.check(
|
|
293
|
+
z.describe('Assets the vault may spend from this account, in asset base units.'),
|
|
294
|
+
z.meta({ examples: ['0'] }),
|
|
295
|
+
),
|
|
296
|
+
assetBalance: Schema.DecimalString.check(
|
|
297
|
+
z.describe('Assets this account currently holds, in asset base units.'),
|
|
298
|
+
z.meta({ examples: ['250000000'] }),
|
|
299
|
+
),
|
|
300
|
+
assetToken: Schema.tokenAddress('0x20c000000000000000000000b9537d11c60e8b50').check(
|
|
301
|
+
z.describe('TIP-20 asset token accepted by the vault.'),
|
|
302
|
+
),
|
|
303
|
+
id: Schema.Address.check(
|
|
304
|
+
z.describe('Stable resource ID for this vault position, equal to the account address.'),
|
|
305
|
+
z.meta({ examples: ['0xbe058e1c4df8a4366a387bf595b284246a93039e'] }),
|
|
306
|
+
),
|
|
307
|
+
shareAllowance: Schema.DecimalString.check(
|
|
308
|
+
z.describe('Earn shares the vault may spend from this account, in share base units.'),
|
|
309
|
+
z.meta({ examples: ['0'] }),
|
|
310
|
+
),
|
|
311
|
+
shareBalance: Schema.DecimalString.check(
|
|
312
|
+
z.describe('Earn shares this account currently holds, in share base units.'),
|
|
313
|
+
z.meta({ examples: ['99500000'] }),
|
|
314
|
+
),
|
|
315
|
+
shareToken: Schema.tokenAddress('0x20c000000000000000000000300e14ab91a10769').check(
|
|
316
|
+
z.describe('TIP-20 token representing Earn shares.'),
|
|
317
|
+
),
|
|
318
|
+
value: Schema.DecimalString.check(
|
|
319
|
+
z.describe(
|
|
320
|
+
'Current asset value of this account’s Earn shares, including fees, in asset base units.',
|
|
321
|
+
),
|
|
322
|
+
z.meta({ examples: ['100000000'] }),
|
|
323
|
+
),
|
|
324
|
+
})
|
|
325
|
+
|
|
326
|
+
const earningsBase = z.strictObject({
|
|
327
|
+
account: Schema.Address.check(
|
|
328
|
+
z.describe('Account whose vault earnings were calculated.'),
|
|
329
|
+
z.meta({ examples: ['0x68f94cfca22e5969c0553bbeab00a2acde88939b'] }),
|
|
330
|
+
),
|
|
331
|
+
assetToken: Schema.TokenAddress.check(
|
|
332
|
+
z.describe('TIP-20 asset token accepted by the vault.'),
|
|
333
|
+
z.meta({ examples: ['0x20c000000000000000000000ff04042ee92fd449'] }),
|
|
334
|
+
),
|
|
335
|
+
currentValue: Schema.DecimalString.check(
|
|
336
|
+
z.describe(
|
|
337
|
+
'Asset value of the account’s active Earn shares at the latest indexed block, in asset base units.',
|
|
338
|
+
),
|
|
339
|
+
z.meta({ examples: ['600000'] }),
|
|
340
|
+
),
|
|
341
|
+
id: Schema.Address.check(
|
|
342
|
+
z.describe('Stable resource ID for these vault earnings, equal to the account address.'),
|
|
343
|
+
z.meta({ examples: ['0x68f94cfca22e5969c0553bbeab00a2acde88939b'] }),
|
|
344
|
+
),
|
|
345
|
+
})
|
|
346
|
+
|
|
347
|
+
const earningsPeriod = z
|
|
348
|
+
.enum(['active', 'lifetime'])
|
|
349
|
+
.check(z.describe('Earnings period to calculate.'), z.meta({ examples: ['lifetime'] }))
|
|
350
|
+
|
|
351
|
+
const earnings = z.union([
|
|
352
|
+
z.extend(earningsBase, {
|
|
353
|
+
lifetimeEarnings: z
|
|
354
|
+
.string()
|
|
355
|
+
.check(
|
|
356
|
+
z.regex(/^-?\d+$/),
|
|
357
|
+
z.describe(
|
|
358
|
+
'Current share value plus completed redemptions, exact withdrawals, and finalized async assets, minus asset deposits, at the latest indexed block.',
|
|
359
|
+
),
|
|
360
|
+
z.meta({ examples: ['0'] }),
|
|
361
|
+
),
|
|
362
|
+
period: z
|
|
363
|
+
.literal('lifetime')
|
|
364
|
+
.check(
|
|
365
|
+
z.describe('Returns lifetime net asset earnings.'),
|
|
366
|
+
z.meta({ examples: ['lifetime'] }),
|
|
367
|
+
),
|
|
368
|
+
status: z
|
|
369
|
+
.literal('complete')
|
|
370
|
+
.check(
|
|
371
|
+
z.describe('Earnings include a complete asset-denominated cost basis.'),
|
|
372
|
+
z.meta({ examples: ['complete'] }),
|
|
373
|
+
),
|
|
374
|
+
}),
|
|
375
|
+
z.extend(earningsBase, {
|
|
376
|
+
activeEarnings: z
|
|
377
|
+
.string()
|
|
378
|
+
.check(
|
|
379
|
+
z.regex(/^-?\d+$/),
|
|
380
|
+
z.describe(
|
|
381
|
+
'Current share value minus the weighted-average asset cost basis of shares still held, at the latest indexed block.',
|
|
382
|
+
),
|
|
383
|
+
z.meta({ examples: ['0'] }),
|
|
384
|
+
),
|
|
385
|
+
period: z
|
|
386
|
+
.literal('active')
|
|
387
|
+
.check(
|
|
388
|
+
z.describe('Returns earnings on shares still held.'),
|
|
389
|
+
z.meta({ examples: ['active'] }),
|
|
390
|
+
),
|
|
391
|
+
status: z
|
|
392
|
+
.literal('complete')
|
|
393
|
+
.check(
|
|
394
|
+
z.describe('Earnings include a complete asset-denominated cost basis.'),
|
|
395
|
+
z.meta({ examples: ['complete'] }),
|
|
396
|
+
),
|
|
397
|
+
}),
|
|
398
|
+
z.extend(earningsBase, {
|
|
399
|
+
period: earningsPeriod,
|
|
400
|
+
status: z
|
|
401
|
+
.literal('incomplete_cost_basis')
|
|
402
|
+
.check(
|
|
403
|
+
z.describe(
|
|
404
|
+
'Earnings are unavailable when indexed activity cannot reconstruct the remaining asset cost basis.',
|
|
405
|
+
),
|
|
406
|
+
z.meta({ examples: ['incomplete_cost_basis'] }),
|
|
407
|
+
),
|
|
408
|
+
}),
|
|
409
|
+
z.extend(earningsBase, {
|
|
410
|
+
period: z
|
|
411
|
+
.literal('lifetime')
|
|
412
|
+
.check(
|
|
413
|
+
z.describe('Returns lifetime net asset earnings.'),
|
|
414
|
+
z.meta({ examples: ['lifetime'] }),
|
|
415
|
+
),
|
|
416
|
+
status: z
|
|
417
|
+
.literal('pending_redemption')
|
|
418
|
+
.check(
|
|
419
|
+
z.describe('Earnings are unavailable while an async redemption remains open.'),
|
|
420
|
+
z.meta({ examples: ['pending_redemption'] }),
|
|
421
|
+
),
|
|
422
|
+
}),
|
|
423
|
+
])
|
|
424
|
+
|
|
425
|
+
const meta = z
|
|
426
|
+
.object({
|
|
427
|
+
valuation: z
|
|
428
|
+
.optional(Valuation.schema.Pricing)
|
|
429
|
+
.check(
|
|
430
|
+
z.describe(
|
|
431
|
+
'Rate provenance for valued fields. Present when `include=tvl` consulted conversion rates; absent when TVL was not requested, every value was identity-valued, or rates were unavailable.',
|
|
432
|
+
),
|
|
433
|
+
),
|
|
434
|
+
})
|
|
435
|
+
.check(z.describe('Rate provenance for valued fields.'))
|
|
436
|
+
|
|
437
|
+
const collectionFilters = z.strictObject({
|
|
438
|
+
asset: z
|
|
439
|
+
.optional(Schema.Address)
|
|
440
|
+
.check(z.describe('Only include vaults accepting this asset address.')),
|
|
441
|
+
capability: Schema.includeQuery(
|
|
442
|
+
capability,
|
|
443
|
+
'Comma-separated capabilities that every returned vault must support.',
|
|
444
|
+
),
|
|
445
|
+
chainId: Schema.ChainIdQuery,
|
|
446
|
+
cursor: Schema.Cursor,
|
|
447
|
+
'engine.type': z
|
|
448
|
+
.optional(engineType)
|
|
449
|
+
.check(z.describe('Only include vaults with this inferred engine type.')),
|
|
450
|
+
include: includeQuery,
|
|
451
|
+
limit: Schema.Limit,
|
|
452
|
+
})
|
|
453
|
+
|
|
454
|
+
const collectionQuery = z
|
|
455
|
+
.extend(collectionFilters, { 'apy.window': EarnRates.schema.Window })
|
|
456
|
+
.check(z.describe('Query parameters for listing Earn vaults.'))
|
|
457
|
+
|
|
458
|
+
const vaultSelector = z.strictObject({
|
|
459
|
+
chainId: Schema.ChainIdQuery,
|
|
460
|
+
include: includeQuery,
|
|
461
|
+
})
|
|
462
|
+
|
|
463
|
+
/** Schemas for the getEarnVaults operation. */
|
|
464
|
+
export namespace getEarnVaults {
|
|
465
|
+
/** Query parameters for all compatible deployed Earn vaults. */
|
|
466
|
+
export const Query = collectionQuery
|
|
467
|
+
|
|
468
|
+
/** Paginated list of compatible deployed Earn vaults. */
|
|
469
|
+
export const Response = z
|
|
470
|
+
.strictObject({
|
|
471
|
+
data: z
|
|
472
|
+
.array(Vault)
|
|
473
|
+
.check(z.describe('Compatible deployed Earn vaults in deployment order.')),
|
|
474
|
+
meta: z.optional(meta),
|
|
475
|
+
nextCursor: Schema.NextCursor,
|
|
476
|
+
})
|
|
477
|
+
.check(z.describe('A page of compatible deployed Earn vaults.'))
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/** Schemas for the getVerifiedEarnVaults operation. */
|
|
481
|
+
export namespace getVerifiedEarnVaults {
|
|
482
|
+
/** Collection query without rates or valuation, for surfaces that cannot measure them. */
|
|
483
|
+
export const BaseQuery = Schema.describe(
|
|
484
|
+
z.extend(collectionFilters, { include: baseIncludeQuery }),
|
|
485
|
+
'Query parameters for listing Earn vaults.',
|
|
486
|
+
)
|
|
487
|
+
|
|
488
|
+
/** Query parameters for registry-curated Earn vaults. */
|
|
489
|
+
export const Query = collectionQuery
|
|
490
|
+
|
|
491
|
+
/** Paginated list of registry-curated Earn vaults. */
|
|
492
|
+
export const Response = z
|
|
493
|
+
.strictObject({
|
|
494
|
+
data: z
|
|
495
|
+
.array(VerifiedVault)
|
|
496
|
+
.check(z.describe('Registry-curated Earn vaults ordered by vault address.')),
|
|
497
|
+
meta: z.optional(meta),
|
|
498
|
+
nextCursor: Schema.NextCursor,
|
|
499
|
+
})
|
|
500
|
+
.check(z.describe('A page of registry-curated Earn vaults.'))
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/** Schemas for the getEarnVault operation. */
|
|
504
|
+
export namespace getEarnVault {
|
|
505
|
+
/** Path parameters identifying one Earn vault. */
|
|
506
|
+
export const Params = z
|
|
507
|
+
.strictObject({
|
|
508
|
+
vaultId: Schema.Address.check(z.describe('Earn vault contract address.')),
|
|
509
|
+
})
|
|
510
|
+
.check(z.describe('Path parameters identifying one Earn vault.'))
|
|
511
|
+
|
|
512
|
+
/** Detail query without rates or valuation, for surfaces that cannot measure them. */
|
|
513
|
+
export const BaseQuery = Schema.describe(
|
|
514
|
+
z.extend(vaultSelector, { include: baseIncludeQuery }),
|
|
515
|
+
'Query parameters selecting one Earn vault.',
|
|
516
|
+
)
|
|
517
|
+
|
|
518
|
+
/** Query parameters selecting the chain containing the vault. */
|
|
519
|
+
export const Query = z
|
|
520
|
+
.extend(vaultSelector, { 'apy.window': EarnRates.schema.Window })
|
|
521
|
+
.check(z.describe('Query parameters selecting one Earn vault.'))
|
|
522
|
+
|
|
523
|
+
/** One compatible Earn vault resolved directly from current chain state. */
|
|
524
|
+
export const Response = Schema.describe(
|
|
525
|
+
z.extend(vault, { meta: z.optional(meta) }),
|
|
526
|
+
'A compatible Earn vault resolved from chain state, with rate provenance for its valued fields.',
|
|
527
|
+
)
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/** Schemas for the getEarnVaultPosition operation. */
|
|
531
|
+
export namespace getEarnVaultPosition {
|
|
532
|
+
/** Path parameters identifying the Earn vault and account. */
|
|
533
|
+
export const Params = z
|
|
534
|
+
.strictObject({
|
|
535
|
+
address: Schema.Address.check(z.describe('Account whose Earn position to read.')),
|
|
536
|
+
vaultId: Schema.address('0xdb48b00fb28d9a8db881fcd671c3fb1bf8c486b6').check(
|
|
537
|
+
z.describe('Earn vault contract address.'),
|
|
538
|
+
),
|
|
539
|
+
})
|
|
540
|
+
.check(z.describe('Path parameters identifying an Earn vault position.'))
|
|
541
|
+
|
|
542
|
+
/** Query parameters selecting the chain containing the vault. */
|
|
543
|
+
export const Query = z
|
|
544
|
+
.strictObject({ chainId: Schema.ChainIdQuery })
|
|
545
|
+
.check(z.describe('Query parameters selecting an Earn vault position.'))
|
|
546
|
+
|
|
547
|
+
/** Current asset and Earn-share state for one account in one vault. */
|
|
548
|
+
export const Response = Schema.describe(
|
|
549
|
+
position,
|
|
550
|
+
'Current asset and Earn-share balances, allowances, and asset value for an account in one Earn vault.',
|
|
551
|
+
)
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/** Schemas for the getEarnVaultEarnings operation. */
|
|
555
|
+
export namespace getEarnVaultEarnings {
|
|
556
|
+
/** Path parameters identifying the Earn vault and account. */
|
|
557
|
+
export const Params = z
|
|
558
|
+
.strictObject({
|
|
559
|
+
address: Schema.Address.check(z.describe('Account whose vault earnings to read.')),
|
|
560
|
+
vaultId: Schema.address('0xf4ae63687d6753a78e7f551d2eda1d0d31a5ea3a').check(
|
|
561
|
+
z.describe('Earn vault contract address.'),
|
|
562
|
+
),
|
|
563
|
+
})
|
|
564
|
+
.check(z.describe('Path parameters identifying an Earn vault account.'))
|
|
565
|
+
|
|
566
|
+
/** Query parameters selecting the chain containing the vault. */
|
|
567
|
+
export const Query = z
|
|
568
|
+
.strictObject({
|
|
569
|
+
chainId: Schema.ChainIdQuery,
|
|
570
|
+
period: z._default(earningsPeriod, 'lifetime'),
|
|
571
|
+
})
|
|
572
|
+
.check(z.describe('Query parameters selecting an Earn vault account.'))
|
|
573
|
+
|
|
574
|
+
/** Earnings for one account and period in one Earn vault. */
|
|
575
|
+
export const Response = Schema.describe(
|
|
576
|
+
earnings,
|
|
577
|
+
'Indexed asset value and cost-basis-aware earnings for an account in one Earn vault.',
|
|
578
|
+
)
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
/** Creates the public Earn-vault handlers. */
|
|
583
|
+
export function earn(options: earn.Options = {}) {
|
|
584
|
+
const oracle = options.fx?.oracle ?? FxOracle.ecb()
|
|
585
|
+
return new Hono<App.Environment>()
|
|
586
|
+
.get(
|
|
587
|
+
'/v1/earn/vaults',
|
|
588
|
+
Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }),
|
|
589
|
+
OpenApi.validate('query', schema.getEarnVaults.Query, {
|
|
590
|
+
code: 'query_invalid',
|
|
591
|
+
message: 'Invalid query parameters',
|
|
592
|
+
}),
|
|
593
|
+
OpenApi.describeRoute({
|
|
594
|
+
description:
|
|
595
|
+
'Lists compatible Earn vaults discovered from deployment events and resolved from current chain state.',
|
|
596
|
+
operationId: 'getEarnVaults',
|
|
597
|
+
responses: OpenApi.responses({
|
|
598
|
+
errors: { 502: 'Could not read Earn deployment or vault data.' },
|
|
599
|
+
success: {
|
|
600
|
+
description: 'A page of compatible deployed Earn vaults.',
|
|
601
|
+
schema: schema.getEarnVaults.Response,
|
|
602
|
+
},
|
|
603
|
+
}),
|
|
604
|
+
summary: 'List vaults',
|
|
605
|
+
tags: ['Earn'],
|
|
606
|
+
}),
|
|
607
|
+
// Live state and rate enrichment are embedded, so every vault read caches
|
|
608
|
+
// as current-state rather than slow-changing metadata.
|
|
609
|
+
Cache.response<App.Environment>({
|
|
610
|
+
cacheControl: Cache.policies.state,
|
|
611
|
+
key: (c) => Cache.urlKey(c, schema.getEarnVaults.Query),
|
|
612
|
+
name: 'tempo-api:earn-vaults:v2',
|
|
613
|
+
}),
|
|
614
|
+
async (c) => {
|
|
615
|
+
if (Auth.narrowAccess) return Auth.paidAccessError(c)
|
|
616
|
+
if (OpenApi.narrowValidation)
|
|
617
|
+
return OpenApi.validationError(c, {
|
|
618
|
+
code: 'query_invalid',
|
|
619
|
+
message: 'Invalid query parameters',
|
|
620
|
+
})
|
|
621
|
+
|
|
622
|
+
const query = c.req.valid('query')
|
|
623
|
+
try {
|
|
624
|
+
const chainId = query.chainId ?? c.get('chainId')
|
|
625
|
+
const data = await listVaults(c, { ...query, chainId, oracle })
|
|
626
|
+
return c.json(Response.validated(schema.getEarnVaults.Response, data), 200)
|
|
627
|
+
} catch (cause) {
|
|
628
|
+
return Response.upstream(c, cause)
|
|
629
|
+
}
|
|
630
|
+
},
|
|
631
|
+
)
|
|
632
|
+
.get(
|
|
633
|
+
'/v1/earn/vaults/verified',
|
|
634
|
+
Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }),
|
|
635
|
+
OpenApi.validate('query', schema.getVerifiedEarnVaults.Query, {
|
|
636
|
+
code: 'query_invalid',
|
|
637
|
+
message: 'Invalid query parameters',
|
|
638
|
+
}),
|
|
639
|
+
OpenApi.describeRoute({
|
|
640
|
+
description:
|
|
641
|
+
'Lists registry-curated Earn vaults after resolving their current onchain configuration.',
|
|
642
|
+
operationId: 'getVerifiedEarnVaults',
|
|
643
|
+
responses: OpenApi.responses({
|
|
644
|
+
errors: { 502: 'Could not read curated Earn registry or vault data.' },
|
|
645
|
+
success: {
|
|
646
|
+
description: 'A page of registry-curated Earn vaults.',
|
|
647
|
+
schema: schema.getVerifiedEarnVaults.Response,
|
|
648
|
+
},
|
|
649
|
+
}),
|
|
650
|
+
summary: 'List verified vaults',
|
|
651
|
+
tags: ['Earn'],
|
|
652
|
+
}),
|
|
653
|
+
Cache.response<App.Environment>({
|
|
654
|
+
cacheControl: Cache.policies.state,
|
|
655
|
+
key: (c) => Cache.urlKey(c, schema.getVerifiedEarnVaults.Query),
|
|
656
|
+
name: 'tempo-api:earn-vaults:v2',
|
|
657
|
+
}),
|
|
658
|
+
async (c) => {
|
|
659
|
+
if (Auth.narrowAccess) return Auth.paidAccessError(c)
|
|
660
|
+
if (OpenApi.narrowValidation)
|
|
661
|
+
return OpenApi.validationError(c, {
|
|
662
|
+
code: 'query_invalid',
|
|
663
|
+
message: 'Invalid query parameters',
|
|
664
|
+
})
|
|
665
|
+
|
|
666
|
+
const query = c.req.valid('query')
|
|
667
|
+
try {
|
|
668
|
+
const chainId = query.chainId ?? c.get('chainId')
|
|
669
|
+
const data = await listVerifiedVaults(c, { ...query, chainId, oracle })
|
|
670
|
+
return c.json(Response.validated(schema.getVerifiedEarnVaults.Response, data), 200)
|
|
671
|
+
} catch (cause) {
|
|
672
|
+
return Response.upstream(c, cause)
|
|
673
|
+
}
|
|
674
|
+
},
|
|
675
|
+
)
|
|
676
|
+
.get(
|
|
677
|
+
'/v1/earn/vaults/:vaultId/positions/:address',
|
|
678
|
+
Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }),
|
|
679
|
+
OpenApi.validate('param', schema.getEarnVaultPosition.Params, {
|
|
680
|
+
code: 'position_invalid',
|
|
681
|
+
message: 'Invalid vault position',
|
|
682
|
+
}),
|
|
683
|
+
OpenApi.validate('query', schema.getEarnVaultPosition.Query, {
|
|
684
|
+
code: 'query_invalid',
|
|
685
|
+
message: 'Invalid query parameters',
|
|
686
|
+
}),
|
|
687
|
+
OpenApi.describeRoute({
|
|
688
|
+
description:
|
|
689
|
+
'Gets an account’s asset and Earn-share balances, allowances, and current asset value for one Earn vault.',
|
|
690
|
+
operationId: 'getEarnVaultPosition',
|
|
691
|
+
responses: OpenApi.responses({
|
|
692
|
+
errors: {
|
|
693
|
+
400: {
|
|
694
|
+
codes: [
|
|
695
|
+
'chain_id_invalid',
|
|
696
|
+
'chain_id_unsupported',
|
|
697
|
+
'position_invalid',
|
|
698
|
+
'query_invalid',
|
|
699
|
+
],
|
|
700
|
+
},
|
|
701
|
+
404: {
|
|
702
|
+
codes: ['earn_vault_not_found'],
|
|
703
|
+
description: 'No compatible Earn vault was found at the supplied vault address.',
|
|
704
|
+
},
|
|
705
|
+
502: 'Could not read the Earn vault position.',
|
|
706
|
+
},
|
|
707
|
+
success: {
|
|
708
|
+
description: 'Current Earn position for one account in one vault.',
|
|
709
|
+
schema: schema.getEarnVaultPosition.Response,
|
|
710
|
+
},
|
|
711
|
+
}),
|
|
712
|
+
summary: 'Get account position',
|
|
713
|
+
tags: ['Earn'],
|
|
714
|
+
}),
|
|
715
|
+
Cache.response<App.Environment>({
|
|
716
|
+
cacheControl: Cache.policies.state,
|
|
717
|
+
key: (c) => Cache.urlKey(c, schema.getEarnVaultPosition.Query),
|
|
718
|
+
name: 'tempo-api:earn-vault-positions:v1',
|
|
719
|
+
}),
|
|
720
|
+
async (c) => {
|
|
721
|
+
if (Auth.narrowAccess) return Auth.paidAccessError(c)
|
|
722
|
+
if (OpenApi.narrowValidation)
|
|
723
|
+
return Response.error(c, {
|
|
724
|
+
code: 'chain_id_invalid',
|
|
725
|
+
message: 'Invalid chain id',
|
|
726
|
+
status: 400,
|
|
727
|
+
})
|
|
728
|
+
if (OpenApi.narrowValidation)
|
|
729
|
+
return Response.error(c, {
|
|
730
|
+
code: 'chain_id_unsupported',
|
|
731
|
+
message: 'Unsupported chain id',
|
|
732
|
+
status: 400,
|
|
733
|
+
})
|
|
734
|
+
if (OpenApi.narrowValidation)
|
|
735
|
+
return OpenApi.validationError(c, {
|
|
736
|
+
code: 'position_invalid',
|
|
737
|
+
message: 'Invalid request parameters',
|
|
738
|
+
})
|
|
739
|
+
if (OpenApi.narrowValidation)
|
|
740
|
+
return OpenApi.validationError(c, {
|
|
741
|
+
code: 'query_invalid',
|
|
742
|
+
message: 'Invalid query parameters',
|
|
743
|
+
})
|
|
744
|
+
|
|
745
|
+
const { address, vaultId } = c.req.valid('param')
|
|
746
|
+
const query = c.req.valid('query')
|
|
747
|
+
const chainId = query.chainId ?? c.get('chainId')
|
|
748
|
+
try {
|
|
749
|
+
const position = await c
|
|
750
|
+
.get('getClient')(chainId)
|
|
751
|
+
.earn.getPosition({ account: address, vault: vaultId })
|
|
752
|
+
return c.json(
|
|
753
|
+
Response.validated(schema.getEarnVaultPosition.Response, {
|
|
754
|
+
account: address,
|
|
755
|
+
assetAllowance: position.assetAllowance.toString(),
|
|
756
|
+
assetBalance: position.assetBalance.toString(),
|
|
757
|
+
assetToken: position.assetToken,
|
|
758
|
+
id: address,
|
|
759
|
+
shareAllowance: position.shareAllowance.toString(),
|
|
760
|
+
shareBalance: position.shareBalance.toString(),
|
|
761
|
+
shareToken: position.shareToken,
|
|
762
|
+
value: position.value.toString(),
|
|
763
|
+
}),
|
|
764
|
+
200,
|
|
765
|
+
)
|
|
766
|
+
} catch (cause) {
|
|
767
|
+
try {
|
|
768
|
+
await resolveVaultDiscovery(c, { chainId, include: [], vaultAddress: vaultId })
|
|
769
|
+
} catch (vaultCause) {
|
|
770
|
+
if (isIncompatible(vaultCause))
|
|
771
|
+
return Response.error(c, {
|
|
772
|
+
code: 'earn_vault_not_found',
|
|
773
|
+
message: 'Earn vault not found',
|
|
774
|
+
status: 404,
|
|
775
|
+
})
|
|
776
|
+
}
|
|
777
|
+
return Response.upstream(c, cause)
|
|
778
|
+
}
|
|
779
|
+
},
|
|
780
|
+
)
|
|
781
|
+
.get(
|
|
782
|
+
'/v1/earn/vaults/:vaultId/earnings/:address',
|
|
783
|
+
Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }),
|
|
784
|
+
OpenApi.validate('param', schema.getEarnVaultEarnings.Params, {
|
|
785
|
+
code: 'earnings_invalid',
|
|
786
|
+
message: 'Invalid vault earnings',
|
|
787
|
+
}),
|
|
788
|
+
OpenApi.validate('query', schema.getEarnVaultEarnings.Query, {
|
|
789
|
+
code: 'query_invalid',
|
|
790
|
+
message: 'Invalid query parameters',
|
|
791
|
+
}),
|
|
792
|
+
OpenApi.describeRoute({
|
|
793
|
+
description:
|
|
794
|
+
'Gets an account’s indexed asset value and earnings for lifetime history or shares still held.',
|
|
795
|
+
operationId: 'getEarnVaultEarnings',
|
|
796
|
+
responses: OpenApi.responses({
|
|
797
|
+
errors: {
|
|
798
|
+
400: {
|
|
799
|
+
codes: [
|
|
800
|
+
'chain_id_invalid',
|
|
801
|
+
'chain_id_unsupported',
|
|
802
|
+
'earnings_invalid',
|
|
803
|
+
'query_invalid',
|
|
804
|
+
],
|
|
805
|
+
},
|
|
806
|
+
404: {
|
|
807
|
+
codes: ['earn_vault_not_found'],
|
|
808
|
+
description: 'No compatible Earn vault was found at this address.',
|
|
809
|
+
},
|
|
810
|
+
502: 'Could not read the Earn vault earnings.',
|
|
811
|
+
},
|
|
812
|
+
success: {
|
|
813
|
+
description: 'Cost-basis-aware earnings for one account in one vault.',
|
|
814
|
+
schema: schema.getEarnVaultEarnings.Response,
|
|
815
|
+
},
|
|
816
|
+
}),
|
|
817
|
+
summary: 'Get vault earnings',
|
|
818
|
+
tags: ['Earn'],
|
|
819
|
+
}),
|
|
820
|
+
Cache.response<App.Environment>({
|
|
821
|
+
cacheControl: Cache.policies.state,
|
|
822
|
+
key: (c) => Cache.urlKey(c, schema.getEarnVaultEarnings.Query),
|
|
823
|
+
name: 'tempo-api:earn-vault-earnings:v2',
|
|
824
|
+
}),
|
|
825
|
+
async (c) => {
|
|
826
|
+
if (Auth.narrowAccess) return Auth.paidAccessError(c)
|
|
827
|
+
if (OpenApi.narrowValidation)
|
|
828
|
+
return Response.error(c, {
|
|
829
|
+
code: 'chain_id_invalid',
|
|
830
|
+
message: 'Invalid chain id',
|
|
831
|
+
status: 400,
|
|
832
|
+
})
|
|
833
|
+
if (OpenApi.narrowValidation)
|
|
834
|
+
return Response.error(c, {
|
|
835
|
+
code: 'chain_id_unsupported',
|
|
836
|
+
message: 'Unsupported chain id',
|
|
837
|
+
status: 400,
|
|
838
|
+
})
|
|
839
|
+
if (OpenApi.narrowValidation)
|
|
840
|
+
return OpenApi.validationError(c, {
|
|
841
|
+
code: 'earnings_invalid',
|
|
842
|
+
message: 'Invalid request parameters',
|
|
843
|
+
})
|
|
844
|
+
if (OpenApi.narrowValidation)
|
|
845
|
+
return OpenApi.validationError(c, {
|
|
846
|
+
code: 'query_invalid',
|
|
847
|
+
message: 'Invalid query parameters',
|
|
848
|
+
})
|
|
849
|
+
|
|
850
|
+
const { address, vaultId } = c.req.valid('param')
|
|
851
|
+
const query = c.req.valid('query')
|
|
852
|
+
const chainId = query.chainId ?? c.get('chainId')
|
|
853
|
+
try {
|
|
854
|
+
const data = await getVaultEarnings(c, {
|
|
855
|
+
account: address,
|
|
856
|
+
chainId,
|
|
857
|
+
period: query.period,
|
|
858
|
+
vault: vaultId,
|
|
859
|
+
})
|
|
860
|
+
return c.json(Response.validated(schema.getEarnVaultEarnings.Response, data), 200)
|
|
861
|
+
} catch (cause) {
|
|
862
|
+
try {
|
|
863
|
+
await resolveVaultDiscovery(c, { chainId, include: [], vaultAddress: vaultId })
|
|
864
|
+
} catch (vaultCause) {
|
|
865
|
+
if (isIncompatible(vaultCause))
|
|
866
|
+
return Response.error(c, {
|
|
867
|
+
code: 'earn_vault_not_found',
|
|
868
|
+
message: 'Earn vault not found',
|
|
869
|
+
status: 404,
|
|
870
|
+
})
|
|
871
|
+
}
|
|
872
|
+
return Response.upstream(c, cause)
|
|
873
|
+
}
|
|
874
|
+
},
|
|
875
|
+
)
|
|
876
|
+
.get(
|
|
877
|
+
'/v1/earn/vaults/:vaultId',
|
|
878
|
+
Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }),
|
|
879
|
+
OpenApi.validate('param', schema.getEarnVault.Params, {
|
|
880
|
+
code: 'vault_id_invalid',
|
|
881
|
+
message: 'Invalid vault id',
|
|
882
|
+
}),
|
|
883
|
+
OpenApi.validate('query', schema.getEarnVault.Query, {
|
|
884
|
+
code: 'query_invalid',
|
|
885
|
+
message: 'Invalid query parameters',
|
|
886
|
+
}),
|
|
887
|
+
OpenApi.describeRoute({
|
|
888
|
+
description:
|
|
889
|
+
'Resolves any compatible Earn vault directly from current chain state and enriches it when curated.',
|
|
890
|
+
operationId: 'getEarnVault',
|
|
891
|
+
responses: OpenApi.responses({
|
|
892
|
+
errors: {
|
|
893
|
+
404: {
|
|
894
|
+
codes: ['earn_vault_not_found'],
|
|
895
|
+
description: 'No compatible Earn vault was found at this address.',
|
|
896
|
+
},
|
|
897
|
+
502: 'Could not read Earn vault data.',
|
|
898
|
+
},
|
|
899
|
+
success: {
|
|
900
|
+
description: 'One compatible Earn vault.',
|
|
901
|
+
schema: schema.getEarnVault.Response,
|
|
902
|
+
},
|
|
903
|
+
}),
|
|
904
|
+
summary: 'Get vault',
|
|
905
|
+
tags: ['Earn'],
|
|
906
|
+
}),
|
|
907
|
+
Cache.response<App.Environment>({
|
|
908
|
+
cacheControl: Cache.policies.state,
|
|
909
|
+
key: (c) => Cache.urlKey(c, schema.getEarnVault.Query),
|
|
910
|
+
name: 'tempo-api:earn-vaults:v2',
|
|
911
|
+
}),
|
|
912
|
+
async (c) => {
|
|
913
|
+
if (Auth.narrowAccess) return Auth.paidAccessError(c)
|
|
914
|
+
if (OpenApi.narrowValidation)
|
|
915
|
+
return OpenApi.validationError(c, {
|
|
916
|
+
code: 'vault_id_invalid',
|
|
917
|
+
message: 'Invalid request parameters',
|
|
918
|
+
})
|
|
919
|
+
if (OpenApi.narrowValidation)
|
|
920
|
+
return OpenApi.validationError(c, {
|
|
921
|
+
code: 'query_invalid',
|
|
922
|
+
message: 'Invalid request parameters',
|
|
923
|
+
})
|
|
924
|
+
|
|
925
|
+
const { vaultId } = c.req.valid('param')
|
|
926
|
+
const query = c.req.valid('query')
|
|
927
|
+
try {
|
|
928
|
+
const chainId = query.chainId ?? c.get('chainId')
|
|
929
|
+
const data = await getVault(c, {
|
|
930
|
+
'apy.window': query['apy.window'],
|
|
931
|
+
chainId,
|
|
932
|
+
include: query.include,
|
|
933
|
+
oracle,
|
|
934
|
+
vaultAddress: vaultId,
|
|
935
|
+
})
|
|
936
|
+
return c.json(Response.validated(schema.getEarnVault.Response, data), 200)
|
|
937
|
+
} catch (cause) {
|
|
938
|
+
if (cause instanceof NotFoundError)
|
|
939
|
+
return Response.error(c, {
|
|
940
|
+
code: 'earn_vault_not_found',
|
|
941
|
+
message: 'Earn vault not found',
|
|
942
|
+
status: 404,
|
|
943
|
+
})
|
|
944
|
+
return Response.upstream(c, cause)
|
|
945
|
+
}
|
|
946
|
+
},
|
|
947
|
+
)
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
export declare namespace earn {
|
|
951
|
+
/** Options for the public Earn-vault handlers. */
|
|
952
|
+
type Options = {
|
|
953
|
+
/** FX configuration backing TVL valuation. */
|
|
954
|
+
fx?: Valuation.addresses.Fx | undefined
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
/** Reads one account's indexed value and returns earnings when the history is complete. */
|
|
959
|
+
export async function getVaultEarnings(
|
|
960
|
+
c: Context<App.Environment>,
|
|
961
|
+
options: getVaultEarnings.Options,
|
|
962
|
+
) {
|
|
963
|
+
const client = c.get('getClient')(options.chainId)
|
|
964
|
+
const tidx = c.get('getTidx')(options.chainId)
|
|
965
|
+
const blockNumber = await getLatestIndexedBlockNumber(tidx)
|
|
966
|
+
const position = client.earn.getPosition({
|
|
967
|
+
account: options.account,
|
|
968
|
+
blockNumber: BigInt(blockNumber),
|
|
969
|
+
vault: options.vault,
|
|
970
|
+
})
|
|
971
|
+
if (options.period === 'active') {
|
|
972
|
+
const current = await position
|
|
973
|
+
const base = {
|
|
974
|
+
account: options.account,
|
|
975
|
+
assetToken: current.assetToken,
|
|
976
|
+
currentValue: current.value.toString(),
|
|
977
|
+
id: options.account,
|
|
978
|
+
period: options.period,
|
|
979
|
+
}
|
|
980
|
+
const activeCostBasis = await getActiveCostBasis(tidx, {
|
|
981
|
+
account: options.account,
|
|
982
|
+
blockNumber,
|
|
983
|
+
shareBalance: current.shareBalance,
|
|
984
|
+
shareToken: current.shareToken,
|
|
985
|
+
vault: options.vault,
|
|
986
|
+
})
|
|
987
|
+
if (activeCostBasis === undefined) return { ...base, status: 'incomplete_cost_basis' as const }
|
|
988
|
+
return {
|
|
989
|
+
...base,
|
|
990
|
+
activeEarnings: (current.value - activeCostBasis).toString(),
|
|
991
|
+
status: 'complete' as const,
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
const [history, current] = await Promise.all([
|
|
995
|
+
getVaultEarningsHistory(tidx, {
|
|
996
|
+
account: options.account,
|
|
997
|
+
blockNumber,
|
|
998
|
+
vault: options.vault,
|
|
999
|
+
}),
|
|
1000
|
+
position,
|
|
1001
|
+
])
|
|
1002
|
+
const externalShareTransfer = await hasExternalShareTransfer(tidx, {
|
|
1003
|
+
account: options.account,
|
|
1004
|
+
blockNumber,
|
|
1005
|
+
shareToken: current.shareToken,
|
|
1006
|
+
vault: options.vault,
|
|
1007
|
+
})
|
|
1008
|
+
const base = {
|
|
1009
|
+
account: options.account,
|
|
1010
|
+
assetToken: current.assetToken,
|
|
1011
|
+
currentValue: current.value.toString(),
|
|
1012
|
+
id: options.account,
|
|
1013
|
+
period: options.period,
|
|
1014
|
+
}
|
|
1015
|
+
if (history.incompleteCostBasis || externalShareTransfer)
|
|
1016
|
+
return { ...base, status: 'incomplete_cost_basis' as const }
|
|
1017
|
+
if (history.pendingRedemption) return { ...base, status: 'pending_redemption' as const }
|
|
1018
|
+
const lifetimeEarnings =
|
|
1019
|
+
current.value + history.redeemed + history.withdrewExact + history.finalized - history.deposited
|
|
1020
|
+
return { ...base, lifetimeEarnings: lifetimeEarnings.toString(), status: 'complete' as const }
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
export declare namespace getVaultEarnings {
|
|
1024
|
+
/** Inputs identifying the account and vault to calculate. */
|
|
1025
|
+
type Options = {
|
|
1026
|
+
account: z.output<typeof Schema.Address>
|
|
1027
|
+
chainId: z.output<typeof Schema.ChainId>
|
|
1028
|
+
period: z.output<typeof schema.getEarnVaultEarnings.Query>['period']
|
|
1029
|
+
vault: z.output<typeof Schema.Address>
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
/** Reads the latest block whose indexed logs back the earnings calculation. */
|
|
1034
|
+
async function getLatestIndexedBlockNumber(tidx: Tidx.Client) {
|
|
1035
|
+
const result = await tidx.fetch({
|
|
1036
|
+
engine: 'clickhouse',
|
|
1037
|
+
query: 'SELECT num FROM blocks ORDER BY num DESC LIMIT 1' as string,
|
|
1038
|
+
})
|
|
1039
|
+
const blockNumber = Value.toNumber(result.rows[0]?.['num'])
|
|
1040
|
+
if (blockNumber === undefined) throw new Error('TIDX returned no indexed block.')
|
|
1041
|
+
return blockNumber
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
/** Reads the indexed cash flows and exceptional states behind one earnings calculation. */
|
|
1045
|
+
async function getVaultEarningsHistory(
|
|
1046
|
+
tidx: Tidx.Client,
|
|
1047
|
+
options: getVaultEarningsHistory.Options,
|
|
1048
|
+
) {
|
|
1049
|
+
const result = await tidx.fetch({
|
|
1050
|
+
engine: 'clickhouse',
|
|
1051
|
+
query: `
|
|
1052
|
+
SELECT
|
|
1053
|
+
(
|
|
1054
|
+
SELECT toString(sum(toUInt256(assets)))
|
|
1055
|
+
FROM Deposited
|
|
1056
|
+
WHERE address = '${options.vault}'
|
|
1057
|
+
AND receiver = '${options.account}'
|
|
1058
|
+
AND block_num <= ${options.blockNumber}
|
|
1059
|
+
) AS deposited_assets,
|
|
1060
|
+
(
|
|
1061
|
+
SELECT toString(sum(toUInt256(finalized.assets)))
|
|
1062
|
+
FROM RedeemFinalized AS finalized
|
|
1063
|
+
INNER JOIN RedeemRequested AS requested
|
|
1064
|
+
ON requested.address = finalized.address
|
|
1065
|
+
AND requested."requestId" = finalized."requestId"
|
|
1066
|
+
WHERE finalized.address = '${options.vault}'
|
|
1067
|
+
AND requested.requester = '${options.account}'
|
|
1068
|
+
AND finalized.block_num <= ${options.blockNumber}
|
|
1069
|
+
AND requested.block_num <= ${options.blockNumber}
|
|
1070
|
+
) AS finalized_assets,
|
|
1071
|
+
(
|
|
1072
|
+
SELECT count()
|
|
1073
|
+
FROM RedeemRequested AS requested
|
|
1074
|
+
LEFT ANTI JOIN RedeemFinalized AS finalized
|
|
1075
|
+
ON finalized.address = requested.address
|
|
1076
|
+
AND finalized."requestId" = requested."requestId"
|
|
1077
|
+
AND finalized.block_num <= ${options.blockNumber}
|
|
1078
|
+
LEFT ANTI JOIN RedeemCancelled AS cancelled
|
|
1079
|
+
ON cancelled.address = requested.address
|
|
1080
|
+
AND cancelled."requestId" = requested."requestId"
|
|
1081
|
+
AND cancelled.block_num <= ${options.blockNumber}
|
|
1082
|
+
WHERE requested.address = '${options.vault}'
|
|
1083
|
+
AND requested.requester = '${options.account}'
|
|
1084
|
+
AND requested.block_num <= ${options.blockNumber}
|
|
1085
|
+
) AS pending_redemptions,
|
|
1086
|
+
(
|
|
1087
|
+
SELECT toString(sum(toUInt256(assets)))
|
|
1088
|
+
FROM Redeemed
|
|
1089
|
+
WHERE address = '${options.vault}'
|
|
1090
|
+
AND caller = '${options.account}'
|
|
1091
|
+
AND block_num <= ${options.blockNumber}
|
|
1092
|
+
) AS redeemed_assets,
|
|
1093
|
+
(
|
|
1094
|
+
SELECT count()
|
|
1095
|
+
FROM RedeemCancelled AS cancelled
|
|
1096
|
+
INNER JOIN RedeemRequested AS requested
|
|
1097
|
+
ON requested.address = cancelled.address
|
|
1098
|
+
AND requested."requestId" = cancelled."requestId"
|
|
1099
|
+
WHERE cancelled.address = '${options.vault}'
|
|
1100
|
+
AND cancelled.block_num <= ${options.blockNumber}
|
|
1101
|
+
AND requested.block_num <= ${options.blockNumber}
|
|
1102
|
+
AND requested.requester != cancelled.receiver
|
|
1103
|
+
AND (
|
|
1104
|
+
requested.requester = '${options.account}'
|
|
1105
|
+
OR cancelled.receiver = '${options.account}'
|
|
1106
|
+
)
|
|
1107
|
+
) AS transferred_cancellations,
|
|
1108
|
+
(
|
|
1109
|
+
SELECT count()
|
|
1110
|
+
FROM VenueSharesDeposited
|
|
1111
|
+
WHERE address = '${options.vault}'
|
|
1112
|
+
AND receiver = '${options.account}'
|
|
1113
|
+
AND block_num <= ${options.blockNumber}
|
|
1114
|
+
) AS venue_deposits,
|
|
1115
|
+
(
|
|
1116
|
+
SELECT toString(sum(toUInt256(assets)))
|
|
1117
|
+
FROM WithdrewExact
|
|
1118
|
+
WHERE address = '${options.vault}'
|
|
1119
|
+
AND caller = '${options.account}'
|
|
1120
|
+
AND block_num <= ${options.blockNumber}
|
|
1121
|
+
) AS withdrew_exact
|
|
1122
|
+
` as string,
|
|
1123
|
+
signatures: [
|
|
1124
|
+
depositedSignature,
|
|
1125
|
+
redeemCancelledSignature,
|
|
1126
|
+
redeemFinalizedSignature,
|
|
1127
|
+
redeemRequestedSignature,
|
|
1128
|
+
redeemedSignature,
|
|
1129
|
+
venueSharesDepositedSignature,
|
|
1130
|
+
withdrewExactSignature,
|
|
1131
|
+
],
|
|
1132
|
+
})
|
|
1133
|
+
const row = result.rows[0]
|
|
1134
|
+
const deposited = Value.toIntegerString(row?.['deposited_assets'])
|
|
1135
|
+
const finalized = Value.toIntegerString(row?.['finalized_assets'])
|
|
1136
|
+
const pendingRedemptions = Value.toNumber(row?.['pending_redemptions'])
|
|
1137
|
+
const redeemed = Value.toIntegerString(row?.['redeemed_assets'])
|
|
1138
|
+
const transferredCancellations = Value.toNumber(row?.['transferred_cancellations'])
|
|
1139
|
+
const venueDeposits = Value.toNumber(row?.['venue_deposits'])
|
|
1140
|
+
const withdrewExact = Value.toIntegerString(row?.['withdrew_exact'])
|
|
1141
|
+
if (
|
|
1142
|
+
deposited === undefined ||
|
|
1143
|
+
finalized === undefined ||
|
|
1144
|
+
pendingRedemptions === undefined ||
|
|
1145
|
+
redeemed === undefined ||
|
|
1146
|
+
transferredCancellations === undefined ||
|
|
1147
|
+
venueDeposits === undefined ||
|
|
1148
|
+
withdrewExact === undefined
|
|
1149
|
+
)
|
|
1150
|
+
throw new Error('TIDX returned invalid Earn earnings history.')
|
|
1151
|
+
return {
|
|
1152
|
+
deposited: BigInt(deposited),
|
|
1153
|
+
finalized: BigInt(finalized),
|
|
1154
|
+
incompleteCostBasis: transferredCancellations > 0 || venueDeposits > 0,
|
|
1155
|
+
pendingRedemption: pendingRedemptions > 0,
|
|
1156
|
+
redeemed: BigInt(redeemed),
|
|
1157
|
+
withdrewExact: BigInt(withdrewExact),
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
declare namespace getVaultEarningsHistory {
|
|
1162
|
+
type Options = {
|
|
1163
|
+
account: z.output<typeof Schema.Address>
|
|
1164
|
+
blockNumber: number
|
|
1165
|
+
vault: z.output<typeof Schema.Address>
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
/** Returns whether an account sent or received Earn shares outside known vault flows. */
|
|
1170
|
+
async function hasExternalShareTransfer(
|
|
1171
|
+
tidx: Tidx.Client,
|
|
1172
|
+
options: hasExternalShareTransfer.Options,
|
|
1173
|
+
) {
|
|
1174
|
+
// Vault exits pull shares into the vault before burning. Reconcile counts by transaction and amount so unmatched direct sends remain external.
|
|
1175
|
+
const result = await tidx.fetch({
|
|
1176
|
+
engine: 'clickhouse',
|
|
1177
|
+
query: `
|
|
1178
|
+
SELECT
|
|
1179
|
+
(
|
|
1180
|
+
SELECT count()
|
|
1181
|
+
FROM token_transfers
|
|
1182
|
+
WHERE token = '${options.shareToken.toLowerCase()}'
|
|
1183
|
+
AND block_num <= ${options.blockNumber}
|
|
1184
|
+
AND (
|
|
1185
|
+
("from" = '${options.account}' AND "to" != '${options.vault}')
|
|
1186
|
+
OR ("to" = '${options.account}' AND "from" != '${zeroAddress}')
|
|
1187
|
+
)
|
|
1188
|
+
) + (
|
|
1189
|
+
SELECT count()
|
|
1190
|
+
FROM (
|
|
1191
|
+
SELECT tx_hash, toUInt256(amount) AS amount, count() AS transfer_count
|
|
1192
|
+
FROM token_transfers
|
|
1193
|
+
WHERE token = '${options.shareToken.toLowerCase()}'
|
|
1194
|
+
AND "from" = '${options.account}'
|
|
1195
|
+
AND "to" = '${options.vault}'
|
|
1196
|
+
AND block_num <= ${options.blockNumber}
|
|
1197
|
+
GROUP BY tx_hash, amount
|
|
1198
|
+
) AS candidate
|
|
1199
|
+
LEFT JOIN (
|
|
1200
|
+
SELECT tx_hash, amount, count() AS exit_count
|
|
1201
|
+
FROM (
|
|
1202
|
+
SELECT tx_hash, toUInt256(earnShares) AS amount
|
|
1203
|
+
FROM Redeemed
|
|
1204
|
+
WHERE address = '${options.vault}'
|
|
1205
|
+
AND caller = '${options.account}'
|
|
1206
|
+
AND block_num <= ${options.blockNumber}
|
|
1207
|
+
UNION ALL
|
|
1208
|
+
SELECT tx_hash, toUInt256(earnShares) AS amount
|
|
1209
|
+
FROM RedeemRequested
|
|
1210
|
+
WHERE address = '${options.vault}'
|
|
1211
|
+
AND requester = '${options.account}'
|
|
1212
|
+
AND block_num <= ${options.blockNumber}
|
|
1213
|
+
UNION ALL
|
|
1214
|
+
SELECT tx_hash, toUInt256(earnSharesBurned) AS amount
|
|
1215
|
+
FROM WithdrewExact
|
|
1216
|
+
WHERE address = '${options.vault}'
|
|
1217
|
+
AND caller = '${options.account}'
|
|
1218
|
+
AND block_num <= ${options.blockNumber}
|
|
1219
|
+
) AS protocol_exit
|
|
1220
|
+
GROUP BY tx_hash, amount
|
|
1221
|
+
) AS matched
|
|
1222
|
+
ON matched.tx_hash = candidate.tx_hash AND matched.amount = candidate.amount
|
|
1223
|
+
WHERE candidate.transfer_count > coalesce(matched.exit_count, 0)
|
|
1224
|
+
) AS count
|
|
1225
|
+
` as string,
|
|
1226
|
+
signatures: [redeemedSignature, redeemRequestedSignature, withdrewExactSignature],
|
|
1227
|
+
})
|
|
1228
|
+
const count = Value.toNumber(result.rows[0]?.['count'])
|
|
1229
|
+
if (count === undefined) throw new Error('TIDX returned an invalid Earn-share transfer count.')
|
|
1230
|
+
return count > 0
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
declare namespace hasExternalShareTransfer {
|
|
1234
|
+
type Options = {
|
|
1235
|
+
account: z.output<typeof Schema.Address>
|
|
1236
|
+
blockNumber: number
|
|
1237
|
+
shareToken: z.output<typeof Schema.Address>
|
|
1238
|
+
vault: z.output<typeof Schema.Address>
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
/** Calculates the asset cost basis attached to an account's remaining Earn shares. */
|
|
1243
|
+
export function calculateActiveCostBasis(options: calculateActiveCostBasis.Options) {
|
|
1244
|
+
const requests = new Map<string, { costBasis: bigint | undefined; shares: bigint }>()
|
|
1245
|
+
let costBasis: bigint | undefined = 0n
|
|
1246
|
+
let shares = 0n
|
|
1247
|
+
|
|
1248
|
+
const remove = (burned: bigint) => {
|
|
1249
|
+
if (burned > shares || shares === 0n) return undefined
|
|
1250
|
+
const removed = (() => {
|
|
1251
|
+
if (costBasis === undefined) return undefined
|
|
1252
|
+
return burned === shares ? costBasis : (costBasis * burned) / shares
|
|
1253
|
+
})()
|
|
1254
|
+
if (burned === shares) costBasis = 0n
|
|
1255
|
+
else if (costBasis !== undefined && removed !== undefined) costBasis -= removed
|
|
1256
|
+
shares -= burned
|
|
1257
|
+
return { costBasis: removed }
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
for (const action of options.actions) {
|
|
1261
|
+
if (action.kind === 'deposit') {
|
|
1262
|
+
if (costBasis !== undefined) costBasis += action.assets
|
|
1263
|
+
shares += action.shares
|
|
1264
|
+
continue
|
|
1265
|
+
}
|
|
1266
|
+
if (action.kind === 'unknown') {
|
|
1267
|
+
costBasis = undefined
|
|
1268
|
+
shares += action.shares
|
|
1269
|
+
continue
|
|
1270
|
+
}
|
|
1271
|
+
if (action.kind === 'cancel') {
|
|
1272
|
+
const restored = requests.get(action.requestId)
|
|
1273
|
+
if (restored === undefined || restored.shares !== action.shares) return undefined
|
|
1274
|
+
if (costBasis === undefined || restored.costBasis === undefined) costBasis = undefined
|
|
1275
|
+
else costBasis += restored.costBasis
|
|
1276
|
+
shares += restored.shares
|
|
1277
|
+
requests.delete(action.requestId)
|
|
1278
|
+
continue
|
|
1279
|
+
}
|
|
1280
|
+
const removed = remove(action.shares)
|
|
1281
|
+
if (removed === undefined) return undefined
|
|
1282
|
+
if (action.kind === 'request')
|
|
1283
|
+
requests.set(action.requestId, { costBasis: removed.costBasis, shares: action.shares })
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
return shares === options.shareBalance && costBasis !== undefined ? costBasis : undefined
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
export declare namespace calculateActiveCostBasis {
|
|
1290
|
+
/** One indexed share or cost-basis mutation. */
|
|
1291
|
+
export type Action =
|
|
1292
|
+
| {
|
|
1293
|
+
/** Action discriminator. */
|
|
1294
|
+
kind: 'cancel'
|
|
1295
|
+
/** Async redemption request being cancelled. */
|
|
1296
|
+
requestId: string
|
|
1297
|
+
/** Shares restored to the account. */
|
|
1298
|
+
shares: bigint
|
|
1299
|
+
}
|
|
1300
|
+
| {
|
|
1301
|
+
/** Assets added to the account's cost basis. */
|
|
1302
|
+
assets: bigint
|
|
1303
|
+
/** Action discriminator. */
|
|
1304
|
+
kind: 'deposit'
|
|
1305
|
+
/** Shares issued for the deposit. */
|
|
1306
|
+
shares: bigint
|
|
1307
|
+
}
|
|
1308
|
+
| {
|
|
1309
|
+
/** Action discriminator. */
|
|
1310
|
+
kind: 'redeem'
|
|
1311
|
+
/** Shares removed from the account. */
|
|
1312
|
+
shares: bigint
|
|
1313
|
+
}
|
|
1314
|
+
| {
|
|
1315
|
+
/** Action discriminator. */
|
|
1316
|
+
kind: 'request'
|
|
1317
|
+
/** Async redemption request holding the removed basis. */
|
|
1318
|
+
requestId: string
|
|
1319
|
+
/** Shares removed from the account. */
|
|
1320
|
+
shares: bigint
|
|
1321
|
+
}
|
|
1322
|
+
| {
|
|
1323
|
+
/** Action discriminator. */
|
|
1324
|
+
kind: 'unknown'
|
|
1325
|
+
/** Shares received without an asset-denominated cost basis. */
|
|
1326
|
+
shares: bigint
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
/** Inputs for calculating the remaining cost basis. */
|
|
1330
|
+
export type Options = {
|
|
1331
|
+
/** Indexed mutations in chain order. */
|
|
1332
|
+
actions: readonly Action[]
|
|
1333
|
+
/** Share balance read at the same indexed block. */
|
|
1334
|
+
shareBalance: bigint
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
/** Reads the active asset cost basis for shares held at one indexed block. */
|
|
1339
|
+
async function getActiveCostBasis(tidx: Tidx.Client, options: getActiveCostBasis.Options) {
|
|
1340
|
+
const result = await tidx.fetch({
|
|
1341
|
+
engine: 'clickhouse',
|
|
1342
|
+
query: `
|
|
1343
|
+
SELECT kind, request_id, shares, assets
|
|
1344
|
+
FROM (
|
|
1345
|
+
SELECT
|
|
1346
|
+
'deposit' AS kind,
|
|
1347
|
+
block_num,
|
|
1348
|
+
log_idx,
|
|
1349
|
+
'' AS request_id,
|
|
1350
|
+
toString(toUInt256(earnShares)) AS shares,
|
|
1351
|
+
toString(toUInt256(assets)) AS assets
|
|
1352
|
+
FROM Deposited
|
|
1353
|
+
WHERE address = '${options.vault}'
|
|
1354
|
+
AND receiver = '${options.account}'
|
|
1355
|
+
AND block_num <= ${options.blockNumber}
|
|
1356
|
+
UNION ALL
|
|
1357
|
+
SELECT
|
|
1358
|
+
'redeem' AS kind,
|
|
1359
|
+
block_num,
|
|
1360
|
+
log_idx,
|
|
1361
|
+
'' AS request_id,
|
|
1362
|
+
toString(toUInt256(earnShares)) AS shares,
|
|
1363
|
+
'0' AS assets
|
|
1364
|
+
FROM Redeemed
|
|
1365
|
+
WHERE address = '${options.vault}'
|
|
1366
|
+
AND caller = '${options.account}'
|
|
1367
|
+
AND block_num <= ${options.blockNumber}
|
|
1368
|
+
UNION ALL
|
|
1369
|
+
SELECT
|
|
1370
|
+
'redeem' AS kind,
|
|
1371
|
+
block_num,
|
|
1372
|
+
log_idx,
|
|
1373
|
+
'' AS request_id,
|
|
1374
|
+
toString(toUInt256(earnSharesBurned)) AS shares,
|
|
1375
|
+
'0' AS assets
|
|
1376
|
+
FROM WithdrewExact
|
|
1377
|
+
WHERE address = '${options.vault}'
|
|
1378
|
+
AND caller = '${options.account}'
|
|
1379
|
+
AND block_num <= ${options.blockNumber}
|
|
1380
|
+
UNION ALL
|
|
1381
|
+
SELECT
|
|
1382
|
+
'request' AS kind,
|
|
1383
|
+
block_num,
|
|
1384
|
+
log_idx,
|
|
1385
|
+
"requestId" AS request_id,
|
|
1386
|
+
toString(toUInt256(earnShares)) AS shares,
|
|
1387
|
+
'0' AS assets
|
|
1388
|
+
FROM RedeemRequested
|
|
1389
|
+
WHERE address = '${options.vault}'
|
|
1390
|
+
AND requester = '${options.account}'
|
|
1391
|
+
AND block_num <= ${options.blockNumber}
|
|
1392
|
+
UNION ALL
|
|
1393
|
+
SELECT
|
|
1394
|
+
'cancel' AS kind,
|
|
1395
|
+
cancelled.block_num AS block_num,
|
|
1396
|
+
cancelled.log_idx AS log_idx,
|
|
1397
|
+
cancelled."requestId" AS request_id,
|
|
1398
|
+
toString(toUInt256(cancelled.earnShares)) AS shares,
|
|
1399
|
+
'0' AS assets
|
|
1400
|
+
FROM RedeemCancelled AS cancelled
|
|
1401
|
+
INNER JOIN RedeemRequested AS requested
|
|
1402
|
+
ON requested.address = cancelled.address
|
|
1403
|
+
AND requested."requestId" = cancelled."requestId"
|
|
1404
|
+
WHERE cancelled.address = '${options.vault}'
|
|
1405
|
+
AND requested.requester = '${options.account}'
|
|
1406
|
+
AND cancelled.receiver = '${options.account}'
|
|
1407
|
+
AND cancelled.block_num <= ${options.blockNumber}
|
|
1408
|
+
AND requested.block_num <= ${options.blockNumber}
|
|
1409
|
+
UNION ALL
|
|
1410
|
+
SELECT
|
|
1411
|
+
'unknown' AS kind,
|
|
1412
|
+
block_num,
|
|
1413
|
+
log_idx,
|
|
1414
|
+
'' AS request_id,
|
|
1415
|
+
toString(toUInt256(earnShares)) AS shares,
|
|
1416
|
+
'0' AS assets
|
|
1417
|
+
FROM VenueSharesDeposited
|
|
1418
|
+
WHERE address = '${options.vault}'
|
|
1419
|
+
AND receiver = '${options.account}'
|
|
1420
|
+
AND block_num <= ${options.blockNumber}
|
|
1421
|
+
UNION ALL
|
|
1422
|
+
SELECT
|
|
1423
|
+
'unknown' AS kind,
|
|
1424
|
+
block_num,
|
|
1425
|
+
log_idx,
|
|
1426
|
+
'' AS request_id,
|
|
1427
|
+
toString(toUInt256(amount)) AS shares,
|
|
1428
|
+
'0' AS assets
|
|
1429
|
+
FROM token_transfers
|
|
1430
|
+
WHERE token = '${options.shareToken.toLowerCase()}'
|
|
1431
|
+
AND "to" = '${options.account}'
|
|
1432
|
+
AND "from" != '${zeroAddress}'
|
|
1433
|
+
AND "from" != '${options.vault}'
|
|
1434
|
+
AND block_num <= ${options.blockNumber}
|
|
1435
|
+
UNION ALL
|
|
1436
|
+
SELECT
|
|
1437
|
+
'redeem' AS kind,
|
|
1438
|
+
block_num,
|
|
1439
|
+
log_idx,
|
|
1440
|
+
'' AS request_id,
|
|
1441
|
+
toString(toUInt256(amount)) AS shares,
|
|
1442
|
+
'0' AS assets
|
|
1443
|
+
FROM token_transfers
|
|
1444
|
+
WHERE token = '${options.shareToken.toLowerCase()}'
|
|
1445
|
+
AND "from" = '${options.account}'
|
|
1446
|
+
AND "to" != '${options.vault}'
|
|
1447
|
+
AND block_num <= ${options.blockNumber}
|
|
1448
|
+
) AS actions
|
|
1449
|
+
ORDER BY block_num, log_idx
|
|
1450
|
+
` as string,
|
|
1451
|
+
signatures: [
|
|
1452
|
+
depositedSignature,
|
|
1453
|
+
redeemCancelledSignature,
|
|
1454
|
+
redeemRequestedSignature,
|
|
1455
|
+
redeemedSignature,
|
|
1456
|
+
venueSharesDepositedSignature,
|
|
1457
|
+
withdrewExactSignature,
|
|
1458
|
+
],
|
|
1459
|
+
})
|
|
1460
|
+
const actions: calculateActiveCostBasis.Action[] = []
|
|
1461
|
+
for (const row of result.rows) {
|
|
1462
|
+
const kind = Value.toText(row['kind'])
|
|
1463
|
+
if (kind === 'deposit') {
|
|
1464
|
+
const assets = Value.toIntegerString(row['assets'])
|
|
1465
|
+
const shares = Value.toIntegerString(row['shares'])
|
|
1466
|
+
if (assets === undefined || shares === undefined) return undefined
|
|
1467
|
+
actions.push({ assets: BigInt(assets), kind, shares: BigInt(shares) })
|
|
1468
|
+
continue
|
|
1469
|
+
}
|
|
1470
|
+
if (kind === 'redeem') {
|
|
1471
|
+
const shares = Value.toIntegerString(row['shares'])
|
|
1472
|
+
if (shares === undefined) return undefined
|
|
1473
|
+
actions.push({ kind, shares: BigInt(shares) })
|
|
1474
|
+
continue
|
|
1475
|
+
}
|
|
1476
|
+
if (kind === 'cancel') {
|
|
1477
|
+
const requestId = Value.toText(row['request_id'])
|
|
1478
|
+
const shares = Value.toIntegerString(row['shares'])
|
|
1479
|
+
if (requestId === undefined || shares === undefined) return undefined
|
|
1480
|
+
actions.push({ kind, requestId, shares: BigInt(shares) })
|
|
1481
|
+
continue
|
|
1482
|
+
}
|
|
1483
|
+
if (kind === 'request') {
|
|
1484
|
+
const requestId = Value.toText(row['request_id'])
|
|
1485
|
+
const shares = Value.toIntegerString(row['shares'])
|
|
1486
|
+
if (requestId === undefined || shares === undefined) return undefined
|
|
1487
|
+
actions.push({ kind, requestId, shares: BigInt(shares) })
|
|
1488
|
+
continue
|
|
1489
|
+
}
|
|
1490
|
+
if (kind === 'unknown') {
|
|
1491
|
+
const shares = Value.toIntegerString(row['shares'])
|
|
1492
|
+
if (shares === undefined) return undefined
|
|
1493
|
+
actions.push({ kind, shares: BigInt(shares) })
|
|
1494
|
+
continue
|
|
1495
|
+
}
|
|
1496
|
+
return undefined
|
|
1497
|
+
}
|
|
1498
|
+
return calculateActiveCostBasis({ actions, shareBalance: options.shareBalance })
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
declare namespace getActiveCostBasis {
|
|
1502
|
+
type Options = {
|
|
1503
|
+
account: z.output<typeof Schema.Address>
|
|
1504
|
+
blockNumber: number
|
|
1505
|
+
shareBalance: bigint
|
|
1506
|
+
shareToken: z.output<typeof Schema.Address>
|
|
1507
|
+
vault: z.output<typeof Schema.Address>
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
/** Lists compatible deployed Earn vaults. */
|
|
1512
|
+
export async function listVaults(c: Context<App.Environment>, options: listVaults.Options) {
|
|
1513
|
+
const db = Db.get(c.get('dbCached'))
|
|
1514
|
+
const [records, snapshot] = await Promise.all([
|
|
1515
|
+
core_EarnVaults.list(db, { chainId: options.chainId }),
|
|
1516
|
+
VerifiedTokens.snapshot(c, options.chainId),
|
|
1517
|
+
])
|
|
1518
|
+
const registry = new Map(records.map((record) => [record.vaultAddress.toLowerCase(), record]))
|
|
1519
|
+
const decoded = options.cursor ? Cursor.decode(options.cursor, ['int', 'int']) : undefined
|
|
1520
|
+
let position = decoded
|
|
1521
|
+
? ([Number(decoded[0]), Number(decoded[1])] as listVaults.Position)
|
|
1522
|
+
: undefined
|
|
1523
|
+
let hasMore = false
|
|
1524
|
+
let scanned = 0
|
|
1525
|
+
const matches: listVaults.Match[] = []
|
|
1526
|
+
|
|
1527
|
+
while (matches.length <= options.limit && scanned < maxScannedDeployments) {
|
|
1528
|
+
const page = await queryDeployments(c, {
|
|
1529
|
+
asset: options.asset,
|
|
1530
|
+
chainId: options.chainId,
|
|
1531
|
+
cursor: position,
|
|
1532
|
+
limit: discoveryBatchLimit({
|
|
1533
|
+
filtered: options.capability.length > 0 || options['engine.type'] !== undefined,
|
|
1534
|
+
limit: options.limit,
|
|
1535
|
+
matches: matches.length,
|
|
1536
|
+
remaining: maxScannedDeployments - scanned,
|
|
1537
|
+
}),
|
|
1538
|
+
})
|
|
1539
|
+
hasMore = page.hasMore
|
|
1540
|
+
if (page.items.length === 0) {
|
|
1541
|
+
hasMore = false
|
|
1542
|
+
break
|
|
1543
|
+
}
|
|
1544
|
+
scanned += page.items.length
|
|
1545
|
+
|
|
1546
|
+
const discovered = await Promise.all(
|
|
1547
|
+
page.items.map(async (item) => {
|
|
1548
|
+
const record = registry.get(item.vaultAddress.toLowerCase())
|
|
1549
|
+
try {
|
|
1550
|
+
const discovery = await resolveVaultDiscovery(c, {
|
|
1551
|
+
chainId: options.chainId,
|
|
1552
|
+
include: discoveryInclude(options),
|
|
1553
|
+
vaultAddress: item.vaultAddress,
|
|
1554
|
+
})
|
|
1555
|
+
return { discovery, position: item.position, record }
|
|
1556
|
+
} catch (cause) {
|
|
1557
|
+
if (!record && isIncompatible(cause)) return undefined
|
|
1558
|
+
throw cause
|
|
1559
|
+
}
|
|
1560
|
+
}),
|
|
1561
|
+
)
|
|
1562
|
+
for (const match of discovered) {
|
|
1563
|
+
if (!match || !matchesVaultFilters(match.discovery, options)) continue
|
|
1564
|
+
matches.push(match)
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
position = page.items.at(-1)!.position
|
|
1568
|
+
if (!hasMore) break
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
const page = matches.slice(0, options.limit)
|
|
1572
|
+
const discoveries = page.map(({ discovery }) => discovery)
|
|
1573
|
+
const include = vaultInclude(options)
|
|
1574
|
+
const [apy, rates, tokens] = await Promise.all([
|
|
1575
|
+
resolvePageApy(c, {
|
|
1576
|
+
chainId: options.chainId,
|
|
1577
|
+
discoveries,
|
|
1578
|
+
include,
|
|
1579
|
+
window: options['apy.window'],
|
|
1580
|
+
}),
|
|
1581
|
+
resolvePageRates(c, { discoveries, include, oracle: options.oracle, snapshot }),
|
|
1582
|
+
resolvePageTokens(c, { chainId: options.chainId, discoveries, include, snapshot }),
|
|
1583
|
+
])
|
|
1584
|
+
const data = page.map((match) =>
|
|
1585
|
+
resolveVault(c, { ...match, apy, include, rates, snapshot, tokens }),
|
|
1586
|
+
)
|
|
1587
|
+
const last = matches[options.limit - 1]
|
|
1588
|
+
const nextPosition =
|
|
1589
|
+
matches.length > options.limit ? last?.position : hasMore ? position : undefined
|
|
1590
|
+
return {
|
|
1591
|
+
data,
|
|
1592
|
+
...(rates ? { meta: { valuation: Valuation.pricing(rates, options.oracle) } } : {}),
|
|
1593
|
+
nextCursor: nextPosition ? Cursor.encode(nextPosition) : null,
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
|
|
1597
|
+
export declare namespace listVaults {
|
|
1598
|
+
/** One compatible deployment found while scanning TIDX. */
|
|
1599
|
+
type Match = {
|
|
1600
|
+
discovery: EarnVaults.Discovery
|
|
1601
|
+
position: Position
|
|
1602
|
+
record?: RegistryRecord | undefined
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1605
|
+
/** Options for listing compatible Earn vaults. */
|
|
1606
|
+
type Options = z.output<typeof schema.getEarnVaults.Query> & {
|
|
1607
|
+
chainId: z.output<typeof Schema.ChainId>
|
|
1608
|
+
/** FX rate oracle backing TVL valuation. */
|
|
1609
|
+
oracle: FxOracle.Oracle
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
/** TIDX deployment cursor position. */
|
|
1613
|
+
type Position = [number, number]
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
/** Lists registry-curated Earn vaults. */
|
|
1617
|
+
export async function listVerifiedVaults(
|
|
1618
|
+
c: Context<App.Environment>,
|
|
1619
|
+
options: listVerifiedVaults.Options,
|
|
1620
|
+
) {
|
|
1621
|
+
const db = Db.get(c.get('dbCached'))
|
|
1622
|
+
const [records, snapshot] = await Promise.all([
|
|
1623
|
+
core_EarnVaults.list(db, { chainId: options.chainId }),
|
|
1624
|
+
VerifiedTokens.snapshot(c, options.chainId),
|
|
1625
|
+
])
|
|
1626
|
+
const decoded = options.cursor ? Cursor.decode(options.cursor, ['address']) : undefined
|
|
1627
|
+
const cursor = decoded?.[0]?.toString().toLowerCase()
|
|
1628
|
+
const candidates = records.filter(
|
|
1629
|
+
(record) => !cursor || record.vaultAddress.toLowerCase() > cursor,
|
|
1630
|
+
)
|
|
1631
|
+
const matches: listVerifiedVaults.Match[] = []
|
|
1632
|
+
|
|
1633
|
+
let offset = 0
|
|
1634
|
+
while (offset < candidates.length && matches.length <= options.limit) {
|
|
1635
|
+
const batchSize = discoveryBatchLimit({
|
|
1636
|
+
filtered: options.capability.length > 0 || options['engine.type'] !== undefined,
|
|
1637
|
+
limit: options.limit,
|
|
1638
|
+
matches: matches.length,
|
|
1639
|
+
remaining: candidates.length - offset,
|
|
1640
|
+
})
|
|
1641
|
+
const batch = candidates.slice(offset, offset + batchSize)
|
|
1642
|
+
offset += batch.length
|
|
1643
|
+
const discovered = await Promise.all(
|
|
1644
|
+
batch.map(async (record) => ({
|
|
1645
|
+
discovery: await resolveVaultDiscovery(c, {
|
|
1646
|
+
chainId: options.chainId,
|
|
1647
|
+
include: discoveryInclude(options),
|
|
1648
|
+
vaultAddress: Schema.Address.parse(record.vaultAddress.toLowerCase()),
|
|
1649
|
+
}),
|
|
1650
|
+
record,
|
|
1651
|
+
})),
|
|
1652
|
+
)
|
|
1653
|
+
for (const match of discovered) {
|
|
1654
|
+
if (!matchesVaultFilters(match.discovery, options)) continue
|
|
1655
|
+
matches.push(match)
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1659
|
+
const page = matches.slice(0, options.limit)
|
|
1660
|
+
const discoveries = page.map(({ discovery }) => discovery)
|
|
1661
|
+
const include = vaultInclude(options)
|
|
1662
|
+
const [apy, rates, tokens] = await Promise.all([
|
|
1663
|
+
resolvePageApy(c, {
|
|
1664
|
+
chainId: options.chainId,
|
|
1665
|
+
discoveries,
|
|
1666
|
+
include,
|
|
1667
|
+
window: options['apy.window'],
|
|
1668
|
+
}),
|
|
1669
|
+
resolvePageRates(c, { discoveries, include, oracle: options.oracle, snapshot }),
|
|
1670
|
+
resolvePageTokens(c, { chainId: options.chainId, discoveries, include, snapshot }),
|
|
1671
|
+
])
|
|
1672
|
+
const data = page.map((match) =>
|
|
1673
|
+
Response.validated(
|
|
1674
|
+
schema.VerifiedVault,
|
|
1675
|
+
resolveVault(c, { ...match, apy, include, rates, snapshot, tokens }),
|
|
1676
|
+
),
|
|
1677
|
+
)
|
|
1678
|
+
const last = matches[options.limit - 1]
|
|
1679
|
+
return {
|
|
1680
|
+
data,
|
|
1681
|
+
...(rates ? { meta: { valuation: Valuation.pricing(rates, options.oracle) } } : {}),
|
|
1682
|
+
nextCursor:
|
|
1683
|
+
matches.length > options.limit && last ? Cursor.encode([last.record.vaultAddress]) : null,
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
export declare namespace listVerifiedVaults {
|
|
1688
|
+
/** One verified vault and its current onchain state. */
|
|
1689
|
+
type Match = {
|
|
1690
|
+
discovery: EarnVaults.Discovery
|
|
1691
|
+
record: RegistryRecord
|
|
1692
|
+
}
|
|
1693
|
+
|
|
1694
|
+
/** Options for listing verified Earn vaults. */
|
|
1695
|
+
type Options = z.output<typeof schema.getVerifiedEarnVaults.Query> & {
|
|
1696
|
+
chainId: z.output<typeof Schema.ChainId>
|
|
1697
|
+
/** FX rate oracle backing TVL valuation. */
|
|
1698
|
+
oracle: FxOracle.Oracle
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1702
|
+
/** Gets one compatible Earn vault. */
|
|
1703
|
+
export async function getVault(c: Context<App.Environment>, options: getVault.Options) {
|
|
1704
|
+
const db = Db.get(c.get('dbCached'))
|
|
1705
|
+
const [record, snapshot] = await Promise.all([
|
|
1706
|
+
core_EarnVaults.get(db, {
|
|
1707
|
+
chainId: options.chainId,
|
|
1708
|
+
vaultAddress: options.vaultAddress,
|
|
1709
|
+
}),
|
|
1710
|
+
VerifiedTokens.snapshot(c, options.chainId),
|
|
1711
|
+
])
|
|
1712
|
+
try {
|
|
1713
|
+
const discovery = await resolveVaultDiscovery(c, {
|
|
1714
|
+
chainId: options.chainId,
|
|
1715
|
+
include: discoveryInclude({ capability: [], include: options.include }),
|
|
1716
|
+
vaultAddress: options.vaultAddress,
|
|
1717
|
+
})
|
|
1718
|
+
const discoveries = [discovery]
|
|
1719
|
+
const include = vaultInclude(options)
|
|
1720
|
+
const [apy, rates, tokens] = await Promise.all([
|
|
1721
|
+
resolvePageApy(c, {
|
|
1722
|
+
chainId: options.chainId,
|
|
1723
|
+
discoveries,
|
|
1724
|
+
include,
|
|
1725
|
+
window: options['apy.window'],
|
|
1726
|
+
}),
|
|
1727
|
+
resolvePageRates(c, { discoveries, include, oracle: options.oracle, snapshot }),
|
|
1728
|
+
resolvePageTokens(c, { chainId: options.chainId, discoveries, include, snapshot }),
|
|
1729
|
+
])
|
|
1730
|
+
return {
|
|
1731
|
+
...resolveVault(c, {
|
|
1732
|
+
apy,
|
|
1733
|
+
discovery,
|
|
1734
|
+
include,
|
|
1735
|
+
rates,
|
|
1736
|
+
record,
|
|
1737
|
+
snapshot,
|
|
1738
|
+
tokens,
|
|
1739
|
+
}),
|
|
1740
|
+
...(rates ? { meta: { valuation: Valuation.pricing(rates, options.oracle) } } : {}),
|
|
1741
|
+
}
|
|
1742
|
+
} catch (cause) {
|
|
1743
|
+
if (cause instanceof EarnVaults.NotFoundError || (!record && isIncompatible(cause)))
|
|
1744
|
+
throw new NotFoundError()
|
|
1745
|
+
throw cause
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1749
|
+
export declare namespace getVault {
|
|
1750
|
+
/** Options for getting one Earn vault. */
|
|
1751
|
+
type Options = {
|
|
1752
|
+
/** Canonical rate window the vault's APY covers. */
|
|
1753
|
+
'apy.window': z.output<typeof schema.getEarnVault.Query>['apy.window']
|
|
1754
|
+
chainId: z.output<typeof Schema.ChainId>
|
|
1755
|
+
include: z.output<typeof schema.getEarnVault.Query>['include']
|
|
1756
|
+
/** FX rate oracle backing TVL valuation. */
|
|
1757
|
+
oracle: FxOracle.Oracle
|
|
1758
|
+
vaultAddress: z.output<typeof Schema.Address>
|
|
1759
|
+
}
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1762
|
+
// Selecting a rate window is a request for the rate it measures, mirroring how
|
|
1763
|
+
// a capability filter promotes `capabilities`.
|
|
1764
|
+
function vaultInclude(options: vaultInclude.Options) {
|
|
1765
|
+
const { include } = options
|
|
1766
|
+
if (options['apy.window'] === undefined || include.includes('apy')) return include
|
|
1767
|
+
return [...include, 'apy' as const]
|
|
1768
|
+
}
|
|
1769
|
+
|
|
1770
|
+
declare namespace vaultInclude {
|
|
1771
|
+
type Options = Pick<z.output<typeof schema.getEarnVault.Query>, 'apy.window' | 'include'>
|
|
1772
|
+
}
|
|
1773
|
+
|
|
1774
|
+
function discoveryInclude(
|
|
1775
|
+
options: discoveryInclude.Options,
|
|
1776
|
+
): readonly EarnVaults.resolve.Include[] {
|
|
1777
|
+
const includeCapabilities =
|
|
1778
|
+
options.include.includes('capabilities') ||
|
|
1779
|
+
options.include.includes('zone') ||
|
|
1780
|
+
options.capability.length > 0
|
|
1781
|
+
return [
|
|
1782
|
+
...(options.include.includes('access') ? (['access'] as const) : []),
|
|
1783
|
+
...(includeCapabilities ? (['capabilities'] as const) : []),
|
|
1784
|
+
]
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
declare namespace discoveryInclude {
|
|
1788
|
+
type Options = Pick<z.output<typeof schema.getEarnVaults.Query>, 'capability' | 'include'>
|
|
1789
|
+
}
|
|
1790
|
+
|
|
1791
|
+
async function resolveVaultDiscovery(
|
|
1792
|
+
c: Context<App.Environment>,
|
|
1793
|
+
options: resolveVaultDiscovery.Options,
|
|
1794
|
+
) {
|
|
1795
|
+
return Store.memoize(
|
|
1796
|
+
() =>
|
|
1797
|
+
Timing.time(c, 'earn_vault_discovery', () =>
|
|
1798
|
+
EarnVaults.resolve({
|
|
1799
|
+
getClient: c.get('getClient'),
|
|
1800
|
+
include: options.include,
|
|
1801
|
+
input: {
|
|
1802
|
+
chainId: options.chainId,
|
|
1803
|
+
vaultAddress: options.vaultAddress,
|
|
1804
|
+
},
|
|
1805
|
+
zones: [...c.get('zones').values()],
|
|
1806
|
+
}),
|
|
1807
|
+
),
|
|
1808
|
+
{
|
|
1809
|
+
key: `earn-vault:v3:${options.chainId}:${options.vaultAddress.toLowerCase()}:include:${options.include.join(',') || 'base'}`,
|
|
1810
|
+
store: c.get('store'),
|
|
1811
|
+
// Matches the routes' `state` policy `max-age` so the two cache layers do
|
|
1812
|
+
// not compound staleness on live vault state.
|
|
1813
|
+
ttl: Ttl.seconds(30),
|
|
1814
|
+
},
|
|
1815
|
+
)
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1818
|
+
declare namespace resolveVaultDiscovery {
|
|
1819
|
+
type Options = {
|
|
1820
|
+
chainId: z.output<typeof Schema.ChainId>
|
|
1821
|
+
include: readonly EarnVaults.resolve.Include[]
|
|
1822
|
+
vaultAddress: z.output<typeof Schema.Address>
|
|
1823
|
+
}
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
// Measuring a rate costs indexer boundary queries plus historical quotes against
|
|
1827
|
+
// an archive node, so an unrequested rate reaches neither.
|
|
1828
|
+
function resolvePageApy(c: Context<App.Environment>, options: resolvePageApy.Options) {
|
|
1829
|
+
if (!options.include.includes('apy')) return undefined
|
|
1830
|
+
return Timing.time(c, 'earn_apy', () =>
|
|
1831
|
+
EarnRates.resolve({
|
|
1832
|
+
chainId: options.chainId,
|
|
1833
|
+
getClient: c.get('getClient'),
|
|
1834
|
+
getTidx: c.get('getTidx'),
|
|
1835
|
+
store: c.get('store'),
|
|
1836
|
+
vaults: options.discoveries.map(({ vaultAddress }) => vaultAddress),
|
|
1837
|
+
window: options.window,
|
|
1838
|
+
}),
|
|
1839
|
+
)
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
declare namespace resolvePageApy {
|
|
1843
|
+
type Options = {
|
|
1844
|
+
chainId: z.output<typeof Schema.ChainId>
|
|
1845
|
+
discoveries: readonly EarnVaults.Discovery[]
|
|
1846
|
+
include: z.output<typeof schema.getEarnVault.Query>['include']
|
|
1847
|
+
window: z.output<typeof schema.getEarnVault.Query>['apy.window']
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
|
|
1851
|
+
// The TVL denomination is a fixed constant, not caller input, so a rate set
|
|
1852
|
+
// lacking it leaves `tvl` unpriced instead of failing the whole vault read.
|
|
1853
|
+
function resolvePageRates(c: Context<App.Environment>, options: resolvePageRates.Options) {
|
|
1854
|
+
// Valuing total assets is the only reason this read consults the oracle.
|
|
1855
|
+
if (!options.include.includes('tvl')) return undefined
|
|
1856
|
+
return Valuation.ratesFor(c, {
|
|
1857
|
+
currencies: options.discoveries.flatMap((discovery) => {
|
|
1858
|
+
const currency = options.snapshot.byAddress.get(discovery.assetToken.address)?.currency
|
|
1859
|
+
return currency === undefined ? [] : [currency]
|
|
1860
|
+
}),
|
|
1861
|
+
denomination: tvlDenomination,
|
|
1862
|
+
oracle: options.oracle,
|
|
1863
|
+
}).catch((cause) => {
|
|
1864
|
+
if (cause instanceof Valuation.UnsupportedDenominationError) return undefined
|
|
1865
|
+
throw cause
|
|
1866
|
+
})
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1869
|
+
declare namespace resolvePageRates {
|
|
1870
|
+
type Options = {
|
|
1871
|
+
discoveries: readonly EarnVaults.Discovery[]
|
|
1872
|
+
include: z.output<typeof schema.getEarnVault.Query>['include']
|
|
1873
|
+
oracle: FxOracle.Oracle
|
|
1874
|
+
snapshot: VerifiedTokens.Snapshot
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
|
|
1878
|
+
async function resolvePageTokens(c: Context<App.Environment>, options: resolvePageTokens.Options) {
|
|
1879
|
+
const metadata = new Map(
|
|
1880
|
+
options.discoveries.flatMap(({ assetToken, shareToken }) => [
|
|
1881
|
+
[Schema.Address.parse(assetToken.address.toLowerCase()), assetToken] as const,
|
|
1882
|
+
[Schema.Address.parse(shareToken.address.toLowerCase()), shareToken] as const,
|
|
1883
|
+
]),
|
|
1884
|
+
)
|
|
1885
|
+
return Tokens.resolveTokens(c, {
|
|
1886
|
+
addresses: [...metadata.keys()],
|
|
1887
|
+
chainId: options.chainId,
|
|
1888
|
+
include: [
|
|
1889
|
+
'token.verified',
|
|
1890
|
+
...(options.include.includes('token.logoUri') ? (['token.logoUri'] as const) : []),
|
|
1891
|
+
],
|
|
1892
|
+
metadata,
|
|
1893
|
+
snapshot: options.snapshot,
|
|
1894
|
+
})
|
|
1895
|
+
}
|
|
1896
|
+
|
|
1897
|
+
declare namespace resolvePageTokens {
|
|
1898
|
+
type Options = {
|
|
1899
|
+
chainId: z.output<typeof Schema.ChainId>
|
|
1900
|
+
discoveries: readonly EarnVaults.Discovery[]
|
|
1901
|
+
include: z.output<typeof schema.getEarnVault.Query>['include']
|
|
1902
|
+
snapshot: VerifiedTokens.Snapshot
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1905
|
+
|
|
1906
|
+
function resolveVault(c: Context<App.Environment>, options: resolveVault.Options) {
|
|
1907
|
+
const { discovery, record } = options
|
|
1908
|
+
const valued = options.include.includes('tvl')
|
|
1909
|
+
? Valuation.valuationFor({
|
|
1910
|
+
amount: BigInt(discovery.state.totalAssets),
|
|
1911
|
+
denomination: tvlDenomination,
|
|
1912
|
+
rates: options.rates,
|
|
1913
|
+
token: options.snapshot.byAddress.get(discovery.assetToken.address),
|
|
1914
|
+
})
|
|
1915
|
+
: undefined
|
|
1916
|
+
return serializeVault({
|
|
1917
|
+
apy: options.apy?.get(discovery.vaultAddress) ?? null,
|
|
1918
|
+
assetToken: getToken(options.tokens, discovery.assetToken.address),
|
|
1919
|
+
discovery,
|
|
1920
|
+
include: options.include,
|
|
1921
|
+
record,
|
|
1922
|
+
shareToken: getToken(options.tokens, discovery.shareToken.address),
|
|
1923
|
+
tvl: valued
|
|
1924
|
+
? {
|
|
1925
|
+
amount: core_Value.from(valued.amount, tvlDecimals).toString(),
|
|
1926
|
+
currency: valued.currency,
|
|
1927
|
+
decimals: tvlDecimals,
|
|
1928
|
+
formatted: valued.amount,
|
|
1929
|
+
}
|
|
1930
|
+
: null,
|
|
1931
|
+
zones: [...c.get('zones').values()],
|
|
1932
|
+
})
|
|
1933
|
+
}
|
|
1934
|
+
|
|
1935
|
+
declare namespace resolveVault {
|
|
1936
|
+
type Options = {
|
|
1937
|
+
apy: ReadonlyMap<string, EarnRates.Apy | null> | undefined
|
|
1938
|
+
discovery: EarnVaults.Discovery
|
|
1939
|
+
include: z.output<typeof schema.getEarnVault.Query>['include']
|
|
1940
|
+
rates: Awaited<ReturnType<typeof Valuation.ratesFor>>
|
|
1941
|
+
record?: RegistryRecord | undefined
|
|
1942
|
+
snapshot: VerifiedTokens.Snapshot
|
|
1943
|
+
tokens: Tokens.resolveTokens.ReturnType
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
|
|
1947
|
+
/** Serializes resolved onchain and curated fields into the shared vault contract. */
|
|
1948
|
+
export function serializeVault(options: serializeVault.Options): z.output<typeof schema.Vault> {
|
|
1949
|
+
const { discovery, record } = options
|
|
1950
|
+
if (options.include.includes('access') && !discovery.access)
|
|
1951
|
+
throw new Error('Earn vault access was not resolved.')
|
|
1952
|
+
if (options.include.includes('capabilities') && !discovery.capabilities)
|
|
1953
|
+
throw new Error('Earn vault capabilities were not resolved.')
|
|
1954
|
+
const vaultAddress = Schema.Address.parse(discovery.vaultAddress.toLowerCase())
|
|
1955
|
+
return Response.validated(schema.Vault, {
|
|
1956
|
+
...(options.include.includes('access') ? { access: discovery.access } : {}),
|
|
1957
|
+
...(options.include.includes('apy') ? { apy: options.apy } : {}),
|
|
1958
|
+
assetToken: options.assetToken,
|
|
1959
|
+
...(options.include.includes('capabilities') ? { capabilities: discovery.capabilities } : {}),
|
|
1960
|
+
description: record?.description ?? null,
|
|
1961
|
+
engine: {
|
|
1962
|
+
address: discovery.engine.address.toLowerCase(),
|
|
1963
|
+
type: discovery.engine.type,
|
|
1964
|
+
venue: discovery.engine.venue?.toLowerCase() ?? null,
|
|
1965
|
+
},
|
|
1966
|
+
id: vaultAddress,
|
|
1967
|
+
instantLiquidity: discovery.instantLiquidity,
|
|
1968
|
+
label: record?.label ?? options.shareToken.name,
|
|
1969
|
+
sharePrice:
|
|
1970
|
+
discovery.sharePrice === null
|
|
1971
|
+
? null
|
|
1972
|
+
: {
|
|
1973
|
+
amount: discovery.sharePrice,
|
|
1974
|
+
currency: options.assetToken.currency,
|
|
1975
|
+
decimals: options.assetToken.decimals,
|
|
1976
|
+
formatted: core_Value.format(BigInt(discovery.sharePrice), options.assetToken.decimals),
|
|
1977
|
+
},
|
|
1978
|
+
shareToken: options.shareToken,
|
|
1979
|
+
slug: record?.slug ?? null,
|
|
1980
|
+
state: discovery.state,
|
|
1981
|
+
...(options.include.includes('tvl') ? { tvl: options.tvl } : {}),
|
|
1982
|
+
vaultAddress,
|
|
1983
|
+
verified: record !== undefined,
|
|
1984
|
+
...(options.include.includes('zone')
|
|
1985
|
+
? { zone: record ? resolveZone({ discovery, record, zones: options.zones }) : null }
|
|
1986
|
+
: {}),
|
|
1987
|
+
})
|
|
1988
|
+
}
|
|
1989
|
+
|
|
1990
|
+
export declare namespace serializeVault {
|
|
1991
|
+
/** Values used to serialize one resolved Earn vault. */
|
|
1992
|
+
type Options = {
|
|
1993
|
+
/** Measured rate, or null when unavailable; omitted unless `include` carries `apy`. */
|
|
1994
|
+
apy: EarnRates.Apy | null
|
|
1995
|
+
/** Resolved asset token. */
|
|
1996
|
+
assetToken: z.output<typeof Tokens.schema.Token>
|
|
1997
|
+
/** Live onchain vault state. */
|
|
1998
|
+
discovery: EarnVaults.Discovery
|
|
1999
|
+
/** Optional vault fields selected by the request. */
|
|
2000
|
+
include: z.output<typeof schema.getEarnVault.Query>['include']
|
|
2001
|
+
/** Curated registry row, when verified. */
|
|
2002
|
+
record?: core_EarnVaults.Record | undefined
|
|
2003
|
+
/** Resolved share token. */
|
|
2004
|
+
shareToken: z.output<typeof Tokens.schema.Token>
|
|
2005
|
+
/** USD value of the assets, or null when unpriced; omitted unless `include` carries `tvl`. */
|
|
2006
|
+
tvl: z.output<typeof schema.Vault>['tvl']
|
|
2007
|
+
/** Private Zones available to the vault. */
|
|
2008
|
+
zones: readonly Chain[]
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
|
|
2012
|
+
function resolveZone(options: resolveZone.Options): z.output<typeof schema.Vault.shape.zone> {
|
|
2013
|
+
if (!options.discovery.capabilities?.privateRouting) return null
|
|
2014
|
+
const hasInputs = options.record.privateInputTokens.length > 0
|
|
2015
|
+
const hasOutputs = options.record.privateOutputTokens.length > 0
|
|
2016
|
+
if (!hasInputs && !hasOutputs) return null
|
|
2017
|
+
if (hasInputs !== hasOutputs)
|
|
2018
|
+
throw new Error('Private input and output tokens must both be configured.')
|
|
2019
|
+
|
|
2020
|
+
const configured = options.zones.filter((zone) => zone.sourceId === options.record.chainId)
|
|
2021
|
+
if (configured.length !== 1)
|
|
2022
|
+
throw new Error(`Expected one Earn Zone for chain ${options.record.chainId}.`)
|
|
2023
|
+
const zone = configured[0]!
|
|
2024
|
+
return {
|
|
2025
|
+
chainId: zone.id,
|
|
2026
|
+
inputTokens: options.record.privateInputTokens.map((token) =>
|
|
2027
|
+
Schema.Address.parse(token.toLowerCase()),
|
|
2028
|
+
),
|
|
2029
|
+
name: zone.name,
|
|
2030
|
+
outputTokens: options.record.privateOutputTokens.map((token) =>
|
|
2031
|
+
Schema.Address.parse(token.toLowerCase()),
|
|
2032
|
+
),
|
|
2033
|
+
}
|
|
2034
|
+
}
|
|
2035
|
+
|
|
2036
|
+
declare namespace resolveZone {
|
|
2037
|
+
type Options = {
|
|
2038
|
+
discovery: EarnVaults.Discovery
|
|
2039
|
+
record: RegistryRecord
|
|
2040
|
+
zones: readonly Chain[]
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
2043
|
+
|
|
2044
|
+
function getToken(
|
|
2045
|
+
tokens: Tokens.resolveTokens.ReturnType,
|
|
2046
|
+
address: z.output<typeof Schema.Address>,
|
|
2047
|
+
): z.output<typeof Tokens.schema.Token> {
|
|
2048
|
+
const token = tokens.get(Schema.Address.parse(address.toLowerCase()))
|
|
2049
|
+
if (!token) throw new Error(`Token metadata was not resolved for ${address}.`)
|
|
2050
|
+
return Response.validated(Tokens.schema.Token, token)
|
|
2051
|
+
}
|
|
2052
|
+
|
|
2053
|
+
async function queryDeployments(
|
|
2054
|
+
c: Context<App.Environment>,
|
|
2055
|
+
options: queryDeployments.Options,
|
|
2056
|
+
): Promise<queryDeployments.Result> {
|
|
2057
|
+
const filters = ['deployment_rank = 1']
|
|
2058
|
+
if (options.asset) filters.push(`lower(asset) = '${options.asset.toLowerCase()}'`)
|
|
2059
|
+
if (options.cursor)
|
|
2060
|
+
filters.push(
|
|
2061
|
+
Cursor.keyset([
|
|
2062
|
+
{
|
|
2063
|
+
literal: Cursor.literal(options.cursor[0], 'int'),
|
|
2064
|
+
name: 'block_num',
|
|
2065
|
+
order: 'desc',
|
|
2066
|
+
},
|
|
2067
|
+
{
|
|
2068
|
+
literal: Cursor.literal(options.cursor[1], 'int'),
|
|
2069
|
+
name: 'log_idx',
|
|
2070
|
+
order: 'desc',
|
|
2071
|
+
},
|
|
2072
|
+
]),
|
|
2073
|
+
)
|
|
2074
|
+
|
|
2075
|
+
// ClickHouse supports ordering and windowing over decoded event CTEs.
|
|
2076
|
+
const result = await c
|
|
2077
|
+
.get('getTidx')(options.chainId)
|
|
2078
|
+
.fetch({
|
|
2079
|
+
chainId: options.chainId,
|
|
2080
|
+
engine: 'clickhouse',
|
|
2081
|
+
query: `
|
|
2082
|
+
SELECT "earnVault", asset, block_num, log_idx
|
|
2083
|
+
FROM (
|
|
2084
|
+
SELECT
|
|
2085
|
+
"earnVault",
|
|
2086
|
+
asset,
|
|
2087
|
+
block_num,
|
|
2088
|
+
log_idx,
|
|
2089
|
+
row_number() OVER (
|
|
2090
|
+
PARTITION BY lower("earnVault")
|
|
2091
|
+
ORDER BY block_num DESC, log_idx DESC
|
|
2092
|
+
) AS deployment_rank
|
|
2093
|
+
FROM EarnStackDeployed
|
|
2094
|
+
)
|
|
2095
|
+
WHERE ${filters.join(' AND ')}
|
|
2096
|
+
ORDER BY block_num DESC, log_idx DESC
|
|
2097
|
+
LIMIT ${options.limit + 1}
|
|
2098
|
+
` as string,
|
|
2099
|
+
signatures: [deployedSignature],
|
|
2100
|
+
})
|
|
2101
|
+
|
|
2102
|
+
const rows: readonly Record<string, unknown>[] = result.rows
|
|
2103
|
+
const items = rows.slice(0, options.limit).map((row) => {
|
|
2104
|
+
const vaultAddress = Schema.Address.safeParse(Value.toText(row['earnVault']))
|
|
2105
|
+
const asset = Schema.Address.safeParse(Value.toText(row['asset']))
|
|
2106
|
+
const blockNumber = Value.toNumber(row['block_num'])
|
|
2107
|
+
const logIndex = Value.toNumber(row['log_idx'])
|
|
2108
|
+
if (
|
|
2109
|
+
!vaultAddress.success ||
|
|
2110
|
+
!asset.success ||
|
|
2111
|
+
blockNumber === undefined ||
|
|
2112
|
+
logIndex === undefined
|
|
2113
|
+
)
|
|
2114
|
+
throw new Error('TIDX returned an invalid Earn deployment row.')
|
|
2115
|
+
return {
|
|
2116
|
+
asset: asset.data,
|
|
2117
|
+
position: [blockNumber, logIndex] as queryDeployments.Position,
|
|
2118
|
+
vaultAddress: vaultAddress.data,
|
|
2119
|
+
}
|
|
2120
|
+
})
|
|
2121
|
+
return { hasMore: rows.length > options.limit, items }
|
|
2122
|
+
}
|
|
2123
|
+
|
|
2124
|
+
declare namespace queryDeployments {
|
|
2125
|
+
type Item = {
|
|
2126
|
+
asset: z.output<typeof Schema.Address>
|
|
2127
|
+
position: Position
|
|
2128
|
+
vaultAddress: z.output<typeof Schema.Address>
|
|
2129
|
+
}
|
|
2130
|
+
|
|
2131
|
+
type Options = {
|
|
2132
|
+
asset?: z.output<typeof Schema.Address> | undefined
|
|
2133
|
+
chainId: z.output<typeof Schema.ChainId>
|
|
2134
|
+
cursor?: Position | undefined
|
|
2135
|
+
limit: number
|
|
2136
|
+
}
|
|
2137
|
+
|
|
2138
|
+
type Position = [number, number]
|
|
2139
|
+
|
|
2140
|
+
type Result = {
|
|
2141
|
+
hasMore: boolean
|
|
2142
|
+
items: readonly Item[]
|
|
2143
|
+
}
|
|
2144
|
+
}
|
|
2145
|
+
|
|
2146
|
+
/** Tests live vault state against the shared collection filters. */
|
|
2147
|
+
export function matchesVaultFilters(
|
|
2148
|
+
discovery: EarnVaults.Discovery,
|
|
2149
|
+
options: matchesVaultFilters.Options,
|
|
2150
|
+
): boolean {
|
|
2151
|
+
if (options.asset && discovery.assetToken.address.toLowerCase() !== options.asset.toLowerCase())
|
|
2152
|
+
return false
|
|
2153
|
+
const capabilities = discovery.capabilities
|
|
2154
|
+
if (options.capability.length > 0 && !capabilities)
|
|
2155
|
+
throw new Error('Earn vault capabilities were not resolved.')
|
|
2156
|
+
if (capabilities && !options.capability.every((name) => capabilities[name])) return false
|
|
2157
|
+
if (options['engine.type'] && discovery.engine.type !== options['engine.type']) return false
|
|
2158
|
+
return true
|
|
2159
|
+
}
|
|
2160
|
+
|
|
2161
|
+
export declare namespace matchesVaultFilters {
|
|
2162
|
+
/** Filters shared by the all-vault and verified-vault collections. */
|
|
2163
|
+
type Options = Pick<
|
|
2164
|
+
z.output<typeof schema.getEarnVaults.Query>,
|
|
2165
|
+
'asset' | 'capability' | 'engine.type'
|
|
2166
|
+
>
|
|
2167
|
+
}
|
|
2168
|
+
|
|
2169
|
+
/** Returns whether a failed read proves the address is not a compatible Earn vault. */
|
|
2170
|
+
export function isIncompatible(cause: unknown) {
|
|
2171
|
+
if (cause instanceof EarnVaults.NotFoundError) return true
|
|
2172
|
+
if (cause instanceof EarnVaults.VerificationError) return cause.result.status === 'mismatch'
|
|
2173
|
+
if (!(cause instanceof ContractFunctionExecutionError)) return false
|
|
2174
|
+
return Boolean(
|
|
2175
|
+
cause.walk(
|
|
2176
|
+
(error) =>
|
|
2177
|
+
error instanceof ContractFunctionRevertedError ||
|
|
2178
|
+
error instanceof ContractFunctionZeroDataError,
|
|
2179
|
+
),
|
|
2180
|
+
)
|
|
2181
|
+
}
|
|
2182
|
+
|
|
2183
|
+
type RegistryRecord = Awaited<ReturnType<typeof core_EarnVaults.list>>[number]
|
|
2184
|
+
|
|
2185
|
+
/** Thrown when no compatible Earn vault exists at the requested address. */
|
|
2186
|
+
export class NotFoundError extends Error {
|
|
2187
|
+
override name = 'Earn.NotFoundError'
|
|
2188
|
+
}
|