@lukso/transaction-decoder 1.3.0-dev.f500300 → 1.3.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/browser.cjs +73 -41
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.cts +1 -1
- package/dist/browser.d.ts +1 -1
- package/dist/browser.js +4 -4
- package/dist/cdn/transaction-decoder.global.js +13 -13
- package/dist/cdn/transaction-decoder.global.js.map +1 -1
- package/dist/{chunk-U7L4W2YL.js → chunk-G7JZHSYX.js} +12 -11
- package/dist/chunk-G7JZHSYX.js.map +1 -0
- package/dist/{chunk-EDDQHEAA.js → chunk-GGBHTWJL.js} +5 -5
- package/dist/chunk-GGBHTWJL.js.map +1 -0
- package/dist/{chunk-NDBDNXBI.js → chunk-GXZOF3QY.js} +27 -3
- package/dist/chunk-GXZOF3QY.js.map +1 -0
- package/dist/{chunk-T4H2HHIB.js → chunk-XVHJWV5U.js} +32 -25
- package/dist/chunk-XVHJWV5U.js.map +1 -0
- package/dist/data.cjs +62 -31
- package/dist/data.cjs.map +1 -1
- package/dist/data.d.cts +2 -2
- package/dist/data.d.ts +2 -2
- package/dist/data.js +2 -2
- package/dist/index.cjs +73 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +4 -4
- package/dist/server.cjs +43 -31
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +2 -1
- package/dist/server.d.ts +2 -1
- package/dist/server.js +12 -7
- package/dist/server.js.map +1 -1
- package/dist/{utils-BEpSreRR.d.cts → utils-CBAkjQh3.d.cts} +1 -1
- package/dist/{utils-De_c6fUK.d.ts → utils-xT9-km0r.d.ts} +1 -1
- package/package.json +3 -3
- package/src/core/dataModel.ts +31 -1
- package/src/core/integrateDecoder.ts +2 -1
- package/src/decoder/browserCache.ts +6 -1
- package/src/decoder/errors.ts +2 -2
- package/src/decoder/events.ts +3 -3
- package/src/decoder/functionSignature.ts +9 -9
- package/src/decoder/getDataFromExternalSources.ts +2 -2
- package/src/decoder/interfaces.ts +1 -1
- package/src/decoder/kvCache.ts +6 -1
- package/src/decoder/lruCache.ts +6 -1
- package/src/decoder/lsp7TransferBatch.test.ts +3 -0
- package/src/decoder/plugins/enhanceBurntPix.ts +2 -1
- package/src/decoder/plugins/enhanceGraffiti.ts +17 -3
- package/src/decoder/plugins/enhanceLSP26FollowerSystem.ts +8 -4
- package/src/decoder/plugins/enhanceLSP6KeyManager.ts +1 -0
- package/src/decoder/plugins/enhanceLSP7DigitalAsset.ts +7 -5
- package/src/decoder/plugins/enhanceLSP9Vault.ts +8 -7
- package/src/decoder/plugins/enhanceRetrieveAbi.ts +6 -5
- package/src/decoder/plugins/index.ts +1 -3
- package/src/decoder/plugins/schemaDefault.ts +4 -3
- package/src/decoder/plugins/standardPlugin.ts +1 -1
- package/src/decoder/singleGQL.ts +2 -2
- package/src/decoder/transaction.ts +2 -1
- package/src/decoder/utils.ts +2 -2
- package/src/example/usage.ts +4 -3
- package/src/server/addressResolver.ts +1 -1
- package/src/server/decodeTransactionSync.ts +1 -0
- package/src/server/decodeTransactionsBatch.ts +1 -1
- package/src/server/finishDecoding.ts +8 -4
- package/src/server/lsp23Resolver.ts +3 -2
- package/src/server/types.ts +1 -1
- package/src/shared/addressResolver.ts +3 -3
- package/src/utils/json-bigint.ts +4 -4
- package/dist/chunk-EDDQHEAA.js.map +0 -1
- package/dist/chunk-NDBDNXBI.js.map +0 -1
- package/dist/chunk-T4H2HHIB.js.map +0 -1
- package/dist/chunk-U7L4W2YL.js.map +0 -1
package/dist/server.d.cts
CHANGED
|
@@ -181,9 +181,10 @@ declare class ServerDecoderCaches {
|
|
|
181
181
|
*/
|
|
182
182
|
declare class ServerAddressResolver {
|
|
183
183
|
private graphqlEndpoint;
|
|
184
|
+
private chain;
|
|
184
185
|
private caches;
|
|
185
186
|
private cacheAdapter;
|
|
186
|
-
constructor(graphqlEndpoint: string,
|
|
187
|
+
constructor(graphqlEndpoint: string, chain: Chain, caches: ServerDecoderCaches);
|
|
187
188
|
/**
|
|
188
189
|
* Resolve addresses, using cache when possible
|
|
189
190
|
*/
|
package/dist/server.d.ts
CHANGED
|
@@ -181,9 +181,10 @@ declare class ServerDecoderCaches {
|
|
|
181
181
|
*/
|
|
182
182
|
declare class ServerAddressResolver {
|
|
183
183
|
private graphqlEndpoint;
|
|
184
|
+
private chain;
|
|
184
185
|
private caches;
|
|
185
186
|
private cacheAdapter;
|
|
186
|
-
constructor(graphqlEndpoint: string,
|
|
187
|
+
constructor(graphqlEndpoint: string, chain: Chain, caches: ServerDecoderCaches);
|
|
187
188
|
/**
|
|
188
189
|
* Resolve addresses, using cache when possible
|
|
189
190
|
*/
|
package/dist/server.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
fetchMultipleAddresses
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-GGBHTWJL.js";
|
|
4
4
|
import {
|
|
5
5
|
__name,
|
|
6
6
|
collectDataKeys,
|
|
@@ -8,12 +8,13 @@ import {
|
|
|
8
8
|
decodeTransaction,
|
|
9
9
|
needsEnhancement,
|
|
10
10
|
pluginRegistry
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-XVHJWV5U.js";
|
|
12
12
|
|
|
13
13
|
// src/server/addressResolver.ts
|
|
14
14
|
var ServerAddressResolver = class {
|
|
15
|
-
constructor(graphqlEndpoint,
|
|
15
|
+
constructor(graphqlEndpoint, chain, caches) {
|
|
16
16
|
this.graphqlEndpoint = graphqlEndpoint;
|
|
17
|
+
this.chain = chain;
|
|
17
18
|
this.caches = caches;
|
|
18
19
|
this.cacheAdapter = {
|
|
19
20
|
get: /* @__PURE__ */ __name((key) => this.caches.getAddress(key), "get"),
|
|
@@ -421,7 +422,7 @@ async function decodeTransactionsBatch(transactions, options, caches) {
|
|
|
421
422
|
}
|
|
422
423
|
return decodeTransaction(tx, enhancedOptionsArray[i]);
|
|
423
424
|
});
|
|
424
|
-
const
|
|
425
|
+
const remainingTime = timeoutMs * 0.6 - phase1Time;
|
|
425
426
|
const enhancedResults = await Promise.all(enhancePromises);
|
|
426
427
|
enhancedResults.forEach((enhanced, i) => {
|
|
427
428
|
if (enhanced) {
|
|
@@ -498,15 +499,19 @@ function createErrorResult2(transaction) {
|
|
|
498
499
|
__name(createErrorResult2, "createErrorResult");
|
|
499
500
|
|
|
500
501
|
// src/server/finishDecoding.ts
|
|
501
|
-
var
|
|
502
|
+
var debug = createDebug("decoder:finishDecoding");
|
|
502
503
|
async function finishDecoding(transaction, options, caches) {
|
|
503
504
|
const startTime = Date.now();
|
|
504
|
-
const {
|
|
505
|
+
const {
|
|
506
|
+
timeoutMs = 5e3,
|
|
507
|
+
// Give more time for finishing
|
|
508
|
+
chain
|
|
509
|
+
} = options;
|
|
505
510
|
try {
|
|
506
511
|
const txHash = transaction.hash || transaction.transactionHash;
|
|
507
512
|
if (txHash) {
|
|
508
513
|
const cached = caches.getTransaction(txHash);
|
|
509
|
-
if (cached
|
|
514
|
+
if (cached && cached.enhancementAttempted) {
|
|
510
515
|
return {
|
|
511
516
|
...cached,
|
|
512
517
|
cached: true,
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server/addressResolver.ts","../src/server/caches.ts","../src/server/decodeTransactionSync.ts","../src/server/decodeTransactionsBatch.ts","../src/server/finishDecoding.ts","../src/server/index.ts"],"sourcesContent":["import type { Chain } from 'viem'\nimport { fetchMultipleAddresses } from '../shared/addressResolver'\nimport type { AddressIdentityCache } from '../shared/cache'\nimport type { DataKey, EnhancedInfo } from '../types'\nimport type { ServerDecoderCaches } from './caches'\n\n/**\n * Server-side address resolver with caching\n */\nexport class ServerAddressResolver {\n private cacheAdapter: AddressIdentityCache\n\n constructor(\n private graphqlEndpoint: string,\n _chain: Chain,\n private caches: ServerDecoderCaches\n ) {\n // Create adapter to use ServerDecoderCaches as AddressIdentityCache\n this.cacheAdapter = {\n get: (key: DataKey) => this.caches.getAddress(key),\n set: (key: DataKey, value: EnhancedInfo) =>\n this.caches.setAddress(key, value),\n has: (key: DataKey) => this.caches.hasAddress(key),\n getMany: (keys: DataKey[]) => this.caches.getAddresses(keys),\n }\n }\n\n /**\n * Resolve addresses, using cache when possible\n */\n async resolveAddresses(\n addresses: readonly DataKey[]\n ): Promise<Map<DataKey, EnhancedInfo>> {\n // Use the shared implementation with cache adapter\n return fetchMultipleAddresses(\n addresses,\n this.graphqlEndpoint,\n this.cacheAdapter\n )\n }\n\n /**\n * Resolve addresses with timeout\n */\n async resolveAddressesWithTimeout(\n addresses: DataKey[],\n timeoutMs: number\n ): Promise<Map<DataKey, EnhancedInfo>> {\n return Promise.race([\n this.resolveAddresses(addresses),\n new Promise<Map<DataKey, EnhancedInfo>>((resolve) => {\n setTimeout(() => {\n // On timeout, return whatever we have cached\n const results = this.caches.getAddresses(addresses)\n resolve(results)\n }, timeoutMs)\n }),\n ])\n }\n\n /**\n * Warm the cache with specific addresses\n */\n async warmCache(addresses: DataKey[]): Promise<void> {\n // Simply call resolveAddresses which will cache any uncached addresses\n await this.resolveAddresses(addresses)\n }\n}\n","import { LRUCache } from 'lru-cache'\nimport type { Abi } from 'viem'\nimport type { DecoderResult, Info } from '../decoder/types'\nimport type { DataKey, EnhancedInfo } from '../types'\nimport type { CacheStats } from './types'\n\n/**\n * Multi-level caching system for server-side decoder\n */\nexport class ServerDecoderCaches {\n // Level 1: Decoded transaction cache (keyed by transaction hash)\n private transactionCache: LRUCache<string, DecoderResult>\n private transactionStats = { hits: 0, misses: 0 }\n\n // Level 2: Address metadata cache (keyed by address or address:tokenId)\n private addressCache: LRUCache<string, EnhancedInfo>\n private addressStats = { hits: 0, misses: 0 }\n\n // Level 3: Contract ABI cache (keyed by address)\n private abiCache: LRUCache<string, Abi>\n private abiStats = { hits: 0, misses: 0 }\n\n // Level 4: Schema decode cache (keyed by key:value)\n private schemaCache: LRUCache<string, Info>\n private schemaStats = { hits: 0, misses: 0 }\n\n constructor(\n options: {\n transactionCacheSize?: number\n addressCacheSize?: number\n abiCacheSize?: number\n schemaCacheSize?: number\n } = {}\n ) {\n // Transaction cache - store complete decoded results\n this.transactionCache = new LRUCache<string, DecoderResult>({\n max: options.transactionCacheSize || 10000,\n ttl: 1000 * 60 * 60, // 1 hour TTL\n updateAgeOnGet: true,\n updateAgeOnHas: true,\n })\n\n // Address cache - store profile/asset metadata\n this.addressCache = new LRUCache<string, EnhancedInfo>({\n max: options.addressCacheSize || 50000,\n ttl: 1000 * 60 * 60 * 24, // 24 hour TTL\n updateAgeOnGet: true,\n updateAgeOnHas: true,\n })\n\n // ABI cache - store contract ABIs\n this.abiCache = new LRUCache<string, Abi>({\n max: options.abiCacheSize || 5000,\n ttl: 1000 * 60 * 60 * 24 * 7, // 7 day TTL (ABIs rarely change)\n updateAgeOnGet: true,\n updateAgeOnHas: true,\n })\n\n // Schema cache - store decoded schema values\n this.schemaCache = new LRUCache<string, Info>({\n max: options.schemaCacheSize || 10000,\n ttl: 1000 * 60 * 60, // 1 hour TTL\n updateAgeOnGet: true,\n updateAgeOnHas: true,\n })\n }\n\n /**\n * Get cache key for a data key (address or address:tokenId)\n */\n private getDataKeyCacheKey(key: DataKey): string {\n return key.toLowerCase()\n }\n\n // Transaction cache methods\n getTransaction(hash: string): DecoderResult | undefined {\n const result = this.transactionCache.get(hash.toLowerCase())\n if (result) {\n this.transactionStats.hits++\n return { ...result, cached: true }\n }\n this.transactionStats.misses++\n return undefined\n }\n\n setTransaction(hash: string, result: DecoderResult): void {\n this.transactionCache.set(hash.toLowerCase(), result)\n }\n\n // Address cache methods\n getAddress(key: DataKey): EnhancedInfo | undefined {\n const cacheKey = this.getDataKeyCacheKey(key)\n const result = this.addressCache.get(cacheKey)\n if (result) {\n this.addressStats.hits++\n return result\n }\n this.addressStats.misses++\n return undefined\n }\n\n setAddress(key: DataKey, data: EnhancedInfo): void {\n const cacheKey = this.getDataKeyCacheKey(key)\n this.addressCache.set(cacheKey, data)\n }\n\n hasAddress(key: DataKey): boolean {\n return this.addressCache.has(this.getDataKeyCacheKey(key))\n }\n\n getAddresses(keys: DataKey[]): Map<DataKey, EnhancedInfo> {\n const results = new Map<DataKey, EnhancedInfo>()\n for (const key of keys) {\n const data = this.getAddress(key)\n if (data) {\n results.set(key, data)\n }\n }\n return results\n }\n\n // ABI cache methods\n getAbi(address: string): Abi | undefined {\n const result = this.abiCache.get(address.toLowerCase())\n if (result) {\n this.abiStats.hits++\n return result\n }\n this.abiStats.misses++\n return undefined\n }\n\n setAbi(address: string, abi: Abi): void {\n this.abiCache.set(address.toLowerCase(), abi)\n }\n\n hasAbi(address: string): boolean {\n return this.abiCache.has(address.toLowerCase())\n }\n\n // Schema cache methods\n getSchema(key: string, value: string): Info | undefined {\n const cacheKey = `${key}:${value}`\n const result = this.schemaCache.get(cacheKey)\n if (result) {\n this.schemaStats.hits++\n return result\n }\n this.schemaStats.misses++\n return undefined\n }\n\n setSchema(key: string, value: string, info: Info): void {\n const cacheKey = `${key}:${value}`\n this.schemaCache.set(cacheKey, info)\n }\n\n // Cache management\n clear(): void {\n this.transactionCache.clear()\n this.addressCache.clear()\n this.abiCache.clear()\n this.schemaCache.clear()\n\n // Reset stats\n this.transactionStats = { hits: 0, misses: 0 }\n this.addressStats = { hits: 0, misses: 0 }\n this.abiStats = { hits: 0, misses: 0 }\n this.schemaStats = { hits: 0, misses: 0 }\n }\n\n getStats(): CacheStats {\n const calculateHitRate = (stats: { hits: number; misses: number }) => {\n const total = stats.hits + stats.misses\n return total > 0 ? stats.hits / total : 0\n }\n\n return {\n transactions: {\n size: this.transactionCache.size,\n maxSize: this.transactionCache.max,\n hits: this.transactionStats.hits,\n misses: this.transactionStats.misses,\n hitRate: calculateHitRate(this.transactionStats),\n },\n addresses: {\n size: this.addressCache.size,\n maxSize: this.addressCache.max,\n hits: this.addressStats.hits,\n misses: this.addressStats.misses,\n hitRate: calculateHitRate(this.addressStats),\n },\n abis: {\n size: this.abiCache.size,\n maxSize: this.abiCache.max,\n hits: this.abiStats.hits,\n misses: this.abiStats.misses,\n hitRate: calculateHitRate(this.abiStats),\n },\n schemas: {\n size: this.schemaCache.size,\n maxSize: this.schemaCache.max,\n hits: this.schemaStats.hits,\n misses: this.schemaStats.misses,\n hitRate: calculateHitRate(this.schemaStats),\n },\n }\n }\n}\n","import { collectDataKeys } from '../core/addressCollector'\nimport { pluginRegistry } from '../decoder/registry'\nimport { decodeTransaction as decodeTransactionCore } from '../decoder/transaction'\nimport type { DecoderResult } from '../decoder/types'\nimport { needsEnhancement } from '../decoder/utils'\nimport type { ServerDecoderCaches } from './caches'\nimport type { ServerDecoderOptions } from './types'\n\n/**\n * Decode a single transaction with time-bounded enhancement\n */\nexport async function decodeTransactionSync(\n transaction: DecoderResult,\n options: ServerDecoderOptions,\n caches: ServerDecoderCaches\n): Promise<DecoderResult> {\n const startTime = Date.now()\n const { timeoutMs = 800, enableEnhancement = true, chain } = options\n\n // Check transaction cache first\n if (transaction.hash) {\n const cached = caches.getTransaction(transaction.hash)\n if (cached) {\n return cached\n }\n }\n\n try {\n // Phase 1: Immediate decode (sync plugins only)\n const phase1Start = Date.now()\n const plugins = await pluginRegistry.getAll({ syncOnly: true })\n const schemaPlugins = pluginRegistry.getAllSchema()\n\n const immediateOptions = {\n chain,\n plugins,\n schemaPlugins,\n wrappers: [],\n async: false,\n }\n const immediateResult = await decodeTransactionCore(\n transaction,\n immediateOptions\n )\n\n if (!immediateResult) {\n return {\n ...createErrorResult(transaction),\n phase: 'immediate',\n cached: false,\n timeTaken: Date.now() - startTime,\n }\n }\n\n let currentResult: DecoderResult = immediateResult\n let phase: 'immediate' | 'enhanced' | 'complete' = 'immediate'\n\n // Transfer collected wrappers if any\n if (immediateOptions.wrappers.length > 0) {\n ;(currentResult as any).wrappers = immediateOptions.wrappers\n }\n\n // Collect addresses from the decoded result\n const addresses = collectDataKeys(currentResult)\n currentResult.addresses = addresses\n\n // Check if we have time for enhancement\n const phase1Time = Date.now() - phase1Start\n if (enableEnhancement && phase1Time < timeoutMs * 0.6) {\n // Check if enhancement is actually needed\n if (!needsEnhancement(currentResult)) {\n // Already fully decoded during immediate phase\n phase = 'enhanced'\n } else {\n // Phase 2: Enhancement with async plugins\n try {\n const allPlugins = await pluginRegistry.getAll()\n const enhancedOptions = {\n chain,\n plugins: allPlugins,\n schemaPlugins,\n wrappers: [],\n async: true,\n }\n const enhancedResult = await Promise.race([\n decodeTransactionCore(transaction, enhancedOptions),\n // Timeout for phase 2\n new Promise<null>((resolve) =>\n setTimeout(() => resolve(null), timeoutMs * 0.6 - phase1Time)\n ),\n ])\n\n if (enhancedResult) {\n currentResult = enhancedResult\n phase = 'enhanced'\n\n // Merge wrappers from both phases (immediate + enhanced)\n const allWrappers = [\n ...((immediateOptions.wrappers || []) as any[]),\n ...(enhancedOptions.wrappers || []),\n ].filter(\n (w, i, arr) =>\n // Deduplicate by checking if this is the first occurrence\n arr.findIndex(\n (x) => JSON.stringify(x) === JSON.stringify(w)\n ) === i\n )\n\n if (allWrappers.length > 0) {\n ;(currentResult as any).wrappers = allWrappers\n }\n\n // Re-collect addresses from enhanced result\n currentResult.addresses = collectDataKeys(currentResult)\n }\n } catch (error) {\n console.error('Enhancement failed:', error)\n }\n }\n }\n\n const result: DecoderResult = {\n ...currentResult,\n phase,\n cached: false,\n timeTaken: Date.now() - startTime,\n }\n\n // Cache the result if we have a hash\n if (transaction.hash) {\n caches.setTransaction(transaction.hash, result)\n }\n\n return result\n } catch (error) {\n console.error('Failed to decode transaction:', error)\n return {\n ...createErrorResult(transaction),\n phase: 'immediate',\n cached: false,\n timeTaken: Date.now() - startTime,\n }\n }\n}\n\nfunction createErrorResult(transaction: DecoderResult): DecoderResult {\n return {\n ...transaction,\n isDecoded: false,\n resultType: 'error',\n errorType: 'UNKNOWN',\n sig: '0x' as `0x${string}`,\n addresses: [],\n } as DecoderResult\n}\n","import { collectDataKeys } from '../core/addressCollector'\nimport { pluginRegistry } from '../decoder/registry'\nimport { decodeTransaction as decodeTransactionCore } from '../decoder/transaction'\nimport type { DecoderResult, ResultShared } from '../decoder/types'\nimport { needsEnhancement } from '../decoder/utils'\nimport type { ServerDecoderCaches } from './caches'\nimport type { BatchDecodeResult, ServerDecoderOptions } from './types'\n\n/**\n * Decode multiple transactions with batching and time budget\n */\nexport async function decodeTransactionsBatch(\n transactions: DecoderResult[],\n options: ServerDecoderOptions,\n caches: ServerDecoderCaches\n): Promise<BatchDecodeResult> {\n const startTime = Date.now()\n const { timeoutMs = 800, enableEnhancement = true, chain } = options\n\n // Step 1: Check cache for all transactions\n const results: (DecoderResult | null)[] = transactions.map((tx) => {\n if (tx.transactionHash) {\n const cached = caches.getTransaction(tx.transactionHash)\n if (cached) return cached\n }\n return null\n })\n\n // Find uncached transactions\n const uncachedIndexes: number[] = []\n const uncachedTransactions: DecoderResult[] = []\n results.forEach((result, index) => {\n if (!result) {\n uncachedIndexes.push(index)\n uncachedTransactions.push(transactions[index])\n }\n })\n\n // If all are cached, return early\n if (uncachedTransactions.length === 0) {\n return {\n results: results as DecoderResult[],\n }\n }\n\n try {\n // Get plugins once for all transactions\n const syncPlugins = await pluginRegistry.getAll({ syncOnly: true })\n const allPlugins = await pluginRegistry.getAll()\n const schemaPlugins = pluginRegistry.getAllSchema()\n\n // Phase 1: Immediate decode for all uncached transactions\n const phase1Start = Date.now()\n const immediateOptionsArray = uncachedTransactions.map(() => ({\n chain,\n plugins: syncPlugins,\n schemaPlugins,\n wrappers: [],\n async: false,\n }))\n\n const immediateResults: DecoderResult[] = (\n await Promise.all(\n uncachedTransactions.map(async (tx, i) => {\n return await decodeTransactionCore(tx, immediateOptionsArray[i])\n })\n )\n ).filter(Boolean) as DecoderResult[]\n\n // Create result objects and collect addresses\n const newResults: DecoderResult[] = immediateResults\n .map((result, i) => {\n const data = result || createErrorResult(uncachedTransactions[i])\n\n // Transfer wrappers from immediate phase options\n if (immediateOptionsArray[i].wrappers.length > 0) {\n ;(data as any).wrappers = immediateOptionsArray[i].wrappers\n }\n\n // Collect addresses from the decoded result\n data.addresses = collectDataKeys(data)\n ;(data as ResultShared).timeTaken = Date.now() - startTime\n return data\n })\n .filter(Boolean) as DecoderResult[]\n\n // Check if we have time for enhancement\n const phase1Time = Date.now() - phase1Start\n if (enableEnhancement && phase1Time < timeoutMs * 0.6) {\n // Phase 2: Enhancement with async plugins (batch all transactions)\n try {\n const enhancedOptionsArray = uncachedTransactions.map(() => ({\n chain,\n plugins: allPlugins,\n schemaPlugins,\n wrappers: [],\n async: true,\n }))\n\n const enhancePromises = uncachedTransactions.map((tx, i) => {\n // Only enhance if immediate decode succeeded\n if (!immediateResults[i]) return null\n\n // Check if enhancement is actually needed\n if (!needsEnhancement(immediateResults[i])) {\n // Already fully decoded during immediate phase\n return null\n }\n\n return decodeTransactionCore(tx, enhancedOptionsArray[i])\n })\n\n // Wait for all enhancements with remaining time budget\n const _remainingTime = timeoutMs * 0.6 - phase1Time\n const enhancedResults = await Promise.all(enhancePromises)\n\n // Update results with enhanced data\n enhancedResults.forEach((enhanced, i) => {\n if (enhanced) {\n // Merge wrappers from both phases (immediate + enhanced)\n const immediateWrappers = immediateOptionsArray[i].wrappers || []\n const enhancedWrappers = enhancedOptionsArray[i].wrappers || []\n const allWrappers = [\n ...immediateWrappers,\n ...enhancedWrappers,\n ].filter(\n (w, idx, arr) =>\n // Deduplicate by checking if this is the first occurrence\n arr.findIndex(\n (x) => JSON.stringify(x) === JSON.stringify(w)\n ) === idx\n )\n\n // Enhancement returned a new result\n newResults[i] = enhanced\n\n // Add merged wrappers if any\n if (allWrappers.length > 0) {\n ;(newResults[i] as any).wrappers = allWrappers\n }\n\n // Re-collect addresses from enhanced result\n newResults[i].addresses = collectDataKeys(enhanced)\n newResults[i].phase = 'enhanced'\n } else if (\n immediateResults[i] &&\n !needsEnhancement(immediateResults[i])\n ) {\n // Enhancement was skipped because already fully decoded\n newResults[i].phase = 'enhanced'\n }\n })\n } catch (error) {\n console.error('Batch enhancement failed:', error)\n }\n }\n\n // Update timings\n const totalTime = Date.now() - startTime\n newResults.forEach((result) => {\n result.timeTaken = totalTime\n })\n\n // Cache all new results\n newResults.forEach((result, i) => {\n const tx = uncachedTransactions[i]\n if (tx.hash) {\n caches.setTransaction(tx.hash, result)\n }\n })\n\n // Merge cached and new results\n uncachedIndexes.forEach((originalIndex, i) => {\n results[originalIndex] = newResults[i]\n })\n\n return {\n results: results as DecoderResult[],\n }\n } catch (error) {\n console.error('Batch decode failed:', error)\n // Return error results for uncached transactions\n uncachedIndexes.forEach((originalIndex) => {\n results[originalIndex] = {\n ...createErrorResult(transactions[originalIndex]),\n phase: 'immediate',\n cached: false,\n timeTaken: Date.now() - startTime,\n }\n })\n\n return {\n results: results as DecoderResult[],\n }\n }\n}\n\nfunction createErrorResult(transaction: DecoderResult): DecoderResult {\n return {\n ...transaction,\n isDecoded: false,\n resultType: 'error',\n errorType: 'UNKNOWN',\n sig: '0x' as `0x${string}`,\n addresses: [],\n } as DecoderResult\n}\n","import { pluginRegistry } from '../decoder/registry'\nimport { decodeTransaction as decodeTransactionCore } from '../decoder/transaction'\nimport type { DecoderResult } from '../decoder/types'\nimport { createDebug } from '../utils/debug'\nimport type { ServerDecoderCaches } from './caches'\nimport type { ServerDecoderOptions } from './types'\n\nconst _debug = createDebug('decoder:finishDecoding')\n\n/**\n * Finish decoding a transaction by running enhancement phase\n * This only does phase 2 (async plugins) - address resolution should be done separately\n */\nexport async function finishDecoding(\n transaction: DecoderResult,\n options: ServerDecoderOptions,\n caches: ServerDecoderCaches\n): Promise<DecoderResult> {\n const startTime = Date.now()\n const { chain } = options\n\n try {\n // Check cache first\n const txHash = transaction.hash || transaction.transactionHash\n if (txHash) {\n const cached = caches.getTransaction(txHash)\n if (cached?.enhancementAttempted) {\n return {\n ...cached,\n cached: true,\n timeTaken: 0,\n } as DecoderResult\n }\n }\n\n // Get all plugins\n const allPlugins = await pluginRegistry.getAll()\n const schemaPlugins = pluginRegistry.getAllSchema()\n\n const enhancedOptions = {\n chain,\n plugins: allPlugins,\n schemaPlugins,\n wrappers: [],\n async: true,\n }\n\n // Wrappers and children must be removed when finishing decoding, because otherwise\n // the decoder will build hierarchical structures which are infinite.\n const {\n wrappers,\n children: _children,\n addresses: _addresses,\n ...transactionWithoutWrappers\n } = transaction as DecoderResult & {\n children?: unknown[]\n wrappers?: unknown[]\n addresses?: unknown[]\n }\n\n // Simply pass the entire transaction hierarchy to decodeTransactionCore\n // It will handle children properly and return a fully enhanced copy\n const enhancedResult = await decodeTransactionCore(\n transactionWithoutWrappers as DecoderResult,\n enhancedOptions\n )\n\n if (!enhancedResult) {\n if (txHash) {\n caches.setTransaction(txHash, {\n ...transaction,\n enhancementAttempted: true,\n })\n }\n return transaction\n }\n\n const result = {\n ...enhancedResult,\n // Only add wrappers if there are any\n ...((wrappers?.length || 0) > 0 ? { wrappers } : {}),\n cached: false,\n timeTaken: Date.now() - startTime,\n enhancementAttempted: true,\n } as DecoderResult\n\n // Always update cache with the enhanced result\n if (txHash) {\n caches.setTransaction(txHash, result)\n }\n\n return result\n } catch (error) {\n console.error('Failed to finish decoding transaction:', error)\n return {\n ...createErrorResult(transaction),\n phase: 'immediate',\n cached: false,\n timeTaken: Date.now() - startTime,\n }\n }\n}\n\nfunction createErrorResult(transaction: DecoderResult): DecoderResult {\n return {\n ...transaction,\n resultType: 'error',\n errorType: 'UNKNOWN',\n sig: '0x' as `0x${string}`,\n addresses: [],\n } as DecoderResult\n}\n","import { ServerAddressResolver } from './addressResolver'\nimport { ServerDecoderCaches } from './caches'\nimport { decodeTransactionSync } from './decodeTransactionSync'\nimport { decodeTransactionsBatch } from './decodeTransactionsBatch'\nimport { finishDecoding } from './finishDecoding'\nimport type {\n ServerDecoder,\n ServerDecoderConfig,\n ServerDecoderOptions,\n} from './types'\n\n// Import plugins to ensure they are registered\nimport '../decoder/plugins'\n\n/**\n * Create a server-optimized decoder instance\n */\nexport function createServerDecoder(\n config: ServerDecoderConfig\n): ServerDecoder {\n // Create caches\n const caches = new ServerDecoderCaches({\n transactionCacheSize: config.transactionCacheSize,\n addressCacheSize: config.addressCacheSize,\n abiCacheSize: config.abiCacheSize,\n schemaCacheSize: config.schemaCacheSize,\n })\n\n // Create address resolver\n const addressResolver = new ServerAddressResolver(\n config.graphqlEndpoint,\n config.defaultChain,\n caches\n )\n\n // Return server decoder interface\n return {\n async decodeTransaction(transaction, options) {\n const opts: ServerDecoderOptions = {\n chain: config.defaultChain,\n timeoutMs: config.defaultTimeout,\n ...options,\n }\n return decodeTransactionSync(transaction, opts, caches)\n },\n\n async decodeTransactionsBatch(transactions, options) {\n const opts: ServerDecoderOptions = {\n chain: config.defaultChain,\n timeoutMs: config.defaultTimeout,\n ...options,\n }\n return decodeTransactionsBatch(transactions, opts, caches)\n },\n\n async finishDecoding(transaction, options) {\n const opts: ServerDecoderOptions = {\n chain: config.defaultChain,\n timeoutMs: config.defaultTimeout,\n ...options,\n }\n return finishDecoding(transaction, opts, caches)\n },\n\n clearCaches() {\n caches.clear()\n },\n\n getCacheStats() {\n return caches.getStats()\n },\n\n async warmAddressCache(addresses) {\n await addressResolver.warmCache(addresses)\n },\n\n async resolveAddresses(addresses, timeoutMs = 3000) {\n return addressResolver.resolveAddressesWithTimeout(addresses, timeoutMs)\n },\n }\n}\n"],"mappings":"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","names":["createErrorResult","createErrorResult"]}
|
|
1
|
+
{"version":3,"sources":["../src/server/addressResolver.ts","../src/server/caches.ts","../src/server/decodeTransactionSync.ts","../src/server/decodeTransactionsBatch.ts","../src/server/finishDecoding.ts","../src/server/index.ts"],"sourcesContent":["import type { Chain } from 'viem'\nimport { fetchMultipleAddresses } from '../shared/addressResolver'\nimport type { AddressIdentityCache } from '../shared/cache'\nimport type { DataKey, EnhancedInfo } from '../types'\nimport type { ServerDecoderCaches } from './caches'\n\n/**\n * Server-side address resolver with caching\n */\nexport class ServerAddressResolver {\n private cacheAdapter: AddressIdentityCache\n\n constructor(\n private graphqlEndpoint: string,\n private chain: Chain,\n private caches: ServerDecoderCaches\n ) {\n // Create adapter to use ServerDecoderCaches as AddressIdentityCache\n this.cacheAdapter = {\n get: (key: DataKey) => this.caches.getAddress(key),\n set: (key: DataKey, value: EnhancedInfo) =>\n this.caches.setAddress(key, value),\n has: (key: DataKey) => this.caches.hasAddress(key),\n getMany: (keys: DataKey[]) => this.caches.getAddresses(keys),\n }\n }\n\n /**\n * Resolve addresses, using cache when possible\n */\n async resolveAddresses(\n addresses: readonly DataKey[]\n ): Promise<Map<DataKey, EnhancedInfo>> {\n // Use the shared implementation with cache adapter\n return fetchMultipleAddresses(\n addresses,\n this.graphqlEndpoint,\n this.cacheAdapter\n )\n }\n\n /**\n * Resolve addresses with timeout\n */\n async resolveAddressesWithTimeout(\n addresses: DataKey[],\n timeoutMs: number\n ): Promise<Map<DataKey, EnhancedInfo>> {\n return Promise.race([\n this.resolveAddresses(addresses),\n new Promise<Map<DataKey, EnhancedInfo>>((resolve) => {\n setTimeout(() => {\n // On timeout, return whatever we have cached\n const results = this.caches.getAddresses(addresses)\n resolve(results)\n }, timeoutMs)\n }),\n ])\n }\n\n /**\n * Warm the cache with specific addresses\n */\n async warmCache(addresses: DataKey[]): Promise<void> {\n // Simply call resolveAddresses which will cache any uncached addresses\n await this.resolveAddresses(addresses)\n }\n}\n","import { LRUCache } from 'lru-cache'\nimport type { Abi } from 'viem'\nimport type { DecoderResult, Info } from '../decoder/types'\nimport type { DataKey, EnhancedInfo } from '../types'\nimport type { CacheStats } from './types'\n\n/**\n * Multi-level caching system for server-side decoder\n */\nexport class ServerDecoderCaches {\n // Level 1: Decoded transaction cache (keyed by transaction hash)\n private transactionCache: LRUCache<string, DecoderResult>\n private transactionStats = { hits: 0, misses: 0 }\n\n // Level 2: Address metadata cache (keyed by address or address:tokenId)\n private addressCache: LRUCache<string, EnhancedInfo>\n private addressStats = { hits: 0, misses: 0 }\n\n // Level 3: Contract ABI cache (keyed by address)\n private abiCache: LRUCache<string, Abi>\n private abiStats = { hits: 0, misses: 0 }\n\n // Level 4: Schema decode cache (keyed by key:value)\n private schemaCache: LRUCache<string, Info>\n private schemaStats = { hits: 0, misses: 0 }\n\n constructor(\n options: {\n transactionCacheSize?: number\n addressCacheSize?: number\n abiCacheSize?: number\n schemaCacheSize?: number\n } = {}\n ) {\n // Transaction cache - store complete decoded results\n this.transactionCache = new LRUCache<string, DecoderResult>({\n max: options.transactionCacheSize || 10000,\n ttl: 1000 * 60 * 60, // 1 hour TTL\n updateAgeOnGet: true,\n updateAgeOnHas: true,\n })\n\n // Address cache - store profile/asset metadata\n this.addressCache = new LRUCache<string, EnhancedInfo>({\n max: options.addressCacheSize || 50000,\n ttl: 1000 * 60 * 60 * 24, // 24 hour TTL\n updateAgeOnGet: true,\n updateAgeOnHas: true,\n })\n\n // ABI cache - store contract ABIs\n this.abiCache = new LRUCache<string, Abi>({\n max: options.abiCacheSize || 5000,\n ttl: 1000 * 60 * 60 * 24 * 7, // 7 day TTL (ABIs rarely change)\n updateAgeOnGet: true,\n updateAgeOnHas: true,\n })\n\n // Schema cache - store decoded schema values\n this.schemaCache = new LRUCache<string, Info>({\n max: options.schemaCacheSize || 10000,\n ttl: 1000 * 60 * 60, // 1 hour TTL\n updateAgeOnGet: true,\n updateAgeOnHas: true,\n })\n }\n\n /**\n * Get cache key for a data key (address or address:tokenId)\n */\n private getDataKeyCacheKey(key: DataKey): string {\n return key.toLowerCase()\n }\n\n // Transaction cache methods\n getTransaction(hash: string): DecoderResult | undefined {\n const result = this.transactionCache.get(hash.toLowerCase())\n if (result) {\n this.transactionStats.hits++\n return { ...result, cached: true }\n }\n this.transactionStats.misses++\n return undefined\n }\n\n setTransaction(hash: string, result: DecoderResult): void {\n this.transactionCache.set(hash.toLowerCase(), result)\n }\n\n // Address cache methods\n getAddress(key: DataKey): EnhancedInfo | undefined {\n const cacheKey = this.getDataKeyCacheKey(key)\n const result = this.addressCache.get(cacheKey)\n if (result) {\n this.addressStats.hits++\n return result\n }\n this.addressStats.misses++\n return undefined\n }\n\n setAddress(key: DataKey, data: EnhancedInfo): void {\n const cacheKey = this.getDataKeyCacheKey(key)\n this.addressCache.set(cacheKey, data)\n }\n\n hasAddress(key: DataKey): boolean {\n return this.addressCache.has(this.getDataKeyCacheKey(key))\n }\n\n getAddresses(keys: DataKey[]): Map<DataKey, EnhancedInfo> {\n const results = new Map<DataKey, EnhancedInfo>()\n for (const key of keys) {\n const data = this.getAddress(key)\n if (data) {\n results.set(key, data)\n }\n }\n return results\n }\n\n // ABI cache methods\n getAbi(address: string): Abi | undefined {\n const result = this.abiCache.get(address.toLowerCase())\n if (result) {\n this.abiStats.hits++\n return result\n }\n this.abiStats.misses++\n return undefined\n }\n\n setAbi(address: string, abi: Abi): void {\n this.abiCache.set(address.toLowerCase(), abi)\n }\n\n hasAbi(address: string): boolean {\n return this.abiCache.has(address.toLowerCase())\n }\n\n // Schema cache methods\n getSchema(key: string, value: string): Info | undefined {\n const cacheKey = `${key}:${value}`\n const result = this.schemaCache.get(cacheKey)\n if (result) {\n this.schemaStats.hits++\n return result\n }\n this.schemaStats.misses++\n return undefined\n }\n\n setSchema(key: string, value: string, info: Info): void {\n const cacheKey = `${key}:${value}`\n this.schemaCache.set(cacheKey, info)\n }\n\n // Cache management\n clear(): void {\n this.transactionCache.clear()\n this.addressCache.clear()\n this.abiCache.clear()\n this.schemaCache.clear()\n\n // Reset stats\n this.transactionStats = { hits: 0, misses: 0 }\n this.addressStats = { hits: 0, misses: 0 }\n this.abiStats = { hits: 0, misses: 0 }\n this.schemaStats = { hits: 0, misses: 0 }\n }\n\n getStats(): CacheStats {\n const calculateHitRate = (stats: { hits: number; misses: number }) => {\n const total = stats.hits + stats.misses\n return total > 0 ? stats.hits / total : 0\n }\n\n return {\n transactions: {\n size: this.transactionCache.size,\n maxSize: this.transactionCache.max,\n hits: this.transactionStats.hits,\n misses: this.transactionStats.misses,\n hitRate: calculateHitRate(this.transactionStats),\n },\n addresses: {\n size: this.addressCache.size,\n maxSize: this.addressCache.max,\n hits: this.addressStats.hits,\n misses: this.addressStats.misses,\n hitRate: calculateHitRate(this.addressStats),\n },\n abis: {\n size: this.abiCache.size,\n maxSize: this.abiCache.max,\n hits: this.abiStats.hits,\n misses: this.abiStats.misses,\n hitRate: calculateHitRate(this.abiStats),\n },\n schemas: {\n size: this.schemaCache.size,\n maxSize: this.schemaCache.max,\n hits: this.schemaStats.hits,\n misses: this.schemaStats.misses,\n hitRate: calculateHitRate(this.schemaStats),\n },\n }\n }\n}\n","import type { Transaction } from 'viem'\nimport { collectDataKeys } from '../core/addressCollector'\nimport { pluginRegistry } from '../decoder/registry'\nimport { decodeTransaction as decodeTransactionCore } from '../decoder/transaction'\nimport type { DecoderResult } from '../decoder/types'\nimport { needsEnhancement } from '../decoder/utils'\nimport type { ServerDecoderCaches } from './caches'\nimport type { ServerDecoderOptions } from './types'\n\n/**\n * Decode a single transaction with time-bounded enhancement\n */\nexport async function decodeTransactionSync(\n transaction: DecoderResult,\n options: ServerDecoderOptions,\n caches: ServerDecoderCaches\n): Promise<DecoderResult> {\n const startTime = Date.now()\n const { timeoutMs = 800, enableEnhancement = true, chain } = options\n\n // Check transaction cache first\n if (transaction.hash) {\n const cached = caches.getTransaction(transaction.hash)\n if (cached) {\n return cached\n }\n }\n\n try {\n // Phase 1: Immediate decode (sync plugins only)\n const phase1Start = Date.now()\n const plugins = await pluginRegistry.getAll({ syncOnly: true })\n const schemaPlugins = pluginRegistry.getAllSchema()\n\n const immediateOptions = {\n chain,\n plugins,\n schemaPlugins,\n wrappers: [],\n async: false,\n }\n const immediateResult = await decodeTransactionCore(\n transaction,\n immediateOptions\n )\n\n if (!immediateResult) {\n return {\n ...createErrorResult(transaction),\n phase: 'immediate',\n cached: false,\n timeTaken: Date.now() - startTime,\n }\n }\n\n let currentResult: DecoderResult = immediateResult\n let phase: 'immediate' | 'enhanced' | 'complete' = 'immediate'\n\n // Transfer collected wrappers if any\n if (immediateOptions.wrappers.length > 0) {\n ;(currentResult as any).wrappers = immediateOptions.wrappers\n }\n\n // Collect addresses from the decoded result\n const addresses = collectDataKeys(currentResult)\n currentResult.addresses = addresses\n\n // Check if we have time for enhancement\n const phase1Time = Date.now() - phase1Start\n if (enableEnhancement && phase1Time < timeoutMs * 0.6) {\n // Check if enhancement is actually needed\n if (!needsEnhancement(currentResult)) {\n // Already fully decoded during immediate phase\n phase = 'enhanced'\n } else {\n // Phase 2: Enhancement with async plugins\n try {\n const allPlugins = await pluginRegistry.getAll()\n const enhancedOptions = {\n chain,\n plugins: allPlugins,\n schemaPlugins,\n wrappers: [],\n async: true,\n }\n const enhancedResult = await Promise.race([\n decodeTransactionCore(transaction, enhancedOptions),\n // Timeout for phase 2\n new Promise<null>((resolve) =>\n setTimeout(() => resolve(null), timeoutMs * 0.6 - phase1Time)\n ),\n ])\n\n if (enhancedResult) {\n currentResult = enhancedResult\n phase = 'enhanced'\n\n // Merge wrappers from both phases (immediate + enhanced)\n const allWrappers = [\n ...((immediateOptions.wrappers || []) as any[]),\n ...(enhancedOptions.wrappers || []),\n ].filter(\n (w, i, arr) =>\n // Deduplicate by checking if this is the first occurrence\n arr.findIndex(\n (x) => JSON.stringify(x) === JSON.stringify(w)\n ) === i\n )\n\n if (allWrappers.length > 0) {\n ;(currentResult as any).wrappers = allWrappers\n }\n\n // Re-collect addresses from enhanced result\n currentResult.addresses = collectDataKeys(currentResult)\n }\n } catch (error) {\n console.error('Enhancement failed:', error)\n }\n }\n }\n\n const result: DecoderResult = {\n ...currentResult,\n phase,\n cached: false,\n timeTaken: Date.now() - startTime,\n }\n\n // Cache the result if we have a hash\n if (transaction.hash) {\n caches.setTransaction(transaction.hash, result)\n }\n\n return result\n } catch (error) {\n console.error('Failed to decode transaction:', error)\n return {\n ...createErrorResult(transaction),\n phase: 'immediate',\n cached: false,\n timeTaken: Date.now() - startTime,\n }\n }\n}\n\nfunction createErrorResult(transaction: DecoderResult): DecoderResult {\n return {\n ...transaction,\n isDecoded: false,\n resultType: 'error',\n errorType: 'UNKNOWN',\n sig: '0x' as `0x${string}`,\n addresses: [],\n } as DecoderResult\n}\n","import { collectDataKeys } from '../core/addressCollector'\nimport { pluginRegistry } from '../decoder/registry'\nimport { decodeTransaction as decodeTransactionCore } from '../decoder/transaction'\nimport type { DecoderResult, ResultShared } from '../decoder/types'\nimport { needsEnhancement } from '../decoder/utils'\nimport type { ServerDecoderCaches } from './caches'\nimport type { BatchDecodeResult, ServerDecoderOptions } from './types'\n\n/**\n * Decode multiple transactions with batching and time budget\n */\nexport async function decodeTransactionsBatch(\n transactions: DecoderResult[],\n options: ServerDecoderOptions,\n caches: ServerDecoderCaches\n): Promise<BatchDecodeResult> {\n const startTime = Date.now()\n const { timeoutMs = 800, enableEnhancement = true, chain } = options\n\n // Step 1: Check cache for all transactions\n const results: (DecoderResult | null)[] = transactions.map((tx) => {\n if (tx.transactionHash) {\n const cached = caches.getTransaction(tx.transactionHash)\n if (cached) return cached\n }\n return null\n })\n\n // Find uncached transactions\n const uncachedIndexes: number[] = []\n const uncachedTransactions: DecoderResult[] = []\n results.forEach((result, index) => {\n if (!result) {\n uncachedIndexes.push(index)\n uncachedTransactions.push(transactions[index])\n }\n })\n\n // If all are cached, return early\n if (uncachedTransactions.length === 0) {\n return {\n results: results as DecoderResult[],\n }\n }\n\n try {\n // Get plugins once for all transactions\n const syncPlugins = await pluginRegistry.getAll({ syncOnly: true })\n const allPlugins = await pluginRegistry.getAll()\n const schemaPlugins = pluginRegistry.getAllSchema()\n\n // Phase 1: Immediate decode for all uncached transactions\n const phase1Start = Date.now()\n const immediateOptionsArray = uncachedTransactions.map(() => ({\n chain,\n plugins: syncPlugins,\n schemaPlugins,\n wrappers: [],\n async: false,\n }))\n\n const immediateResults: DecoderResult[] = (\n await Promise.all(\n uncachedTransactions.map(async (tx, i) => {\n return await decodeTransactionCore(tx, immediateOptionsArray[i])\n })\n )\n ).filter(Boolean) as DecoderResult[]\n\n // Create result objects and collect addresses\n const newResults: DecoderResult[] = immediateResults\n .map((result, i) => {\n const data = result || createErrorResult(uncachedTransactions[i])\n\n // Transfer wrappers from immediate phase options\n if (immediateOptionsArray[i].wrappers.length > 0) {\n ;(data as any).wrappers = immediateOptionsArray[i].wrappers\n }\n\n // Collect addresses from the decoded result\n data.addresses = collectDataKeys(data)\n ;(data as ResultShared).timeTaken = Date.now() - startTime\n return data\n })\n .filter(Boolean) as DecoderResult[]\n\n // Check if we have time for enhancement\n const phase1Time = Date.now() - phase1Start\n if (enableEnhancement && phase1Time < timeoutMs * 0.6) {\n // Phase 2: Enhancement with async plugins (batch all transactions)\n try {\n const enhancedOptionsArray = uncachedTransactions.map(() => ({\n chain,\n plugins: allPlugins,\n schemaPlugins,\n wrappers: [],\n async: true,\n }))\n\n const enhancePromises = uncachedTransactions.map((tx, i) => {\n // Only enhance if immediate decode succeeded\n if (!immediateResults[i]) return null\n\n // Check if enhancement is actually needed\n if (!needsEnhancement(immediateResults[i])) {\n // Already fully decoded during immediate phase\n return null\n }\n\n return decodeTransactionCore(tx, enhancedOptionsArray[i])\n })\n\n // Wait for all enhancements with remaining time budget\n const remainingTime = timeoutMs * 0.6 - phase1Time\n const enhancedResults = await Promise.all(enhancePromises)\n\n // Update results with enhanced data\n enhancedResults.forEach((enhanced, i) => {\n if (enhanced) {\n // Merge wrappers from both phases (immediate + enhanced)\n const immediateWrappers = immediateOptionsArray[i].wrappers || []\n const enhancedWrappers = enhancedOptionsArray[i].wrappers || []\n const allWrappers = [\n ...immediateWrappers,\n ...enhancedWrappers,\n ].filter(\n (w, idx, arr) =>\n // Deduplicate by checking if this is the first occurrence\n arr.findIndex(\n (x) => JSON.stringify(x) === JSON.stringify(w)\n ) === idx\n )\n\n // Enhancement returned a new result\n newResults[i] = enhanced\n\n // Add merged wrappers if any\n if (allWrappers.length > 0) {\n ;(newResults[i] as any).wrappers = allWrappers\n }\n\n // Re-collect addresses from enhanced result\n newResults[i].addresses = collectDataKeys(enhanced)\n newResults[i].phase = 'enhanced'\n } else if (\n immediateResults[i] &&\n !needsEnhancement(immediateResults[i])\n ) {\n // Enhancement was skipped because already fully decoded\n newResults[i].phase = 'enhanced'\n }\n })\n } catch (error) {\n console.error('Batch enhancement failed:', error)\n }\n }\n\n // Update timings\n const totalTime = Date.now() - startTime\n newResults.forEach((result) => {\n result.timeTaken = totalTime\n })\n\n // Cache all new results\n newResults.forEach((result, i) => {\n const tx = uncachedTransactions[i]\n if (tx.hash) {\n caches.setTransaction(tx.hash, result)\n }\n })\n\n // Merge cached and new results\n uncachedIndexes.forEach((originalIndex, i) => {\n results[originalIndex] = newResults[i]\n })\n\n return {\n results: results as DecoderResult[],\n }\n } catch (error) {\n console.error('Batch decode failed:', error)\n // Return error results for uncached transactions\n uncachedIndexes.forEach((originalIndex) => {\n results[originalIndex] = {\n ...createErrorResult(transactions[originalIndex]),\n phase: 'immediate',\n cached: false,\n timeTaken: Date.now() - startTime,\n }\n })\n\n return {\n results: results as DecoderResult[],\n }\n }\n}\n\nfunction createErrorResult(transaction: DecoderResult): DecoderResult {\n return {\n ...transaction,\n isDecoded: false,\n resultType: 'error',\n errorType: 'UNKNOWN',\n sig: '0x' as `0x${string}`,\n addresses: [],\n } as DecoderResult\n}\n","import { collectDataKeys } from '../core/addressCollector'\nimport { pluginRegistry } from '../decoder/registry'\nimport { decodeTransaction as decodeTransactionCore } from '../decoder/transaction'\nimport type { DecoderResult, ResultShared } from '../decoder/types'\nimport { createDebug } from '../utils/debug'\nimport type { ServerDecoderCaches } from './caches'\nimport type { ServerDecoderOptions } from './types'\n\nconst debug = createDebug('decoder:finishDecoding')\n\n/**\n * Finish decoding a transaction by running enhancement phase\n * This only does phase 2 (async plugins) - address resolution should be done separately\n */\nexport async function finishDecoding(\n transaction: DecoderResult,\n options: ServerDecoderOptions,\n caches: ServerDecoderCaches\n): Promise<DecoderResult> {\n const startTime = Date.now()\n const {\n timeoutMs = 5000, // Give more time for finishing\n chain,\n } = options\n\n try {\n // Check cache first\n const txHash = transaction.hash || transaction.transactionHash\n if (txHash) {\n const cached = caches.getTransaction(txHash)\n if (cached && cached.enhancementAttempted) {\n return {\n ...cached,\n cached: true,\n timeTaken: 0,\n } as DecoderResult\n }\n }\n\n // Get all plugins\n const allPlugins = await pluginRegistry.getAll()\n const schemaPlugins = pluginRegistry.getAllSchema()\n\n const enhancedOptions = {\n chain,\n plugins: allPlugins,\n schemaPlugins,\n wrappers: [],\n async: true,\n }\n\n // Wrappers and children must be removed when finishing decoding, because otherwise\n // the decoder will build hierarchical structures which are infinite.\n const {\n wrappers,\n children: _children,\n addresses: _addresses,\n ...transactionWithoutWrappers\n } = transaction as DecoderResult & {\n children?: unknown[]\n wrappers?: unknown[]\n addresses?: unknown[]\n }\n\n // Simply pass the entire transaction hierarchy to decodeTransactionCore\n // It will handle children properly and return a fully enhanced copy\n const enhancedResult = await decodeTransactionCore(\n transactionWithoutWrappers as DecoderResult,\n enhancedOptions\n )\n\n if (!enhancedResult) {\n if (txHash) {\n caches.setTransaction(txHash, {\n ...transaction,\n enhancementAttempted: true,\n })\n }\n return transaction\n }\n\n const result = {\n ...enhancedResult,\n // Only add wrappers if there are any\n ...((wrappers?.length || 0) > 0 ? { wrappers } : {}),\n cached: false,\n timeTaken: Date.now() - startTime,\n enhancementAttempted: true,\n } as DecoderResult\n\n // Always update cache with the enhanced result\n if (txHash) {\n caches.setTransaction(txHash, result)\n }\n\n return result\n } catch (error) {\n console.error('Failed to finish decoding transaction:', error)\n return {\n ...createErrorResult(transaction),\n phase: 'immediate',\n cached: false,\n timeTaken: Date.now() - startTime,\n }\n }\n}\n\nfunction createErrorResult(transaction: DecoderResult): DecoderResult {\n return {\n ...transaction,\n resultType: 'error',\n errorType: 'UNKNOWN',\n sig: '0x' as `0x${string}`,\n addresses: [],\n } as DecoderResult\n}\n","import { ServerAddressResolver } from './addressResolver'\nimport { ServerDecoderCaches } from './caches'\nimport { decodeTransactionSync } from './decodeTransactionSync'\nimport { decodeTransactionsBatch } from './decodeTransactionsBatch'\nimport { finishDecoding } from './finishDecoding'\nimport type {\n ServerDecoder,\n ServerDecoderConfig,\n ServerDecoderOptions,\n} from './types'\n\n// Import plugins to ensure they are registered\nimport '../decoder/plugins'\n\n/**\n * Create a server-optimized decoder instance\n */\nexport function createServerDecoder(\n config: ServerDecoderConfig\n): ServerDecoder {\n // Create caches\n const caches = new ServerDecoderCaches({\n transactionCacheSize: config.transactionCacheSize,\n addressCacheSize: config.addressCacheSize,\n abiCacheSize: config.abiCacheSize,\n schemaCacheSize: config.schemaCacheSize,\n })\n\n // Create address resolver\n const addressResolver = new ServerAddressResolver(\n config.graphqlEndpoint,\n config.defaultChain,\n caches\n )\n\n // Return server decoder interface\n return {\n async decodeTransaction(transaction, options) {\n const opts: ServerDecoderOptions = {\n chain: config.defaultChain,\n timeoutMs: config.defaultTimeout,\n ...options,\n }\n return decodeTransactionSync(transaction, opts, caches)\n },\n\n async decodeTransactionsBatch(transactions, options) {\n const opts: ServerDecoderOptions = {\n chain: config.defaultChain,\n timeoutMs: config.defaultTimeout,\n ...options,\n }\n return decodeTransactionsBatch(transactions, opts, caches)\n },\n\n async finishDecoding(transaction, options) {\n const opts: ServerDecoderOptions = {\n chain: config.defaultChain,\n timeoutMs: config.defaultTimeout,\n ...options,\n }\n return finishDecoding(transaction, opts, caches)\n },\n\n clearCaches() {\n caches.clear()\n },\n\n getCacheStats() {\n return caches.getStats()\n },\n\n async warmAddressCache(addresses) {\n await addressResolver.warmCache(addresses)\n },\n\n async resolveAddresses(addresses, timeoutMs = 3000) {\n return addressResolver.resolveAddressesWithTimeout(addresses, timeoutMs)\n },\n }\n}\n"],"mappings":"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","names":["createErrorResult","createErrorResult"]}
|
|
@@ -80,7 +80,7 @@ declare function decodeKeyValueRaw(key: Hex, value: Hex, options: DecoderOptions
|
|
|
80
80
|
* It's essentially the same code as decodeFunctionData, but also
|
|
81
81
|
* returning a namedArgs where we zip together the args and the inputs.
|
|
82
82
|
*/
|
|
83
|
-
declare function customDecodeFunctionData<const abi extends Abi | readonly unknown[],
|
|
83
|
+
declare function customDecodeFunctionData<const abi extends Abi | readonly unknown[], preferError = false>(parameters: Partial<DecodeFunctionDataParameters<abi> & {
|
|
84
84
|
namedArgs?: Record<number, AbiParameter & {
|
|
85
85
|
value?: unknown;
|
|
86
86
|
}> | Record<string, unknown>;
|
|
@@ -80,7 +80,7 @@ declare function decodeKeyValueRaw(key: Hex, value: Hex, options: DecoderOptions
|
|
|
80
80
|
* It's essentially the same code as decodeFunctionData, but also
|
|
81
81
|
* returning a namedArgs where we zip together the args and the inputs.
|
|
82
82
|
*/
|
|
83
|
-
declare function customDecodeFunctionData<const abi extends Abi | readonly unknown[],
|
|
83
|
+
declare function customDecodeFunctionData<const abi extends Abi | readonly unknown[], preferError = false>(parameters: Partial<DecodeFunctionDataParameters<abi> & {
|
|
84
84
|
namedArgs?: Record<number, AbiParameter & {
|
|
85
85
|
value?: unknown;
|
|
86
86
|
}> | Record<string, unknown>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lukso/transaction-decoder",
|
|
3
|
-
"version": "1.3.0
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Transaction decoder for LUKSO blockchain with reactive state management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -91,11 +91,11 @@
|
|
|
91
91
|
"build:watch": "tsup --watch --dts",
|
|
92
92
|
"build:lib": "tsup",
|
|
93
93
|
"dev": "tsup --watch --dts",
|
|
94
|
+
"type-check": "tsc --noEmit",
|
|
94
95
|
"lint": "biome lint",
|
|
95
96
|
"lint:fix": "biome lint --fix",
|
|
96
97
|
"test": "vitest run",
|
|
97
98
|
"test:watch": "vitest",
|
|
98
|
-
"clean": "rm -rf dist"
|
|
99
|
-
"typecheck": "tsc --noEmit"
|
|
99
|
+
"clean": "rm -rf dist"
|
|
100
100
|
}
|
|
101
101
|
}
|
package/src/core/dataModel.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Core data model implementation
|
|
2
2
|
import { batch, effect, type Signal, signal } from '@preact/signals-core'
|
|
3
3
|
import type { Address, Hex } from 'viem'
|
|
4
|
-
import { isHex, size } from 'viem'
|
|
4
|
+
import { hexToBigInt, isHex, size, slice } from 'viem'
|
|
5
5
|
import type {
|
|
6
6
|
AddressState,
|
|
7
7
|
DataKey,
|
|
@@ -80,6 +80,36 @@ export class DataModel implements IDataModel {
|
|
|
80
80
|
this.options = options
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Extract a 20-byte address from a potentially 32-byte hex value
|
|
85
|
+
* If the input is 32 bytes, validates it's zero-padded and takes the rightmost 20 bytes
|
|
86
|
+
* If the input is 20 bytes, returns it as-is
|
|
87
|
+
*/
|
|
88
|
+
private extractAddress(hex: Hex): Address {
|
|
89
|
+
if (!isHex(hex)) {
|
|
90
|
+
throw new Error(`Invalid hex value: ${hex}`)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const bytes = size(hex)
|
|
94
|
+
|
|
95
|
+
if (bytes === 32) {
|
|
96
|
+
// Check if the first 12 bytes are zeros (valid padding)
|
|
97
|
+
const first12Bytes = slice(hex, 0, 12)
|
|
98
|
+
if (hexToBigInt(first12Bytes) !== 0n) {
|
|
99
|
+
throw new Error(
|
|
100
|
+
`Invalid 32-byte address: first 12 bytes must be zero for a padded address, got ${first12Bytes}`
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
// 32 bytes with valid padding - extract the rightmost 20 bytes
|
|
104
|
+
return slice(hex, 12, 32) as Address
|
|
105
|
+
}
|
|
106
|
+
if (bytes === 20) {
|
|
107
|
+
// 20 bytes - already a proper address
|
|
108
|
+
return hex as Address
|
|
109
|
+
}
|
|
110
|
+
throw new Error(`Invalid address length: ${bytes} bytes`)
|
|
111
|
+
}
|
|
112
|
+
|
|
83
113
|
/**
|
|
84
114
|
* Get or create a signal for a specific key
|
|
85
115
|
*/
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { effect } from '@preact/signals-core'
|
|
2
|
+
import type { Address, Transaction } from 'viem'
|
|
2
3
|
import { lukso } from 'viem/chains'
|
|
3
4
|
import { decodeTransaction } from '../decoder/decodeTransaction'
|
|
4
5
|
import { defaultPlugins, defaultSchemaPlugins } from '../decoder/plugins'
|
|
@@ -122,7 +123,7 @@ export class DecoderIntegration {
|
|
|
122
123
|
const signals = this.dataModel.addTransactions(transactions)
|
|
123
124
|
|
|
124
125
|
// Start decoding for each transaction
|
|
125
|
-
const decodingPromises = transactions.map(async (tx,
|
|
126
|
+
const decodingPromises = transactions.map(async (tx, index) => {
|
|
126
127
|
// Create fresh wrappers array for each transaction
|
|
127
128
|
const transactionOptions: DecoderOptions = {
|
|
128
129
|
...this.decoderOptions,
|
|
@@ -173,7 +173,12 @@ export class BrowserDecoderCache implements DecoderCache {
|
|
|
173
173
|
}
|
|
174
174
|
|
|
175
175
|
// If we have a stale entry and stale-while-revalidate is enabled
|
|
176
|
-
if (
|
|
176
|
+
if (
|
|
177
|
+
cached &&
|
|
178
|
+
cached.stale &&
|
|
179
|
+
now < cached.stale &&
|
|
180
|
+
!this.promises.has(key)
|
|
181
|
+
) {
|
|
177
182
|
// Return stale value and revalidate in background
|
|
178
183
|
const backgroundPromise = factory(options?.signal)
|
|
179
184
|
.then(async (fresh) => {
|
package/src/decoder/errors.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { type Chain, decodeAbiParameters, slice } from 'viem'
|
|
|
2
2
|
import defaultPlugins from './plugins'
|
|
3
3
|
import { decodeTransaction } from './transaction'
|
|
4
4
|
import {
|
|
5
|
-
|
|
5
|
+
DecoderResult,
|
|
6
6
|
ErrorType,
|
|
7
7
|
type ResultError,
|
|
8
8
|
type SchemaPlugin,
|
|
@@ -30,7 +30,7 @@ export const ErrorTypeMap: {
|
|
|
30
30
|
[ErrorType.EMPTY_REVERT]: 'transaction.error.types.empty_revert',
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
const
|
|
33
|
+
const CONTRACT_ERROR_THROWN = 'transactions.error.contract_error_thrown'
|
|
34
34
|
|
|
35
35
|
function populateEmptyRevertInfo(
|
|
36
36
|
input: `0x${string}`
|
package/src/decoder/events.ts
CHANGED
|
@@ -166,7 +166,7 @@ export function customDecodeEventLog<
|
|
|
166
166
|
* @returns Promise<ResultType>
|
|
167
167
|
*/
|
|
168
168
|
export function decodeEvent<abi extends Abi | readonly unknown[] = Abi>(
|
|
169
|
-
|
|
169
|
+
chain: Chain,
|
|
170
170
|
abi: abi,
|
|
171
171
|
log: DecodeEventResult
|
|
172
172
|
):
|
|
@@ -175,9 +175,9 @@ export function decodeEvent<abi extends Abi | readonly unknown[] = Abi>(
|
|
|
175
175
|
args: ArrayArgs
|
|
176
176
|
} & DecodeEventResult)
|
|
177
177
|
| undefined {
|
|
178
|
-
const { data: _data } = log as Log
|
|
178
|
+
const { data: _data, address, ...rest } = log as Log
|
|
179
179
|
|
|
180
|
-
let
|
|
180
|
+
let lastError: Error | undefined
|
|
181
181
|
try {
|
|
182
182
|
const result = customDecodeEventLog({
|
|
183
183
|
abi,
|
|
@@ -77,7 +77,7 @@ export async function fetchAbi(
|
|
|
77
77
|
let isProxy = false
|
|
78
78
|
let decoderVerifiedContract = false
|
|
79
79
|
let factoryName: string | undefined
|
|
80
|
-
const
|
|
80
|
+
const originalKey = key
|
|
81
81
|
|
|
82
82
|
const addressUrl = new URL(`/api/v2/addresses/${key}`, explorer)
|
|
83
83
|
const addressRes = await fetch(addressUrl, { signal })
|
|
@@ -173,13 +173,12 @@ export const getFunctionSignature = async (
|
|
|
173
173
|
preferError = false,
|
|
174
174
|
options?: DecoderOptions
|
|
175
175
|
): Promise<
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
| undefined
|
|
176
|
+
ResultType & {
|
|
177
|
+
__decoder: string
|
|
178
|
+
__decoderVerifiedContract?: boolean
|
|
179
|
+
__decoderIsProxy?: boolean
|
|
180
|
+
standard?: string
|
|
181
|
+
}
|
|
183
182
|
> => {
|
|
184
183
|
// Remove 0x prefix
|
|
185
184
|
if (to && isAddress(to) && isAddressEqual(to, zeroAddress)) {
|
|
@@ -262,6 +261,7 @@ export const getFunctionSignature = async (
|
|
|
262
261
|
{ signal: options?.signal }
|
|
263
262
|
)
|
|
264
263
|
// Wait for cached or new promise to resolve
|
|
264
|
+
// biome-ignore lint/suspicious/noExplicitAny: any is easier in this particular case
|
|
265
265
|
const methods = (await signatureEntry) as any
|
|
266
266
|
if (methods?.results?.length > 0) {
|
|
267
267
|
// We got one or more results.
|
|
@@ -334,7 +334,7 @@ export const getFunctionSignature = async (
|
|
|
334
334
|
__decoderVerifiedContract?: boolean
|
|
335
335
|
}
|
|
336
336
|
}
|
|
337
|
-
} catch (
|
|
337
|
+
} catch (error) {
|
|
338
338
|
// Ignore to try next record
|
|
339
339
|
}
|
|
340
340
|
}
|
|
@@ -96,7 +96,7 @@ export const getDataFromExternalSources = (
|
|
|
96
96
|
urlDataWithHash as URLDataWithHash,
|
|
97
97
|
ipfsGateway
|
|
98
98
|
))
|
|
99
|
-
let
|
|
99
|
+
let length = 'unknown'
|
|
100
100
|
if (!url.startsWith('data:') && /[=?/]$/.test(url)) {
|
|
101
101
|
// this URL is not verifiable and the URL ends with a / or ? or = meaning it's not a file
|
|
102
102
|
// and more likely to be some kind of directory or query BaseU=== "errorRI
|
|
@@ -116,7 +116,7 @@ export const getDataFromExternalSources = (
|
|
|
116
116
|
.arrayBuffer()
|
|
117
117
|
.then((buffer) => new Uint8Array(buffer))
|
|
118
118
|
})
|
|
119
|
-
|
|
119
|
+
length = receivedData.length.toString()
|
|
120
120
|
const captureHashes: Record<string, string> = {}
|
|
121
121
|
const captureErrors: string[] = []
|
|
122
122
|
if (receivedData.length >= 2) {
|
package/src/decoder/kvCache.ts
CHANGED
|
@@ -179,7 +179,12 @@ export class KVDecoderCache implements DecoderCache {
|
|
|
179
179
|
}
|
|
180
180
|
|
|
181
181
|
// If we have a stale entry and stale-while-revalidate is enabled
|
|
182
|
-
if (
|
|
182
|
+
if (
|
|
183
|
+
cached &&
|
|
184
|
+
cached.stale &&
|
|
185
|
+
now < cached.stale &&
|
|
186
|
+
!this.promises.has(key)
|
|
187
|
+
) {
|
|
183
188
|
// Return stale value and revalidate in background
|
|
184
189
|
const backgroundPromise = factory(options?.signal)
|
|
185
190
|
.then(async (fresh) => {
|
package/src/decoder/lruCache.ts
CHANGED
|
@@ -122,7 +122,12 @@ export class LRUDecoderCache implements DecoderCache {
|
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
// If we have a stale entry and stale-while-revalidate is enabled
|
|
125
|
-
if (
|
|
125
|
+
if (
|
|
126
|
+
cached &&
|
|
127
|
+
cached.stale &&
|
|
128
|
+
now < cached.stale &&
|
|
129
|
+
!this.promises.has(key)
|
|
130
|
+
) {
|
|
126
131
|
// Return stale value and revalidate in background
|
|
127
132
|
const backgroundPromise = factory(options?.signal)
|
|
128
133
|
.then(async (fresh) => {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { lsp7DigitalAssetAbi as LSP7 } from '@lukso/lsp7-contracts/abi'
|
|
2
|
+
import { decodeFunctionData } from 'viem'
|
|
1
3
|
import { lukso } from 'viem/chains'
|
|
2
4
|
import { describe, expect, it } from 'vitest'
|
|
3
5
|
import { JSONbigString } from '../browser'
|
|
@@ -5,6 +7,7 @@ import { defaultSchemaPlugins } from './plugins'
|
|
|
5
7
|
import { pluginRegistry } from './registry'
|
|
6
8
|
import { decodeTransaction as decodeTransactionCore } from './transaction'
|
|
7
9
|
import type { DecoderResult } from './types'
|
|
10
|
+
import { customDecodeFunctionData } from './utils'
|
|
8
11
|
|
|
9
12
|
describe('LSP7 TransferBatch Decoding', () => {
|
|
10
13
|
it('should decode transferBatch transaction 0xc97646850ebd1f6a778847c25cb15589187bd29cd6f6ad06b349714a1a45408a', async () => {
|
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
ResultAggregate,
|
|
9
9
|
} from '../types'
|
|
10
10
|
import { createAggregationKey, standardPlugin } from '.'
|
|
11
|
+
import { enhanceSetData } from './enhanceSetData'
|
|
11
12
|
import RegistryAbi from './RegistryAbi'
|
|
12
13
|
|
|
13
14
|
// Define aggregation state type
|
|
@@ -114,7 +115,7 @@ export const enhanceBurntPixPlugin = standardPlugin(
|
|
|
114
115
|
export async function enhanceBurntPix(
|
|
115
116
|
result: DecoderResult,
|
|
116
117
|
pluginOptions: PluginOptions,
|
|
117
|
-
|
|
118
|
+
options: DecoderOptions
|
|
118
119
|
): Promise<DecoderResult | undefined> {
|
|
119
120
|
// Mark refine transactions as aggregatable
|
|
120
121
|
if ('functionName' in result && result.functionName === 'refine') {
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type AbiParameter,
|
|
3
|
+
bytesToString,
|
|
4
|
+
type Hex,
|
|
5
|
+
hexToBytes,
|
|
6
|
+
size,
|
|
7
|
+
slice,
|
|
8
|
+
} from 'viem'
|
|
2
9
|
import type {
|
|
3
10
|
DecodeEventResult,
|
|
4
11
|
DecoderOptions,
|
|
@@ -16,7 +23,7 @@ export const enhanceGraffitiPlugin: DecoderPlugin = Object.freeze({
|
|
|
16
23
|
{ abiName: 'graffiti', decoderName: 'graffiti' },
|
|
17
24
|
options
|
|
18
25
|
),
|
|
19
|
-
decodeEvent: async (
|
|
26
|
+
decodeEvent: async (log: DecodeEventResult, options: DecoderOptions) =>
|
|
20
27
|
undefined,
|
|
21
28
|
required: true,
|
|
22
29
|
priority: 1000,
|
|
@@ -28,7 +35,14 @@ export async function enhanceGraffiti(
|
|
|
28
35
|
_pluginOptions: PluginOptions,
|
|
29
36
|
_options: DecoderOptions
|
|
30
37
|
) {
|
|
31
|
-
const { input } = result as ResultType
|
|
38
|
+
const { functionName, sig, args, input } = result as ResultType & {
|
|
39
|
+
sig?: `0x${string}`
|
|
40
|
+
functionName?: string
|
|
41
|
+
args: Array<AbiParameter & { value?: unknown }>
|
|
42
|
+
namedArgs?:
|
|
43
|
+
| Record<number, AbiParameter & { value?: unknown }>
|
|
44
|
+
| Record<string, unknown>
|
|
45
|
+
}
|
|
32
46
|
if (
|
|
33
47
|
input &&
|
|
34
48
|
size(input || '0x') >= 4 &&
|
|
@@ -44,10 +44,12 @@ export async function enhanceLSP26FollowerSystem(
|
|
|
44
44
|
_pluginOptions: PluginOptions,
|
|
45
45
|
_options: DecoderOptions
|
|
46
46
|
) {
|
|
47
|
-
const { functionName, args
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
const { functionName, sig, args, input, blockNumber, to, from, value } =
|
|
48
|
+
result as ResultType & {
|
|
49
|
+
sig?: `0x${string}`
|
|
50
|
+
functionName?: string
|
|
51
|
+
args: Array<AbiParameter & { value?: unknown }>
|
|
52
|
+
}
|
|
51
53
|
const { args: _args, ...partialResult } = result as ResultExecute
|
|
52
54
|
switch (functionName) {
|
|
53
55
|
case 'follow':
|
|
@@ -63,6 +65,7 @@ export async function enhanceLSP26FollowerSystem(
|
|
|
63
65
|
} as DecoderResult,
|
|
64
66
|
],
|
|
65
67
|
} as DecoderResult
|
|
68
|
+
break
|
|
66
69
|
case 'followBatch':
|
|
67
70
|
case 'unfollowBatch':
|
|
68
71
|
return {
|
|
@@ -77,6 +80,7 @@ export async function enhanceLSP26FollowerSystem(
|
|
|
77
80
|
address,
|
|
78
81
|
})),
|
|
79
82
|
} as DecoderResult
|
|
83
|
+
break
|
|
80
84
|
}
|
|
81
85
|
return undefined
|
|
82
86
|
}
|