tapimo 0.5.2 → 0.6.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 +13987 -5755
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js.map +1 -1
- package/dist/admin/App.d.ts +910 -412
- package/dist/admin/App.d.ts.map +1 -1
- package/dist/admin/App.js +4 -0
- package/dist/admin/App.js.map +1 -1
- package/dist/admin/apps/early-access.d.ts +148 -0
- package/dist/admin/apps/early-access.d.ts.map +1 -0
- package/dist/admin/apps/early-access.js +133 -0
- package/dist/admin/apps/early-access.js.map +1 -0
- package/dist/admin/apps/verified-tokens.d.ts +643 -118
- package/dist/admin/apps/verified-tokens.d.ts.map +1 -1
- package/dist/admin/apps/verified-tokens.js +214 -1
- package/dist/admin/apps/verified-tokens.js.map +1 -1
- package/dist/admin/ui.generated.d.ts +1 -1
- package/dist/admin/ui.generated.d.ts.map +1 -1
- package/dist/admin/ui.generated.js +45 -33
- package/dist/admin/ui.generated.js.map +1 -1
- package/dist/apps/data/App.d.ts +3733 -2428
- package/dist/apps/data/App.d.ts.map +1 -1
- package/dist/apps/data/App.js +11 -6
- package/dist/apps/data/App.js.map +1 -1
- package/dist/apps/data/FundingQuoteProviders.d.ts +34 -1
- package/dist/apps/data/FundingQuoteProviders.d.ts.map +1 -1
- package/dist/apps/data/FundingQuoteProviders.js +193 -2
- package/dist/apps/data/FundingQuoteProviders.js.map +1 -1
- package/dist/apps/data/FxOracle.d.ts +71 -0
- package/dist/apps/data/FxOracle.d.ts.map +1 -0
- package/dist/apps/data/FxOracle.js +97 -0
- package/dist/apps/data/FxOracle.js.map +1 -0
- package/dist/apps/data/index.d.ts +1 -0
- package/dist/apps/data/index.d.ts.map +1 -1
- package/dist/apps/data/index.js +1 -0
- package/dist/apps/data/index.js.map +1 -1
- package/dist/apps/data/routes/activities.d.ts +3575 -1358
- package/dist/apps/data/routes/activities.d.ts.map +1 -1
- package/dist/apps/data/routes/activities.js +230 -88
- package/dist/apps/data/routes/activities.js.map +1 -1
- package/dist/apps/data/routes/addresses.d.ts +963 -342
- package/dist/apps/data/routes/addresses.d.ts.map +1 -1
- package/dist/apps/data/routes/addresses.js +11 -9
- package/dist/apps/data/routes/addresses.js.map +1 -1
- package/dist/apps/data/routes/balances.d.ts +108 -57
- package/dist/apps/data/routes/balances.d.ts.map +1 -1
- package/dist/apps/data/routes/balances.js +88 -45
- package/dist/apps/data/routes/balances.js.map +1 -1
- package/dist/apps/data/routes/coingecko.d.ts +169 -169
- package/dist/apps/data/routes/exchanges.d.ts +952 -201
- package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
- package/dist/apps/data/routes/exchanges.js +518 -76
- package/dist/apps/data/routes/exchanges.js.map +1 -1
- package/dist/apps/data/routes/fee-amm.d.ts +24 -24
- package/dist/apps/data/routes/funding.d.ts +8 -2
- package/dist/apps/data/routes/funding.d.ts.map +1 -1
- package/dist/apps/data/routes/funding.js +32 -6
- package/dist/apps/data/routes/funding.js.map +1 -1
- package/dist/apps/data/routes/indexer.d.ts +5 -5
- package/dist/apps/data/routes/receipts.d.ts +392 -315
- package/dist/apps/data/routes/receipts.d.ts.map +1 -1
- package/dist/apps/data/routes/receipts.js +152 -77
- package/dist/apps/data/routes/receipts.js.map +1 -1
- package/dist/apps/data/routes/tokens.d.ts +166 -173
- package/dist/apps/data/routes/tokens.d.ts.map +1 -1
- package/dist/apps/data/routes/tokens.js +14 -12
- package/dist/apps/data/routes/tokens.js.map +1 -1
- package/dist/apps/data/routes/transactions.d.ts +277 -536
- package/dist/apps/data/routes/transactions.d.ts.map +1 -1
- package/dist/apps/data/routes/transactions.js +96 -77
- package/dist/apps/data/routes/transactions.js.map +1 -1
- package/dist/apps/data/routes/transfers.d.ts +82 -17
- package/dist/apps/data/routes/transfers.d.ts.map +1 -1
- package/dist/apps/data/routes/transfers.js +70 -13
- package/dist/apps/data/routes/transfers.js.map +1 -1
- package/dist/apps/data/routes/valuation.d.ts +307 -0
- package/dist/apps/data/routes/valuation.d.ts.map +1 -0
- package/dist/apps/data/routes/valuation.js +292 -0
- package/dist/apps/data/routes/valuation.js.map +1 -0
- package/dist/apps/data/routes/verified-tokens.d.ts.map +1 -1
- package/dist/apps/data/routes/verified-tokens.js +7 -5
- package/dist/apps/data/routes/verified-tokens.js.map +1 -1
- package/dist/apps/data/routes/webhooks.d.ts +459 -479
- package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
- package/dist/apps/data/routes/webhooks.js +124 -25
- package/dist/apps/data/routes/webhooks.js.map +1 -1
- package/dist/apps/index.d.ts +1 -1
- package/dist/apps/index.d.ts.map +1 -1
- package/dist/apps/index.js +1 -1
- package/dist/apps/index.js.map +1 -1
- package/dist/apps/management/App.d.ts +8606 -1681
- package/dist/apps/management/App.d.ts.map +1 -1
- package/dist/apps/management/App.js +12 -1
- package/dist/apps/management/App.js.map +1 -1
- package/dist/apps/management/routes/api-keys.d.ts +23 -0
- package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
- package/dist/apps/management/routes/api-keys.js +5 -3
- package/dist/apps/management/routes/api-keys.js.map +1 -1
- package/dist/apps/management/routes/billing.d.ts +88 -48
- package/dist/apps/management/routes/billing.d.ts.map +1 -1
- package/dist/apps/management/routes/billing.js +10 -2
- package/dist/apps/management/routes/billing.js.map +1 -1
- package/dist/apps/management/routes/faucet.d.ts +218 -0
- package/dist/apps/management/routes/faucet.d.ts.map +1 -0
- package/dist/apps/management/routes/faucet.js +139 -0
- package/dist/apps/management/routes/faucet.js.map +1 -0
- package/dist/apps/management/routes/invitations.d.ts +121 -121
- package/dist/apps/management/routes/invitations.d.ts.map +1 -1
- package/dist/apps/management/routes/invitations.js +3 -0
- package/dist/apps/management/routes/invitations.js.map +1 -1
- package/dist/apps/management/routes/invite-links.d.ts +197 -168
- package/dist/apps/management/routes/invite-links.d.ts.map +1 -1
- package/dist/apps/management/routes/invite-links.js +26 -1
- package/dist/apps/management/routes/invite-links.js.map +1 -1
- package/dist/apps/management/routes/me.d.ts +2 -0
- package/dist/apps/management/routes/me.d.ts.map +1 -1
- package/dist/apps/management/routes/me.js +4 -0
- package/dist/apps/management/routes/me.js.map +1 -1
- package/dist/apps/management/routes/members.d.ts +49 -49
- package/dist/apps/management/routes/orgs.d.ts +91 -91
- package/dist/apps/management/routes/projects.d.ts +115 -115
- package/dist/apps/management/routes/usage.d.ts +35 -32
- package/dist/apps/management/routes/usage.d.ts.map +1 -1
- package/dist/apps/management/routes/usage.js +4 -0
- package/dist/apps/management/routes/usage.js.map +1 -1
- package/dist/apps/management/routes/verified-token-requests.d.ts +697 -0
- package/dist/apps/management/routes/verified-token-requests.d.ts.map +1 -0
- package/dist/apps/management/routes/verified-token-requests.js +271 -0
- package/dist/apps/management/routes/verified-token-requests.js.map +1 -0
- package/dist/apps/management/routes/webhooks.d.ts +6977 -0
- package/dist/apps/management/routes/webhooks.d.ts.map +1 -0
- package/dist/apps/management/routes/webhooks.js +573 -0
- package/dist/apps/management/routes/webhooks.js.map +1 -0
- package/dist/apps/mcp.d.ts +9 -2
- package/dist/apps/mcp.d.ts.map +1 -1
- package/dist/apps/mcp.js +9 -4
- package/dist/apps/mcp.js.map +1 -1
- package/dist/cli/Cli.d.ts.map +1 -1
- package/dist/cli/Cli.js +7 -2
- package/dist/cli/Cli.js.map +1 -1
- package/dist/db/Db.d.ts +4 -0
- package/dist/db/Db.d.ts.map +1 -1
- package/dist/db/Db.js +83 -0
- package/dist/db/Db.js.map +1 -1
- package/dist/db/Schema.d.ts +41 -0
- package/dist/db/Schema.d.ts.map +1 -1
- package/dist/db/Schema.js +45 -0
- package/dist/db/Schema.js.map +1 -1
- package/dist/db/tables/earlyAccess.d.ts +50 -0
- package/dist/db/tables/earlyAccess.d.ts.map +1 -0
- package/dist/db/tables/earlyAccess.js +63 -0
- package/dist/db/tables/earlyAccess.js.map +1 -0
- package/dist/db/tables/invitations.d.ts +12 -1
- package/dist/db/tables/invitations.d.ts.map +1 -1
- package/dist/db/tables/invitations.js +23 -0
- package/dist/db/tables/invitations.js.map +1 -1
- package/dist/db/tables/inviteLinks.d.ts +10 -2
- package/dist/db/tables/inviteLinks.d.ts.map +1 -1
- package/dist/db/tables/inviteLinks.js +10 -1
- package/dist/db/tables/inviteLinks.js.map +1 -1
- package/dist/db/tables/sponsoredTransactions.d.ts +2 -0
- package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
- package/dist/db/tables/sponsoredTransactions.js +2 -0
- package/dist/db/tables/sponsoredTransactions.js.map +1 -1
- package/dist/db/tables/verifiedTokenRequests.d.ts +94 -0
- package/dist/db/tables/verifiedTokenRequests.d.ts.map +1 -0
- package/dist/db/tables/verifiedTokenRequests.js +120 -0
- package/dist/db/tables/verifiedTokenRequests.js.map +1 -0
- package/dist/db/tables/webhookSubscriptions.d.ts +14 -0
- package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
- package/dist/db/tables/webhookSubscriptions.js +16 -0
- package/dist/db/tables/webhookSubscriptions.js.map +1 -1
- package/dist/internal/Auth.d.ts +43 -2
- package/dist/internal/Auth.d.ts.map +1 -1
- package/dist/internal/Auth.js +60 -45
- package/dist/internal/Auth.js.map +1 -1
- package/dist/internal/FundingQuotes.d.ts +69 -15
- package/dist/internal/FundingQuotes.d.ts.map +1 -1
- package/dist/internal/FundingQuotes.js +74 -25
- package/dist/internal/FundingQuotes.js.map +1 -1
- package/dist/internal/Log.d.ts +19 -1
- package/dist/internal/Log.d.ts.map +1 -1
- package/dist/internal/Log.js +2 -0
- package/dist/internal/Log.js.map +1 -1
- package/dist/internal/MetricSink.d.ts.map +1 -1
- package/dist/internal/MetricSink.js +9 -0
- 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 +3 -0
- package/dist/internal/OpenApi.js.map +1 -1
- package/dist/internal/Schema.d.ts +14 -5
- package/dist/internal/Schema.d.ts.map +1 -1
- package/dist/internal/Schema.js +23 -5
- package/dist/internal/Schema.js.map +1 -1
- package/dist/internal/Value.d.ts +18 -0
- package/dist/internal/Value.d.ts.map +1 -1
- package/dist/internal/Value.js +11 -1
- package/dist/internal/Value.js.map +1 -1
- package/dist/internal/VerifiedTokens.d.ts.map +1 -1
- package/dist/internal/VerifiedTokens.js +10 -1
- package/dist/internal/VerifiedTokens.js.map +1 -1
- package/dist/internal/Viem.d.ts +1 -1
- package/dist/internal/Webhooks.d.ts +24 -3
- package/dist/internal/Webhooks.d.ts.map +1 -1
- package/dist/internal/Webhooks.js +34 -8
- package/dist/internal/Webhooks.js.map +1 -1
- package/package.json +2 -2
- package/src/App.ts +9 -1
- package/src/Client.test-d.ts +638 -6
- package/src/admin/App.ts +4 -0
- package/src/admin/apps/early-access.test.ts +125 -0
- package/src/admin/apps/early-access.ts +175 -0
- package/src/admin/apps/verified-tokens.test.ts +201 -0
- package/src/admin/apps/verified-tokens.ts +532 -286
- package/src/admin/ui/plugin.ts +2 -1
- package/src/admin/ui/src/lib/early-access.ts +63 -0
- package/src/admin/ui/src/lib/verified-tokens.ts +79 -0
- package/src/admin/ui/src/routeTree.gen.ts +33 -2
- package/src/admin/ui/src/routes/__root.tsx +2 -1
- package/src/admin/ui/src/routes/early-access.tsx +157 -0
- package/src/admin/ui/src/routes/verified-tokens.tsx +230 -19
- package/src/admin/ui.generated.ts +48 -33
- package/src/apps/data/App.ts +22 -14
- package/src/apps/data/FundingQuoteProviders.test.ts +298 -0
- package/src/apps/data/FundingQuoteProviders.ts +257 -4
- package/src/apps/data/FxOracle.test.ts +118 -0
- package/src/apps/data/FxOracle.ts +153 -0
- package/src/apps/data/index.ts +1 -0
- package/src/apps/data/routes/activities.test.ts +173 -3
- package/src/apps/data/routes/activities.ts +403 -132
- package/src/apps/data/routes/addresses.ts +19 -9
- package/src/apps/data/routes/balances.test.ts +144 -11
- package/src/apps/data/routes/balances.ts +140 -51
- package/src/apps/data/routes/exchanges.test.ts +540 -9
- package/src/apps/data/routes/exchanges.ts +690 -103
- package/src/apps/data/routes/funding.test.ts +84 -0
- package/src/apps/data/routes/funding.ts +38 -6
- package/src/apps/data/routes/receipts.test.ts +125 -23
- package/src/apps/data/routes/receipts.ts +205 -100
- package/src/apps/data/routes/tokens.test.ts +43 -0
- package/src/apps/data/routes/tokens.ts +27 -12
- package/src/apps/data/routes/transactions.test.ts +72 -19
- package/src/apps/data/routes/transactions.ts +162 -92
- package/src/apps/data/routes/transfers.test.ts +146 -4
- package/src/apps/data/routes/transfers.ts +91 -13
- package/src/apps/data/routes/valuation.test.ts +422 -0
- package/src/apps/data/routes/valuation.ts +423 -0
- package/src/apps/data/routes/verified-tokens.ts +14 -2
- package/src/apps/data/routes/webhooks.test.ts +56 -8
- package/src/apps/data/routes/webhooks.ts +144 -27
- package/src/apps/index.ts +1 -1
- package/src/apps/management/App.ts +13 -0
- package/src/apps/management/routes/api-keys.test.ts +87 -0
- package/src/apps/management/routes/api-keys.ts +4 -3
- package/src/apps/management/routes/billing.test.ts +112 -1
- package/src/apps/management/routes/billing.ts +7 -2
- package/src/apps/management/routes/faucet.test.ts +79 -0
- package/src/apps/management/routes/faucet.ts +185 -0
- package/src/apps/management/routes/invitations.test.ts +172 -0
- package/src/apps/management/routes/invitations.ts +3 -0
- package/src/apps/management/routes/invite-links.test.ts +117 -0
- package/src/apps/management/routes/invite-links.ts +43 -1
- package/src/apps/management/routes/me.test.ts +140 -88
- package/src/apps/management/routes/me.ts +6 -0
- package/src/apps/management/routes/usage.test.ts +6 -0
- package/src/apps/management/routes/usage.ts +7 -0
- package/src/apps/management/routes/verified-token-requests.test.ts +377 -0
- package/src/apps/management/routes/verified-token-requests.ts +397 -0
- package/src/apps/management/routes/webhooks.test.ts +426 -0
- package/src/apps/management/routes/webhooks.ts +672 -0
- package/src/apps/mcp.test.ts +13 -0
- package/src/apps/mcp.ts +18 -5
- package/src/cli/Cli.test.ts +36 -0
- package/src/cli/Cli.ts +7 -2
- package/src/db/Db.test.ts +19 -0
- package/src/db/Db.ts +95 -0
- package/src/db/Schema.ts +53 -0
- package/src/db/tables/earlyAccess.ts +86 -0
- package/src/db/tables/invitations.ts +26 -1
- package/src/db/tables/inviteLinks.ts +22 -3
- package/src/db/tables/sponsoredTransactions.ts +4 -0
- package/src/db/tables/verifiedTokenRequests.test.ts +200 -0
- package/src/db/tables/verifiedTokenRequests.ts +182 -0
- package/src/db/tables/webhookSubscriptions.ts +31 -0
- package/src/internal/Auth.ts +73 -45
- package/src/internal/FundingQuotes.test.ts +143 -1
- package/src/internal/FundingQuotes.ts +95 -28
- package/src/internal/Log.test-d.ts +21 -0
- package/src/internal/Log.test.ts +50 -0
- package/src/internal/Log.ts +24 -1
- package/src/internal/MetricSink.test.ts +160 -0
- package/src/internal/MetricSink.ts +10 -0
- package/src/internal/OpenApi.ts +3 -0
- package/src/internal/Schema.ts +50 -5
- package/src/internal/Value.test.ts +20 -0
- package/src/internal/Value.ts +24 -1
- package/src/internal/VerifiedTokens.ts +9 -1
- package/src/internal/Webhooks.test.ts +140 -0
- package/src/internal/Webhooks.ts +53 -9
|
@@ -14,10 +14,14 @@ import * as Store from '../../../internal/Store.js';
|
|
|
14
14
|
import * as Timing from '../../../internal/Timing.js';
|
|
15
15
|
import * as Ttl from '../../../internal/Ttl.js';
|
|
16
16
|
import * as Value from '../../../internal/Value.js';
|
|
17
|
+
import * as VerifiedTokens from '../../../internal/VerifiedTokens.js';
|
|
18
|
+
import * as FxOracle from '../FxOracle.js';
|
|
17
19
|
import * as Tokens from './tokens.js';
|
|
18
20
|
import * as Transfers from './transfers.js';
|
|
21
|
+
import * as Valuation from './valuation.js';
|
|
19
22
|
/** Example transaction hash surfaced in OpenAPI docs. */
|
|
20
23
|
const exampleHash = '0x4845ae2098724ab26a5d89370dce5124d044be6a5acc164afc348662de67d474';
|
|
24
|
+
const tokenFields = ['token.logoUri', 'token.verified'];
|
|
21
25
|
/** Zod schemas owned by the activity handlers. */
|
|
22
26
|
export var schema;
|
|
23
27
|
(function (schema) {
|
|
@@ -25,19 +29,31 @@ export var schema;
|
|
|
25
29
|
const Signer = z
|
|
26
30
|
.union([z.literal('self'), Schema.Address])
|
|
27
31
|
.check(z.describe('Who signed the activity: `self`, or the access-key address used to sign it.'));
|
|
28
|
-
/**
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
32
|
+
/** A token with required RPC metadata and optional curated fields. */
|
|
33
|
+
schema.Token = Schema.describe(Tokens.schema.TokenReference, 'A token referenced by an activity item.');
|
|
34
|
+
/** A token amount carrying its nominal value in the requested denomination. */
|
|
35
|
+
const ValuedAmount = z.extend(Schema.TokenAmount, {
|
|
36
|
+
valuation: z
|
|
37
|
+
.optional(z.nullable(Valuation.schema.Value))
|
|
38
|
+
.check(z.describe('The amount’s nominal value in the requested `denomination`. `null` when the token is ' +
|
|
39
|
+
'unverified, its display currency has no rate, or rates were unavailable.')),
|
|
40
|
+
});
|
|
41
|
+
/** Self-contained amount for a destination token. */
|
|
42
|
+
const DestinationAmount = ValuedAmount.check(z.describe('Amount associated with `destinationToken`.'));
|
|
43
|
+
/** Self-contained amount for a refunded token. */
|
|
44
|
+
const RefundAmount = ValuedAmount.check(z.describe('Amount associated with `refund`.'));
|
|
45
|
+
/** Self-contained amount for a source token. */
|
|
46
|
+
const SourceAmount = ValuedAmount.check(z.describe('Amount associated with `sourceToken`.'));
|
|
47
|
+
/** Page-level resources: valuation rate provenance. */
|
|
48
|
+
schema.Meta = z
|
|
49
|
+
.object({
|
|
50
|
+
pricing: z
|
|
51
|
+
.optional(Valuation.schema.Pricing)
|
|
52
|
+
.check(z.describe('Rate provenance for amount valuations. Present when conversion rates were ' +
|
|
53
|
+
'consulted; absent when every value was identity-valued or rates were unavailable.')),
|
|
54
|
+
})
|
|
55
|
+
.check(z.describe('Page-level resources attached to this response.'));
|
|
56
|
+
/** A token transfer with subject-relative direction and signer fields. */
|
|
41
57
|
schema.Transfer = z
|
|
42
58
|
.object({
|
|
43
59
|
attribution: z
|
|
@@ -46,9 +62,12 @@ export var schema;
|
|
|
46
62
|
blockNumber: z
|
|
47
63
|
.number()
|
|
48
64
|
.check(z.int(), z.nonnegative(), z.describe('Block number where this transfer was included.'), z.meta({ examples: [12345678] })),
|
|
65
|
+
destinationAmount: z
|
|
66
|
+
.optional(DestinationAmount)
|
|
67
|
+
.check(z.describe('Amount delivered to the recipient for a cross-token transfer. Omitted with `destinationToken` for a same-token transfer.')),
|
|
49
68
|
destinationToken: z
|
|
50
69
|
.optional(schema.Token)
|
|
51
|
-
.check(z.describe('Token
|
|
70
|
+
.check(z.describe('Token delivered to the recipient when it differs from the source token. Omitted for a same-token transfer.')),
|
|
52
71
|
direction: z
|
|
53
72
|
.enum(['in', 'out'])
|
|
54
73
|
.check(z.describe('The address’s side of the transfer: `in` means received, and `out` means sent.')),
|
|
@@ -60,13 +79,17 @@ export var schema;
|
|
|
60
79
|
signer: z
|
|
61
80
|
.optional(Signer)
|
|
62
81
|
.check(z.describe('For outbound transfers, who signed it: `self` or the access-key address. Omitted for inbound transfers.')),
|
|
63
|
-
|
|
82
|
+
sourceAmount: SourceAmount,
|
|
83
|
+
sourceToken: schema.Token.check(z.describe('Token that moved in the transfer.')),
|
|
64
84
|
timestamp: z
|
|
65
85
|
.iso.datetime()
|
|
66
86
|
.check(z.describe('Block timestamp for the transfer.'), z.meta({ examples: ['2024-01-01T00:00:00Z'] })), // prettier-ignore
|
|
67
87
|
transactionHash: Schema.Hash.check(z.describe('Transaction hash that contains this transfer.')),
|
|
68
88
|
})
|
|
69
|
-
.check(z.
|
|
89
|
+
.check(z.refine((data) => (data.destinationToken === undefined) === (data.destinationAmount === undefined), {
|
|
90
|
+
error: '`destinationAmount` and `destinationToken` must be returned together.',
|
|
91
|
+
path: ['destinationAmount'],
|
|
92
|
+
}), z.describe('One token transfer involving the requested address.'));
|
|
70
93
|
/**
|
|
71
94
|
* One transaction log, decoded into a known Tempo event when possible. The
|
|
72
95
|
* raw fields (`address`/`data`/`logIndex`/`topics`) are always present so no
|
|
@@ -126,7 +149,7 @@ export var schema;
|
|
|
126
149
|
z
|
|
127
150
|
.object({
|
|
128
151
|
...base,
|
|
129
|
-
data: schema.Transfer.check(z.describe('Transfer details
|
|
152
|
+
data: schema.Transfer.check(z.describe('Transfer details with feed-relative direction and signer fields.')),
|
|
130
153
|
type: z
|
|
131
154
|
.literal('transfer')
|
|
132
155
|
.check(z.describe('Activity type that tells you which `data` shape this entry uses.')),
|
|
@@ -138,7 +161,8 @@ export var schema;
|
|
|
138
161
|
data: z
|
|
139
162
|
.object({
|
|
140
163
|
recipient: Schema.Address.check(z.describe('Address that received the transfer.')),
|
|
141
|
-
|
|
164
|
+
sourceAmount: SourceAmount,
|
|
165
|
+
sourceToken: schema.Token.check(z.describe('Token that was minted.')),
|
|
142
166
|
})
|
|
143
167
|
.check(z.describe('A token mint activity.')),
|
|
144
168
|
type: z
|
|
@@ -153,7 +177,8 @@ export var schema;
|
|
|
153
177
|
.object({
|
|
154
178
|
sender: Schema.Address.check(z.describe('Address whose token balance was burned.')),
|
|
155
179
|
signer: Signer,
|
|
156
|
-
|
|
180
|
+
sourceAmount: SourceAmount,
|
|
181
|
+
sourceToken: schema.Token.check(z.describe('Token that was burned.')),
|
|
157
182
|
})
|
|
158
183
|
.check(z.describe('A token burn activity.')),
|
|
159
184
|
type: z
|
|
@@ -166,8 +191,10 @@ export var schema;
|
|
|
166
191
|
...base,
|
|
167
192
|
data: z
|
|
168
193
|
.object({
|
|
194
|
+
destinationAmount: DestinationAmount,
|
|
169
195
|
destinationToken: schema.Token.check(z.describe('Token the address received in the swap.')),
|
|
170
196
|
signer: Signer,
|
|
197
|
+
sourceAmount: SourceAmount,
|
|
171
198
|
sourceToken: schema.Token.check(z.describe('Token the address sent into the swap.')),
|
|
172
199
|
})
|
|
173
200
|
.check(z.describe('Swap inferred from token transfers through the DEX precompile. This feed entry is a summary, so per-fill details, route, and rate are not included.')),
|
|
@@ -182,7 +209,8 @@ export var schema;
|
|
|
182
209
|
data: z
|
|
183
210
|
.object({
|
|
184
211
|
signer: Signer,
|
|
185
|
-
|
|
212
|
+
sourceAmount: SourceAmount,
|
|
213
|
+
sourceToken: schema.Token.check(z.describe('Token approved for spending.')),
|
|
186
214
|
spender: Schema.Address.check(z.describe('Address allowed to spend the approved amount.')),
|
|
187
215
|
})
|
|
188
216
|
.check(z.describe('A token allowance approval activity.')),
|
|
@@ -199,9 +227,15 @@ export var schema;
|
|
|
199
227
|
refund: z
|
|
200
228
|
.optional(schema.Token)
|
|
201
229
|
.check(z.describe('Token refunded to the address when the session closed, if any.')),
|
|
230
|
+
refundAmount: z
|
|
231
|
+
.optional(RefundAmount)
|
|
232
|
+
.check(z.describe('Amount refunded to the address when the session closed, if any.')),
|
|
202
233
|
signer: Signer,
|
|
203
234
|
})
|
|
204
|
-
.check(z.
|
|
235
|
+
.check(z.refine((data) => (data.refund === undefined) === (data.refundAmount === undefined), {
|
|
236
|
+
error: '`refundAmount` and `refund` must be returned together.',
|
|
237
|
+
path: ['refundAmount'],
|
|
238
|
+
}), z.describe('A payment-channel session close activity.')),
|
|
205
239
|
type: z
|
|
206
240
|
.literal('session-closed')
|
|
207
241
|
.check(z.describe('Activity type that tells you which `data` shape this entry uses.')),
|
|
@@ -266,7 +300,8 @@ export var schema;
|
|
|
266
300
|
.object({
|
|
267
301
|
sender: Schema.Address.check(z.describe('Address whose blocked balance was burned by policy.')),
|
|
268
302
|
signer: Signer,
|
|
269
|
-
|
|
303
|
+
sourceAmount: SourceAmount,
|
|
304
|
+
sourceToken: schema.Token.check(z.describe('Token that was burned.')),
|
|
270
305
|
})
|
|
271
306
|
.check(z.describe('A compliance burn of funds the receive policy blocked, distinct from a normal burn.')),
|
|
272
307
|
type: z
|
|
@@ -283,7 +318,8 @@ export var schema;
|
|
|
283
318
|
payee: Schema.Address.check(z.describe('Address that receives payments from the channel.')),
|
|
284
319
|
payer: Schema.Address.check(z.describe('Address that funds the channel.')),
|
|
285
320
|
signer: Signer,
|
|
286
|
-
|
|
321
|
+
sourceAmount: SourceAmount,
|
|
322
|
+
sourceToken: schema.Token.check(z.describe('Token locked into the channel.')),
|
|
287
323
|
})
|
|
288
324
|
.check(z.describe('A payment channel was opened and funded.')),
|
|
289
325
|
type: z
|
|
@@ -298,7 +334,8 @@ export var schema;
|
|
|
298
334
|
.object({
|
|
299
335
|
channelId: Schema.Hex.check(z.describe('Identifier of the payment channel.')),
|
|
300
336
|
signer: Signer,
|
|
301
|
-
|
|
337
|
+
sourceAmount: SourceAmount,
|
|
338
|
+
sourceToken: schema.Token.check(z.describe('Token added to the channel deposit.')),
|
|
302
339
|
})
|
|
303
340
|
.check(z.describe('A payment channel deposit was topped up.')),
|
|
304
341
|
type: z
|
|
@@ -315,7 +352,8 @@ export var schema;
|
|
|
315
352
|
payee: Schema.Address.check(z.describe('Address that received the settled payment.')),
|
|
316
353
|
payer: Schema.Address.check(z.describe('Address that funded the channel.')),
|
|
317
354
|
signer: Signer,
|
|
318
|
-
|
|
355
|
+
sourceAmount: SourceAmount,
|
|
356
|
+
sourceToken: schema.Token.check(z.describe('Token paid out in this settlement.')),
|
|
319
357
|
})
|
|
320
358
|
.check(z.describe('An incremental payment-channel settlement to the payee.')),
|
|
321
359
|
type: z
|
|
@@ -333,13 +371,25 @@ export var schema;
|
|
|
333
371
|
payer: Schema.Address.check(z.describe('Address that funded the channel.')),
|
|
334
372
|
refund: z
|
|
335
373
|
.optional(schema.Token)
|
|
336
|
-
.check(z.describe('Token
|
|
374
|
+
.check(z.describe('Token refunded to the payer on close, if any.')),
|
|
375
|
+
refundAmount: z
|
|
376
|
+
.optional(RefundAmount)
|
|
377
|
+
.check(z.describe('Amount refunded to the payer on close, if any.')),
|
|
337
378
|
signer: Signer,
|
|
379
|
+
sourceAmount: z
|
|
380
|
+
.optional(SourceAmount)
|
|
381
|
+
.check(z.describe('Final amount paid to the payee on close, if any.')),
|
|
338
382
|
sourceToken: z
|
|
339
383
|
.optional(schema.Token)
|
|
340
|
-
.check(z.describe('Token
|
|
384
|
+
.check(z.describe('Token paid out to the payee on close, if any.')),
|
|
341
385
|
})
|
|
342
|
-
.check(z.
|
|
386
|
+
.check(z.refine((data) => (data.refund === undefined) === (data.refundAmount === undefined), {
|
|
387
|
+
error: '`refundAmount` and `refund` must be returned together.',
|
|
388
|
+
path: ['refundAmount'],
|
|
389
|
+
}), z.refine((data) => (data.sourceToken === undefined) === (data.sourceAmount === undefined), {
|
|
390
|
+
error: '`sourceAmount` and `sourceToken` must be returned together.',
|
|
391
|
+
path: ['sourceAmount'],
|
|
392
|
+
}), z.describe('A payment channel was closed, paying out the payee and refunding the payer.')),
|
|
343
393
|
type: z
|
|
344
394
|
.literal('channel-closed')
|
|
345
395
|
.check(z.describe('Activity type that tells you which `data` shape this entry uses.')),
|
|
@@ -371,7 +421,8 @@ export var schema;
|
|
|
371
421
|
.enum(['bid', 'ask'])
|
|
372
422
|
.check(z.describe('Order side: `bid` buys the base token, `ask` sells it.'), z.meta({ examples: ['bid'] })), // prettier-ignore
|
|
373
423
|
signer: Signer,
|
|
374
|
-
|
|
424
|
+
sourceAmount: SourceAmount,
|
|
425
|
+
sourceToken: schema.Token.check(z.describe('Token escrowed for the order.')),
|
|
375
426
|
tick: z
|
|
376
427
|
.number()
|
|
377
428
|
.check(z.int(), z.describe('Price tick the order was placed at.'), z.meta({ examples: [0] })),
|
|
@@ -402,7 +453,8 @@ export var schema;
|
|
|
402
453
|
data: z
|
|
403
454
|
.object({
|
|
404
455
|
signer: Signer,
|
|
405
|
-
|
|
456
|
+
sourceAmount: SourceAmount,
|
|
457
|
+
sourceToken: schema.Token.check(z.describe('Token used for the distributed fees.')),
|
|
406
458
|
validator: Schema.Address.check(z.describe('Validator that received the distributed fees.')),
|
|
407
459
|
})
|
|
408
460
|
.check(z.describe('Accrued validator fees were distributed.')),
|
|
@@ -416,9 +468,11 @@ export var schema;
|
|
|
416
468
|
...base,
|
|
417
469
|
data: z
|
|
418
470
|
.object({
|
|
419
|
-
|
|
471
|
+
destinationAmount: DestinationAmount,
|
|
472
|
+
destinationToken: schema.Token.check(z.describe('Token received from the fee AMM.')),
|
|
420
473
|
signer: Signer,
|
|
421
|
-
|
|
474
|
+
sourceAmount: SourceAmount,
|
|
475
|
+
sourceToken: schema.Token.check(z.describe('Token sent into the fee AMM.')),
|
|
422
476
|
swapper: Schema.Address.check(z.describe('Address that performed the rebalance swap.')),
|
|
423
477
|
})
|
|
424
478
|
.check(z.describe('A fee-AMM rebalance swap between a validator and user token.')),
|
|
@@ -434,7 +488,8 @@ export var schema;
|
|
|
434
488
|
.object({
|
|
435
489
|
funder: Schema.Address.check(z.describe('Address that funded the reward pool.')),
|
|
436
490
|
signer: Signer,
|
|
437
|
-
|
|
491
|
+
sourceAmount: SourceAmount,
|
|
492
|
+
sourceToken: schema.Token.check(z.describe('Token added to the reward pool.')),
|
|
438
493
|
})
|
|
439
494
|
.check(z.describe('A token reward pool was funded.')),
|
|
440
495
|
type: z
|
|
@@ -465,7 +520,8 @@ export var schema;
|
|
|
465
520
|
account: Schema.Address.check(z.describe('Account the access key belongs to.')),
|
|
466
521
|
publicKey: Schema.Address.check(z.describe('Public key of the access key whose limit changed.')),
|
|
467
522
|
signer: Signer,
|
|
468
|
-
|
|
523
|
+
sourceAmount: SourceAmount,
|
|
524
|
+
sourceToken: schema.Token.check(z.describe('Token whose spending limit was updated.')),
|
|
469
525
|
})
|
|
470
526
|
.check(z.describe('An access key’s per-token spending limit was updated.')),
|
|
471
527
|
type: z
|
|
@@ -507,7 +563,8 @@ export var schema;
|
|
|
507
563
|
.enum(['bid', 'ask'])
|
|
508
564
|
.check(z.describe('Side of the flipped order: `bid` buys the base token, `ask` sells it.'), z.meta({ examples: ['bid'] })), // prettier-ignore
|
|
509
565
|
signer: Signer,
|
|
510
|
-
|
|
566
|
+
sourceAmount: SourceAmount,
|
|
567
|
+
sourceToken: schema.Token.check(z.describe('Token the flipped order rests with.')),
|
|
511
568
|
tick: z
|
|
512
569
|
.number()
|
|
513
570
|
.check(z.int(), z.describe('Price tick the original order filled at.'), z.meta({ examples: [0] })),
|
|
@@ -1085,6 +1142,12 @@ export var schema;
|
|
|
1085
1142
|
schema.Entry = z
|
|
1086
1143
|
.union([...schema.items, schema.Group])
|
|
1087
1144
|
.check(z.describe('Either one activity item, or a grouped set of access-key activity items.'));
|
|
1145
|
+
/** Optional token fields that require sources beyond RPC metadata. */
|
|
1146
|
+
schema.Include = z
|
|
1147
|
+
.enum(tokenFields)
|
|
1148
|
+
.check(z.describe('Additional token fields to include in activity responses.'));
|
|
1149
|
+
/** Parses comma-separated optional token fields. */
|
|
1150
|
+
schema.includeQuery = Schema.includeQuery(schema.Include, 'Comma-separated token fields to include, such as `token.logoUri,token.verified`.');
|
|
1088
1151
|
/** Schemas for the getAddressActivities operation. */
|
|
1089
1152
|
let getAddressActivities;
|
|
1090
1153
|
(function (getAddressActivities) {
|
|
@@ -1099,10 +1162,12 @@ export var schema;
|
|
|
1099
1162
|
.strictObject({
|
|
1100
1163
|
chainId: Schema.ChainIdQuery,
|
|
1101
1164
|
cursor: Schema.Cursor,
|
|
1165
|
+
denomination: Schema.Denomination,
|
|
1102
1166
|
// Folding is opt-in: by default every item is returned at the root.
|
|
1103
1167
|
group: z
|
|
1104
1168
|
._default(Schema.booleanQuery(), false)
|
|
1105
1169
|
.check(z.describe('Set to `true` to fold consecutive items signed by the same access key on the same UTC day into `group` entries. Defaults to `false`, which returns every item separately.'), z.meta({ examples: [true] })),
|
|
1170
|
+
include: schema.includeQuery,
|
|
1106
1171
|
limit: Schema.Limit,
|
|
1107
1172
|
// Raw-log capture is opt-in: it can add a large `events` array to every
|
|
1108
1173
|
// item, so the default feed stays lean.
|
|
@@ -1120,6 +1185,9 @@ export var schema;
|
|
|
1120
1185
|
getAddressActivities.Response = z
|
|
1121
1186
|
.object({
|
|
1122
1187
|
data: z.array(schema.Entry).check(z.describe('Activity feed entries for the address.')),
|
|
1188
|
+
meta: z
|
|
1189
|
+
.optional(schema.Meta)
|
|
1190
|
+
.check(z.describe('Page-level resources, such as valuation rate provenance.')),
|
|
1123
1191
|
nextCursor: Schema.NextCursor,
|
|
1124
1192
|
})
|
|
1125
1193
|
.check(z.describe('A page of human-readable activity for the address.'));
|
|
@@ -1137,6 +1205,8 @@ export var schema;
|
|
|
1137
1205
|
getTransactionActivities.Query = z
|
|
1138
1206
|
.strictObject({
|
|
1139
1207
|
chainId: Schema.ChainIdQuery,
|
|
1208
|
+
denomination: Schema.Denomination,
|
|
1209
|
+
include: schema.includeQuery,
|
|
1140
1210
|
// Raw-log capture is opt-in: it can add a large `events` array to every
|
|
1141
1211
|
// item, so the default response stays lean.
|
|
1142
1212
|
logs: z
|
|
@@ -1153,6 +1223,9 @@ export var schema;
|
|
|
1153
1223
|
getTransactionActivities.Response = z
|
|
1154
1224
|
.object({
|
|
1155
1225
|
data: z.array(schema.Item).check(z.describe('Activity items classified from the transaction.')),
|
|
1226
|
+
meta: z
|
|
1227
|
+
.optional(schema.Meta)
|
|
1228
|
+
.check(z.describe('Page-level resources, such as valuation rate provenance.')),
|
|
1156
1229
|
})
|
|
1157
1230
|
.check(z.describe('The human-readable activity that happened on a transaction.'));
|
|
1158
1231
|
})(getTransactionActivities = schema.getTransactionActivities || (schema.getTransactionActivities = {}));
|
|
@@ -1308,6 +1381,11 @@ const minGroupEntries = 5;
|
|
|
1308
1381
|
const maxGroupSize = 50;
|
|
1309
1382
|
/** Token-bearing keys on an item's `data` payload, walked for enrichment. */
|
|
1310
1383
|
const tokenKeys = ['destinationToken', 'refund', 'sourceToken'];
|
|
1384
|
+
const amountKeyByTokenKey = {
|
|
1385
|
+
destinationToken: 'destinationAmount',
|
|
1386
|
+
refund: 'refundAmount',
|
|
1387
|
+
sourceToken: 'sourceAmount',
|
|
1388
|
+
};
|
|
1311
1389
|
/** Builds common public activity fields from the normalized transaction hash and representative log. */
|
|
1312
1390
|
function baseFor(options) {
|
|
1313
1391
|
return {
|
|
@@ -1336,7 +1414,8 @@ function baseFor(options) {
|
|
|
1336
1414
|
* consecutive access-key-signed items into `group` entries. Pagination uses the
|
|
1337
1415
|
* same `(block_num, tx_idx)` keyset cursor the pipeline emits.
|
|
1338
1416
|
*/
|
|
1339
|
-
export function addresses() {
|
|
1417
|
+
export function addresses(options = {}) {
|
|
1418
|
+
const oracle = options.fx?.oracle ?? FxOracle.ecb();
|
|
1340
1419
|
return new Hono().get('/v1/addresses/:address/activities', Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }), OpenApi.validate('param', schema.getAddressActivities.Params, {
|
|
1341
1420
|
code: 'address_invalid',
|
|
1342
1421
|
message: 'Check the account address and try again.',
|
|
@@ -1347,7 +1426,7 @@ export function addresses() {
|
|
|
1347
1426
|
description: 'Get a human-readable feed of what an address has been doing onchain, including payments sent and received, swaps, approvals, and more.',
|
|
1348
1427
|
operationId: 'getAddressActivities',
|
|
1349
1428
|
responses: OpenApi.responses({
|
|
1350
|
-
errors: { 502: 'Tempo could not read activity data from
|
|
1429
|
+
errors: { 502: 'Tempo could not read activity or token data from an upstream service.' },
|
|
1351
1430
|
success: {
|
|
1352
1431
|
description: 'A page of address activity entries.',
|
|
1353
1432
|
schema: schema.getAddressActivities.Response,
|
|
@@ -1374,15 +1453,13 @@ export function addresses() {
|
|
|
1374
1453
|
});
|
|
1375
1454
|
const { address } = c.req.valid('param');
|
|
1376
1455
|
const query = c.req.valid('query');
|
|
1377
|
-
// Cursor pages
|
|
1378
|
-
// cache them aggressively; the head page keeps the route's short `feed`
|
|
1379
|
-
// default.
|
|
1456
|
+
// Cursor pages carry current valuations and curated verification data.
|
|
1380
1457
|
if (query.cursor !== undefined)
|
|
1381
|
-
Cache.setPolicy(c, Cache.policies.
|
|
1458
|
+
Cache.setPolicy(c, Cache.policies.metadata);
|
|
1382
1459
|
try {
|
|
1383
1460
|
const chainId = query.chainId ?? c.get('chainId');
|
|
1384
1461
|
const provider = tidx({ chainId, tidx: c.get('getTidx')(chainId) });
|
|
1385
|
-
const { items, nextCursor } = await Timing.time(c, 'address_activities', () => Store.memoize(() => list(provider, {
|
|
1462
|
+
const { items: unenrichedItems, nextCursor } = await Timing.time(c, 'address_activities', () => Store.memoize(() => list(provider, {
|
|
1386
1463
|
address: address,
|
|
1387
1464
|
cursor: query.cursor,
|
|
1388
1465
|
group: query.group,
|
|
@@ -1394,20 +1471,26 @@ export function addresses() {
|
|
|
1394
1471
|
store: c.get('store'),
|
|
1395
1472
|
ttl: Ttl.seconds(15),
|
|
1396
1473
|
}));
|
|
1397
|
-
//
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1474
|
+
// Build immutable token and structured amount copies from RPC metadata.
|
|
1475
|
+
const { items, rates } = await enrichTokens(c, {
|
|
1476
|
+
chainId,
|
|
1477
|
+
denomination: query.denomination ?? 'USD',
|
|
1478
|
+
include: query.include,
|
|
1479
|
+
items: unenrichedItems,
|
|
1480
|
+
oracle,
|
|
1481
|
+
});
|
|
1402
1482
|
// Fold consecutive access-key-signed items into `group` entries only
|
|
1403
1483
|
// when requested; otherwise every item is returned at the root.
|
|
1404
1484
|
const data = query.group ? groupByAccessKey(items) : items;
|
|
1405
1485
|
return c.json(Response.validated(schema.getAddressActivities.Response, {
|
|
1406
1486
|
data,
|
|
1487
|
+
...(rates ? { meta: { pricing: Valuation.pricing(rates, oracle) } } : {}),
|
|
1407
1488
|
nextCursor,
|
|
1408
1489
|
}), 200);
|
|
1409
1490
|
}
|
|
1410
1491
|
catch (cause) {
|
|
1492
|
+
if (cause instanceof Valuation.UnsupportedDenominationError)
|
|
1493
|
+
return Response.error(c, { code: 'query_invalid', message: cause.message, status: 400 });
|
|
1411
1494
|
return Response.upstream(c, cause);
|
|
1412
1495
|
}
|
|
1413
1496
|
});
|
|
@@ -1422,7 +1505,8 @@ export function addresses() {
|
|
|
1422
1505
|
* classified item(s) — usually one headline activity — with the full per-tx
|
|
1423
1506
|
* event set available via `logs=true`.
|
|
1424
1507
|
*/
|
|
1425
|
-
export function transactions() {
|
|
1508
|
+
export function transactions(options = {}) {
|
|
1509
|
+
const oracle = options.fx?.oracle ?? FxOracle.ecb();
|
|
1426
1510
|
return new Hono().get('/v1/transactions/:transactionHash/activities', Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }), OpenApi.validate('param', schema.getTransactionActivities.Params, {
|
|
1427
1511
|
code: 'transaction_invalid',
|
|
1428
1512
|
message: 'Check the transaction hash and try again.',
|
|
@@ -1438,7 +1522,7 @@ export function transactions() {
|
|
|
1438
1522
|
description: 'No mined transaction was found for that hash.',
|
|
1439
1523
|
codes: ['transaction_not_found'],
|
|
1440
1524
|
},
|
|
1441
|
-
502: 'Tempo could not read activity data from
|
|
1525
|
+
502: 'Tempo could not read activity or token data from an upstream service.',
|
|
1442
1526
|
},
|
|
1443
1527
|
success: {
|
|
1444
1528
|
description: 'The classified activity for the transaction.',
|
|
@@ -1448,10 +1532,8 @@ export function transactions() {
|
|
|
1448
1532
|
summary: 'List transaction activities',
|
|
1449
1533
|
tags: ['Activities'],
|
|
1450
1534
|
}), Cache.response({
|
|
1451
|
-
//
|
|
1452
|
-
//
|
|
1453
|
-
// is not cached with a long header that would mask the eventual result;
|
|
1454
|
-
// the handler upgrades the 200 to `immutable` below.
|
|
1535
|
+
// Default to no-store so a 404 does not mask the eventual mined result.
|
|
1536
|
+
// Successful responses use the metadata policy for current valuations.
|
|
1455
1537
|
cacheControl: Cache.policies.noStore,
|
|
1456
1538
|
name: 'tempo-api:transactions:v1',
|
|
1457
1539
|
key: (c) => Cache.urlKey(c, schema.getTransactionActivities.Query),
|
|
@@ -1472,7 +1554,7 @@ export function transactions() {
|
|
|
1472
1554
|
const query = c.req.valid('query');
|
|
1473
1555
|
const chainId = query.chainId ?? c.get('chainId');
|
|
1474
1556
|
try {
|
|
1475
|
-
const
|
|
1557
|
+
const unenrichedItems = await Timing.time(c, 'transaction_activities', () => Store.memoize(() => getTransactionActivities({
|
|
1476
1558
|
chainId,
|
|
1477
1559
|
logs: query.logs,
|
|
1478
1560
|
store: c.get('store'),
|
|
@@ -1483,20 +1565,30 @@ export function transactions() {
|
|
|
1483
1565
|
store: c.get('store'),
|
|
1484
1566
|
ttl: Ttl.seconds(15),
|
|
1485
1567
|
}));
|
|
1486
|
-
if (
|
|
1568
|
+
if (unenrichedItems === null)
|
|
1487
1569
|
return Response.error(c, {
|
|
1488
1570
|
code: 'transaction_not_found',
|
|
1489
1571
|
message: 'Transaction not found',
|
|
1490
1572
|
status: 404,
|
|
1491
1573
|
});
|
|
1492
|
-
//
|
|
1493
|
-
Cache.setPolicy(c, Cache.policies.
|
|
1494
|
-
//
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1574
|
+
// Mined activity still carries current valuations and verification data.
|
|
1575
|
+
Cache.setPolicy(c, Cache.policies.metadata);
|
|
1576
|
+
// Build immutable token and structured amount copies from RPC metadata.
|
|
1577
|
+
const { items, rates } = await enrichTokens(c, {
|
|
1578
|
+
chainId,
|
|
1579
|
+
denomination: query.denomination ?? 'USD',
|
|
1580
|
+
include: query.include,
|
|
1581
|
+
items: unenrichedItems,
|
|
1582
|
+
oracle,
|
|
1583
|
+
});
|
|
1584
|
+
return c.json(Response.validated(schema.getTransactionActivities.Response, {
|
|
1585
|
+
data: items,
|
|
1586
|
+
...(rates ? { meta: { pricing: Valuation.pricing(rates, oracle) } } : {}),
|
|
1587
|
+
}), 200);
|
|
1498
1588
|
}
|
|
1499
1589
|
catch (cause) {
|
|
1590
|
+
if (cause instanceof Valuation.UnsupportedDenominationError)
|
|
1591
|
+
return Response.error(c, { code: 'query_invalid', message: cause.message, status: 400 });
|
|
1500
1592
|
return Response.upstream(c, cause);
|
|
1501
1593
|
}
|
|
1502
1594
|
});
|
|
@@ -1595,7 +1687,7 @@ export async function list(provider, options) {
|
|
|
1595
1687
|
allItems.push(...page.flatMap((txGroup) => classifyGroup(txGroup, viewer, fingerprintMap, logs).map(withTitle)));
|
|
1596
1688
|
lastGroup = page[page.length - 1];
|
|
1597
1689
|
const enough = group
|
|
1598
|
-
?
|
|
1690
|
+
? groupByAccessKeyItems(allItems).length >= minGroupEntries
|
|
1599
1691
|
: allItems.length >= limit;
|
|
1600
1692
|
if (enough || !hasMore)
|
|
1601
1693
|
break;
|
|
@@ -1605,8 +1697,8 @@ export async function list(provider, options) {
|
|
|
1605
1697
|
let nextCursor = null;
|
|
1606
1698
|
if (hasMore && lastGroup)
|
|
1607
1699
|
nextCursor = provider.cursorForGroup(lastGroup);
|
|
1608
|
-
// Items carry
|
|
1609
|
-
//
|
|
1700
|
+
// Items carry private `address`/`amount` stubs; the caller splits them into
|
|
1701
|
+
// public token references and structured amounts via {@link enrichTokens}.
|
|
1610
1702
|
return { items: allItems, nextCursor };
|
|
1611
1703
|
}
|
|
1612
1704
|
/**
|
|
@@ -3014,7 +3106,7 @@ function lowerOrNull(value) {
|
|
|
3014
3106
|
const text = Value.toText(value);
|
|
3015
3107
|
return text ? text.toLowerCase() : null;
|
|
3016
3108
|
}
|
|
3017
|
-
/** Builds a stub
|
|
3109
|
+
/** Builds a token stub whose metadata is filled by {@link enrichItem}. */
|
|
3018
3110
|
function token(amount, address) {
|
|
3019
3111
|
return { address: address.toLowerCase(), amount: (amount ?? 0n).toString() };
|
|
3020
3112
|
}
|
|
@@ -3027,48 +3119,94 @@ function collectTokens(item, set) {
|
|
|
3027
3119
|
set.add(t.address.toLowerCase());
|
|
3028
3120
|
}
|
|
3029
3121
|
}
|
|
3030
|
-
/**
|
|
3031
|
-
* Resolves metadata for every token referenced across a page of items and
|
|
3032
|
-
* spreads it into each item's stub tokens, in place. Routes through the shared
|
|
3033
|
-
* {@link Tokens.getTokenMetadata} (one `token.getMetadata` RPC per token,
|
|
3034
|
-
* memoized under the `token:v1:…` key shared with `/tokens` and `/transfers`)
|
|
3035
|
-
* instead of a parallel metadata fetch. Resolution is best-effort: a token
|
|
3036
|
-
* whose metadata is unavailable keeps just `address`/`amount`.
|
|
3037
|
-
*/
|
|
3122
|
+
/** Resolves core metadata into immutable items. Optional logo and verification sources are best-effort. */
|
|
3038
3123
|
async function enrichTokens(c, options) {
|
|
3039
|
-
const { chainId, items } = options;
|
|
3124
|
+
const { chainId, denomination, include, items, oracle } = options;
|
|
3040
3125
|
const addresses = new Set();
|
|
3041
3126
|
for (const item of items)
|
|
3042
3127
|
collectTokens(item, addresses);
|
|
3128
|
+
// Valuation keys off the curated snapshot; a snapshot failure degrades the
|
|
3129
|
+
// values to `null` rather than failing the feed.
|
|
3130
|
+
const snapshot = addresses.size > 0
|
|
3131
|
+
? await VerifiedTokens.snapshot(c, chainId).catch(() => undefined)
|
|
3132
|
+
: undefined;
|
|
3133
|
+
const rates = await Valuation.ratesFor(c, {
|
|
3134
|
+
currencies: snapshot
|
|
3135
|
+
? [...addresses].flatMap((address) => {
|
|
3136
|
+
const held = snapshot.byAddress.get(address)?.currency;
|
|
3137
|
+
return held === undefined ? [] : [held];
|
|
3138
|
+
})
|
|
3139
|
+
: [],
|
|
3140
|
+
denomination,
|
|
3141
|
+
oracle,
|
|
3142
|
+
});
|
|
3043
3143
|
if (addresses.size === 0)
|
|
3044
|
-
return;
|
|
3045
|
-
const
|
|
3046
|
-
|
|
3047
|
-
|
|
3144
|
+
return { items: items, rates };
|
|
3145
|
+
const includeLogoUri = include.includes('token.logoUri');
|
|
3146
|
+
const includeVerified = include.includes('token.verified');
|
|
3147
|
+
const resolved = await Timing.time(c, 'tokens', () => Promise.all([...addresses].map(async (address) => {
|
|
3148
|
+
const [logoUri, metadata] = await Promise.all([
|
|
3149
|
+
includeLogoUri
|
|
3150
|
+
? Tokens.getTokenLogo(c, { address, chainId }).catch(() => undefined)
|
|
3151
|
+
: undefined,
|
|
3152
|
+
Tokens.getTokenMetadata(c, { address, chainId }),
|
|
3153
|
+
]);
|
|
3154
|
+
return [
|
|
3155
|
+
address.toLowerCase(),
|
|
3156
|
+
{
|
|
3157
|
+
currency: metadata.currency,
|
|
3158
|
+
decimals: metadata.decimals,
|
|
3159
|
+
logoUri: includeLogoUri
|
|
3160
|
+
? (logoUri ?? snapshot?.byAddress.get(address)?.logoUri ?? metadata.logoUri)
|
|
3161
|
+
: undefined,
|
|
3162
|
+
name: metadata.name,
|
|
3163
|
+
symbol: metadata.symbol,
|
|
3164
|
+
verified: includeVerified && snapshot ? snapshot.byAddress.has(address) : undefined,
|
|
3165
|
+
},
|
|
3166
|
+
];
|
|
3167
|
+
})));
|
|
3048
3168
|
const byAddress = new Map(resolved);
|
|
3049
|
-
|
|
3050
|
-
enrichItem(item, byAddress)
|
|
3169
|
+
return {
|
|
3170
|
+
items: items.map((item) => enrichItem(item, byAddress, { denomination, rates, snapshot })),
|
|
3171
|
+
rates,
|
|
3172
|
+
};
|
|
3051
3173
|
}
|
|
3052
|
-
/**
|
|
3053
|
-
function enrichItem(item, byAddress) {
|
|
3054
|
-
const
|
|
3174
|
+
/** Returns an enriched copy of an item without mutating its cached token stubs. */
|
|
3175
|
+
function enrichItem(item, byAddress, valuation) {
|
|
3176
|
+
const source = item.data;
|
|
3177
|
+
const data = { ...item.data };
|
|
3055
3178
|
for (const key of tokenKeys) {
|
|
3056
|
-
const t =
|
|
3179
|
+
const t = source[key];
|
|
3057
3180
|
if (!t)
|
|
3058
3181
|
continue;
|
|
3059
3182
|
const meta = byAddress.get(t.address.toLowerCase());
|
|
3060
3183
|
if (!meta)
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3184
|
+
throw new Error(`Token metadata unavailable for ${t.address}`);
|
|
3185
|
+
data[amountKeyByTokenKey[key]] = {
|
|
3186
|
+
...Value.tokenAmount({
|
|
3187
|
+
baseUnits: t.amount,
|
|
3188
|
+
currency: meta.currency,
|
|
3189
|
+
decimals: meta.decimals,
|
|
3190
|
+
}),
|
|
3191
|
+
// Valued via the curated display currency, never the on-chain metadata.
|
|
3192
|
+
valuation: Valuation.valuationFor({
|
|
3193
|
+
amount: BigInt(t.amount),
|
|
3194
|
+
denomination: valuation.denomination,
|
|
3195
|
+
rates: valuation.rates,
|
|
3196
|
+
token: valuation.snapshot?.byAddress.get(t.address.toLowerCase()),
|
|
3197
|
+
}),
|
|
3198
|
+
};
|
|
3064
3199
|
data[key] = {
|
|
3065
|
-
|
|
3200
|
+
address: t.address,
|
|
3066
3201
|
currency: meta.currency,
|
|
3067
3202
|
decimals: meta.decimals,
|
|
3203
|
+
...(meta.logoUri !== undefined ? { logoUri: meta.logoUri } : {}),
|
|
3068
3204
|
name: meta.name,
|
|
3069
3205
|
symbol: meta.symbol,
|
|
3206
|
+
...(meta.verified !== undefined ? { verified: meta.verified } : {}),
|
|
3070
3207
|
};
|
|
3071
3208
|
}
|
|
3209
|
+
return { ...item, data };
|
|
3072
3210
|
}
|
|
3073
3211
|
/**
|
|
3074
3212
|
* Folds adjacent items signed by the same access key on the same UTC calendar
|
|
@@ -3076,6 +3214,10 @@ function enrichItem(item, byAddress) {
|
|
|
3076
3214
|
* Must be called once over the full, timestamp-sorted item list.
|
|
3077
3215
|
*/
|
|
3078
3216
|
export function groupByAccessKey(items) {
|
|
3217
|
+
return groupByAccessKeyItems(items);
|
|
3218
|
+
}
|
|
3219
|
+
/** Groups items while preserving whether their token data has been enriched. */
|
|
3220
|
+
function groupByAccessKeyItems(items) {
|
|
3079
3221
|
const entries = [];
|
|
3080
3222
|
let currentGroup = null;
|
|
3081
3223
|
for (const item of items) {
|