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
|
@@ -239,6 +239,12 @@ export namespace schema {
|
|
|
239
239
|
'A compact TIP-20 token reference with identity and display fields only.',
|
|
240
240
|
)
|
|
241
241
|
|
|
242
|
+
/** RPC token metadata embedded in resources, with optional curated fields. */
|
|
243
|
+
export const TokenReference = Schema.describe(
|
|
244
|
+
z.partial(z.omit(Token, { id: true }), { logoUri: true, verified: true }),
|
|
245
|
+
'A compact TIP-20 token reference with RPC metadata and optional enrichments.',
|
|
246
|
+
)
|
|
247
|
+
|
|
242
248
|
/** Schemas for the getTokenBySymbol operation. */
|
|
243
249
|
export namespace getTokenBySymbol {
|
|
244
250
|
/** Hono route pattern for verified token symbols. */
|
|
@@ -458,9 +464,9 @@ export namespace schema {
|
|
|
458
464
|
})
|
|
459
465
|
.check(z.describe('Path parameters for listing transactions involving this token contract.'))
|
|
460
466
|
|
|
461
|
-
/** Optional
|
|
467
|
+
/** Optional scoped-token resources and fee-token fields requested via `include`. */
|
|
462
468
|
export const Include = z
|
|
463
|
-
.enum(['feeToken', 'token', 'totalCount'])
|
|
469
|
+
.enum(['feeToken.logoUri', 'feeToken.verified', 'token', 'totalCount'])
|
|
464
470
|
.check(z.describe('Related resources to include only when you request them with `include`.'))
|
|
465
471
|
|
|
466
472
|
/**
|
|
@@ -470,7 +476,7 @@ export namespace schema {
|
|
|
470
476
|
*/
|
|
471
477
|
export const includeQuery = Schema.includeQuery(
|
|
472
478
|
Include,
|
|
473
|
-
'Comma-separated related resources to include, such as `feeToken,token,totalCount`.',
|
|
479
|
+
'Comma-separated related resources to include, such as `feeToken.logoUri,feeToken.verified,token,totalCount`.',
|
|
474
480
|
)
|
|
475
481
|
|
|
476
482
|
/** Query parameters for token transaction requests. */
|
|
@@ -974,17 +980,22 @@ export function tokens() {
|
|
|
974
980
|
const { token: address } = c.req.valid('param')
|
|
975
981
|
const query = c.req.valid('query')
|
|
976
982
|
|
|
977
|
-
// Cursor pages are anchored below the head
|
|
978
|
-
//
|
|
979
|
-
if (query.cursor !== undefined)
|
|
983
|
+
// Cursor pages are anchored below the head. Cache chain data as immutable,
|
|
984
|
+
// but refresh requested token metadata on the metadata schedule.
|
|
985
|
+
if (query.cursor !== undefined)
|
|
986
|
+
Cache.setPolicy(
|
|
987
|
+
c,
|
|
988
|
+
query.include.some(
|
|
989
|
+
(resource) => resource === 'token' || resource.startsWith('feeToken.'),
|
|
990
|
+
)
|
|
991
|
+
? Cache.policies.metadata
|
|
992
|
+
: Cache.policies.immutable,
|
|
993
|
+
)
|
|
980
994
|
|
|
981
995
|
try {
|
|
982
996
|
const chainId = query.chainId ?? c.get('chainId')
|
|
983
|
-
// Resolve the transaction page and
|
|
984
|
-
//
|
|
985
|
-
// transaction query rather than adding to it. The `feeToken`
|
|
986
|
-
// include flows through to `listTransactions` for per-row embeds;
|
|
987
|
-
// `token` is a root-level embed for the token being scoped to.
|
|
997
|
+
// Resolve the transaction page and scoped token concurrently so the
|
|
998
|
+
// token lookup is hidden behind the transaction query.
|
|
988
999
|
const includeToken = query.include.includes('token')
|
|
989
1000
|
// `totalCount` is opt-in; count transactions touching this token
|
|
990
1001
|
// (address-scoped to the contract) under the same filters as the
|
|
@@ -1010,7 +1021,10 @@ export function tokens() {
|
|
|
1010
1021
|
feeToken: query.feeToken,
|
|
1011
1022
|
fromBlock: query['blockNumber.from'],
|
|
1012
1023
|
fromTimestamp: query['timestamp.from'],
|
|
1013
|
-
include: query.include.
|
|
1024
|
+
include: query.include.filter(
|
|
1025
|
+
(resource): resource is 'feeToken.logoUri' | 'feeToken.verified' =>
|
|
1026
|
+
resource === 'feeToken.logoUri' || resource === 'feeToken.verified',
|
|
1027
|
+
),
|
|
1014
1028
|
limit: query.limit,
|
|
1015
1029
|
order: query.order,
|
|
1016
1030
|
page: query.page,
|
|
@@ -1176,6 +1190,7 @@ export function getTokenMetadata(c: Context<App.Environment>, options: getTokenM
|
|
|
1176
1190
|
|
|
1177
1191
|
return Store.memoize(
|
|
1178
1192
|
async () => {
|
|
1193
|
+
// TODO(viem): Flatten concurrent metadata multicalls before encoding aggregate3 calldata.
|
|
1179
1194
|
const fresh = await getClient(chainId).token.getMetadata({ token: address as Address })
|
|
1180
1195
|
return {
|
|
1181
1196
|
currency: fresh.currency,
|
|
@@ -21,7 +21,27 @@ beforeAll(async () => {
|
|
|
21
21
|
})
|
|
22
22
|
|
|
23
23
|
describe('GET /transactions/:transactionHash', () => {
|
|
24
|
-
test('
|
|
24
|
+
test('parses granular fee-token includes', () => {
|
|
25
|
+
expect(
|
|
26
|
+
Transactions.schema.getTransaction.Query.parse({
|
|
27
|
+
include: 'feeToken.logoUri,feeToken.verified,receipt',
|
|
28
|
+
}).include,
|
|
29
|
+
).toMatchInlineSnapshot(`
|
|
30
|
+
[
|
|
31
|
+
"feeToken.logoUri",
|
|
32
|
+
"feeToken.verified",
|
|
33
|
+
"receipt",
|
|
34
|
+
]
|
|
35
|
+
`)
|
|
36
|
+
expect(
|
|
37
|
+
Transactions.schema.getTransaction.Query.safeParse({ include: 'feeToken' }).success,
|
|
38
|
+
).toBe(false)
|
|
39
|
+
expect(
|
|
40
|
+
Transactions.schema.getTransaction.Query.safeParse({ include: 'token.logoUri' }).success,
|
|
41
|
+
).toBe(false)
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
test('humanizes the transaction and resolves its fee token', async () => {
|
|
25
45
|
if (!transactionHash) {
|
|
26
46
|
console.warn('[live-rpc] no recent transaction found; skipping transaction happy path')
|
|
27
47
|
return
|
|
@@ -51,12 +71,24 @@ describe('GET /transactions/:transactionHash', () => {
|
|
|
51
71
|
// transaction; they live on `/transactions/:transactionHash/receipt` instead.
|
|
52
72
|
expect('status' in body).toBe(false)
|
|
53
73
|
expect('gasUsed' in body).toBe(false)
|
|
54
|
-
|
|
55
|
-
|
|
74
|
+
if (body.feeToken) {
|
|
75
|
+
expect(body.feeToken.address).toBe(body.meta.rpc.feeToken)
|
|
76
|
+
expect(typeof body.feeToken.currency).toBe('string')
|
|
77
|
+
expect(Number.isInteger(body.feeToken.decimals)).toBe(true)
|
|
78
|
+
expect(typeof body.feeToken.name).toBe('string')
|
|
79
|
+
expect(typeof body.feeToken.symbol).toBe('string')
|
|
80
|
+
expect(body.feeToken.logoUri).toBeUndefined()
|
|
81
|
+
expect(body.feeToken.verified).toBeUndefined()
|
|
82
|
+
expect(body.feeToken).not.toHaveProperty('amount')
|
|
83
|
+
expect(body.feeToken).not.toHaveProperty('id')
|
|
84
|
+
}
|
|
56
85
|
|
|
57
|
-
//
|
|
86
|
+
// Curated fields are independently opt-in on the fee-token reference.
|
|
58
87
|
const includedResponse = await client.v1.transactions[':transactionHash'].$get(
|
|
59
|
-
{
|
|
88
|
+
{
|
|
89
|
+
param: { transactionHash: transactionHash },
|
|
90
|
+
query: { include: 'feeToken.logoUri,feeToken.verified' },
|
|
91
|
+
},
|
|
60
92
|
TestApp.auth,
|
|
61
93
|
)
|
|
62
94
|
const includedBody = await TestApp.json(
|
|
@@ -65,12 +97,8 @@ describe('GET /transactions/:transactionHash', () => {
|
|
|
65
97
|
)
|
|
66
98
|
expect(includedResponse.status).toBe(200)
|
|
67
99
|
if (includedBody.feeToken) {
|
|
68
|
-
expect(includedBody.feeToken).
|
|
69
|
-
|
|
70
|
-
if (includedBody.meta?.feeToken) {
|
|
71
|
-
expect(includedBody.meta.feeToken.address).toBe(includedBody.feeToken)
|
|
72
|
-
expect(typeof includedBody.meta.feeToken.symbol).toBe('string')
|
|
73
|
-
}
|
|
100
|
+
expect(includedBody.feeToken.address).toBe(includedBody.meta.rpc.feeToken)
|
|
101
|
+
expect(typeof includedBody.feeToken.verified).toBe('boolean')
|
|
74
102
|
}
|
|
75
103
|
})
|
|
76
104
|
|
|
@@ -132,7 +160,28 @@ describe('GET /transactions/:transactionHash', () => {
|
|
|
132
160
|
})
|
|
133
161
|
|
|
134
162
|
describe('GET /transactions', () => {
|
|
135
|
-
test('
|
|
163
|
+
test('parses granular fee-token and list includes', () => {
|
|
164
|
+
expect(
|
|
165
|
+
Transactions.schema.getTransactions.Query.parse({
|
|
166
|
+
include: 'feeToken.logoUri,feeToken.verified,receipt,totalCount',
|
|
167
|
+
}).include,
|
|
168
|
+
).toMatchInlineSnapshot(`
|
|
169
|
+
[
|
|
170
|
+
"feeToken.logoUri",
|
|
171
|
+
"feeToken.verified",
|
|
172
|
+
"receipt",
|
|
173
|
+
"totalCount",
|
|
174
|
+
]
|
|
175
|
+
`)
|
|
176
|
+
expect(
|
|
177
|
+
Transactions.schema.getTransactions.Query.safeParse({ include: 'feeToken' }).success,
|
|
178
|
+
).toBe(false)
|
|
179
|
+
expect(
|
|
180
|
+
Transactions.schema.getTransactions.Query.safeParse({ include: 'token.verified' }).success,
|
|
181
|
+
).toBe(false)
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
test('returns a humanized transaction page with fee-token references', async () => {
|
|
136
185
|
const client = TestApp.client()
|
|
137
186
|
const response = await client.v1.transactions.$get({ query: { limit: '5' } }, TestApp.auth)
|
|
138
187
|
const body = await TestApp.json(response, Transactions.schema.getTransactions.Response)
|
|
@@ -169,13 +218,18 @@ describe('GET /transactions', () => {
|
|
|
169
218
|
expect(typeof transaction!.nonce).toBe('number')
|
|
170
219
|
expect(transaction!.meta.rpc.type).toMatch(/^0x[0-9a-f]+$/)
|
|
171
220
|
// Receipt-derived fields are not on the list payload, matching the detail
|
|
172
|
-
// endpoint; fee-token metadata is
|
|
221
|
+
// endpoint; fee-token core metadata is included by default.
|
|
173
222
|
expect('status' in transaction!).toBe(false)
|
|
174
|
-
|
|
223
|
+
if (transaction!.feeToken) {
|
|
224
|
+
expect(transaction!.feeToken.address).toBe(transaction!.meta.rpc.feeToken)
|
|
225
|
+
expect(typeof transaction!.feeToken.symbol).toBe('string')
|
|
226
|
+
expect(transaction!.feeToken.logoUri).toBeUndefined()
|
|
227
|
+
expect(transaction!.feeToken.verified).toBeUndefined()
|
|
228
|
+
}
|
|
175
229
|
}
|
|
176
230
|
|
|
177
231
|
const includedResponse = await client.v1.transactions.$get(
|
|
178
|
-
{ query: { limit: '5', include: 'feeToken' } },
|
|
232
|
+
{ query: { limit: '5', include: 'feeToken.logoUri,feeToken.verified' } },
|
|
179
233
|
TestApp.auth,
|
|
180
234
|
)
|
|
181
235
|
const includedBody = await TestApp.json(
|
|
@@ -183,11 +237,10 @@ describe('GET /transactions', () => {
|
|
|
183
237
|
Transactions.schema.getTransactions.Response,
|
|
184
238
|
)
|
|
185
239
|
expect(includedResponse.status).toBe(200)
|
|
186
|
-
const withFeeToken = includedBody.data.find((transaction) => transaction.
|
|
240
|
+
const withFeeToken = includedBody.data.find((transaction) => transaction.feeToken)
|
|
187
241
|
if (withFeeToken) {
|
|
188
|
-
|
|
189
|
-
expect(withFeeToken.
|
|
190
|
-
expect(typeof withFeeToken.meta.feeToken!.symbol).toBe('string')
|
|
242
|
+
expect(withFeeToken.feeToken!.address).toBe(withFeeToken.meta.rpc.feeToken)
|
|
243
|
+
expect(typeof withFeeToken.feeToken!.verified).toBe('boolean')
|
|
191
244
|
}
|
|
192
245
|
})
|
|
193
246
|
|
|
@@ -286,20 +286,9 @@ export namespace schema {
|
|
|
286
286
|
.check(z.describe('The transaction exactly as returned by JSON-RPC.'))
|
|
287
287
|
}
|
|
288
288
|
|
|
289
|
-
/**
|
|
290
|
-
* Metadata for a transaction: the verbatim JSON-RPC transaction (always
|
|
291
|
-
* present) plus resources embedded on demand via `include`.
|
|
292
|
-
*
|
|
293
|
-
* The `feeToken` and `receipt` schemas are wrapped in `z.lazy` because
|
|
294
|
-
* `tokens.ts`/`receipts.ts` and `transactions.ts` mutually reference each
|
|
295
|
-
* other's schemas; deferring these lookups avoids the import-cycle crash
|
|
296
|
-
* during module init.
|
|
297
|
-
*/
|
|
289
|
+
/** Transaction metadata with the raw RPC transaction and optional receipt. */
|
|
298
290
|
export const TransactionMeta = z
|
|
299
291
|
.object({
|
|
300
|
-
feeToken: z
|
|
301
|
-
.optional(z.lazy(() => Tokens.schema.getToken.Response))
|
|
302
|
-
.check(z.describe('Fee-token details included only when you request `include=feeToken`.')),
|
|
303
292
|
receipt: z
|
|
304
293
|
.optional(z.lazy(() => Receipts.schema.Receipt))
|
|
305
294
|
.check(
|
|
@@ -367,10 +356,10 @@ export namespace schema {
|
|
|
367
356
|
z.meta({ examples: [4217] }),
|
|
368
357
|
),
|
|
369
358
|
feeToken: z
|
|
370
|
-
.optional(
|
|
359
|
+
.optional(z.lazy(() => Tokens.schema.TokenReference))
|
|
371
360
|
.check(
|
|
372
361
|
z.describe(
|
|
373
|
-
'The
|
|
362
|
+
'The token requested for transaction fees, with RPC metadata and optional curated fields.',
|
|
374
363
|
),
|
|
375
364
|
),
|
|
376
365
|
gas: z
|
|
@@ -484,20 +473,19 @@ export namespace schema {
|
|
|
484
473
|
})
|
|
485
474
|
.check(z.describe('Path parameters used to look up a transaction.'))
|
|
486
475
|
|
|
487
|
-
/** Optional
|
|
476
|
+
/** Optional receipt and fee-token fields that callers opt into via `include`. */
|
|
488
477
|
export const Include = z
|
|
489
|
-
.enum(['feeToken', 'receipt'])
|
|
490
|
-
.check(z.describe('Related
|
|
478
|
+
.enum(['feeToken.logoUri', 'feeToken.verified', 'receipt'])
|
|
479
|
+
.check(z.describe('Related resources you can request with the `include` query parameter.'))
|
|
491
480
|
|
|
492
481
|
/**
|
|
493
482
|
* Parses a comma-separated `include` query value into a list of optional
|
|
494
|
-
* resources to embed.
|
|
495
|
-
*
|
|
496
|
-
* fast.
|
|
483
|
+
* resources to embed. Curated fee-token fields and the receipt only run when
|
|
484
|
+
* explicitly requested.
|
|
497
485
|
*/
|
|
498
486
|
export const includeQuery = Schema.includeQuery(
|
|
499
487
|
Include,
|
|
500
|
-
'Comma-separated related resources to include, such as `feeToken,receipt`.',
|
|
488
|
+
'Comma-separated related resources to include, such as `feeToken.logoUri,feeToken.verified,receipt`.',
|
|
501
489
|
)
|
|
502
490
|
|
|
503
491
|
/** Query parameters for transaction requests. */
|
|
@@ -515,12 +503,11 @@ export namespace schema {
|
|
|
515
503
|
/** Schemas for the getTransactions (list) operation. */
|
|
516
504
|
export namespace getTransactions {
|
|
517
505
|
/**
|
|
518
|
-
* Optional resources for
|
|
519
|
-
* `
|
|
520
|
-
* route keeps its own {@link getTransaction.Include}.
|
|
506
|
+
* Optional resources for transaction rows plus the response-wide capped
|
|
507
|
+
* `totalCount`. The detail route keeps its own include schema.
|
|
521
508
|
*/
|
|
522
509
|
export const Include = z
|
|
523
|
-
.enum(['feeToken', 'receipt', 'totalCount'])
|
|
510
|
+
.enum(['feeToken.logoUri', 'feeToken.verified', 'receipt', 'totalCount'])
|
|
524
511
|
.check(
|
|
525
512
|
z.describe('Related resources to include in each transaction row or in response metadata.'),
|
|
526
513
|
)
|
|
@@ -528,7 +515,7 @@ export namespace schema {
|
|
|
528
515
|
/** Parses the comma-separated `include` value for the transaction list. */
|
|
529
516
|
export const includeQuery = Schema.includeQuery(
|
|
530
517
|
Include,
|
|
531
|
-
'Comma-separated related resources to include, such as `feeToken,receipt,totalCount`.',
|
|
518
|
+
'Comma-separated related resources to include, such as `feeToken.logoUri,feeToken.verified,receipt,totalCount`.',
|
|
532
519
|
)
|
|
533
520
|
|
|
534
521
|
/** Query parameters for transaction list requests. */
|
|
@@ -606,7 +593,7 @@ export function transactions() {
|
|
|
606
593
|
'List transactions across Tempo, with filters for addresses, blocks, timestamps, fees, and status.',
|
|
607
594
|
operationId: 'getTransactions',
|
|
608
595
|
responses: OpenApi.responses({
|
|
609
|
-
errors: { 502: 'Could not read
|
|
596
|
+
errors: { 502: 'Could not read transaction or token data from an upstream service.' },
|
|
610
597
|
success: {
|
|
611
598
|
description: 'A page of transactions.',
|
|
612
599
|
schema: schema.getTransactions.Response,
|
|
@@ -631,10 +618,15 @@ export function transactions() {
|
|
|
631
618
|
const query = c.req.valid('query')
|
|
632
619
|
const chainId = query.chainId ?? c.get('chainId')
|
|
633
620
|
|
|
634
|
-
//
|
|
635
|
-
//
|
|
636
|
-
|
|
637
|
-
|
|
621
|
+
// Cursor pages are anchored below the head. Cache chain data as immutable,
|
|
622
|
+
// but refresh requested curated token fields on the metadata schedule.
|
|
623
|
+
if (query.cursor !== undefined)
|
|
624
|
+
Cache.setPolicy(
|
|
625
|
+
c,
|
|
626
|
+
query.include.some((resource) => resource.startsWith('feeToken.'))
|
|
627
|
+
? Cache.policies.metadata
|
|
628
|
+
: Cache.policies.immutable,
|
|
629
|
+
)
|
|
638
630
|
|
|
639
631
|
try {
|
|
640
632
|
// `totalCount` is opt-in and shares the page's filters; run it
|
|
@@ -711,7 +703,7 @@ export function transactions() {
|
|
|
711
703
|
description: 'No transaction was found for that hash.',
|
|
712
704
|
codes: ['transaction_not_found'],
|
|
713
705
|
},
|
|
714
|
-
502: 'Could not read transaction data from
|
|
706
|
+
502: 'Could not read transaction or token data from upstream JSON-RPC.',
|
|
715
707
|
},
|
|
716
708
|
success: {
|
|
717
709
|
description: 'A single transaction with decoded fields and original JSON-RPC data.',
|
|
@@ -769,9 +761,15 @@ export function transactions() {
|
|
|
769
761
|
|
|
770
762
|
let data = humanizeTransaction(Response.validated(schema.Rpc.Transaction, rpc))
|
|
771
763
|
|
|
772
|
-
//
|
|
773
|
-
//
|
|
774
|
-
if (data.blockNumber !== null)
|
|
764
|
+
// Mined chain data is immutable, while curated token fields can still
|
|
765
|
+
// change. Pending transactions keep the route's no-store policy.
|
|
766
|
+
if (data.blockNumber !== null)
|
|
767
|
+
Cache.setPolicy(
|
|
768
|
+
c,
|
|
769
|
+
query.include.some((resource) => resource.startsWith('feeToken.'))
|
|
770
|
+
? Cache.policies.metadata
|
|
771
|
+
: Cache.policies.immutable,
|
|
772
|
+
)
|
|
775
773
|
|
|
776
774
|
// The receipt is opt-in: fetching it is an extra RPC, so it only runs
|
|
777
775
|
// when requested via `include=receipt` and the transaction is mined.
|
|
@@ -784,22 +782,24 @@ export function transactions() {
|
|
|
784
782
|
const humanized = Receipts.humanizeReceipt(
|
|
785
783
|
Response.validated(Receipts.schema.Rpc.Receipt, receipt),
|
|
786
784
|
)
|
|
787
|
-
|
|
785
|
+
const [receipt_enriched] = await enrichFeeTokens(c, {
|
|
786
|
+
chainId,
|
|
787
|
+
include: query.include,
|
|
788
|
+
rows: [humanized],
|
|
789
|
+
})
|
|
790
|
+
if (!receipt_enriched) throw new Error('Unable to enrich transaction receipt')
|
|
791
|
+
data = { ...data, meta: { ...data.meta, receipt: receipt_enriched } }
|
|
788
792
|
}
|
|
789
793
|
}
|
|
790
794
|
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
Tokens.resolveToken(c, { address: feeToken, chainId }).catch(() => undefined),
|
|
798
|
-
)
|
|
799
|
-
if (token) data = { ...data, meta: { ...data.meta, feeToken: token } }
|
|
800
|
-
}
|
|
795
|
+
const [data_enriched] = await enrichFeeTokens(c, {
|
|
796
|
+
chainId,
|
|
797
|
+
include: query.include,
|
|
798
|
+
rows: [data],
|
|
799
|
+
})
|
|
800
|
+
if (!data_enriched) throw new Error('Unable to enrich transaction')
|
|
801
801
|
|
|
802
|
-
return c.json(Response.validated(schema.getTransaction.Response,
|
|
802
|
+
return c.json(Response.validated(schema.getTransaction.Response, data_enriched), 200)
|
|
803
803
|
} catch (cause) {
|
|
804
804
|
return Response.upstream(c, cause)
|
|
805
805
|
}
|
|
@@ -808,10 +808,9 @@ export function transactions() {
|
|
|
808
808
|
}
|
|
809
809
|
|
|
810
810
|
/**
|
|
811
|
-
* Lists humanized transactions and
|
|
812
|
-
*
|
|
813
|
-
*
|
|
814
|
-
* receipts.
|
|
811
|
+
* Lists humanized transactions with required fee-token metadata and opt-in
|
|
812
|
+
* resources. Status filters page through receipts because execution status
|
|
813
|
+
* lives there.
|
|
815
814
|
*/
|
|
816
815
|
export async function listTransactions(
|
|
817
816
|
c: Context<App.Environment>,
|
|
@@ -858,6 +857,7 @@ export async function listTransactions(
|
|
|
858
857
|
if (include.includes('receipt') && data.length > 0) {
|
|
859
858
|
const receipts = await Receipts.embedReceipts(c, {
|
|
860
859
|
chainId: rest.chainId,
|
|
860
|
+
include,
|
|
861
861
|
receipts: receiptPage?.data,
|
|
862
862
|
rows: data,
|
|
863
863
|
})
|
|
@@ -866,13 +866,15 @@ export async function listTransactions(
|
|
|
866
866
|
return receipt ? { ...row, meta: { ...row.meta, receipt } } : row
|
|
867
867
|
})
|
|
868
868
|
}
|
|
869
|
-
|
|
870
|
-
|
|
869
|
+
return {
|
|
870
|
+
...page,
|
|
871
|
+
data: await enrichFeeTokens(c, { chainId: rest.chainId, include, rows: data }),
|
|
872
|
+
}
|
|
871
873
|
}
|
|
872
874
|
|
|
873
875
|
export declare namespace listTransactions {
|
|
874
876
|
type Options = getTransactions.Options & {
|
|
875
|
-
/** Optional
|
|
877
|
+
/** Optional receipt and curated token fields to embed. */
|
|
876
878
|
include: readonly z.output<typeof schema.getTransaction.Include>[]
|
|
877
879
|
}
|
|
878
880
|
}
|
|
@@ -885,11 +887,8 @@ export declare namespace listTransactions {
|
|
|
885
887
|
*/
|
|
886
888
|
async function transactionsForReceipts(
|
|
887
889
|
c: Context<App.Environment>,
|
|
888
|
-
options:
|
|
889
|
-
|
|
890
|
-
receipts: readonly z.output<typeof Receipts.schema.Receipt>[]
|
|
891
|
-
},
|
|
892
|
-
): Promise<z.output<typeof schema.Transaction>[]> {
|
|
890
|
+
options: transactionsForReceipts.Options,
|
|
891
|
+
): Promise<humanizeTransaction.Output[]> {
|
|
893
892
|
const { chainId, receipts } = options
|
|
894
893
|
if (receipts.length === 0) return []
|
|
895
894
|
const tidx = c.get('getTidx')(chainId)
|
|
@@ -907,7 +906,7 @@ async function transactionsForReceipts(
|
|
|
907
906
|
}),
|
|
908
907
|
)
|
|
909
908
|
|
|
910
|
-
const byHash = new Map<string,
|
|
909
|
+
const byHash = new Map<string, humanizeTransaction.Output>()
|
|
911
910
|
for (const row of result.rows) {
|
|
912
911
|
const rpc = schema.Rpc.Transaction.safeParse(toRpcTransaction(row))
|
|
913
912
|
if (rpc.success) byHash.set(rpc.data.hash.toLowerCase(), humanizeTransaction(rpc.data))
|
|
@@ -917,47 +916,110 @@ async function transactionsForReceipts(
|
|
|
917
916
|
.filter((transaction) => transaction !== undefined)
|
|
918
917
|
}
|
|
919
918
|
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
919
|
+
declare namespace transactionsForReceipts {
|
|
920
|
+
/** Inputs for matching receipt rows to transactions. */
|
|
921
|
+
type Options = {
|
|
922
|
+
/** Chain used to fetch matching transaction rows. */
|
|
923
|
+
chainId: z.output<typeof Schema.ChainId>
|
|
924
|
+
/** Receipt positions and hashes in page order. */
|
|
925
|
+
receipts: readonly Receipt[]
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
/** Receipt fields needed for transaction hydration. */
|
|
929
|
+
type Receipt = {
|
|
930
|
+
/** Block containing the receipt. */
|
|
931
|
+
blockNumber: number
|
|
932
|
+
/** Hash of the transaction that produced the receipt. */
|
|
933
|
+
transactionHash: string
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
/** Resolves required fee-token metadata and optional curated fields without mutating input rows. */
|
|
938
|
+
export async function enrichFeeTokens<const row extends object>(
|
|
939
|
+
c: Context<App.Environment>,
|
|
940
|
+
options: enrichFeeTokens.Options<row>,
|
|
941
|
+
): Promise<enrichFeeTokens.Output<row>[]> {
|
|
942
|
+
const { chainId, include, rows } = options
|
|
943
|
+
const includeLogoUri = include.includes('feeToken.logoUri')
|
|
944
|
+
const includeVerified = include.includes('feeToken.verified')
|
|
945
|
+
const uniqueTokens = [
|
|
946
|
+
...new Set(
|
|
947
|
+
rows
|
|
948
|
+
.map((row) => row.feeToken)
|
|
949
|
+
.filter((address): address is z.output<typeof Schema.Address> => address !== undefined)
|
|
950
|
+
.map((address) => address.toLowerCase())
|
|
951
|
+
.map((address) => Schema.Address.parse(address)),
|
|
934
952
|
),
|
|
935
|
-
|
|
936
|
-
if (uniqueTokens.length === 0)
|
|
953
|
+
]
|
|
954
|
+
if (uniqueTokens.length === 0)
|
|
955
|
+
return rows.map((row) => ({ ...row }) as enrichFeeTokens.Output<row>)
|
|
937
956
|
|
|
938
|
-
const snapshot =
|
|
957
|
+
const snapshot =
|
|
958
|
+
includeLogoUri || includeVerified
|
|
959
|
+
? await VerifiedTokens.snapshot(c, chainId).catch(() => undefined)
|
|
960
|
+
: undefined
|
|
939
961
|
const resolved = await Timing.time(c, 'tokens', () =>
|
|
940
962
|
Promise.all(
|
|
941
|
-
uniqueTokens.map((
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
963
|
+
uniqueTokens.map(async (address) => {
|
|
964
|
+
const [logoUri, metadata] = await Promise.all([
|
|
965
|
+
includeLogoUri
|
|
966
|
+
? Tokens.getTokenLogo(c, { address, chainId }).catch(() => undefined)
|
|
967
|
+
: Promise.resolve(undefined),
|
|
968
|
+
Tokens.getTokenMetadata(c, { address, chainId }),
|
|
969
|
+
])
|
|
970
|
+
return [
|
|
971
|
+
address,
|
|
972
|
+
{
|
|
973
|
+
address,
|
|
974
|
+
currency: metadata.currency,
|
|
975
|
+
decimals: metadata.decimals,
|
|
976
|
+
...(includeLogoUri
|
|
977
|
+
? {
|
|
978
|
+
logoUri: logoUri ?? snapshot?.byAddress.get(address)?.logoUri ?? metadata.logoUri,
|
|
979
|
+
}
|
|
980
|
+
: {}),
|
|
981
|
+
name: metadata.name,
|
|
982
|
+
symbol: metadata.symbol,
|
|
983
|
+
...(includeVerified && snapshot ? { verified: snapshot.byAddress.has(address) } : {}),
|
|
984
|
+
},
|
|
985
|
+
] as const
|
|
986
|
+
}),
|
|
950
987
|
),
|
|
951
988
|
)
|
|
952
989
|
const tokensByAddress = new Map(resolved)
|
|
953
990
|
return rows.map((row) => {
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
991
|
+
if (row.feeToken === undefined) return { ...row } as enrichFeeTokens.Output<row>
|
|
992
|
+
const address = Schema.Address.parse(row.feeToken.toLowerCase())
|
|
993
|
+
const feeToken = tokensByAddress.get(address)
|
|
994
|
+
if (!feeToken) throw new Error('Unable to resolve fee token metadata')
|
|
995
|
+
return { ...row, feeToken } as enrichFeeTokens.Output<row>
|
|
958
996
|
})
|
|
959
997
|
}
|
|
960
998
|
|
|
999
|
+
export declare namespace enrichFeeTokens {
|
|
1000
|
+
/** Fee-token enrichment inputs. */
|
|
1001
|
+
type Options<row extends object> = {
|
|
1002
|
+
/** Chain used for token metadata resolution. */
|
|
1003
|
+
chainId: z.output<typeof Schema.ChainId>
|
|
1004
|
+
/** Requested optional token fields. */
|
|
1005
|
+
include: readonly string[]
|
|
1006
|
+
/** Rows carrying unresolved fee-token addresses. */
|
|
1007
|
+
rows: readonly (row & Unresolved)[]
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
/** A copied row whose fee-token address has been replaced by metadata. */
|
|
1011
|
+
type Output<row> = Omit<row, 'feeToken'> & {
|
|
1012
|
+
/** Resolved fee-token metadata when the row declares a fee token. */
|
|
1013
|
+
feeToken?: z.output<typeof Tokens.schema.TokenReference> | undefined
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
/** Row field before fee-token metadata resolution. */
|
|
1017
|
+
type Unresolved = {
|
|
1018
|
+
/** Fee-token address from indexed or RPC data. */
|
|
1019
|
+
feeToken?: z.output<typeof Schema.Address> | undefined
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
|
|
961
1023
|
export function getTransactions(c: Context<App.Environment>, options: getTransactions.Options) {
|
|
962
1024
|
const { chainId } = options
|
|
963
1025
|
const store = c.get('store')
|
|
@@ -1263,7 +1325,7 @@ export declare namespace scanTransactions {
|
|
|
1263
1325
|
/** Keyset position of the row. */
|
|
1264
1326
|
cursor: readonly [blockNumber: number, transactionIndex: number]
|
|
1265
1327
|
/** The humanized transaction (same shape the read endpoint returns). */
|
|
1266
|
-
data:
|
|
1328
|
+
data: humanizeTransaction.Output
|
|
1267
1329
|
}
|
|
1268
1330
|
/** A page of scanned transactions. */
|
|
1269
1331
|
type Page = {
|
|
@@ -1334,7 +1396,7 @@ function humanizeCall(call: z.output<typeof schema.Call>): z.output<typeof schem
|
|
|
1334
1396
|
*/
|
|
1335
1397
|
export function humanizeTransaction(
|
|
1336
1398
|
rpc: z.output<typeof schema.Rpc.Transaction>,
|
|
1337
|
-
):
|
|
1399
|
+
): humanizeTransaction.Output {
|
|
1338
1400
|
return {
|
|
1339
1401
|
blockHash: rpc.blockHash,
|
|
1340
1402
|
blockNumber: Value.hexToNumber(rpc.blockNumber) ?? null,
|
|
@@ -1361,3 +1423,11 @@ export function humanizeTransaction(
|
|
|
1361
1423
|
value: Value.fromHex(rpc.value) ?? '0',
|
|
1362
1424
|
}
|
|
1363
1425
|
}
|
|
1426
|
+
|
|
1427
|
+
export declare namespace humanizeTransaction {
|
|
1428
|
+
/** Humanized fields before asynchronous fee-token metadata resolution. */
|
|
1429
|
+
type Output = Omit<z.output<typeof schema.Transaction>, 'feeToken'> & {
|
|
1430
|
+
/** Unresolved fee-token address from the RPC transaction. */
|
|
1431
|
+
feeToken?: z.output<typeof Schema.Address> | undefined
|
|
1432
|
+
}
|
|
1433
|
+
}
|