@lukso/transaction-decoder 1.3.0-dev.c21633f → 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.
Files changed (71) hide show
  1. package/dist/browser.cjs +73 -41
  2. package/dist/browser.cjs.map +1 -1
  3. package/dist/browser.d.cts +1 -1
  4. package/dist/browser.d.ts +1 -1
  5. package/dist/browser.js +4 -4
  6. package/dist/cdn/transaction-decoder.global.js +13 -13
  7. package/dist/cdn/transaction-decoder.global.js.map +1 -1
  8. package/dist/{chunk-2ZO6MJJX.js → chunk-G7JZHSYX.js} +12 -11
  9. package/dist/chunk-G7JZHSYX.js.map +1 -0
  10. package/dist/{chunk-FKBKAWB3.js → chunk-GGBHTWJL.js} +5 -5
  11. package/dist/chunk-GGBHTWJL.js.map +1 -0
  12. package/dist/{chunk-NDBDNXBI.js → chunk-GXZOF3QY.js} +27 -3
  13. package/dist/chunk-GXZOF3QY.js.map +1 -0
  14. package/dist/{chunk-T4H2HHIB.js → chunk-XVHJWV5U.js} +32 -25
  15. package/dist/chunk-XVHJWV5U.js.map +1 -0
  16. package/dist/data.cjs +62 -31
  17. package/dist/data.cjs.map +1 -1
  18. package/dist/data.d.cts +2 -2
  19. package/dist/data.d.ts +2 -2
  20. package/dist/data.js +2 -2
  21. package/dist/index.cjs +73 -41
  22. package/dist/index.cjs.map +1 -1
  23. package/dist/index.d.cts +2 -2
  24. package/dist/index.d.ts +2 -2
  25. package/dist/index.js +4 -4
  26. package/dist/server.cjs +43 -31
  27. package/dist/server.cjs.map +1 -1
  28. package/dist/server.d.cts +2 -1
  29. package/dist/server.d.ts +2 -1
  30. package/dist/server.js +12 -7
  31. package/dist/server.js.map +1 -1
  32. package/dist/{utils-BEpSreRR.d.cts → utils-CBAkjQh3.d.cts} +1 -1
  33. package/dist/{utils-De_c6fUK.d.ts → utils-xT9-km0r.d.ts} +1 -1
  34. package/package.json +3 -3
  35. package/src/core/dataModel.ts +31 -1
  36. package/src/core/integrateDecoder.ts +2 -1
  37. package/src/decoder/browserCache.ts +6 -1
  38. package/src/decoder/errors.ts +2 -2
  39. package/src/decoder/events.ts +3 -3
  40. package/src/decoder/functionSignature.ts +9 -9
  41. package/src/decoder/getDataFromExternalSources.ts +2 -2
  42. package/src/decoder/interfaces.ts +1 -1
  43. package/src/decoder/kvCache.ts +6 -1
  44. package/src/decoder/lruCache.ts +6 -1
  45. package/src/decoder/lsp7TransferBatch.test.ts +3 -0
  46. package/src/decoder/plugins/enhanceBurntPix.ts +2 -1
  47. package/src/decoder/plugins/enhanceGraffiti.ts +17 -3
  48. package/src/decoder/plugins/enhanceLSP26FollowerSystem.ts +8 -4
  49. package/src/decoder/plugins/enhanceLSP6KeyManager.ts +1 -0
  50. package/src/decoder/plugins/enhanceLSP7DigitalAsset.ts +7 -5
  51. package/src/decoder/plugins/enhanceLSP9Vault.ts +8 -7
  52. package/src/decoder/plugins/enhanceRetrieveAbi.ts +6 -5
  53. package/src/decoder/plugins/index.ts +1 -3
  54. package/src/decoder/plugins/schemaDefault.ts +4 -3
  55. package/src/decoder/plugins/standardPlugin.ts +1 -1
  56. package/src/decoder/singleGQL.ts +2 -2
  57. package/src/decoder/transaction.ts +2 -1
  58. package/src/decoder/utils.ts +2 -2
  59. package/src/example/usage.ts +4 -3
  60. package/src/server/addressResolver.ts +1 -1
  61. package/src/server/decodeTransactionSync.ts +1 -0
  62. package/src/server/decodeTransactionsBatch.ts +1 -1
  63. package/src/server/finishDecoding.ts +8 -4
  64. package/src/server/lsp23Resolver.ts +3 -2
  65. package/src/server/types.ts +1 -1
  66. package/src/shared/addressResolver.ts +4 -4
  67. package/src/utils/json-bigint.ts +4 -4
  68. package/dist/chunk-2ZO6MJJX.js.map +0 -1
  69. package/dist/chunk-FKBKAWB3.js.map +0 -1
  70. package/dist/chunk-NDBDNXBI.js.map +0 -1
  71. package/dist/chunk-T4H2HHIB.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, _chain: Chain, caches: ServerDecoderCaches);
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, _chain: Chain, caches: ServerDecoderCaches);
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-FKBKAWB3.js";
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-T4H2HHIB.js";
11
+ } from "./chunk-XVHJWV5U.js";
12
12
 
