@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.
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-U7L4W2YL.js → chunk-G7JZHSYX.js} +12 -11
  9. package/dist/chunk-G7JZHSYX.js.map +1 -0
  10. package/dist/{chunk-EDDQHEAA.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 +3 -3
  67. package/src/utils/json-bigint.ts +4 -4
  68. package/dist/chunk-EDDQHEAA.js.map +0 -1
  69. package/dist/chunk-NDBDNXBI.js.map +0 -1
  70. package/dist/chunk-T4H2HHIB.js.map +0 -1
  71. package/dist/chunk-U7L4W2YL.js.map +0 -1
@@ -46,6 +46,7 @@ export async function enhanceKeyManager(
46
46
  sig,
47
47
  args,
48
48
  input,
49
+ blockNumber,
49
50
  to: _to,
50
51
  from: _from,
51
52
  value,
@@ -8,6 +8,7 @@ import {
8
8
  import type { AbiParameter } from 'viem'
9
9
  import { CacheKeyPrefix, makeCacheKey } from '../cache'
10
10
  import { decodeEvent } from '../events'
11
+ import { pluginRegistry } from '../registry'
11
12
  import type {
12
13
  DecodeEventResult,
13
14
  DecoderOptions,
@@ -150,11 +151,12 @@ export async function enhanceLSP26FollowerSystem(
150
151
  _pluginOptions: PluginOptions,
151
152
  _options: DecoderOptions
152
153
  ) {
153
- const { functionName } = result as ResultType & {
154
- sig?: `0x${string}`
155
- functionName?: string
156
- args: Array<AbiParameter & { value?: unknown }>
157
- }
154
+ const { functionName, sig, args, input, blockNumber, to, from, value } =
155
+ result as ResultType & {
156
+ sig?: `0x${string}`
157
+ functionName?: string
158
+ args: Array<AbiParameter & { value?: unknown }>
159
+ }
158
160
  switch (functionName) {
159
161
  }
160
162
  return undefined
@@ -40,14 +40,15 @@ export const enhanceLSP9VaultPlugin = standardPlugin(
40
40
  */
41
41
  export async function enhanceLSP9Vault(
42
42
  result: ResultType & ResultShared & { moduleHint?: string },
43
- _pluginOptions: PluginOptions,
44
- _options: DecoderOptions
43
+ pluginOptions: PluginOptions,
44
+ options: DecoderOptions
45
45
  ) {
46
- const { functionName } = result as ResultType & {
47
- sig?: `0x${string}`
48
- functionName?: string
49
- args: Array<AbiParameter & { value?: unknown }>
50
- }
46
+ const { functionName, sig, args, input, blockNumber, to, from, value } =
47
+ result as ResultType & {
48
+ sig?: `0x${string}`
49
+ functionName?: string
50
+ args: Array<AbiParameter & { value?: unknown }>
51
+ }
51
52
  switch (functionName) {
52
53
  }
53
54
  return undefined
@@ -54,11 +54,12 @@ export async function enhanceRetrieveAbi(
54
54
  _pluginOptions: PluginOptions,
55
55
  options: DecoderOptions
56
56
  ) {
57
- const { input, to, from, value } = result as ResultType & {
58
- sig?: `0x${string}`
59
- functionName?: string
60
- args: Array<AbiParameter & { value?: unknown }>
61
- }
57
+ const { functionName, sig, args, input, blockNumber, to, from, value } =
58
+ result as ResultType & {
59
+ sig?: `0x${string}`
60
+ functionName?: string
61
+ args: Array<AbiParameter & { value?: unknown }>
62
+ }
62
63
  try {
63
64
  const decoded = await getFunctionSignature(
64
65
  options.chain,
@@ -19,9 +19,7 @@ import schemaDefaultPlugin from './schemaDefault'
19
19
 
20
20
  // Force evaluation of plugins to ensure they register (prevent tree-shaking)
21
21
  // These plugins self-register via standardPlugin when imported
22
- ;[profile, keyManager, lsp7, lsp8, lsp9, lsp26, burntPix].forEach((p) => {
23
- p
24
- })
22
+ ;[profile, keyManager, lsp7, lsp8, lsp9, lsp26, burntPix].forEach((p) => p)
25
23
 
26
24
  import type { Hex } from 'viem'
27
25
  import type {
@@ -48,7 +48,7 @@ export function decodeKeyValuePlugin(
48
48
  if (schema) {
49
49
  try {
50
50
  // Get the raw name.
51
- const name = schema.name.replace(/[:[\]]|<.*?>/g, '')
51
+ const name = schema.name.replace(/[:\[\]]|<.*?>/g, '')
52
52
  if (schema.keyType === 'Array') {
53
53
  if (schema.key === key) {
54
54
  // Convert hex string to Uint8Array without using Buffer
@@ -59,7 +59,7 @@ export function decodeKeyValuePlugin(
59
59
  }
60
60
  // Figure out the first and last byte of the value (this is to allow
61
61
  // the older and newer ways to store the array length i.e. uint256, uint128 and so on.)
62
- const [{ start: _start, end } = { start: 0, end: 0 }] = all.reduce(
62
+ const [{ start, end } = { start: 0, end: 0 }] = all.reduce(
63
63
  (
64
64
  acc: Array<{ isZero: boolean; start: number; end: number }>,
65
65
  byte,
@@ -145,7 +145,7 @@ export function decodeKeyValuePlugin(
145
145
  }
146
146
  }
147
147
  // Decode dynamic parts.
148
- let dynamicKeyParts: string[] | string | undefined
148
+ let dynamicKeyParts: string[] | string | undefined = undefined
149
149
  if (isDynamicKeyName(schema.name)) {
150
150
  dynamicKeyParts = decodeMappingKey(key, schema).map(({ value }) =>
151
151
  isHex(value) ? (value as string).toLowerCase() : `${value}`
@@ -167,6 +167,7 @@ export function decodeKeyValuePlugin(
167
167
  defaultSchema
168
168
  ) as unknown as Record<string, unknown>[])
169
169
  : [{ value: undefined }]
170
+ type Params = Parameters<typeof getDataFromExternalSources>
170
171
  let data = rawData?.[0]?.value
171
172
  // Some special cases.
172
173
  if (schema.name === 'LSP8TokenMetadataBaseURI') {
@@ -1,5 +1,5 @@
1
1
  import type { ERC725JSONSchema } from '@erc725/erc725.js'
2
- import type { Abi, AbiParameter, Log, Transaction } from 'viem'
2
+ import type { Abi, AbiParameter, Hex, Log, Transaction } from 'viem'
3
3
  import { pluginRegistry } from '../registry'
4
4
  import type {
5
5
  Aggregation,
@@ -192,7 +192,7 @@ export function subscribeToProfile(
192
192
  avatars,
193
193
  links,
194
194
  tags,
195
- controllers: _controllers,
195
+ controllers,
196
196
  ...rest
197
197
  } = prof || {}
198
198
  if (!id) {
@@ -274,7 +274,7 @@ export async function fetchProfile(
274
274
  avatars,
275
275
  links,
276
276
  tags,
277
- controllers: _controllers,
277
+ controllers,
278
278
  ...rest
279
279
  } = profile || {}
280
280
  if (!id) {
@@ -64,7 +64,7 @@ export async function decodeTransaction(
64
64
  phase: 'enhanced',
65
65
  } as DecoderResult
66
66
  }
67
- let _lastError: Error | undefined
67
+ let lastError: Error | undefined
68
68
 
69
69
  // The caller is responsible for providing the appropriate plugin set
70
70
  // For sync-only decoding, use pluginRegistry.getAll({ syncOnly: true })
@@ -148,6 +148,7 @@ export async function decodeTransaction(
148
148
  }
149
149
  } catch (e) {
150
150
  console.error(e)
151
+ continue
151
152
  }
152
153
  }
153
154
  let phase: 'immediate' | 'enhanced' | 'complete' =
@@ -8,7 +8,7 @@ import {
8
8
  createPublicClient,
9
9
  type DecodeFunctionDataParameters,
10
10
  decodeAbiParameters,
11
- type Hex,
11
+ Hex,
12
12
  http,
13
13
  type PublicClient,
14
14
  slice,
@@ -30,7 +30,7 @@ import type {
30
30
  */
31
31
  export function customDecodeFunctionData<
32
32
  const abi extends Abi | readonly unknown[],
33
- _preferError = false,
33
+ preferError = false,
34
34
  >(
35
35
  parameters: Partial<
36
36
  DecodeFunctionDataParameters<abi> & {
@@ -1,11 +1,12 @@
1
1
  import debug from 'debug'
2
+ import type { Transaction } from 'viem'
2
3
  import { lukso } from 'viem/chains'
3
4
  import { createDataModel } from '../data'
4
5
  import {
5
6
  AddressResolver,
6
7
  createMemoryAddressCache,
7
8
  DecoderIntegration,
8
- type DecoderResult,
9
+ DecoderResult,
9
10
  } from '../index'
10
11
 
11
12
  const setupDecoderLog = debug('app:setupDecoder')
@@ -121,7 +122,7 @@ export async function handleTransactionBatch(transactions: DecoderResult[]) {
121
122
  * Example of manual address resolution
122
123
  */
123
124
  export async function resolveAddresses() {
124
- const { decoder } = await setupDecoder()
125
+ const { dataModel, decoder } = await setupDecoder()
125
126
 
126
127
  // Get missing addresses
127
128
  const missing = decoder.getMissingAddresses()
@@ -138,7 +139,7 @@ export async function resolveAddresses() {
138
139
  }
139
140
 
140
141
  // Mock function for example
141
- async function fetchAddressDataFromAPI(_addresses: unknown[]) {
142
+ async function fetchAddressDataFromAPI(addresses: unknown[]) {
142
143
  // This would be your actual API call
143
144
  return []
144
145
  }
@@ -12,7 +12,7 @@ export class ServerAddressResolver {
12
12
 
13
13
  constructor(
14
14
  private graphqlEndpoint: string,
15
- _chain: Chain,
15
+ private chain: Chain,
16
16
  private caches: ServerDecoderCaches
17
17
  ) {
18
18
  // Create adapter to use ServerDecoderCaches as AddressIdentityCache
@@ -1,3 +1,4 @@
1
+ import type { Transaction } from 'viem'
1
2
  import { collectDataKeys } from '../core/addressCollector'
2
3
  import { pluginRegistry } from '../decoder/registry'
3
4
  import { decodeTransaction as decodeTransactionCore } from '../decoder/transaction'
@@ -111,7 +111,7 @@ export async function decodeTransactionsBatch(
111
111
  })
112
112
 
113
113
  // Wait for all enhancements with remaining time budget
114
- const _remainingTime = timeoutMs * 0.6 - phase1Time
114
+ const remainingTime = timeoutMs * 0.6 - phase1Time
115
115
  const enhancedResults = await Promise.all(enhancePromises)
116
116
 
117
117
  // Update results with enhanced data
@@ -1,11 +1,12 @@
1
+ import { collectDataKeys } from '../core/addressCollector'
1
2
  import { pluginRegistry } from '../decoder/registry'
2
3
  import { decodeTransaction as decodeTransactionCore } from '../decoder/transaction'
3
- import type { DecoderResult } from '../decoder/types'
4
+ import type { DecoderResult, ResultShared } from '../decoder/types'
4
5
  import { createDebug } from '../utils/debug'
5
6
  import type { ServerDecoderCaches } from './caches'
6
7
  import type { ServerDecoderOptions } from './types'
7
8
 
8
- const _debug = createDebug('decoder:finishDecoding')
9
+ const debug = createDebug('decoder:finishDecoding')
9
10
 
10
11
  /**
11
12
  * Finish decoding a transaction by running enhancement phase
@@ -17,14 +18,17 @@ export async function finishDecoding(
17
18
  caches: ServerDecoderCaches
18
19
  ): Promise<DecoderResult> {
19
20
  const startTime = Date.now()
20
- const { chain } = options
21
+ const {
22
+ timeoutMs = 5000, // Give more time for finishing
23
+ chain,
24
+ } = options
21
25
 
22
26
  try {
23
27
  // Check cache first
24
28
  const txHash = transaction.hash || transaction.transactionHash
25
29
  if (txHash) {
26
30
  const cached = caches.getTransaction(txHash)
27
- if (cached?.enhancementAttempted) {
31
+ if (cached && cached.enhancementAttempted) {
28
32
  return {
29
33
  ...cached,
30
34
  cached: true,
@@ -1,4 +1,4 @@
1
- import type { Address } from 'viem'
1
+ import type { Address, Chain } from 'viem'
2
2
  import {
3
3
  bytesToHex,
4
4
  decodeAbiParameters,
@@ -254,6 +254,7 @@ export function buildLSP23DeploymentQuery(config: HypersyncQueryConfig) {
254
254
  profileAddresses,
255
255
  fromBlock = 0,
256
256
  toBlock,
257
+ chainId,
257
258
  } = config
258
259
 
259
260
  // Prefer querying by profile addresses (more efficient)
@@ -368,7 +369,7 @@ export function parseLSP23DeploymentsFromHypersync(
368
369
  : null
369
370
 
370
371
  // Match transactions with traces
371
- for (const [txHash, _profileAddress] of create2Traces) {
372
+ for (const [txHash, profileAddress] of create2Traces) {
372
373
  const tx = txMap.get(txHash)
373
374
  if (!tx) continue
374
375
 
@@ -1,4 +1,4 @@
1
- import type { Chain } from 'viem'
1
+ import type { Chain, Transaction } from 'viem'
2
2
  import type { DataKey, DecoderResult, EnhancedInfo } from '../types'
3
3
 
4
4
  /**
@@ -324,7 +324,7 @@ export async function fetchMultipleAddresses(
324
324
  // Process tokens (must be before assets per addressGQL.ts logic)
325
325
  if (data.Token) {
326
326
  for (const token of data.Token) {
327
- const { id: _id, baseAsset, tokenId, ...rest } = token
327
+ const { id, baseAsset, tokenId, ...rest } = token
328
328
 
329
329
  // Tokens have a composite ID format and baseAsset reference
330
330
  if (baseAsset?.id && tokenId) {
@@ -572,7 +572,7 @@ export async function getImage(
572
572
  : undefined
573
573
  }
574
574
  try {
575
- let isImage: string | undefined
575
+ let isImage: string | undefined = undefined
576
576
  if (typeof caches !== 'undefined' && !ignoreHead) {
577
577
  const cache = await caches.open('image-types')
578
578
  const cached = await cache.match(url)
@@ -588,7 +588,7 @@ export async function getImage(
588
588
  // We use this to determine what type of images we have.
589
589
  // If the images came from the indexer then this test
590
590
  // has already been done on the indexer and we can skip it here.
591
- const _now = Date.now()
591
+ const now = Date.now()
592
592
  isImage = await fetch(url, { method: 'HEAD' })
593
593
  .then((response) => {
594
594
  if (response.ok) {
@@ -18,12 +18,12 @@ export const JSONbigString = {
18
18
  /**
19
19
  * Stringify an object, converting BigInt values to strings with 'n' suffix
20
20
  */
21
- stringify: (obj: any, _replacer?: any, space?: string | number): string => {
21
+ stringify: (obj: any, replacer?: any, space?: string | number): string => {
22
22
  return JSON.stringify(
23
23
  obj,
24
- (_key, value) => {
24
+ (key, value) => {
25
25
  if (typeof value === 'bigint') {
26
- return `${value.toString()}n`
26
+ return value.toString() + 'n'
27
27
  }
28
28
  return value
29
29
  },
@@ -35,7 +35,7 @@ export const JSONbigString = {
35
35
  * Parse a JSON string, converting strings ending with 'n' back to BigInt
36
36
  */
37
37
  parse: (text: string): any => {
38
- return JSON.parse(text, (_key, value) => {
38
+ return JSON.parse(text, (key, value) => {
39
39
  if (typeof value === 'string' && /^\d+n$/.test(value)) {
40
40
  return BigInt(value.slice(0, -1))
41
41
  }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/shared/addressResolver.ts"],"sourcesContent":["import request, { gql } from 'graphql-request'\nimport type { Address, Chain, Hex } from 'viem'\nimport { lukso } from 'viem/chains'\nimport type { DataKey, EnhancedInfo } from '../types'\nimport type { AddressIdentityCache } from './cache'\n\n/**\n * GraphQL queries for address resolution\n * Using the exact schema from addressGQL.ts\n */\nconst addressesGql = gql`\nquery AddressQuery($profiles: [String!], $assets: [String!], $tokens: [String!]) {\n Profile(\n where: {id: {_in: $profiles}}\n ) {\n fullName\n id\n name\n tags\n description\n standard\n controllers {\n address\n tags\n permissions\n }\n owner {\n id\n }\n profileImages(where: {error: {_is_null: true}}, order_by: {width: asc}) {\n width\n height\n src\n verified\n }\n backgroundImages(where: {error: {_is_null: true}}, order_by: {width: asc}) {\n width\n height\n src\n verified\n }\n avatars(where: {error: {_is_null: true}}, order_by: {width: asc}) {\n width\n height\n src\n verified\n }\n }\n Token(where: {id: {_in: $tokens}}) {\n id\n baseAsset {\n id\n description\n icons {\n src\n verified\n width\n height\n }\n isCollection\n isLSP7\n isUnknown\n name\n standard\n interfaces\n decimals\n owner_id\n lsp4Creators {\n profile_id\n }\n }\n formattedTokenId\n icons {\n src\n verified\n width\n height\n }\n images(where: {index: {_eq: 0}}) {\n src\n verified\n width\n height\n }\n lsp4TokenName\n lsp4TokenSymbol\n lsp4TokenType\n lsp8TokenIdFormat\n tokenId\n name\n description\n lsp4Creators {\n profile_id\n }\n }\n Asset(where: {id: {_in: $assets}}) {\n id\n images(where: {index: {_eq: 0}}) {\n src\n width\n verified\n height\n }\n interfaces\n isCollection\n isLSP7\n isUnknown\n lsp4TokenName\n lsp4TokenSymbol\n lsp4TokenType\n method\n name\n icons {\n src\n width\n height\n }\n description\n decimals\n standard\n owner_id\n lsp4Creators {\n profile_id\n }\n }\n}\n`\n\n// Image data structure from GraphQL\nexport interface ImageData {\n width?: number\n height?: number\n url?: string // Raw URL (may be ipfs://)\n src?: string // Resolved HTTPS URL (fallback to url if not present)\n verified?: boolean\n}\n\n// Link data structure from GraphQL\nexport interface LinkData {\n url: string\n title?: string\n}\n\n// Profile data from GraphQL\nexport interface ProfileData {\n id: Hex\n name?: string\n fullName?: string\n tags?: string[]\n description?: string\n links?: LinkData[]\n standard?: string\n controllers?: Array<{\n address: string\n tags?: string[]\n permissions?: Hex\n }>\n owner?: { id: string }\n profileImages?: ImageData[]\n backgroundImages?: ImageData[]\n avatars?: ImageData[]\n}\n\n// Asset data from GraphQL\nexport interface AssetData {\n id: Hex\n name?: string\n standard?: string\n lsp4TokenName?: string\n lsp4TokenSymbol?: string\n lsp4TokenType?: string\n method?: string\n description?: string\n links?: LinkData[]\n decimals?: number\n interfaces?: string[]\n isCollection?: boolean\n isLSP7?: boolean\n isUnknown?: boolean\n icons?: ImageData[]\n images?: ImageData[]\n}\n\n// Token data from GraphQL\nexport interface TokenData {\n id: Hex\n tokenId?: Hex\n name?: string\n description?: string\n links?: LinkData[]\n lsp4TokenName?: string\n lsp4TokenSymbol?: string\n lsp4TokenType?: string\n lsp8TokenIdFormat?: string\n formattedTokenId?: string\n baseAsset?: {\n id: Hex\n description?: string\n icons?: ImageData[]\n isCollection?: boolean\n isLSP7?: boolean\n isUnknown?: boolean\n name?: string\n standard?: string\n interfaces?: string[]\n decimals?: number\n }\n icons?: ImageData[]\n images?: ImageData[]\n}\n\nexport type TFetchAddressData = {\n Profile?: ProfileData[]\n Asset?: AssetData[]\n Token?: TokenData[]\n}\n\n/**\n * Fetch multiple addresses from GraphQL and return them as a Map\n * This is the shared implementation that both server and core can use\n */\nexport async function fetchMultipleAddresses(\n addresses: readonly DataKey[],\n graphqlEndpoint: string,\n cache?: AddressIdentityCache\n): Promise<Map<DataKey, EnhancedInfo>> {\n const results = new Map<DataKey, EnhancedInfo>()\n\n if (addresses.length === 0) {\n return results\n }\n\n // Check cache first if provided\n const uncachedAddresses: DataKey[] = []\n\n if (cache) {\n // Try to get many at once if supported\n if (cache.getMany) {\n const cachedResults = await cache.getMany(addresses)\n for (const [key, value] of cachedResults) {\n results.set(key, value)\n }\n // Find which ones we still need to fetch\n for (const addr of addresses) {\n if (!results.has(addr)) {\n uncachedAddresses.push(addr)\n }\n }\n } else {\n // Fall back to individual lookups\n for (const addr of addresses) {\n const cached = await cache.get(addr)\n if (cached) {\n results.set(addr, cached)\n } else {\n uncachedAddresses.push(addr)\n }\n }\n }\n\n // If all were cached, return early\n if (uncachedAddresses.length === 0) {\n return results\n }\n } else {\n // No cache, fetch all\n uncachedAddresses.push(...addresses)\n }\n\n // Parse addresses and tokens\n const profiles: string[] = []\n const assets: string[] = []\n const tokens: string[] = []\n const tokenMapping = new Map<string, { address: Address; tokenId: string }>()\n\n for (const key of uncachedAddresses) {\n const hasDash = key.includes('-')\n const hasColon = key.includes(':')\n\n if (hasColon || hasDash) {\n const normalizedKey = key.replace(/[-:]/, '-')\n tokens.push(normalizedKey)\n const [address, tokenId] = key.split(/[-:]/)\n tokenMapping.set(key, { address: address as Address, tokenId })\n } else {\n // Regular addresses - could be profiles or assets\n profiles.push(key)\n assets.push(key)\n }\n }\n\n try {\n // Fetch data from GraphQL\n const data = (await request(graphqlEndpoint, addressesGql, {\n profiles,\n assets,\n tokens,\n })) as TFetchAddressData\n\n // Process profiles\n if (data.Profile) {\n for (const profile of data.Profile) {\n if (profile.standard !== 'LSP0ERC725Account') {\n continue\n }\n const enhancedInfo: EnhancedInfo = {\n address: profile.id as Address,\n __gqltype: 'Profile',\n name: profile.name || profile.fullName,\n fullName: profile.fullName,\n standard: profile.standard,\n tags: profile.tags,\n description: profile.description,\n owner: profile.owner,\n controllers: profile.controllers,\n profileImages: profile.profileImages,\n backgroundImages: profile.backgroundImages,\n avatars: profile.avatars,\n }\n results.set(profile.id as Address, enhancedInfo)\n }\n }\n\n // Process tokens (must be before assets per addressGQL.ts logic)\n if (data.Token) {\n for (const token of data.Token) {\n const { id: _id, baseAsset, tokenId, ...rest } = token\n\n // Tokens have a composite ID format and baseAsset reference\n if (baseAsset?.id && tokenId) {\n const enhancedInfo: EnhancedInfo = {\n address: baseAsset.id as Address,\n tokenId: tokenId as Address,\n __gqltype: 'Token',\n ...rest,\n baseAsset,\n }\n // Store with both dash and colon separators to handle both formats\n const keyWithColon = `${baseAsset.id}:${tokenId}` as DataKey\n const keyWithDash = `${baseAsset.id}-${tokenId}` as DataKey\n results.set(keyWithColon, enhancedInfo)\n results.set(keyWithDash, enhancedInfo)\n }\n }\n }\n\n // Process assets\n if (data.Asset) {\n for (const asset of data.Asset) {\n if (asset.standard === 'LSP0ERC725Account') {\n // Skip profiles - already processed\n continue\n }\n const enhancedInfo: EnhancedInfo = {\n address: asset.id as Address,\n __gqltype: 'Asset',\n ...asset,\n }\n if (!results.has(asset.id as Address)) {\n results.set(asset.id as Address, enhancedInfo)\n }\n }\n }\n\n // Cache the newly fetched results\n if (cache) {\n const newEntries: Array<[DataKey, EnhancedInfo]> = []\n\n // Collect all new entries\n for (const [key, value] of results) {\n // Only cache entries that were fetched (not from cache)\n const isCached = addresses.some(\n (addr) => addr.toLowerCase() === key.toLowerCase()\n )\n\n if (\n isCached &&\n uncachedAddresses.some(\n (addr) => addr.toLowerCase() === key.toLowerCase()\n )\n ) {\n newEntries.push([key, value])\n }\n }\n\n // Use batch update if available\n if (cache.setMany && newEntries.length > 0) {\n await cache.setMany(newEntries)\n } else {\n // Fall back to individual updates\n for (const [key, value] of newEntries) {\n await cache.set(key, value)\n }\n }\n }\n\n return results\n } catch (error) {\n console.error('Failed to fetch addresses:', error)\n return results\n }\n}\n\n/**\n * Get GraphQL endpoint for a given chain\n */\nexport function getGraphQLEndpoint(chain: Chain): string {\n return chain.id === lukso.id\n ? 'https://envio.lukso-mainnet.universal.tech/v1/graphql'\n : 'https://envio.lukso-testnet.universal.tech/v1/graphql'\n}\n\n/**\n * GraphQL query to find profiles controlled by specific addresses\n */\nconst profilesByControllerGql = gql`\nquery ProfilesByController($controllerAddresses: [String!]) {\n Profile(\n where: {\n controllers: {\n address: { _in: $controllerAddresses }\n tags: {\n _contains: [\n \"ADDCONTROLLER\"\n \"EDITPERMISSIONS\"\n \"SUPER_TRANSFERVALUE\"\n \"TRANSFERVALUE\"\n \"SUPER_CALL\"\n \"CALL\"\n \"SUPER_STATICCALL\"\n \"STATICCALL\"\n \"DEPLOY\"\n \"SUPER_SETDATA\"\n \"SETDATA\"\n \"ENCRYPT\"\n \"DECRYPT\"\n \"SIGN\"\n \"EXECUTE_RELAY_CALL\"\n ]\n }\n }\n }\n order_by: { blockNumber: asc }\n ) {\n fullName\n id\n name\n tags\n description\n standard\n controllers {\n address\n tags\n permissions\n }\n owner {\n id\n }\n profileImages(where: {error: {_is_null: true}}, order_by: {width: asc}) {\n width\n height\n src\n verified\n }\n backgroundImages(where: {error: {_is_null: true}}, order_by: {width: asc}) {\n width\n height\n src\n verified\n }\n avatars(where: {error: {_is_null: true}}, order_by: {width: asc}) {\n width\n height\n src\n verified\n }\n }\n}\n`\n\n/**\n * Find profiles controlled by specific controller addresses\n * @param controllerAddresses - Array of controller addresses to search for\n * @param chain - Which chain to query\n * @returns Array of profile data\n */\nexport async function fetchProfilesByControllers(\n controllerAddresses: readonly Address[],\n chain: Chain\n): Promise<ProfileData[]> {\n const graphqlEndpoint = getGraphQLEndpoint(chain)\n\n try {\n const data = (await request(graphqlEndpoint, profilesByControllerGql, {\n controllerAddresses: controllerAddresses.map((addr) =>\n addr.toLowerCase()\n ),\n })) as { Profile?: ProfileData[] }\n\n return data.Profile || []\n } catch (error) {\n console.error(\n `Failed to fetch profiles by controllers on ${chain.name}:`,\n error\n )\n return []\n }\n}\n\nexport type ImageURL = {\n url?: string\n data?: string\n src?: string\n width: number\n height: number\n index?: number\n verified?: string\n}\n\n/**\n * Assuming the images are sorted ascending by width and/or height pick the first\n * image that's larger than the requested size * dpr and process that one.\n * By default this will assume the data came from the indexer and therefore\n * we do not need to verify the existence of all the images (i.e. HEAD requests for\n * each image) Setting ignoreHead to false is important during RPC mode so that\n * we can skip images that are not really available.\n *\n * @param images - array of images\n * @param options - specify arguments for search/processing\n * @returns { width, height, src } - the image that fits the criteria\n */\nexport async function getImage(\n images: ImageURL[],\n options: {\n width: number\n height?: number\n index?: number\n ignoreVerification?: boolean\n forcePng?: boolean\n ignoreHead?: boolean\n fallback?: string\n dpr?: number\n }\n): Promise<{ width: number; height: number; src?: string } | undefined> {\n const {\n width,\n height: _height,\n index,\n ignoreVerification,\n ignoreHead = true, // By default we don't want to do HEAD requests for all images.\n dpr = 1,\n } = options\n const boost = dpr === 1 ? 1.5 : 1\n const height = _height || width\n const { src: _src, verified } =\n (images || []).find(\n (i) =>\n i.width >= width * boost * dpr &&\n i.height &&\n i.height >= height * boost * dpr &&\n (index ? i.index === index : i.index === undefined)\n ) ||\n images?.at(-1) ||\n {}\n // We're talking about images here, so we should be using /image/ instead of /ipfs/\n const url = _src?.startsWith('https://api.universalprofile.cloud/ipfs/')\n ? _src?.replace(/\\/ipfs\\//, '/image/')\n : _src\n if (!url) {\n return options.fallback\n ? { src: options.fallback, width: 128, height: 128 }\n : undefined\n }\n try {\n let isImage: string | undefined\n if (typeof caches !== 'undefined' && !ignoreHead) {\n const cache = await caches.open('image-types')\n const cached = await cache.match(url)\n if (cached) {\n const response = await cached.json()\n if (response) {\n isImage = response\n }\n }\n }\n if (!isImage && !ignoreHead) {\n // HEAD will return 200, 404 and so including the 'content-type'\n // We use this to determine what type of images we have.\n // If the images came from the indexer then this test\n // has already been done on the indexer and we can skip it here.\n const _now = Date.now()\n isImage = await fetch(url, { method: 'HEAD' })\n .then((response) => {\n if (response.ok) {\n const mime = response.headers.get('content-type') || ''\n response.body?.cancel()\n return /^image\\//.test(mime) ? mime : undefined\n }\n response.body?.cancel()\n return undefined\n })\n .catch((error) => {\n console.error((error as Error).stack)\n return undefined\n })\n if (isImage != null && typeof caches !== 'undefined') {\n const cache = await caches.open('image-types')\n await cache\n .put(url, new Response(JSON.stringify(isImage)))\n .catch((error) => {\n console.error((error as Error).stack, url)\n })\n }\n }\n if (isImage || ignoreHead) {\n const finalUrl = new URL(url)\n const { searchParams } = finalUrl\n const qs = new URLSearchParams(searchParams)\n if (width) {\n qs.set('width', `${width * boost}`)\n }\n if (width || height) {\n qs.set('height', `${(height || width) * boost}`)\n }\n qs.set('fit', 'cover')\n qs.set('dpr', dpr.toString())\n if (\n !options.ignoreHead &&\n !/\\/svg/.test(isImage || '') &&\n options.forcePng\n ) {\n qs.set('format', 'png')\n }\n finalUrl.search = qs.toString()\n const image = finalUrl.toString()\n return {\n width,\n height: height || width,\n src:\n verified === 'INVALID' && !ignoreVerification\n ? `${image}&blur=30`\n : image,\n }\n }\n } catch (error) {\n console.error((error as Error).stack)\n }\n return options.fallback\n ? { src: options.fallback, width: 128, height: 128 }\n : undefined\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/core/dataModel.ts","../src/core/instance.ts","../src/decoder/decodeTransaction.ts","../src/shared/constants.ts"],"sourcesContent":["// Core data model implementation\nimport { batch, effect, type Signal, signal } from '@preact/signals-core'\nimport type { Address, Hex } from 'viem'\nimport { isHex, size } from 'viem'\nimport type {\n AddressState,\n DataKey,\n DataModelOptions,\n DecoderResult,\n EnhancedInfo,\n IDataModel,\n IDataModelConsumer,\n TransactionState,\n} from '../types'\nimport { collectDataKeys } from './addressCollector'\n\n// Helper type for deep freezing - kept internal to this module\ntype DeepReadonly<T> = T extends (infer R)[]\n ? DeepReadonlyArray<R>\n : T extends (...args: unknown[]) => unknown\n ? T\n : T extends object\n ? DeepReadonlyObject<T>\n : T\n\ninterface DeepReadonlyArray<T> extends ReadonlyArray<DeepReadonly<T>> {}\n\ntype DeepReadonlyObject<T> = {\n readonly [P in keyof T]: DeepReadonly<T[P]>\n}\n\n/**\n * Deep freeze an object to prevent any modifications\n * Returns the same object if it's already frozen\n */\nexport function deepFreeze<T>(obj: T): T {\n // Primitives and already frozen objects don't need processing\n if (obj === null || typeof obj !== 'object' || Object.isFrozen(obj)) {\n return obj\n }\n\n // Freeze the object itself\n Object.freeze(obj)\n\n // Recursively freeze all properties\n for (const prop of Object.getOwnPropertyNames(obj)) {\n const value = (obj as Record<string, unknown>)[prop]\n if (value !== null && typeof value === 'object') {\n deepFreeze(value)\n }\n }\n\n return obj\n}\n\nexport interface TransactionKey {\n hash: Hex\n decoderIndex?: number // For batch transactions\n}\n\nexport class DataModel implements IDataModel {\n // Nested map structure: Address -> (TokenId | null) -> Signal\n private dataSignals = new Map<Address, Signal<AddressState>>()\n\n // Transaction signals: Hash -> (DecoderIndex | null) -> Signal\n private transactionSignals = new Map<\n Hex,\n Map<number | null, Signal<TransactionState>>\n >()\n\n // Keep track of unique transaction hashes in order\n private transactionOrder: Array<Hex> = []\n\n private options: DataModelOptions\n\n // Track pending resolved data updates\n private pendingResolvedUpdate = false\n\n constructor(options: DataModelOptions = {}) {\n this.options = options\n }\n\n /**\n * Get or create a signal for a specific key\n */\n private getOrCreateSignal(key: DataKey): Signal<AddressState> {\n let sig = this.dataSignals.get(key)\n if (!sig) {\n sig = signal<AddressState>({\n loading: false,\n data: undefined,\n error: undefined,\n lastUpdated: undefined,\n })\n\n this.dataSignals.set(key, sig)\n\n // Notify about missing keys (for external fetching)\n if (this.options.onMissingKeys) {\n // Debounce notifications\n setTimeout(() => {\n const missing = this.getMissingKeys()\n if (missing.length > 0) {\n this.options.onMissingKeys?.(missing)\n }\n }, 0)\n }\n }\n\n return sig\n }\n\n /**\n * Extract transaction key from transaction JSON\n */\n private getTransactionKey(transaction: unknown): TransactionKey {\n if (!transaction || typeof transaction !== 'object') {\n throw new Error('Transaction must be an object')\n }\n\n const tx = transaction as Record<string, unknown>\n if (!tx.hash && !tx.transactionHash) {\n throw new Error('Transaction must have hash or transactionHash')\n }\n\n return {\n hash: (tx.hash || tx.transactionHash) as Hex,\n decoderIndex: tx.decoderIndex ? (tx.decoderIndex as number) : undefined,\n }\n }\n\n /**\n * Get or create the inner map for a transaction hash\n */\n private getOrCreateTransactionMap(\n hash: Hex\n ): Map<number | null, Signal<TransactionState>> {\n const normalizedHash = hash.toLowerCase() as Hex\n let map = this.transactionSignals.get(normalizedHash)\n if (!map) {\n map = new Map()\n this.transactionSignals.set(normalizedHash, map)\n }\n return map\n }\n\n /**\n * Add one or more transactions to the model\n * Collects all addresses from all transactions and marks them as loading\n */\n addTransactions<T extends unknown | unknown[]>(\n jsonTransactions: T\n ): T extends unknown[]\n ? Array<Signal<TransactionState>>\n : Signal<TransactionState> {\n // Normalize input to array\n const transactions = Array.isArray(jsonTransactions)\n ? jsonTransactions\n : [jsonTransactions]\n const isSingle = !Array.isArray(jsonTransactions)\n // First, collect all addresses from all transactions\n const allAddresses = new Set<string>()\n const transactionAddresses: DataKey[][] = []\n\n for (const tx of transactions) {\n const addresses = collectDataKeys(tx)\n transactionAddresses.push(addresses)\n\n // Add to set for deduplication\n for (const addr of addresses) {\n allAddresses.add(addr)\n }\n }\n\n // Convert back to DataKey array\n const uniqueAddresses = Array.from(allAddresses) as DataKey[]\n\n // Mark all addresses as loading at once\n if (uniqueAddresses.length > 0) {\n this.setLoading(uniqueAddresses)\n }\n\n // Now add each transaction\n const results = transactions.map((tx, index) => {\n const key = this.getTransactionKey(tx)\n const normalizedHash = key.hash.toLowerCase() as Hex\n const decoderIndex = key.decoderIndex || null\n\n const isNewHash = !this.transactionSignals.has(normalizedHash)\n const txMap = this.getOrCreateTransactionMap(normalizedHash)\n\n if (txMap.has(decoderIndex)) {\n throw new Error(\n `Transaction already exists: ${normalizedHash}:${decoderIndex || 0}`\n )\n }\n\n // Create frozen data once\n const frozenData = deepFreeze(\n structuredClone(tx)\n ) as unknown as DeepReadonly<DecoderResult>\n\n // Create reactive transaction with frozen data\n const sig = signal<TransactionState>({\n data: frozenData,\n loading: false,\n addresses: Object.freeze([...transactionAddresses[index]]) as DataKey[],\n error: undefined,\n lastUpdated: Date.now(),\n resolvedData: frozenData, // Start with the same frozen data\n addressesResolved: false,\n })\n\n txMap.set(decoderIndex, sig)\n\n // Track transaction order (only for new hashes)\n if (isNewHash) {\n this.transactionOrder.push(normalizedHash)\n }\n\n // Notify about new transaction\n if (this.options.onNewTransaction) {\n this.options.onNewTransaction(tx)\n }\n\n return sig\n })\n\n // Return single signal if input was single, otherwise return array\n return (isSingle ? results[0] : results) as T extends unknown[]\n ? Array<Signal<TransactionState>>\n : Signal<TransactionState>\n }\n\n /**\n * Get an existing transaction signal (returns undefined if not found)\n */\n getTransaction(\n jsonTransaction: unknown\n ): Signal<TransactionState> | undefined {\n const key = this.getTransactionKey(jsonTransaction)\n const normalizedHash = key.hash.toLowerCase() as Hex\n const decoderIndex = key.decoderIndex || null\n\n const txMap = this.transactionSignals.get(normalizedHash)\n if (!txMap) {\n return undefined\n }\n\n return txMap.get(decoderIndex)\n }\n\n /**\n * Get transaction by hash and decoder index\n */\n getTransactionByKey(\n hash: Hex,\n decoderIndex?: number\n ): Signal<TransactionState> | undefined {\n const normalizedHash = hash.toLowerCase() as Hex\n const txMap = this.transactionSignals.get(normalizedHash)\n if (!txMap) {\n return undefined\n }\n\n return txMap.get(decoderIndex || null)\n }\n\n /**\n * Update a transaction's data and re-collect addresses\n * Useful after async decoding completes\n */\n updateTransactionData(\n hash: Hex,\n newData: DecoderResult,\n decoderIndex?: number\n ): void {\n const normalizedHash = hash.toLowerCase() as Hex\n const txMap = this.transactionSignals.get(normalizedHash)\n if (!txMap) return\n\n const sig = txMap.get(decoderIndex ?? null)\n if (!sig) return\n\n // Re-collect addresses with the new decoded data\n const newAddresses = collectDataKeys(newData, true, [\n ...sig.value.addresses,\n ])\n\n // Create frozen data once\n const frozenData = deepFreeze(structuredClone(newData))\n\n // Update the signal with frozen data\n sig.value = {\n ...sig.value,\n data: frozenData,\n addresses: Object.freeze([...newAddresses]) as DataKey[],\n lastUpdated: Date.now(),\n // Start with the current data, will be enhanced when addresses load\n resolvedData: frozenData,\n addressesResolved: false,\n }\n\n // Mark any new addresses as loading\n this.setLoading(newAddresses)\n\n // Check if we can create resolved data immediately\n queueMicrotask(() => {\n this.updateResolvedTransactionData()\n })\n }\n\n /**\n * Get all decoded transactions for a hash by index (insertion order)\n */\n getTransactionsByIndex(\n index: number\n ): Map<number | null, Signal<TransactionState>> | undefined {\n if (index < 0 || index >= this.transactionOrder.length) {\n return undefined\n }\n\n const hash = this.transactionOrder[index]\n return this.transactionSignals.get(hash)\n }\n\n /**\n * Get transaction hash by index\n */\n getTransactionHashByIndex(index: number): Hex | undefined {\n return this.transactionOrder[index]\n }\n\n /**\n * Get number of unique transaction hashes\n */\n getTransactionCount(): number {\n return this.transactionOrder.length\n }\n\n /**\n * Get number of decoded transactions for a specific hash\n */\n getDecodedCount(hash: Hex): number {\n const normalizedHash = hash.toLowerCase() as Hex\n const txMap = this.transactionSignals.get(normalizedHash)\n return txMap ? txMap.size : 0\n }\n\n /**\n * Get all decoded transactions for a specific hash\n */\n getDecodedTransactions(hash: Hex): Array<Signal<TransactionState>> {\n const normalizedHash = hash.toLowerCase() as Hex\n const txMap = this.transactionSignals.get(normalizedHash)\n return txMap ? Array.from(txMap.values()) : []\n }\n\n /**\n * Get address signal (alias for getSignal for clearer API)\n */\n getAddress(address: DataKey): Signal<AddressState> {\n return this.getSignal(address)\n }\n\n /**\n * Inject data into the model\n * Can be called multiple times to progressively add/update data\n */\n injectData(dataList: EnhancedInfo[]): void {\n batch(() => {\n for (const data of dataList) {\n const key: DataKey = data.tokenId\n ? `${data.address as Hex}:${data.tokenId}`\n : (data.address as Hex)\n\n const sig = this.getOrCreateSignal(key)\n\n // Update the signal with frozen data\n sig.value = {\n loading: false,\n data: deepFreeze(structuredClone(data)),\n error: undefined,\n lastUpdated: Date.now(),\n }\n }\n })\n\n // After the batch, check if any transactions need their resolved data updated\n this.updateResolvedTransactionData()\n }\n\n /**\n * Update a single item\n */\n updateData(data: EnhancedInfo): void {\n const key: DataKey = data.tokenId\n ? `${data.address as Hex}:${data.tokenId}`\n : (data.address as Hex)\n\n const sig = this.getOrCreateSignal(key)\n\n sig.value = {\n loading: false,\n data: deepFreeze(structuredClone(data)),\n error: undefined,\n lastUpdated: Date.now(),\n }\n\n // Debounce the resolved data update using a microtask\n if (!this.pendingResolvedUpdate) {\n this.pendingResolvedUpdate = true\n queueMicrotask(() => {\n this.pendingResolvedUpdate = false\n this.updateResolvedTransactionData()\n })\n }\n }\n\n /**\n * Mark keys as loading\n */\n setLoading(keys: DataKey[]): void {\n batch(() => {\n for (const key of keys) {\n const sig = this.getOrCreateSignal(key)\n sig.value = { ...sig.value, loading: true }\n }\n })\n }\n\n /**\n * Mark a key as errored\n */\n setError(key: DataKey, error: string): void {\n const sig = this.getOrCreateSignal(key)\n sig.value = {\n loading: false,\n data: undefined,\n error,\n lastUpdated: Date.now(),\n }\n }\n\n /**\n * Get signal for a key (creates one if doesn't exist)\n */\n getSignal(key: DataKey): Signal<AddressState> {\n return this.getOrCreateSignal(key)\n }\n\n /**\n * Subscribe to key updates\n */\n subscribe(key: DataKey, callback: (state: AddressState) => void): () => void {\n const sig = this.getSignal(key)\n return effect(() => callback(sig.value))\n }\n\n /**\n * Get current state of a key\n */\n getState(key: DataKey): AddressState {\n return this.getSignal(key).value\n }\n\n /**\n * Get all keys that have no data\n */\n getMissingKeys(): DataKey[] {\n const missingKeys: DataKey[] = []\n\n for (const [key] of this.dataSignals) {\n missingKeys.push(key as Hex)\n }\n\n return missingKeys\n }\n\n /**\n * Get all keys currently loading\n */\n getLoadingKeys(): DataKey[] {\n const loadingKeys: DataKey[] = []\n\n for (const [key, sig] of this.dataSignals) {\n if (sig.value.loading) {\n loadingKeys.push(key as Hex)\n }\n }\n\n return loadingKeys\n }\n\n /**\n * Check if we have data for a key\n */\n hasData(key: DataKey): boolean {\n const sig = this.dataSignals.get(key)\n return sig ? sig.value.data !== undefined : false\n }\n\n /**\n * Clear all data\n */\n clear(): void {\n batch(() => {\n // Clear address data\n for (const sig of this.dataSignals.values()) {\n sig.value = {\n loading: false,\n data: undefined,\n error: undefined,\n lastUpdated: undefined,\n }\n }\n\n // Clear transaction data\n for (const txMap of this.transactionSignals.values()) {\n for (const sig of txMap.values()) {\n sig.value = {\n ...sig.value,\n loading: false,\n error: undefined,\n }\n }\n }\n })\n }\n\n /**\n * Remove specific keys from cache\n */\n remove(keys: DataKey[]): void {\n for (const key of keys) {\n this.dataSignals.delete(key)\n }\n }\n\n /**\n * Get all cached keys\n */\n getAllKeys(): ReadonlyArray<DataKey> {\n const keys: DataKey[] = []\n\n for (const [key] of this.dataSignals) {\n keys.push(key as Hex)\n }\n\n return Object.freeze(keys)\n }\n\n /**\n * Get all data as a plain object (for debugging/serialization)\n */\n getAllData(): Readonly<Record<string, AddressState>> {\n const result: Record<string, AddressState> = {}\n\n for (const [key, sig] of this.dataSignals) {\n result[key] = sig.value\n }\n\n return Object.freeze(result)\n }\n\n /**\n * Get all transaction data (for debugging)\n */\n getAllTransactions(): Readonly<Record<string, TransactionState>> {\n const result: Record<string, TransactionState> = {}\n\n for (const [hash, txMap] of this.transactionSignals) {\n for (const [decoderIndex, sig] of txMap) {\n const key = decoderIndex === null ? hash : `${hash}:${decoderIndex}`\n result[key] = sig.value\n }\n }\n\n return Object.freeze(result)\n }\n\n /**\n * Get all transactions in order (returns all decoded transactions grouped by hash)\n */\n getTransactionsInOrder(): Array<{\n hash: Hex\n transactions: Array<Signal<TransactionState>>\n }> {\n const result: Array<{\n hash: Hex\n transactions: Array<Signal<TransactionState>>\n }> = []\n\n for (const hash of this.transactionOrder) {\n const txMap = this.transactionSignals.get(hash)\n if (txMap) {\n result.push({\n hash,\n transactions: Array.from(txMap.values()),\n })\n }\n }\n\n return result\n }\n\n /**\n * Create a resolved version of transaction data with all addresses populated\n */\n createResolvedTransactionData(\n transactionData: DecoderResult,\n addresses: ReadonlyArray<DataKey>\n ): DecoderResult {\n // Clone the transaction data to avoid modifying the original\n const resolved = structuredClone(transactionData)\n\n // Create a map of address data for quick lookup\n const addressMap = new Map<string, EnhancedInfo>()\n\n for (const key of addresses) {\n const addressData = this.getData(key)\n if (addressData) {\n addressMap.set(key.toLowerCase(), addressData)\n }\n }\n\n // Use the path-based approach to replace addresses\n this.replaceAddressesWithPaths(resolved, addressMap)\n\n // Deep freeze the result\n return deepFreeze(resolved)\n }\n\n /**\n * Replace addresses using path information (similar to collectAddressesWithPaths)\n */\n private replaceAddressesWithPaths(\n data: unknown,\n addressMap: Map<string, EnhancedInfo>\n ): void {\n function traverse(\n obj: unknown,\n path: Array<string | number> = [],\n parent?: Record<string, unknown> | unknown[]\n ): void {\n // Handle string case first\n if (typeof obj === 'string' && obj.startsWith('0x')) {\n // Use regex to detect zero-padded addresses\n const isPaddedAddress = /^0x0*([a-fA-F0-9]{40})$/.test(obj)\n\n if (isPaddedAddress || (isHex(obj) && size(obj as Hex) === 20)) {\n // Extract the actual address (remove padding if needed)\n const address = isPaddedAddress\n ? (obj.replace(/^0x0*([a-fA-F0-9]{40})$/, '0x$1') as Address)\n : obj\n\n // Skip if too many zeros (likely not an address)\n if (\n address\n .slice(2)\n .split('')\n .filter((c: string) => c === '0').length > 10\n ) {\n return\n }\n\n // Check for tokenId in parent\n const currentKey = path[path.length - 1]\n const tokenId =\n parent &&\n !Array.isArray(parent) &&\n 'tokenId' in parent &&\n parent.tokenId\n ? (parent.tokenId as Hex)\n : undefined\n\n // Look up the address data\n let addressData: EnhancedInfo | undefined\n if (tokenId) {\n const compositeKey = `${address.toLowerCase()}_${tokenId.toLowerCase()}`\n addressData = addressMap.get(compositeKey)\n } else {\n addressData = addressMap.get(address.toLowerCase())\n }\n\n // Replace the address with the data if found\n if (addressData && parent) {\n if (Array.isArray(parent) && typeof currentKey === 'number') {\n parent[currentKey] = addressData\n } else if (\n !Array.isArray(parent) &&\n typeof currentKey === 'string'\n ) {\n parent[currentKey] = addressData\n }\n }\n }\n return\n }\n\n if (!obj || typeof obj !== 'object') return\n\n if (Array.isArray(obj)) {\n for (let index = 0; index < obj.length; index++) {\n traverse(obj[index], path.concat([index]), obj)\n }\n } else {\n const record = obj as Record<string, unknown>\n for (const [key, value] of Object.entries(record)) {\n traverse(value, path.concat([key]), record)\n }\n }\n }\n\n traverse(data)\n }\n\n /**\n * Update resolved transaction data for all transactions where addresses are loaded\n */\n private updateResolvedTransactionData(): void {\n // Go through all transactions\n for (const [_hash, txMap] of this.transactionSignals) {\n for (const [_decoderIndex, signal] of txMap) {\n const currentState = signal.value\n\n // Skip if already resolved or if no addresses\n if (\n currentState.addressesResolved ||\n currentState.addresses.length === 0\n ) {\n continue\n }\n\n // Check if all addresses are loaded\n let allAddressesLoaded = true\n for (const addressKey of currentState.addresses) {\n const addressState = this.getState(addressKey)\n if (addressState.loading || !addressState.data) {\n allAddressesLoaded = false\n break\n }\n }\n\n // If all addresses are loaded, create resolved data\n if (allAddressesLoaded) {\n const resolvedData = this.createResolvedTransactionData(\n currentState.data as DecoderResult,\n currentState.addresses\n )\n\n // Update the transaction state\n signal.value = {\n ...currentState,\n resolvedData: resolvedData as DeepReadonly<DecoderResult>,\n addressesResolved: true,\n lastUpdated: Date.now(),\n }\n }\n }\n }\n }\n\n /**\n * Get data by key - convenience method that handles both 20 and 32 byte addresses\n */\n getData(key: DataKey): DeepReadonly<EnhancedInfo> | undefined {\n return this.getState(key).data\n }\n\n /**\n * Check if a key is loading\n */\n isLoading(key: DataKey): boolean {\n return this.getState(key).loading\n }\n\n /**\n * Get error for a key\n */\n getError(key: DataKey): string | undefined {\n return this.getState(key).error\n }\n}\n\n/**\n * Create a read-only consumer proxy that only exposes safe read methods\n */\nexport function createConsumerProxy(model: DataModel): IDataModelConsumer {\n const consumerMethods = [\n // Transaction read methods\n 'getTransaction',\n 'getTransactionByKey',\n 'getTransactionsByIndex',\n 'getTransactionHashByIndex',\n 'getTransactionCount',\n 'getDecodedCount',\n 'getDecodedTransactions',\n 'getTransactionsInOrder',\n // Address read methods\n 'getAddress',\n 'getSignal',\n 'subscribe',\n 'getState',\n 'hasData',\n 'getData',\n 'isLoading',\n 'getError',\n // Collection read methods\n 'getAllKeys',\n 'getAllData',\n 'getAllTransactions',\n ]\n\n const proxy = new Proxy(model, {\n get(target, prop, receiver) {\n if (typeof prop === 'string' && consumerMethods.includes(prop)) {\n const value = Reflect.get(target, prop, receiver)\n if (typeof value === 'function') {\n return value.bind(target)\n }\n return value\n }\n // Block access to all other properties and methods\n return undefined\n },\n set() {\n return false // Prevent modifications\n },\n deleteProperty() {\n return false\n },\n defineProperty() {\n return false\n },\n setPrototypeOf() {\n return false\n },\n }) as IDataModelConsumer\n\n return proxy\n}\n\n/**\n * Create a secure DataModel instance\n * Freezes the prototype to prevent prototype pollution attacks\n */\nexport function createDataModel(options?: DataModelOptions): IDataModel {\n const model = new DataModel(options)\n\n // Freeze the prototype to prevent modification\n Object.freeze(DataModel.prototype)\n\n // Freeze the constructor\n Object.freeze(DataModel)\n\n return model\n}\n","import type { IDataModel, IDataModelConsumer } from '../types'\nimport { createConsumerProxy, DataModel } from './dataModel'\n\n// Create the singleton instance\nconst dataModelInstance = new DataModel()\n\n// Freeze the prototype and constructor to prevent prototype pollution\nObject.freeze(DataModel.prototype)\nObject.freeze(DataModel)\n\n// Export the full model for data providers to import\n// Note: We don't freeze dataModel as data providers need to modify it\nexport const dataModel: IDataModel = dataModelInstance\n\n// Create consumer-only proxy for public API (frozen)\nexport const consumerModel: IDataModelConsumer =\n createConsumerProxy(dataModelInstance)\n\n// Export a function to optionally create global instance\n// This allows consumers to control when/if the global is created\nexport function createGlobalInstance(): void {\n if (typeof window !== 'undefined') {\n // Create consumer-only proxy for window\n const consumerProxy = createConsumerProxy(dataModelInstance)\n\n Object.defineProperty(window, 'TransactionDecoder', {\n value: consumerProxy,\n writable: false,\n configurable: false,\n enumerable: true,\n })\n }\n}\n","import { type Signal, signal } from '@preact/signals-core'\nimport type { Hex, Transaction } from 'viem'\nimport { collectDataKeys } from '../core/addressCollector'\nimport { deepFreeze } from '../core/dataModel'\nimport { pluginRegistry } from '../decoder/registry'\nimport { decodeTransaction as decodeTransactionCore } from '../decoder/transaction'\nimport {\n AsyncOperations,\n type DecoderOptions,\n type DecoderResult,\n ErrorType,\n} from '../decoder/types'\nimport { isAsyncOperationEnabled } from '../decoder/utils'\nimport { ERROR_CODES } from '../shared/constants'\nimport type { DataKey, TransactionState } from '../types'\n\n/**\n * Address resolver interface for batch resolution\n */\nexport interface AddressResolver {\n resolveAddresses(addresses: DataKey[]): Promise<void>\n}\n\n/**\n * Result from decoding a transaction\n */\nexport interface TransactionDecoderResult {\n // Immediate sync result\n immediate: DecoderResult\n\n // Signal that updates as async decoding progresses\n signal: Signal<TransactionState>\n}\n\n/**\n * Decode a transaction with progressive enhancement\n * @param transaction - Raw transaction data or array of transactions\n * @param options - Decoder options\n * @returns Immediate result and reactive signal (or array of them)\n */\nexport async function decodeTransaction<\n T extends DecoderResult | DecoderResult[],\n>(\n transaction: T,\n options: DecoderOptions & { addressResolver?: AddressResolver }\n): Promise<\n T extends Transaction[]\n ? TransactionDecoderResult[]\n : TransactionDecoderResult\n> {\n const isBatch = Array.isArray(transaction)\n const transactions: DecoderResult[] = isBatch\n ? (transaction as unknown as DecoderResult[])\n : [transaction as DecoderResult]\n\n const results = await decodeTransactionBatch(transactions, options)\n\n // Return single result if single input\n if (isBatch) {\n return results as T extends Transaction[]\n ? TransactionDecoderResult[]\n : TransactionDecoderResult\n }\n return results[0] as T extends Transaction[]\n ? TransactionDecoderResult[]\n : TransactionDecoderResult\n}\n\n/**\n * Internal batch decoder with three-phase approach\n */\nasync function decodeTransactionBatch(\n transactions: DecoderResult[],\n options: DecoderOptions & { addressResolver?: AddressResolver }\n): Promise<TransactionDecoderResult[]> {\n // Extract names of plugins provided in options (these will override registered ones)\n const overridePluginNames =\n options.plugins\n ?.map((p) => p.name)\n .filter((name): name is string => typeof name === 'string') || []\n\n const overrideSchemaNames =\n options.schemaPlugins\n ?.map((p) => p.name)\n .filter((name): name is string => typeof name === 'string') || []\n\n // Get registered plugins, excluding those being overridden\n const registeredPlugins = await pluginRegistry.getAll({\n excludeNames: overridePluginNames,\n })\n const registeredSchemaPlugins =\n pluginRegistry.getAllSchema(overrideSchemaNames)\n\n // Merge: provided plugins override registered ones\n const allPlugins = [...registeredPlugins, ...(options.plugins || [])]\n const allSchemaPlugins = [\n ...registeredSchemaPlugins,\n ...(options.schemaPlugins || []),\n ]\n\n // Phase 1: Sync decode\n const syncOptions: DecoderOptions = {\n ...options,\n plugins: allPlugins.filter(({ usesAsync }) => !usesAsync),\n schemaPlugins: allSchemaPlugins,\n async: false,\n }\n\n const results = await Promise.all(\n transactions.map(async (tx) => {\n const initialResult = await decodeTransactionCore(tx, syncOptions)\n const initialData = deepFreeze(initialResult || createErrorResult(tx))\n\n // Create signal with frozen data\n const txSignal = signal<TransactionState>({\n loading: false,\n data: initialData as DecoderResult,\n decodingStatus: initialResult ? 'decoded' : 'failed',\n addresses: collectDataKeys(tx),\n addressesResolved: false,\n lastUpdated: Date.now(),\n })\n\n return {\n transaction: tx,\n immediate: initialData,\n signal: txSignal,\n }\n })\n )\n\n // Check if we have any async plugins for phase 2\n // For now, assume we have async plugins if async operations are enabled\n // since plugins themselves no longer have the async property\n const hasAsyncPlugins = true\n const pluginsEnabled = isAsyncOperationEnabled(\n options.async,\n AsyncOperations.ENABLE_PLUGINS\n )\n\n if (hasAsyncPlugins && pluginsEnabled) {\n // Phase 2: ABI retrieval (async plugins)\n const asyncOptions: DecoderOptions = {\n ...options,\n plugins: allPlugins,\n schemaPlugins: allSchemaPlugins,\n async: true,\n }\n\n // Run async decoding for all transactions\n for (const { transaction, signal: txSignal } of results) {\n decodeTransactionCore(transaction, asyncOptions)\n .then((enhanced) => {\n if (enhanced) {\n txSignal.value = {\n ...txSignal.value,\n data: deepFreeze(enhanced) as DecoderResult,\n decodingStatus: 'enhanced',\n addresses: collectDataKeys(enhanced),\n lastUpdated: Date.now(),\n }\n }\n })\n .catch((error) => {\n console.error('Async decode error:', error)\n txSignal.value = {\n ...txSignal.value,\n decodingStatus: 'failed',\n error: error instanceof Error ? error.message : 'Unknown error',\n loading: false,\n }\n })\n }\n }\n\n // Phase 3: Address resolution (if resolver provided and enabled)\n const addressResolveEnabled = isAsyncOperationEnabled(\n options.async,\n AsyncOperations.ENABLE_ADDRESS_RESOLVE\n )\n\n if (options.addressResolver && addressResolveEnabled) {\n // Collect all unique addresses from all transactions\n const allAddresses = new Set<DataKey>()\n for (const { signal: txSignal } of results) {\n for (const addr of txSignal.value.addresses) {\n allAddresses.add(addr)\n }\n }\n\n // Batch resolve addresses\n if (allAddresses.size > 0) {\n options.addressResolver\n .resolveAddresses(Array.from(allAddresses))\n .then(() => {\n // Update all signals to indicate addresses are resolved\n for (const { signal: txSignal } of results) {\n if (txSignal.value.decodingStatus !== 'failed') {\n txSignal.value = {\n ...txSignal.value,\n addressesResolved: true,\n decodingStatus: 'complete',\n lastUpdated: Date.now(),\n }\n }\n }\n })\n .catch((error) => {\n console.error('Address resolution error:', error)\n // Don't fail the transaction, just log the error\n })\n }\n } else if (!hasAsyncPlugins || (!pluginsEnabled && !addressResolveEnabled)) {\n // No async operations enabled, mark as complete\n for (const { signal: txSignal } of results) {\n if (txSignal.value.decodingStatus !== 'failed') {\n txSignal.value = {\n ...txSignal.value,\n decodingStatus: 'complete',\n }\n }\n }\n }\n\n return results.map((r) => ({\n immediate: r.immediate,\n signal: r.signal,\n }))\n}\n\nfunction createErrorResult(transaction: DecoderResult): DecoderResult {\n return {\n ...transaction,\n resultType: 'error' as const,\n isDecoded: false,\n errorType: ErrorType.ERROR,\n sig: transaction.input?.slice(0, 10) as Hex,\n error: {\n code: ERROR_CODES.DECODING_FAILED,\n message: 'Failed to decode transaction',\n details: new Error('Decoder returned undefined'),\n },\n }\n}\n\n/**\n * Decode a transaction and wait for complete result\n * Convenience wrapper for when you need a promise\n */\nexport async function decodeTransactionAsync<\n T extends DecoderResult | DecoderResult[],\n>(\n transaction: T,\n options: DecoderOptions & { addressResolver?: AddressResolver }\n): Promise<T extends Transaction[] ? DecoderResult[] : DecoderResult> {\n const isBatch = Array.isArray(transaction)\n const result = await decodeTransaction(transaction, options)\n const results = isBatch\n ? (result as TransactionDecoderResult[])\n : [result as TransactionDecoderResult]\n\n // Wait for all decodings to complete\n const finalResults = await Promise.all(\n results.map(\n ({ signal }) =>\n new Promise<DecoderResult>((resolve) => {\n const checkComplete = () => {\n const state = signal.value\n if (\n state.decodingStatus === 'complete' ||\n state.decodingStatus === 'failed'\n ) {\n resolve(state.data as DecoderResult)\n } else {\n // Check again on next tick\n setTimeout(checkComplete, 10)\n }\n }\n checkComplete()\n })\n )\n )\n\n if (isBatch) {\n return finalResults as T extends Transaction[]\n ? DecoderResult[]\n : DecoderResult\n }\n return finalResults[0] as T extends Transaction[]\n ? DecoderResult[]\n : DecoderResult\n}\n","/**\n * Shared constants\n */\n\nexport const DECODER_VERSION = '0.1.0'\n\nexport const DEFAULT_CONFIG = {\n endpoint: 'https://api.lukso.network/decoder',\n batchSize: 100,\n retryAttempts: 3,\n timeout: 30000,\n} as const\n\nexport const ERROR_CODES = {\n INVALID_TRANSACTION: 'INVALID_TRANSACTION',\n DECODING_FAILED: 'DECODING_FAILED',\n NETWORK_ERROR: 'NETWORK_ERROR',\n RATE_LIMIT: 'RATE_LIMIT',\n UNAUTHORIZED: 'UNAUTHORIZED',\n NOT_FOUND: 'NOT_FOUND',\n} as const\n"],"mappings":"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","names":["signal","signal","decodeTransaction","signal"]}