tapimo 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/App.d.ts +2296 -1010
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js +2 -2
- package/dist/App.js.map +1 -1
- package/dist/Assets.d.ts +15 -0
- package/dist/Assets.d.ts.map +1 -1
- package/dist/Assets.js +7 -0
- package/dist/Assets.js.map +1 -1
- package/dist/admin/App.d.ts +53 -4
- package/dist/admin/App.d.ts.map +1 -1
- package/dist/admin/apps/api-keys.d.ts +4 -4
- package/dist/admin/apps/earn-vaults.d.ts +114 -0
- package/dist/admin/apps/earn-vaults.d.ts.map +1 -1
- package/dist/admin/apps/earn-vaults.js +59 -6
- package/dist/admin/apps/earn-vaults.js.map +1 -1
- package/dist/admin/apps/organizations.d.ts.map +1 -1
- package/dist/admin/apps/organizations.js +4 -2
- package/dist/admin/apps/organizations.js.map +1 -1
- package/dist/admin/apps/verified-tokens.d.ts +9 -9
- package/dist/admin/ui.generated.d.ts +1 -1
- package/dist/admin/ui.generated.d.ts.map +1 -1
- package/dist/admin/ui.generated.js +151 -151
- package/dist/admin/ui.generated.js.map +1 -1
- package/dist/apps/data/App.d.ts +1699 -749
- package/dist/apps/data/App.d.ts.map +1 -1
- package/dist/apps/data/App.js +56 -7
- package/dist/apps/data/App.js.map +1 -1
- package/dist/apps/data/ZoneSelection.d.ts +62 -0
- package/dist/apps/data/ZoneSelection.d.ts.map +1 -0
- package/dist/apps/data/ZoneSelection.js +44 -0
- package/dist/apps/data/ZoneSelection.js.map +1 -0
- package/dist/apps/data/routes/activities.d.ts +2367 -4
- package/dist/apps/data/routes/activities.d.ts.map +1 -1
- package/dist/apps/data/routes/activities.js +368 -87
- package/dist/apps/data/routes/activities.js.map +1 -1
- package/dist/apps/data/routes/addresses.d.ts +471 -340
- package/dist/apps/data/routes/addresses.d.ts.map +1 -1
- package/dist/apps/data/routes/balances.d.ts +28 -28
- package/dist/apps/data/routes/balances.js +1 -1
- package/dist/apps/data/routes/balances.js.map +1 -1
- package/dist/apps/data/routes/blocks.d.ts +4 -4
- package/dist/apps/data/routes/blocks.js +1 -1
- package/dist/apps/data/routes/blocks.js.map +1 -1
- package/dist/apps/data/routes/coingecko.d.ts +176 -176
- package/dist/apps/data/routes/earn.d.ts +131 -6
- package/dist/apps/data/routes/earn.d.ts.map +1 -1
- package/dist/apps/data/routes/earn.js +157 -25
- package/dist/apps/data/routes/earn.js.map +1 -1
- package/dist/apps/data/routes/exchanges.d.ts +825 -119
- package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
- package/dist/apps/data/routes/exchanges.js +16 -13
- package/dist/apps/data/routes/exchanges.js.map +1 -1
- package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
- package/dist/apps/data/routes/fee-amm.js +9 -11
- package/dist/apps/data/routes/fee-amm.js.map +1 -1
- package/dist/apps/data/routes/indexer.d.ts +34 -34
- package/dist/apps/data/routes/receipts.d.ts +230 -230
- package/dist/apps/data/routes/receipts.js +1 -1
- package/dist/apps/data/routes/receipts.js.map +1 -1
- package/dist/apps/data/routes/rpc.js +24 -10
- package/dist/apps/data/routes/rpc.js.map +1 -1
- package/dist/apps/data/routes/tokenlist.d.ts.map +1 -1
- package/dist/apps/data/routes/tokenlist.js +16 -15
- package/dist/apps/data/routes/tokenlist.js.map +1 -1
- package/dist/apps/data/routes/tokens.d.ts +14 -0
- package/dist/apps/data/routes/tokens.d.ts.map +1 -1
- package/dist/apps/data/routes/tokens.js +34 -15
- package/dist/apps/data/routes/tokens.js.map +1 -1
- package/dist/apps/data/routes/transactions.js +1 -1
- package/dist/apps/data/routes/transactions.js.map +1 -1
- package/dist/apps/data/routes/transfers.d.ts.map +1 -1
- package/dist/apps/data/routes/transfers.js +7 -9
- package/dist/apps/data/routes/transfers.js.map +1 -1
- package/dist/apps/data/routes/webhooks.d.ts +4 -4
- package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
- package/dist/apps/data/routes/webhooks.js +2 -2
- package/dist/apps/data/routes/webhooks.js.map +1 -1
- package/dist/apps/data/routes/zones.d.ts +30 -30
- package/dist/apps/funding/App.d.ts +27 -27
- package/dist/apps/funding/routes/chains.d.ts.map +1 -1
- package/dist/apps/funding/routes/chains.js +5 -4
- package/dist/apps/funding/routes/chains.js.map +1 -1
- package/dist/apps/funding/routes/deposit-addresses.d.ts +16 -16
- package/dist/apps/funding/routes/deposit-addresses.d.ts.map +1 -1
- package/dist/apps/funding/routes/deposit-addresses.js +8 -8
- package/dist/apps/funding/routes/deposit-addresses.js.map +1 -1
- package/dist/apps/funding/routes/providers.d.ts +13 -13
- package/dist/apps/funding/routes/providers.d.ts.map +1 -1
- package/dist/apps/funding/routes/providers.js +3 -2
- package/dist/apps/funding/routes/providers.js.map +1 -1
- package/dist/apps/funding/routes/quotes.d.ts.map +1 -1
- package/dist/apps/funding/routes/quotes.js +2 -2
- package/dist/apps/funding/routes/quotes.js.map +1 -1
- package/dist/apps/management/App.d.ts +627 -293
- package/dist/apps/management/App.d.ts.map +1 -1
- package/dist/apps/management/Billing.d.ts.map +1 -1
- package/dist/apps/management/Billing.js +19 -6
- package/dist/apps/management/Billing.js.map +1 -1
- package/dist/apps/management/routes/api-keys.d.ts +114 -54
- package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
- package/dist/apps/management/routes/api-keys.js +76 -30
- package/dist/apps/management/routes/api-keys.js.map +1 -1
- package/dist/apps/management/routes/billing.d.ts +103 -30
- package/dist/apps/management/routes/billing.d.ts.map +1 -1
- package/dist/apps/management/routes/billing.js +91 -32
- package/dist/apps/management/routes/billing.js.map +1 -1
- package/dist/apps/management/routes/faucet.d.ts +33 -33
- package/dist/apps/management/routes/faucet.d.ts.map +1 -1
- package/dist/apps/management/routes/faucet.js +23 -12
- package/dist/apps/management/routes/faucet.js.map +1 -1
- package/dist/apps/management/routes/invitations.d.ts +46 -13
- package/dist/apps/management/routes/invitations.d.ts.map +1 -1
- package/dist/apps/management/routes/invitations.js +79 -29
- package/dist/apps/management/routes/invitations.js.map +1 -1
- package/dist/apps/management/routes/invite-links.d.ts +86 -41
- package/dist/apps/management/routes/invite-links.d.ts.map +1 -1
- package/dist/apps/management/routes/invite-links.js +100 -41
- package/dist/apps/management/routes/invite-links.js.map +1 -1
- package/dist/apps/management/routes/me.d.ts +5 -5
- package/dist/apps/management/routes/me.d.ts.map +1 -1
- package/dist/apps/management/routes/me.js +14 -10
- package/dist/apps/management/routes/me.js.map +1 -1
- package/dist/apps/management/routes/members.d.ts +93 -72
- package/dist/apps/management/routes/members.d.ts.map +1 -1
- package/dist/apps/management/routes/members.js +37 -18
- package/dist/apps/management/routes/members.js.map +1 -1
- package/dist/apps/management/routes/orgs.d.ts +48 -8
- package/dist/apps/management/routes/orgs.d.ts.map +1 -1
- package/dist/apps/management/routes/orgs.js +48 -19
- package/dist/apps/management/routes/orgs.js.map +1 -1
- package/dist/apps/management/routes/projects.d.ts +90 -28
- package/dist/apps/management/routes/projects.d.ts.map +1 -1
- package/dist/apps/management/routes/projects.js +72 -21
- package/dist/apps/management/routes/projects.js.map +1 -1
- package/dist/apps/management/routes/scopes.d.ts.map +1 -1
- package/dist/apps/management/routes/scopes.js +8 -5
- package/dist/apps/management/routes/scopes.js.map +1 -1
- package/dist/apps/management/routes/usage.d.ts +78 -78
- package/dist/apps/management/routes/usage.d.ts.map +1 -1
- package/dist/apps/management/routes/usage.js +41 -31
- package/dist/apps/management/routes/usage.js.map +1 -1
- package/dist/apps/management/routes/verified-token-requests.d.ts +34 -6
- package/dist/apps/management/routes/verified-token-requests.d.ts.map +1 -1
- package/dist/apps/management/routes/verified-token-requests.js +36 -17
- package/dist/apps/management/routes/verified-token-requests.js.map +1 -1
- package/dist/apps/management/routes/webhooks.d.ts +147 -130
- package/dist/apps/management/routes/webhooks.d.ts.map +1 -1
- package/dist/apps/management/routes/webhooks.js +80 -35
- package/dist/apps/management/routes/webhooks.js.map +1 -1
- package/dist/apps/mpp/internal/Adapter.d.ts +1 -1
- package/dist/apps/mpp/internal/Adapter.d.ts.map +1 -1
- package/dist/apps/mpp/internal/Adapter.js +12 -0
- package/dist/apps/mpp/internal/Adapter.js.map +1 -1
- package/dist/db/Db.d.ts +2 -0
- package/dist/db/Db.d.ts.map +1 -1
- package/dist/db/Db.js +40 -0
- package/dist/db/Db.js.map +1 -1
- package/dist/db/Schema.d.ts +23 -1
- package/dist/db/Schema.d.ts.map +1 -1
- package/dist/db/Schema.js +19 -3
- package/dist/db/Schema.js.map +1 -1
- package/dist/db/tables/earnVaults.d.ts +5 -1
- package/dist/db/tables/earnVaults.d.ts.map +1 -1
- package/dist/db/tables/earnVaults.js +5 -0
- package/dist/db/tables/earnVaults.js.map +1 -1
- package/dist/db/tables/webhookDeliveries.d.ts.map +1 -1
- package/dist/db/tables/webhookDeliveries.js +10 -0
- package/dist/db/tables/webhookDeliveries.js.map +1 -1
- package/dist/db/tables/webhookQueueCompletions.d.ts +15 -0
- package/dist/db/tables/webhookQueueCompletions.d.ts.map +1 -0
- package/dist/db/tables/webhookQueueCompletions.js +32 -0
- package/dist/db/tables/webhookQueueCompletions.js.map +1 -0
- package/dist/db/tables/webhookQueueEvents.d.ts +14 -20
- package/dist/db/tables/webhookQueueEvents.d.ts.map +1 -1
- package/dist/db/tables/webhookQueueEvents.js +68 -47
- package/dist/db/tables/webhookQueueEvents.js.map +1 -1
- package/dist/db/tables/webhookSubscriptions.d.ts +16 -5
- package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
- package/dist/db/tables/webhookSubscriptions.js +29 -5
- package/dist/db/tables/webhookSubscriptions.js.map +1 -1
- package/dist/internal/Auth.d.ts +8 -1
- package/dist/internal/Auth.d.ts.map +1 -1
- package/dist/internal/Auth.js +13 -3
- package/dist/internal/Auth.js.map +1 -1
- package/dist/internal/Cache.d.ts.map +1 -1
- package/dist/internal/Cache.js +11 -7
- package/dist/internal/Cache.js.map +1 -1
- package/dist/internal/EarnVaults.d.ts +41 -2
- package/dist/internal/EarnVaults.d.ts.map +1 -1
- package/dist/internal/EarnVaults.js +167 -0
- package/dist/internal/EarnVaults.js.map +1 -1
- package/dist/internal/OpenApi.d.ts +26 -22
- package/dist/internal/OpenApi.d.ts.map +1 -1
- package/dist/internal/OpenApi.js +128 -39
- package/dist/internal/OpenApi.js.map +1 -1
- package/dist/internal/Response.d.ts +13 -8
- package/dist/internal/Response.d.ts.map +1 -1
- package/dist/internal/Response.js +16 -5
- package/dist/internal/Response.js.map +1 -1
- package/dist/internal/Schema.d.ts +5 -7
- package/dist/internal/Schema.d.ts.map +1 -1
- package/dist/internal/Schema.js +6 -7
- package/dist/internal/Schema.js.map +1 -1
- package/dist/internal/Store.d.ts +15 -6
- package/dist/internal/Store.d.ts.map +1 -1
- package/dist/internal/Store.js +45 -15
- package/dist/internal/Store.js.map +1 -1
- package/dist/internal/Tidx.d.ts +2 -0
- package/dist/internal/Tidx.d.ts.map +1 -1
- package/dist/internal/Tidx.js +16 -4
- package/dist/internal/Tidx.js.map +1 -1
- package/dist/internal/Webhooks.d.ts +29 -12
- package/dist/internal/Webhooks.d.ts.map +1 -1
- package/dist/internal/Webhooks.js +37 -20
- package/dist/internal/Webhooks.js.map +1 -1
- package/dist/internal/funding/Deposit.d.ts +2 -2
- package/dist/internal/funding/Deposit.d.ts.map +1 -1
- package/dist/internal/funding/Deposit.js +9 -8
- package/dist/internal/funding/Deposit.js.map +1 -1
- package/dist/internal/funding/DepositAddress.d.ts +4 -4
- package/dist/internal/funding/DepositAddress.d.ts.map +1 -1
- package/dist/internal/funding/DepositAddress.js +9 -8
- package/dist/internal/funding/DepositAddress.js.map +1 -1
- package/dist/internal/funding/Provider.d.ts.map +1 -1
- package/dist/internal/funding/Provider.js +13 -12
- package/dist/internal/funding/Provider.js.map +1 -1
- package/dist/internal/funding/providers/stargate.d.ts +19 -0
- package/dist/internal/funding/providers/stargate.d.ts.map +1 -0
- package/dist/internal/funding/providers/stargate.js +143 -0
- package/dist/internal/funding/providers/stargate.js.map +1 -0
- package/dist/providers/index.d.ts +7 -0
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +3 -0
- package/dist/providers/index.js.map +1 -1
- package/package.json +2 -2
- package/src/App.test.ts +48 -0
- package/src/App.ts +4 -2
- package/src/Assets.test.ts +18 -0
- package/src/Assets.ts +22 -0
- package/src/Client.test-d.ts +265 -16
- package/src/admin/apps/earn-vaults.test.ts +143 -0
- package/src/admin/apps/earn-vaults.ts +83 -6
- package/src/admin/apps/organizations.ts +6 -2
- package/src/admin/ui/src/routes/api-keys.tsx +36 -0
- package/src/admin/ui.generated.ts +151 -189
- package/src/apps/data/App.test.ts +31 -0
- package/src/apps/data/App.ts +56 -8
- package/src/apps/data/ZoneSelection.test.ts +196 -0
- package/src/apps/data/ZoneSelection.ts +108 -0
- package/src/apps/data/routes/activities.test.ts +328 -1
- package/src/apps/data/routes/activities.ts +498 -93
- package/src/apps/data/routes/balances.ts +1 -1
- package/src/apps/data/routes/blocks.ts +1 -1
- package/src/apps/data/routes/earn.test.ts +183 -23
- package/src/apps/data/routes/earn.ts +225 -29
- package/src/apps/data/routes/earn.zone-access.test.ts +46 -0
- package/src/apps/data/routes/exchanges.test.ts +31 -1
- package/src/apps/data/routes/exchanges.ts +19 -15
- package/src/apps/data/routes/fee-amm.ts +18 -11
- package/src/apps/data/routes/receipts.ts +1 -1
- package/src/apps/data/routes/rpc.test.ts +75 -0
- package/src/apps/data/routes/rpc.ts +23 -9
- package/src/apps/data/routes/tokenlist.ts +21 -18
- package/src/apps/data/routes/tokens.test.ts +29 -0
- package/src/apps/data/routes/tokens.ts +38 -15
- package/src/apps/data/routes/transactions.ts +1 -1
- package/src/apps/data/routes/transfers.test.ts +3 -3
- package/src/apps/data/routes/transfers.ts +12 -9
- package/src/apps/data/routes/webhooks.ts +6 -2
- package/src/apps/data/routes/zones.test.ts +19 -13
- package/src/apps/funding/routes/chains.test.ts +211 -7
- package/src/apps/funding/routes/chains.ts +19 -12
- package/src/apps/funding/routes/deposit-addresses.test.ts +394 -0
- package/src/apps/funding/routes/deposit-addresses.ts +84 -72
- package/src/apps/funding/routes/providers.ts +9 -5
- package/src/apps/funding/routes/quotes.test.ts +46 -0
- package/src/apps/funding/routes/quotes.ts +8 -5
- package/src/apps/funding/routes/transfers.test.ts +35 -32
- package/src/apps/management/Billing.test.ts +26 -0
- package/src/apps/management/Billing.ts +24 -7
- package/src/apps/management/routes/api-keys.test.ts +178 -0
- package/src/apps/management/routes/api-keys.ts +203 -144
- package/src/apps/management/routes/billing.test.ts +209 -0
- package/src/apps/management/routes/billing.ts +254 -177
- package/src/apps/management/routes/faucet.test.ts +39 -0
- package/src/apps/management/routes/faucet.ts +75 -41
- package/src/apps/management/routes/invitations.test.ts +216 -0
- package/src/apps/management/routes/invitations.ts +186 -109
- package/src/apps/management/routes/invite-links.test.ts +263 -1
- package/src/apps/management/routes/invite-links.ts +295 -214
- package/src/apps/management/routes/me.test.ts +49 -0
- package/src/apps/management/routes/me.ts +42 -32
- package/src/apps/management/routes/members.test.ts +124 -1
- package/src/apps/management/routes/members.ts +81 -51
- package/src/apps/management/routes/orgs.test.ts +176 -0
- package/src/apps/management/routes/orgs.ts +101 -59
- package/src/apps/management/routes/projects.test.ts +183 -0
- package/src/apps/management/routes/projects.ts +124 -60
- package/src/apps/management/routes/scopes.test.ts +44 -0
- package/src/apps/management/routes/scopes.ts +37 -28
- package/src/apps/management/routes/usage.test.ts +92 -0
- package/src/apps/management/routes/usage.ts +186 -151
- package/src/apps/management/routes/verified-token-requests.test.ts +114 -0
- package/src/apps/management/routes/verified-token-requests.ts +166 -133
- package/src/apps/management/routes/webhooks.test.ts +234 -0
- package/src/apps/management/routes/webhooks.ts +191 -78
- package/src/apps/mpp/internal/Adapter.ts +13 -1
- package/src/db/Db.test.ts +41 -0
- package/src/db/Db.ts +62 -0
- package/src/db/Schema.ts +28 -3
- package/src/db/tables/earnVaults.test.ts +22 -0
- package/src/db/tables/earnVaults.ts +11 -1
- package/src/db/tables/webhookDeliveries.ts +13 -0
- package/src/db/tables/webhookQueueCompletions.ts +55 -0
- package/src/db/tables/webhookQueueEvents.ts +95 -61
- package/src/db/tables/webhookSubscriptions.ts +45 -6
- package/src/internal/Auth.ts +23 -5
- package/src/internal/Cache.ts +14 -7
- package/src/internal/EarnVaults.capabilities.test.ts +33 -0
- package/src/internal/EarnVaults.test.ts +79 -0
- package/src/internal/EarnVaults.ts +277 -0
- package/src/internal/OpenApi.ts +165 -49
- package/src/internal/Response.test.ts +95 -0
- package/src/internal/Response.ts +40 -2
- package/src/internal/Schema.test.ts +16 -0
- package/src/internal/Schema.ts +7 -7
- package/src/internal/Store.test.ts +186 -0
- package/src/internal/Store.ts +57 -17
- package/src/internal/Tidx.test.ts +19 -0
- package/src/internal/Tidx.ts +16 -4
- package/src/internal/Webhooks.test.ts +122 -8
- package/src/internal/Webhooks.ts +59 -29
- package/src/internal/funding/Deposit.ts +71 -64
- package/src/internal/funding/DepositAddress.ts +50 -43
- package/src/internal/funding/Provider.ts +164 -142
- package/src/internal/funding/providers/index.test.ts +185 -0
- package/src/internal/funding/providers/stargate.ts +184 -0
- package/src/providers/index.test.ts +1 -0
- package/src/providers/index.ts +9 -0
|
@@ -22,6 +22,7 @@ import * as Ttl from '../../../internal/Ttl.js'
|
|
|
22
22
|
import * as Value from '../../../internal/Value.js'
|
|
23
23
|
import * as VerifiedTokens from '../../../internal/VerifiedTokens.js'
|
|
24
24
|
import * as FxOracle from '../FxOracle.js'
|
|
25
|
+
import * as ZoneSelection from '../ZoneSelection.js'
|
|
25
26
|
import * as Tokens from './tokens.js'
|
|
26
27
|
import * as Transfers from './transfers.js'
|
|
27
28
|
import * as Valuation from './valuation.js'
|
|
@@ -29,7 +30,7 @@ import * as Valuation from './valuation.js'
|
|
|
29
30
|
/** Example transaction hash surfaced in OpenAPI docs. */
|
|
30
31
|
const exampleHash = '0x4845ae2098724ab26a5d89370dce5124d044be6a5acc164afc348662de67d474'
|
|
31
32
|
|
|
32
|
-
const
|
|
33
|
+
const includeFields = ['token.logoUri', 'token.verified', 'zones'] as const
|
|
33
34
|
|
|
34
35
|
// TIP-20 tokens live at deterministic `0x20c0…` addresses. Other contracts
|
|
35
36
|
// can emit the same `Transfer` signature but do not expose TIP-20 metadata.
|
|
@@ -202,6 +203,12 @@ export namespace schema {
|
|
|
202
203
|
* transfer's `direction`/`memo`/`attribution`/`signer`) the resource lacks.
|
|
203
204
|
*/
|
|
204
205
|
const base = {
|
|
206
|
+
chainId: z
|
|
207
|
+
.optional(Schema.ChainId)
|
|
208
|
+
.check(
|
|
209
|
+
z.describe('Chain id containing this activity. Returned for multi-Zone requests.'),
|
|
210
|
+
z.meta({ examples: [421700001] }),
|
|
211
|
+
),
|
|
205
212
|
perspective: z
|
|
206
213
|
.enum(['incoming', 'outgoing'])
|
|
207
214
|
.check(
|
|
@@ -989,9 +996,7 @@ export namespace schema {
|
|
|
989
996
|
logoUri: z.string().check(
|
|
990
997
|
z.describe('New logo URL for the token.'),
|
|
991
998
|
z.meta({
|
|
992
|
-
examples: [
|
|
993
|
-
'https://api.tempo.xyz/data/4217/icons/0x20c0000000000000000000008f5425160ebe5525.svg',
|
|
994
|
-
],
|
|
999
|
+
examples: [Tokens.tokenExample.logoUri],
|
|
995
1000
|
}),
|
|
996
1001
|
),
|
|
997
1002
|
signer: Signer,
|
|
@@ -1482,6 +1487,12 @@ export namespace schema {
|
|
|
1482
1487
|
/** A folded access-key group: consecutive same-signer items on one UTC day. */
|
|
1483
1488
|
export const Group = z
|
|
1484
1489
|
.object({
|
|
1490
|
+
chainId: z
|
|
1491
|
+
.optional(Schema.ChainId)
|
|
1492
|
+
.check(
|
|
1493
|
+
z.describe('Chain id containing this activity group. Returned for multi-Zone requests.'),
|
|
1494
|
+
z.meta({ examples: [421700001] }),
|
|
1495
|
+
),
|
|
1485
1496
|
data: z
|
|
1486
1497
|
.object({
|
|
1487
1498
|
items: z.array(Item).check(z.describe('Activity items included in this group.')),
|
|
@@ -1523,15 +1534,15 @@ export namespace schema {
|
|
|
1523
1534
|
.union([...items, Group])
|
|
1524
1535
|
.check(z.describe('Either one activity item, or a grouped set of access-key activity items.'))
|
|
1525
1536
|
|
|
1526
|
-
/** Optional
|
|
1537
|
+
/** Optional activity resources and selection modes. */
|
|
1527
1538
|
export const Include = z
|
|
1528
|
-
.enum(
|
|
1529
|
-
.check(z.describe('Additional
|
|
1539
|
+
.enum(includeFields)
|
|
1540
|
+
.check(z.describe('Additional activity resources and selection modes to include.'))
|
|
1530
1541
|
|
|
1531
|
-
/** Parses comma-separated optional
|
|
1542
|
+
/** Parses comma-separated optional activity resources and selection modes. */
|
|
1532
1543
|
export const includeQuery = Schema.includeQuery(
|
|
1533
1544
|
Include,
|
|
1534
|
-
'Comma-separated
|
|
1545
|
+
'Comma-separated activity options, such as `zones,token.logoUri,token.verified`.',
|
|
1535
1546
|
)
|
|
1536
1547
|
|
|
1537
1548
|
/** Schemas for the getAddressActivities operation. */
|
|
@@ -1636,6 +1647,10 @@ export namespace schema {
|
|
|
1636
1647
|
*/
|
|
1637
1648
|
export const Response = z
|
|
1638
1649
|
.object({
|
|
1650
|
+
chainId: Schema.ChainId.check(
|
|
1651
|
+
z.describe('Chain id containing the transaction.'),
|
|
1652
|
+
z.meta({ examples: [4217] }),
|
|
1653
|
+
),
|
|
1639
1654
|
data: z.array(Item).check(z.describe('Activity items classified from the transaction.')),
|
|
1640
1655
|
meta: z
|
|
1641
1656
|
.optional(schema.Meta)
|
|
@@ -1991,7 +2006,7 @@ export function addresses(options: addresses.Options = {}) {
|
|
|
1991
2006
|
tags: ['Activities'],
|
|
1992
2007
|
}),
|
|
1993
2008
|
Cache.response<App.Environment>({
|
|
1994
|
-
cacheControl: Cache.policies.
|
|
2009
|
+
cacheControl: Cache.policies.noStore,
|
|
1995
2010
|
name: 'tempo-api:addresses:v1',
|
|
1996
2011
|
key: (c) => Cache.urlKey(c, schema.getAddressActivities.Query),
|
|
1997
2012
|
}),
|
|
@@ -2011,19 +2026,19 @@ export function addresses(options: addresses.Options = {}) {
|
|
|
2011
2026
|
const { address } = c.req.valid('param')
|
|
2012
2027
|
const query = c.req.valid('query')
|
|
2013
2028
|
|
|
2014
|
-
|
|
2015
|
-
|
|
2029
|
+
if (!query.include.includes('zones'))
|
|
2030
|
+
Cache.setPolicy(
|
|
2031
|
+
c,
|
|
2032
|
+
query.cursor === undefined ? Cache.policies.feed : Cache.policies.metadata,
|
|
2033
|
+
)
|
|
2016
2034
|
|
|
2017
2035
|
try {
|
|
2018
2036
|
const chainId = query.chainId ?? c.get('chainId')
|
|
2019
|
-
const
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
'address_activities',
|
|
2023
|
-
() =>
|
|
2024
|
-
Store.memoize(
|
|
2037
|
+
const listed = await Timing.time(c, 'address_activities', async () => {
|
|
2038
|
+
if (!query.include.includes('zones')) {
|
|
2039
|
+
const result = await Store.memoize(
|
|
2025
2040
|
() =>
|
|
2026
|
-
list(
|
|
2041
|
+
list(tidx({ chainId, tidx: c.get('getTidx')(chainId) }), {
|
|
2027
2042
|
address: address as Hex.Hex,
|
|
2028
2043
|
cursor: query.cursor,
|
|
2029
2044
|
group: query.group,
|
|
@@ -2036,18 +2051,54 @@ export function addresses(options: addresses.Options = {}) {
|
|
|
2036
2051
|
store: c.get('store'),
|
|
2037
2052
|
ttl: Ttl.seconds(15),
|
|
2038
2053
|
},
|
|
2039
|
-
)
|
|
2040
|
-
|
|
2054
|
+
)
|
|
2055
|
+
return { chainId, kind: 'chain' as const, ...result }
|
|
2056
|
+
}
|
|
2041
2057
|
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2058
|
+
const zoneChainIds = c.get('zoneChainIds')
|
|
2059
|
+
if (!zoneChainIds) throw new Error('Inferred Zone selection was not resolved.')
|
|
2060
|
+
const result = await Store.memoize(
|
|
2061
|
+
() =>
|
|
2062
|
+
listZones({
|
|
2063
|
+
address: address as Hex.Hex,
|
|
2064
|
+
cursor: query.cursor,
|
|
2065
|
+
group: query.group,
|
|
2066
|
+
limit: query.limit,
|
|
2067
|
+
logs: query.logs,
|
|
2068
|
+
providers: zoneChainIds.map((zoneChainId) => ({
|
|
2069
|
+
chainId: zoneChainId,
|
|
2070
|
+
provider: tidx({
|
|
2071
|
+
chainId: zoneChainId,
|
|
2072
|
+
tidx: c.get('getTidx')(zoneChainId),
|
|
2073
|
+
}),
|
|
2074
|
+
})),
|
|
2075
|
+
store: c.get('store'),
|
|
2076
|
+
}),
|
|
2077
|
+
{
|
|
2078
|
+
key: `activities:zones:v1:${zoneChainIds.join(',')}:${address.toLowerCase()}:${query.group ?? false}:${query.logs ?? false}:${query.cursor ?? 'head'}:${query.limit}`,
|
|
2079
|
+
store: c.get('store'),
|
|
2080
|
+
ttl: Ttl.seconds(15),
|
|
2081
|
+
},
|
|
2082
|
+
)
|
|
2083
|
+
return { kind: 'zones' as const, ...result }
|
|
2049
2084
|
})
|
|
2050
2085
|
|
|
2086
|
+
const { items, rates } =
|
|
2087
|
+
listed.kind === 'zones'
|
|
2088
|
+
? await enrichZoneTokens(c, {
|
|
2089
|
+
denomination: query['valuation.currency'],
|
|
2090
|
+
include: query.include,
|
|
2091
|
+
items: listed.items,
|
|
2092
|
+
oracle,
|
|
2093
|
+
})
|
|
2094
|
+
: await enrichTokens(c, {
|
|
2095
|
+
chainId: listed.chainId,
|
|
2096
|
+
denomination: query['valuation.currency'],
|
|
2097
|
+
include: query.include,
|
|
2098
|
+
items: listed.items,
|
|
2099
|
+
oracle,
|
|
2100
|
+
})
|
|
2101
|
+
|
|
2051
2102
|
// Fold consecutive access-key-signed items into `group` entries only
|
|
2052
2103
|
// when requested; otherwise every item is returned at the root.
|
|
2053
2104
|
const data = query.group ? groupByAccessKey(items) : items
|
|
@@ -2056,7 +2107,7 @@ export function addresses(options: addresses.Options = {}) {
|
|
|
2056
2107
|
Response.validated(schema.getAddressActivities.Response, {
|
|
2057
2108
|
data,
|
|
2058
2109
|
...(rates ? { meta: { valuation: Valuation.pricing(rates, oracle) } } : {}),
|
|
2059
|
-
nextCursor,
|
|
2110
|
+
nextCursor: listed.nextCursor,
|
|
2060
2111
|
}),
|
|
2061
2112
|
200,
|
|
2062
2113
|
)
|
|
@@ -2110,6 +2161,10 @@ export function transactions(options: transactions.Options = {}) {
|
|
|
2110
2161
|
description: 'No mined transaction was found for that hash.',
|
|
2111
2162
|
codes: ['transaction_not_found'],
|
|
2112
2163
|
},
|
|
2164
|
+
409: {
|
|
2165
|
+
description: 'More than one readable Zone contains that transaction hash.',
|
|
2166
|
+
codes: ['transaction_ambiguous'],
|
|
2167
|
+
},
|
|
2113
2168
|
502: 'Tempo could not read activity or token data from an upstream service.',
|
|
2114
2169
|
},
|
|
2115
2170
|
success: {
|
|
@@ -2142,48 +2197,123 @@ export function transactions(options: transactions.Options = {}) {
|
|
|
2142
2197
|
|
|
2143
2198
|
const { transactionHash } = c.req.valid('param')
|
|
2144
2199
|
const query = c.req.valid('query')
|
|
2145
|
-
const chainId = query.chainId ?? c.get('chainId')
|
|
2146
2200
|
|
|
2147
2201
|
try {
|
|
2148
|
-
const
|
|
2149
|
-
|
|
2150
|
-
()
|
|
2151
|
-
|
|
2152
|
-
chainId,
|
|
2153
|
-
|
|
2202
|
+
const result = await Timing.time(c, 'transaction_activities', async () => {
|
|
2203
|
+
const selected = await (async () => {
|
|
2204
|
+
if (!query.include.includes('zones'))
|
|
2205
|
+
return {
|
|
2206
|
+
chainId: query.chainId ?? c.get('chainId'),
|
|
2207
|
+
kind: 'selected' as const,
|
|
2208
|
+
receipt: null,
|
|
2209
|
+
}
|
|
2210
|
+
|
|
2211
|
+
const zoneChainIds = c.get('zoneChainIds')
|
|
2212
|
+
if (!zoneChainIds) throw new Error('Inferred Zone selection was not resolved.')
|
|
2213
|
+
// Cache only positive resolution. Missing transactions must remain
|
|
2214
|
+
// visible as soon as their Zone indexer catches up.
|
|
2215
|
+
const match = await Store.memoize(
|
|
2216
|
+
async () => {
|
|
2217
|
+
const probes: readonly ZoneSelection.uniqueMatch.Probe<TransactionReceipt>[] =
|
|
2218
|
+
await Promise.all(
|
|
2219
|
+
zoneChainIds.map(async (chainId) => {
|
|
2220
|
+
try {
|
|
2221
|
+
return {
|
|
2222
|
+
chainId,
|
|
2223
|
+
value: await getTransactionReceipt({
|
|
2224
|
+
chainId,
|
|
2225
|
+
tidx: c.get('getTidx')(chainId),
|
|
2226
|
+
transactionHash,
|
|
2227
|
+
}),
|
|
2228
|
+
}
|
|
2229
|
+
} catch (cause) {
|
|
2230
|
+
return { cause, chainId }
|
|
2231
|
+
}
|
|
2232
|
+
}),
|
|
2233
|
+
)
|
|
2234
|
+
return ZoneSelection.uniqueMatch<TransactionReceipt>(probes)
|
|
2235
|
+
},
|
|
2236
|
+
{
|
|
2237
|
+
key: `activities:zones:v1:${zoneChainIds.join(',')}:tx:${transactionHash.toLowerCase()}`,
|
|
2238
|
+
shouldCache: (match) => match.kind === 'selected',
|
|
2154
2239
|
store: c.get('store'),
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2240
|
+
ttl: Ttl.seconds(15),
|
|
2241
|
+
},
|
|
2242
|
+
)
|
|
2243
|
+
if (match.kind === 'failed') {
|
|
2244
|
+
c.set(
|
|
2245
|
+
'providerFailures',
|
|
2246
|
+
match.failures.map(({ cause, chainId }) => ({
|
|
2247
|
+
...Tidx.providerFailure(cause),
|
|
2248
|
+
chainId,
|
|
2249
|
+
})),
|
|
2250
|
+
)
|
|
2251
|
+
throw match.failures[0]!.cause
|
|
2252
|
+
}
|
|
2253
|
+
if (match.kind !== 'selected') return match
|
|
2254
|
+
return { chainId: match.chainId, kind: 'selected' as const, receipt: match.value }
|
|
2255
|
+
})()
|
|
2256
|
+
|
|
2257
|
+
if (selected.kind !== 'selected') return selected
|
|
2258
|
+
const { chainId } = selected
|
|
2259
|
+
const unenrichedItems = await Store.memoize(
|
|
2260
|
+
() =>
|
|
2261
|
+
selected.receipt === null
|
|
2262
|
+
? getTransactionActivities({
|
|
2263
|
+
chainId,
|
|
2264
|
+
logs: query.logs,
|
|
2265
|
+
store: c.get('store'),
|
|
2266
|
+
tidx: c.get('getTidx')(chainId),
|
|
2267
|
+
transactionHash,
|
|
2268
|
+
})
|
|
2269
|
+
: classifyTransactionActivities({
|
|
2270
|
+
chainId,
|
|
2271
|
+
logs: query.logs,
|
|
2272
|
+
receipt: selected.receipt,
|
|
2273
|
+
store: c.get('store'),
|
|
2274
|
+
tidx: c.get('getTidx')(chainId),
|
|
2275
|
+
transactionHash,
|
|
2276
|
+
}),
|
|
2158
2277
|
{
|
|
2159
2278
|
key: `activities:v1:${chainId}:tx:${transactionHash.toLowerCase()}:${query.logs ?? false}`,
|
|
2160
2279
|
store: c.get('store'),
|
|
2161
2280
|
ttl: Ttl.seconds(15),
|
|
2162
2281
|
},
|
|
2163
|
-
)
|
|
2164
|
-
|
|
2282
|
+
)
|
|
2283
|
+
return unenrichedItems === null
|
|
2284
|
+
? ({ kind: 'not_found' } as const)
|
|
2285
|
+
: ({ chainId, items: unenrichedItems, kind: 'found' } as const)
|
|
2286
|
+
})
|
|
2165
2287
|
|
|
2166
|
-
if (
|
|
2288
|
+
if (result.kind === 'not_found')
|
|
2167
2289
|
return Response.error(c, {
|
|
2168
2290
|
code: 'transaction_not_found',
|
|
2169
2291
|
message: 'Transaction not found',
|
|
2170
2292
|
status: 404,
|
|
2171
2293
|
})
|
|
2294
|
+
if (result.kind === 'ambiguous')
|
|
2295
|
+
return Response.error(c, {
|
|
2296
|
+
code: 'transaction_ambiguous',
|
|
2297
|
+
message: 'Transaction hash matched more than one readable Zone',
|
|
2298
|
+
status: 409,
|
|
2299
|
+
})
|
|
2172
2300
|
|
|
2173
2301
|
// Mined activity can carry current valuations and verification data.
|
|
2174
|
-
Cache.setPolicy(c, Cache.policies.metadata)
|
|
2302
|
+
if (!query.include.includes('zones')) Cache.setPolicy(c, Cache.policies.metadata)
|
|
2303
|
+
c.set('chainId', result.chainId)
|
|
2175
2304
|
|
|
2176
2305
|
// Build immutable token and structured amount copies from RPC metadata.
|
|
2177
2306
|
const { items, rates } = await enrichTokens(c, {
|
|
2178
|
-
chainId,
|
|
2307
|
+
chainId: result.chainId,
|
|
2179
2308
|
denomination: query['valuation.currency'],
|
|
2180
2309
|
include: query.include,
|
|
2181
|
-
items:
|
|
2310
|
+
items: result.items,
|
|
2182
2311
|
oracle,
|
|
2183
2312
|
})
|
|
2184
2313
|
|
|
2185
2314
|
return c.json(
|
|
2186
2315
|
Response.validated(schema.getTransactionActivities.Response, {
|
|
2316
|
+
chainId: result.chainId,
|
|
2187
2317
|
data: items,
|
|
2188
2318
|
...(rates ? { meta: { valuation: Valuation.pricing(rates, oracle) } } : {}),
|
|
2189
2319
|
}),
|
|
@@ -2219,7 +2349,15 @@ export declare namespace transactions {
|
|
|
2219
2349
|
export async function getTransactionActivities(
|
|
2220
2350
|
options: getTransactionActivities.Options,
|
|
2221
2351
|
): Promise<UnenrichedItem[] | null> {
|
|
2222
|
-
const
|
|
2352
|
+
const receipt = await getTransactionReceipt(options)
|
|
2353
|
+
if (!receipt) return null
|
|
2354
|
+
return classifyTransactionActivities({ ...options, receipt })
|
|
2355
|
+
}
|
|
2356
|
+
|
|
2357
|
+
async function getTransactionReceipt(
|
|
2358
|
+
options: getTransactionReceipt.Options,
|
|
2359
|
+
): Promise<TransactionReceipt | null> {
|
|
2360
|
+
const { chainId, tidx: tidxClient } = options
|
|
2223
2361
|
const hash = options.transactionHash.toLowerCase()
|
|
2224
2362
|
|
|
2225
2363
|
// The `receipts` table is indexed by `tx_hash`, so this point lookup needs no
|
|
@@ -2234,9 +2372,33 @@ export async function getTransactionActivities(
|
|
|
2234
2372
|
const receipt = receiptResult.rows[0]
|
|
2235
2373
|
if (!receipt) return null
|
|
2236
2374
|
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2375
|
+
return {
|
|
2376
|
+
blockNum: Number(Value.toNumber(receipt['block_num'])),
|
|
2377
|
+
feePayer: lowerOrNull(receipt['fee_payer']),
|
|
2378
|
+
txSender: lowerOrNull(receipt['from']),
|
|
2379
|
+
}
|
|
2380
|
+
}
|
|
2381
|
+
|
|
2382
|
+
declare namespace getTransactionReceipt {
|
|
2383
|
+
type Options = Pick<getTransactionActivities.Options, 'chainId' | 'tidx' | 'transactionHash'>
|
|
2384
|
+
}
|
|
2385
|
+
|
|
2386
|
+
type TransactionReceipt = {
|
|
2387
|
+
/** Block number containing the transaction. */
|
|
2388
|
+
blockNum: number
|
|
2389
|
+
/** Account that paid the transaction fee, when indexed. */
|
|
2390
|
+
feePayer: Address.Address | null
|
|
2391
|
+
/** Account that sent the transaction, when indexed. */
|
|
2392
|
+
txSender: Address.Address | null
|
|
2393
|
+
}
|
|
2394
|
+
|
|
2395
|
+
async function classifyTransactionActivities(
|
|
2396
|
+
options: classifyTransactionActivities.Options,
|
|
2397
|
+
): Promise<UnenrichedItem[]> {
|
|
2398
|
+
const { chainId, logs = false, receipt, tidx: tidxClient } = options
|
|
2399
|
+
const hash = options.transactionHash.toLowerCase()
|
|
2400
|
+
const { blockNum, feePayer, txSender } = receipt
|
|
2401
|
+
const fingerprintMap_promise = Mpp.fingerprintMap({ store: options.store }).catch(() => ({}))
|
|
2240
2402
|
|
|
2241
2403
|
// `logs` is sorted by block position, so a bare `tx_hash =` scans to genesis;
|
|
2242
2404
|
// pair it with the receipt's block number (see `embedReceipts` in receipts.ts).
|
|
@@ -2269,7 +2431,7 @@ export async function getTransactionActivities(
|
|
|
2269
2431
|
|
|
2270
2432
|
// Best-effort MPP service directory: a fetch failure yields an empty map, so
|
|
2271
2433
|
// enrichment never blocks classification.
|
|
2272
|
-
const fingerprintMap = await
|
|
2434
|
+
const fingerprintMap = await fingerprintMap_promise
|
|
2273
2435
|
|
|
2274
2436
|
// Anchor the viewer on the transaction sender: the sender initiated every
|
|
2275
2437
|
// activity in the transaction, so `perspective` is `outgoing` and `signer`
|
|
@@ -2279,6 +2441,13 @@ export async function getTransactionActivities(
|
|
|
2279
2441
|
return classifyGroup(group, viewer, fingerprintMap, logs).map(withTitle)
|
|
2280
2442
|
}
|
|
2281
2443
|
|
|
2444
|
+
declare namespace classifyTransactionActivities {
|
|
2445
|
+
type Options = getTransactionActivities.Options & {
|
|
2446
|
+
/** Indexed receipt fields used to bound the log lookup. */
|
|
2447
|
+
receipt: TransactionReceipt
|
|
2448
|
+
}
|
|
2449
|
+
}
|
|
2450
|
+
|
|
2282
2451
|
export declare namespace getTransactionActivities {
|
|
2283
2452
|
/** Options for {@link getTransactionActivities}. */
|
|
2284
2453
|
type Options = {
|
|
@@ -2298,8 +2467,8 @@ export declare namespace getTransactionActivities {
|
|
|
2298
2467
|
/**
|
|
2299
2468
|
* Lists classified activity for an address by running the shared pipeline
|
|
2300
2469
|
* (`groupByTx` → `classifyGroup` → `enrichItem`) over rows from a
|
|
2301
|
-
* {@link Provider}. Returns
|
|
2302
|
-
*
|
|
2470
|
+
* {@link Provider}. Returns classified items plus the next cursor; callers run
|
|
2471
|
+
* {@link groupByAccessKey} over the result.
|
|
2303
2472
|
*/
|
|
2304
2473
|
export async function list(provider: Provider, options: list.Options): Promise<list.ReturnType> {
|
|
2305
2474
|
const { address, cursor, group = false, limit = 20, logs = false } = options
|
|
@@ -2307,7 +2476,7 @@ export async function list(provider: Provider, options: list.Options): Promise<l
|
|
|
2307
2476
|
|
|
2308
2477
|
// Best-effort MPP service directory: a fetch failure yields an empty map, so
|
|
2309
2478
|
// enrichment never blocks the feed.
|
|
2310
|
-
const
|
|
2479
|
+
const fingerprintMap_promise = Mpp.fingerprintMap({ store: options.store }).catch(() => ({}))
|
|
2311
2480
|
|
|
2312
2481
|
let currentCursor: string | undefined = cursor
|
|
2313
2482
|
const allItems: UnenrichedItem[] = []
|
|
@@ -2326,6 +2495,7 @@ export async function list(provider: Provider, options: list.Options): Promise<l
|
|
|
2326
2495
|
hasMore = txGroups.length > limit
|
|
2327
2496
|
const page = txGroups.slice(0, limit)
|
|
2328
2497
|
|
|
2498
|
+
const fingerprintMap = await fingerprintMap_promise
|
|
2329
2499
|
if (page.length === 0) break
|
|
2330
2500
|
|
|
2331
2501
|
allItems.push(
|
|
@@ -2374,6 +2544,175 @@ export declare namespace list {
|
|
|
2374
2544
|
}
|
|
2375
2545
|
}
|
|
2376
2546
|
|
|
2547
|
+
const zoneCursorVersion = 1
|
|
2548
|
+
|
|
2549
|
+
type ZonePageState = {
|
|
2550
|
+
/** Zone chain id backing this page state. */
|
|
2551
|
+
chainId: number
|
|
2552
|
+
/** Whether the current buffer reaches the end of this Zone feed. */
|
|
2553
|
+
exhausted: boolean
|
|
2554
|
+
/** Unconsumed transaction groups already fetched from this Zone. */
|
|
2555
|
+
groups: TxGroup[]
|
|
2556
|
+
/** Activity data source for this Zone. */
|
|
2557
|
+
provider: Provider
|
|
2558
|
+
}
|
|
2559
|
+
|
|
2560
|
+
/**
|
|
2561
|
+
* Lists address activity across multiple Zones in one stable timestamp-ordered
|
|
2562
|
+
* feed. Its opaque cursor retains each Zone provider's native continuation.
|
|
2563
|
+
*/
|
|
2564
|
+
export async function listZones(options: listZones.Options): Promise<listZones.ReturnType> {
|
|
2565
|
+
const { address, cursor, limit = 20, logs = false, providers, store } = options
|
|
2566
|
+
const group = options.group ?? false
|
|
2567
|
+
const orderedProviders = [...providers].sort((a, b) => a.chainId - b.chainId)
|
|
2568
|
+
const chainIds = orderedProviders.map(({ chainId }) => chainId)
|
|
2569
|
+
const cursors = decodeZoneCursor(cursor, chainIds)
|
|
2570
|
+
const viewer = address.toLowerCase() as Address.Address
|
|
2571
|
+
const fingerprintMap_promise = Mpp.fingerprintMap({ store }).catch(() => ({}))
|
|
2572
|
+
const states: ZonePageState[] = orderedProviders.map(({ chainId, provider }) => ({
|
|
2573
|
+
chainId,
|
|
2574
|
+
exhausted: false,
|
|
2575
|
+
groups: [],
|
|
2576
|
+
provider,
|
|
2577
|
+
}))
|
|
2578
|
+
const allItems: listZones.Item[] = []
|
|
2579
|
+
let hasMore = false
|
|
2580
|
+
|
|
2581
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
2582
|
+
await Promise.all(
|
|
2583
|
+
states.map(async (state) => {
|
|
2584
|
+
if (state.exhausted || state.groups.length > 0) return
|
|
2585
|
+
const { rows } = await state.provider.fetchRows({
|
|
2586
|
+
address: viewer,
|
|
2587
|
+
cursor: cursors.get(state.chainId),
|
|
2588
|
+
limit,
|
|
2589
|
+
})
|
|
2590
|
+
const groups = groupByTx(rows).slice(0, limit + 1)
|
|
2591
|
+
state.exhausted = groups.length <= limit
|
|
2592
|
+
state.groups.push(...groups)
|
|
2593
|
+
}),
|
|
2594
|
+
)
|
|
2595
|
+
const candidates = states
|
|
2596
|
+
.flatMap((state) => state.groups.map((txGroup) => ({ state, txGroup })))
|
|
2597
|
+
.sort((a, b) => {
|
|
2598
|
+
if (a.txGroup.blockTimestamp !== b.txGroup.blockTimestamp)
|
|
2599
|
+
return b.txGroup.blockTimestamp - a.txGroup.blockTimestamp
|
|
2600
|
+
if (a.state.chainId !== b.state.chainId) return a.state.chainId - b.state.chainId
|
|
2601
|
+
if (a.txGroup.blockNum !== b.txGroup.blockNum)
|
|
2602
|
+
return b.txGroup.blockNum - a.txGroup.blockNum
|
|
2603
|
+
return b.txGroup.txIdx - a.txGroup.txIdx
|
|
2604
|
+
})
|
|
2605
|
+
const page = candidates.slice(0, limit)
|
|
2606
|
+
const fingerprintMap = await fingerprintMap_promise
|
|
2607
|
+
if (page.length === 0) break
|
|
2608
|
+
|
|
2609
|
+
for (const { state, txGroup } of page) {
|
|
2610
|
+
state.groups.splice(state.groups.indexOf(txGroup), 1)
|
|
2611
|
+
cursors.set(state.chainId, state.provider.cursorForGroup(txGroup))
|
|
2612
|
+
allItems.push(
|
|
2613
|
+
...classifyGroup(txGroup, viewer, fingerprintMap, logs).map((item) => ({
|
|
2614
|
+
...withTitle(item),
|
|
2615
|
+
chainId: state.chainId,
|
|
2616
|
+
})),
|
|
2617
|
+
)
|
|
2618
|
+
}
|
|
2619
|
+
|
|
2620
|
+
hasMore = states.some((state) => !state.exhausted || state.groups.length > 0)
|
|
2621
|
+
const enough = group
|
|
2622
|
+
? groupByAccessKeyItems(allItems).length >= minGroupEntries
|
|
2623
|
+
: allItems.length >= limit
|
|
2624
|
+
if (enough || !hasMore) break
|
|
2625
|
+
}
|
|
2626
|
+
|
|
2627
|
+
// A consumed sentinel proves only that the provider may have more rows.
|
|
2628
|
+
// Probe drained buffers so `nextCursor` remains the end-of-list signal.
|
|
2629
|
+
await Promise.all(
|
|
2630
|
+
states.map(async (state) => {
|
|
2631
|
+
if (state.exhausted || state.groups.length > 0) return
|
|
2632
|
+
const { rows } = await state.provider.fetchRows({
|
|
2633
|
+
address: viewer,
|
|
2634
|
+
cursor: cursors.get(state.chainId),
|
|
2635
|
+
limit: 1,
|
|
2636
|
+
})
|
|
2637
|
+
const group = groupByTx(rows)[0]
|
|
2638
|
+
if (group) state.groups.push(group)
|
|
2639
|
+
else state.exhausted = true
|
|
2640
|
+
}),
|
|
2641
|
+
)
|
|
2642
|
+
hasMore = states.some((state) => !state.exhausted || state.groups.length > 0)
|
|
2643
|
+
|
|
2644
|
+
return {
|
|
2645
|
+
items: allItems,
|
|
2646
|
+
nextCursor: hasMore ? encodeZoneCursor(cursors, chainIds) : null,
|
|
2647
|
+
}
|
|
2648
|
+
}
|
|
2649
|
+
|
|
2650
|
+
export declare namespace listZones {
|
|
2651
|
+
/** One Zone activity provider. */
|
|
2652
|
+
type ChainProvider = {
|
|
2653
|
+
/** Zone chain id. */
|
|
2654
|
+
chainId: number
|
|
2655
|
+
/** Activity data source for the Zone. */
|
|
2656
|
+
provider: Provider
|
|
2657
|
+
}
|
|
2658
|
+
|
|
2659
|
+
/** A classified item tagged with its Zone chain id. */
|
|
2660
|
+
type Item = UnenrichedItem & {
|
|
2661
|
+
/** Zone chain id containing the activity. */
|
|
2662
|
+
chainId: number
|
|
2663
|
+
}
|
|
2664
|
+
|
|
2665
|
+
/** Options for {@link listZones}. */
|
|
2666
|
+
type Options = {
|
|
2667
|
+
/** Subject account address. */
|
|
2668
|
+
address: Address.Address
|
|
2669
|
+
/** Opaque multi-Zone cursor from a previous page. */
|
|
2670
|
+
cursor?: string | undefined
|
|
2671
|
+
/** Whether the caller will fold access-key items. */
|
|
2672
|
+
group?: boolean | undefined
|
|
2673
|
+
/** Target number of transaction groups per page. */
|
|
2674
|
+
limit?: number | undefined
|
|
2675
|
+
/** Attach each item's full transaction event capture. */
|
|
2676
|
+
logs?: boolean | undefined
|
|
2677
|
+
/** Zone providers participating in the merged feed. */
|
|
2678
|
+
providers: readonly ChainProvider[]
|
|
2679
|
+
/** Cache store for the MPP fingerprint-directory lookup. */
|
|
2680
|
+
store: Store.Store
|
|
2681
|
+
}
|
|
2682
|
+
|
|
2683
|
+
/** Multi-Zone classified page before token enrichment. */
|
|
2684
|
+
type ReturnType = {
|
|
2685
|
+
/** Timestamp-ordered, chain-tagged activity items. */
|
|
2686
|
+
items: Item[]
|
|
2687
|
+
/** Opaque continuation for every Zone, or null at the end. */
|
|
2688
|
+
nextCursor: string | null
|
|
2689
|
+
}
|
|
2690
|
+
}
|
|
2691
|
+
|
|
2692
|
+
function decodeZoneCursor(cursor: string | undefined, chainIds: readonly number[]) {
|
|
2693
|
+
const fields: Cursor.Field[] = ['int']
|
|
2694
|
+
for (const _chainId of chainIds) fields.push('int', 'id')
|
|
2695
|
+
const decoded = cursor ? Cursor.decode(cursor, fields) : undefined
|
|
2696
|
+
const cursors = new Map<number, string>()
|
|
2697
|
+
if (!decoded || decoded[0] !== zoneCursorVersion) return cursors
|
|
2698
|
+
|
|
2699
|
+
for (let index = 0; index < chainIds.length; index++) {
|
|
2700
|
+
const chainId = chainIds[index]!
|
|
2701
|
+
const offset = index * 2 + 1
|
|
2702
|
+
if (decoded[offset] !== chainId) return new Map()
|
|
2703
|
+
const value = decoded[offset + 1] as string
|
|
2704
|
+
if (value !== 'head') cursors.set(chainId, value)
|
|
2705
|
+
}
|
|
2706
|
+
return cursors
|
|
2707
|
+
}
|
|
2708
|
+
|
|
2709
|
+
function encodeZoneCursor(cursors: ReadonlyMap<number, string>, chainIds: readonly number[]) {
|
|
2710
|
+
return Cursor.encode([
|
|
2711
|
+
zoneCursorVersion,
|
|
2712
|
+
...chainIds.flatMap((chainId) => [chainId, cursors.get(chainId) ?? 'head']),
|
|
2713
|
+
])
|
|
2714
|
+
}
|
|
2715
|
+
|
|
2377
2716
|
/**
|
|
2378
2717
|
* Creates a TIDX-backed {@link Provider} that runs three sub-queries in
|
|
2379
2718
|
* parallel and merges them:
|
|
@@ -4521,49 +4860,63 @@ async function enrichTokens(
|
|
|
4521
4860
|
for (const item of items) collectTokens(item, addresses)
|
|
4522
4861
|
const includeLogoUri = include.includes('token.logoUri')
|
|
4523
4862
|
const includeVerified = include.includes('token.verified')
|
|
4863
|
+
const resolved_promise =
|
|
4864
|
+
addresses.size > 0
|
|
4865
|
+
? Timing.time(c, 'tokens', () =>
|
|
4866
|
+
Promise.all(
|
|
4867
|
+
[...addresses].map(async (address) => {
|
|
4868
|
+
const [logoUri, metadata] = await Promise.all([
|
|
4869
|
+
includeLogoUri
|
|
4870
|
+
? Tokens.getTokenLogo(c, { address, chainId }).catch(() => undefined)
|
|
4871
|
+
: undefined,
|
|
4872
|
+
getActivityTokenMetadata(c, { address, chainId }),
|
|
4873
|
+
])
|
|
4874
|
+
return { address: address.toLowerCase(), logoUri, metadata }
|
|
4875
|
+
}),
|
|
4876
|
+
),
|
|
4877
|
+
)
|
|
4878
|
+
: undefined
|
|
4524
4879
|
// Curated data is needed only for requested valuation or token fields.
|
|
4525
|
-
const
|
|
4880
|
+
const snapshot_promise =
|
|
4526
4881
|
addresses.size > 0 && (denomination !== undefined || includeLogoUri || includeVerified)
|
|
4527
|
-
?
|
|
4528
|
-
: undefined
|
|
4529
|
-
const
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
4882
|
+
? VerifiedTokens.snapshot(c, chainId).catch(() => undefined)
|
|
4883
|
+
: Promise.resolve(undefined)
|
|
4884
|
+
const rates_promise = (async () => {
|
|
4885
|
+
if (!denomination) return undefined
|
|
4886
|
+
const snapshot = await snapshot_promise
|
|
4887
|
+
return Valuation.ratesFor(c, {
|
|
4888
|
+
currencies: snapshot
|
|
4889
|
+
? [...addresses].flatMap((address) => {
|
|
4890
|
+
const held = snapshot.byAddress.get(address)?.currency
|
|
4891
|
+
return held === undefined ? [] : [held]
|
|
4892
|
+
})
|
|
4893
|
+
: [],
|
|
4894
|
+
denomination,
|
|
4895
|
+
oracle,
|
|
4896
|
+
})
|
|
4897
|
+
})()
|
|
4898
|
+
if (!resolved_promise) return { items: items as Item[], rates: await rates_promise }
|
|
4899
|
+
|
|
4900
|
+
const [resolved_raw, rates, snapshot] = await Promise.all([
|
|
4901
|
+
resolved_promise,
|
|
4902
|
+
rates_promise,
|
|
4903
|
+
snapshot_promise,
|
|
4904
|
+
])
|
|
4905
|
+
const resolved = resolved_raw.map(
|
|
4906
|
+
({ address, logoUri, metadata }) =>
|
|
4907
|
+
[
|
|
4908
|
+
address,
|
|
4909
|
+
{
|
|
4910
|
+
currency: metadata.currency,
|
|
4911
|
+
decimals: metadata.decimals,
|
|
4912
|
+
logoUri: includeLogoUri
|
|
4913
|
+
? (logoUri ?? snapshot?.byAddress.get(address)?.logoUri ?? metadata.logoUri)
|
|
4549
4914
|
: undefined,
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
currency: metadata.currency,
|
|
4556
|
-
decimals: metadata.decimals,
|
|
4557
|
-
logoUri: includeLogoUri
|
|
4558
|
-
? (logoUri ?? snapshot?.byAddress.get(address)?.logoUri ?? metadata.logoUri)
|
|
4559
|
-
: undefined,
|
|
4560
|
-
name: metadata.name,
|
|
4561
|
-
symbol: metadata.symbol,
|
|
4562
|
-
verified: includeVerified && snapshot ? snapshot.byAddress.has(address) : undefined,
|
|
4563
|
-
},
|
|
4564
|
-
] as const
|
|
4565
|
-
}),
|
|
4566
|
-
),
|
|
4915
|
+
name: metadata.name,
|
|
4916
|
+
symbol: metadata.symbol,
|
|
4917
|
+
verified: includeVerified && snapshot ? snapshot.byAddress.has(address) : undefined,
|
|
4918
|
+
},
|
|
4919
|
+
] as const,
|
|
4567
4920
|
)
|
|
4568
4921
|
const byAddress = new Map(resolved)
|
|
4569
4922
|
return {
|
|
@@ -4584,6 +4937,54 @@ declare namespace enrichTokens {
|
|
|
4584
4937
|
}
|
|
4585
4938
|
}
|
|
4586
4939
|
|
|
4940
|
+
/** Resolves token metadata on each item's source Zone without changing feed order. */
|
|
4941
|
+
async function enrichZoneTokens(
|
|
4942
|
+
c: Context<App.Environment>,
|
|
4943
|
+
options: enrichZoneTokens.Options,
|
|
4944
|
+
): Promise<{ items: Item[]; rates: FxOracle.RateSet | undefined }> {
|
|
4945
|
+
const byChain = new Map<number, listZones.Item[]>()
|
|
4946
|
+
for (const item of options.items) {
|
|
4947
|
+
const items = byChain.get(item.chainId) ?? []
|
|
4948
|
+
items.push(item)
|
|
4949
|
+
byChain.set(item.chainId, items)
|
|
4950
|
+
}
|
|
4951
|
+
const results = await Promise.all(
|
|
4952
|
+
[...byChain].map(async ([chainId, items]) => ({
|
|
4953
|
+
chainId,
|
|
4954
|
+
...(await enrichTokens(c, {
|
|
4955
|
+
chainId,
|
|
4956
|
+
denomination: options.denomination,
|
|
4957
|
+
include: options.include,
|
|
4958
|
+
items,
|
|
4959
|
+
oracle: options.oracle,
|
|
4960
|
+
})),
|
|
4961
|
+
})),
|
|
4962
|
+
)
|
|
4963
|
+
type Bucket = { index: number; items: Item[] }
|
|
4964
|
+
const buckets = new Map<number, Bucket>()
|
|
4965
|
+
for (const result of results) buckets.set(result.chainId, { index: 0, items: result.items })
|
|
4966
|
+
return {
|
|
4967
|
+
items: options.items.map((item) => {
|
|
4968
|
+
const bucket = buckets.get(item.chainId)!
|
|
4969
|
+
return bucket.items[bucket.index++]!
|
|
4970
|
+
}),
|
|
4971
|
+
rates: results.find((result) => result.rates !== undefined)?.rates,
|
|
4972
|
+
}
|
|
4973
|
+
}
|
|
4974
|
+
|
|
4975
|
+
declare namespace enrichZoneTokens {
|
|
4976
|
+
type Options = {
|
|
4977
|
+
/** Currency the amount valuations are denominated in. */
|
|
4978
|
+
denomination?: string | undefined
|
|
4979
|
+
/** Optional token fields to resolve. */
|
|
4980
|
+
include: readonly z.output<typeof schema.Include>[]
|
|
4981
|
+
/** Chain-tagged items awaiting token enrichment. */
|
|
4982
|
+
items: readonly listZones.Item[]
|
|
4983
|
+
/** FX rate oracle backing amount valuation. */
|
|
4984
|
+
oracle: FxOracle.Oracle
|
|
4985
|
+
}
|
|
4986
|
+
}
|
|
4987
|
+
|
|
4587
4988
|
/** Returns an enriched copy of an item without mutating its cached token stubs. */
|
|
4588
4989
|
function enrichItem(
|
|
4589
4990
|
item: UnenrichedItem,
|
|
@@ -4651,6 +5052,7 @@ export function groupByAccessKey(items: Item[]): Entry[] {
|
|
|
4651
5052
|
}
|
|
4652
5053
|
|
|
4653
5054
|
type GroupableItem = {
|
|
5055
|
+
chainId?: number | undefined
|
|
4654
5056
|
data: object
|
|
4655
5057
|
id: string
|
|
4656
5058
|
perspective: 'incoming' | 'outgoing'
|
|
@@ -4660,6 +5062,7 @@ type GroupableItem = {
|
|
|
4660
5062
|
type GroupedItem<item extends GroupableItem> =
|
|
4661
5063
|
| item
|
|
4662
5064
|
| {
|
|
5065
|
+
chainId?: number | undefined
|
|
4663
5066
|
data: { items: item[]; signer: Address.Address }
|
|
4664
5067
|
id: string
|
|
4665
5068
|
perspective: 'incoming' | 'outgoing'
|
|
@@ -4678,6 +5081,7 @@ function groupByAccessKeyItems<item extends GroupableItem>(items: item[]): Group
|
|
|
4678
5081
|
if (itemSigner !== 'self') {
|
|
4679
5082
|
if (
|
|
4680
5083
|
currentGroup &&
|
|
5084
|
+
currentGroup.items[0]!.chainId === item.chainId &&
|
|
4681
5085
|
Address.isEqual(currentGroup.signer, itemSigner) &&
|
|
4682
5086
|
sameCalendarDay(currentGroup.items[0]!.timestamp, item.timestamp)
|
|
4683
5087
|
) {
|
|
@@ -4717,6 +5121,7 @@ function flushGroup<item extends GroupableItem>(group: {
|
|
|
4717
5121
|
const firstItem = group.items[0]!
|
|
4718
5122
|
const lastItem = group.items[group.items.length - 1]!
|
|
4719
5123
|
return {
|
|
5124
|
+
...(firstItem.chainId === undefined ? {} : { chainId: firstItem.chainId }),
|
|
4720
5125
|
data: { items: group.items, signer: group.signer },
|
|
4721
5126
|
perspective: firstItem.perspective,
|
|
4722
5127
|
id: `${firstItem.id}..${lastItem.id}:${group.items.length}`,
|