13
13
  // src/server/addressResolver.ts
14
14
  var ServerAddressResolver = class {
15
- constructor(graphqlEndpoint, _chain, caches) {
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 _remainingTime = timeoutMs * 0.6 - phase1Time;
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 _debug = createDebug("decoder:finishDecoding");
502
+ var debug = createDebug("decoder:finishDecoding");
502
503
  async function finishDecoding(transaction, options, caches) {
503
504
  const startTime = Date.now();
504
- const { chain } = options;
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?.enhancementAttempted) {
514
+ if (cached && cached.enhancementAttempted) {
510
515
  return {
511
516
  ...cached,
512
517
  cached: true,
@@ -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[], _preferError = false>(parameters: Partial<DecodeFunctionDataParameters<abi> & {
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[], _preferError = false>(parameters: Partial<DecodeFunctionDataParameters<abi> & {
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-dev.c21633f",
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
  }
@@ -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, _index) => {
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 (cached?.stale && now < cached.stale && !this.promises.has(key)) {
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) => {
@@ -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
- type DecoderResult,
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 _CONTRACT_ERROR_THROWN = 'transactions.error.contract_error_thrown'
33
+ const CONTRACT_ERROR_THROWN = 'transactions.error.contract_error_thrown'
34
34
 
35
35
  function populateEmptyRevertInfo(
36
36
  input: `0x${string}`
@@ -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
- _chain: Chain,
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 _lastError: Error | undefined
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 _originalKey = key
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
- | (ResultType & {
177
- __decoder: string
178
- __decoderVerifiedContract?: boolean
179
- __decoderIsProxy?: boolean
180
- standard?: string
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 (_error) {
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 _length = 'unknown'
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
- _length = receivedData.length.toString()
119
+ length = receivedData.length.toString()
120
120
  const captureHashes: Record<string, string> = {}
121
121
  const captureErrors: string[] = []
122
122
  if (receivedData.length >= 2) {
@@ -136,7 +136,7 @@ async function _retrieveInterfaces(
136
136
  return undefined
137
137
  }
138
138
  const client = getPublicClient(chain)
139
- const _contract = getContract({
139
+ const contract = getContract({
140
140
  client,
141
141
  address: multicall3.address,
142
142
  abi: LSP2Fetcher,
@@ -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 (cached?.stale && now < cached.stale && !this.promises.has(key)) {
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) => {
@@ -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 (cached?.stale && now < cached.stale && !this.promises.has(key)) {
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
- _options: DecoderOptions
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 { bytesToString, type Hex, hexToBytes, size, slice } from 'viem'
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 (_log: DecodeEventResult, _options: DecoderOptions) =>
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 } = result as ResultType & {
48
- functionName?: string
49
- args: Array<AbiParameter & { value?: unknown }>
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
  }