@lukso/transaction-decoder 1.0.1-dev.0f1bea5

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 (110) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +486 -0
  3. package/dist/browser.cjs +6912 -0
  4. package/dist/browser.cjs.map +1 -0
  5. package/dist/browser.d.cts +6 -0
  6. package/dist/browser.d.ts +6 -0
  7. package/dist/browser.js +131 -0
  8. package/dist/browser.js.map +1 -0
  9. package/dist/cdn/transaction-decoder.global.js +296 -0
  10. package/dist/cdn/transaction-decoder.global.js.map +1 -0
  11. package/dist/chunk-GGBHTWJL.js +437 -0
  12. package/dist/chunk-GGBHTWJL.js.map +1 -0
  13. package/dist/chunk-GXZOF3QY.js +839 -0
  14. package/dist/chunk-GXZOF3QY.js.map +1 -0
  15. package/dist/chunk-LJ6ES5XF.js +776 -0
  16. package/dist/chunk-LJ6ES5XF.js.map +1 -0
  17. package/dist/chunk-XVHJWV5U.js +4925 -0
  18. package/dist/chunk-XVHJWV5U.js.map +1 -0
  19. package/dist/data.cjs +5518 -0
  20. package/dist/data.cjs.map +1 -0
  21. package/dist/data.d.cts +43 -0
  22. package/dist/data.d.ts +43 -0
  23. package/dist/data.js +55 -0
  24. package/dist/data.js.map +1 -0
  25. package/dist/index-BzXh7poJ.d.cts +524 -0
  26. package/dist/index-BzXh7poJ.d.ts +524 -0
  27. package/dist/index.cjs +6912 -0
  28. package/dist/index.cjs.map +1 -0
  29. package/dist/index.d.cts +756 -0
  30. package/dist/index.d.ts +756 -0
  31. package/dist/index.js +131 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/server.cjs +5644 -0
  34. package/dist/server.cjs.map +1 -0
  35. package/dist/server.d.cts +217 -0
  36. package/dist/server.d.ts +217 -0
  37. package/dist/server.js +644 -0
  38. package/dist/server.js.map +1 -0
  39. package/dist/utils-CBAkjQh3.d.cts +108 -0
  40. package/dist/utils-xT9-km0r.d.ts +108 -0
  41. package/package.json +101 -0
  42. package/src/browser.ts +13 -0
  43. package/src/client/resolveAddresses.ts +157 -0
  44. package/src/core/addressCollector.ts +153 -0
  45. package/src/core/addressResolver.ts +135 -0
  46. package/src/core/dataModel.ts +888 -0
  47. package/src/core/instance.ts +33 -0
  48. package/src/core/integrateDecoder.ts +325 -0
  49. package/src/data.ts +70 -0
  50. package/src/decoder/GENERATOR_PROPOSAL.md +182 -0
  51. package/src/decoder/THREE_PHASE_EXAMPLE.md +108 -0
  52. package/src/decoder/aggregation.ts +218 -0
  53. package/src/decoder/browserCache.ts +237 -0
  54. package/src/decoder/cache/README.md +126 -0
  55. package/src/decoder/cache/index.ts +44 -0
  56. package/src/decoder/cache.ts +139 -0
  57. package/src/decoder/constants.ts +125 -0
  58. package/src/decoder/decodeTransaction.ts +292 -0
  59. package/src/decoder/errors.ts +95 -0
  60. package/src/decoder/events.ts +192 -0
  61. package/src/decoder/functionSignature.ts +344 -0
  62. package/src/decoder/getDataFromExternalSources.ts +248 -0
  63. package/src/decoder/graphqlWS.ts +22 -0
  64. package/src/decoder/interfaces.ts +185 -0
  65. package/src/decoder/keyValue.ts +5 -0
  66. package/src/decoder/kvCache.ts +241 -0
  67. package/src/decoder/lruCache.ts +184 -0
  68. package/src/decoder/lsp7Mint.test.ts +179 -0
  69. package/src/decoder/lsp7TransferBatch.test.ts +105 -0
  70. package/src/decoder/plugins/RegistryAbi.ts +562 -0
  71. package/src/decoder/plugins/enhanceBurntPix.ts +132 -0
  72. package/src/decoder/plugins/enhanceGraffiti.ts +70 -0
  73. package/src/decoder/plugins/enhanceLSP0ERC725Account.ts +179 -0
  74. package/src/decoder/plugins/enhanceLSP26FollowerSystem.ts +88 -0
  75. package/src/decoder/plugins/enhanceLSP6KeyManager.ts +231 -0
  76. package/src/decoder/plugins/enhanceLSP7DigitalAsset.ts +165 -0
  77. package/src/decoder/plugins/enhanceLSP8IdentifiableDigitalAsset.ts +170 -0
  78. package/src/decoder/plugins/enhanceLSP9Vault.ts +57 -0
  79. package/src/decoder/plugins/enhanceRetrieveAbi.ts +85 -0
  80. package/src/decoder/plugins/enhanceSetData.ts +135 -0
  81. package/src/decoder/plugins/index.ts +99 -0
  82. package/src/decoder/plugins/schemaDefault.ts +318 -0
  83. package/src/decoder/plugins/standardPlugin.ts +202 -0
  84. package/src/decoder/registry.ts +322 -0
  85. package/src/decoder/singleGQL.ts +293 -0
  86. package/src/decoder/transaction.ts +198 -0
  87. package/src/decoder/types.ts +465 -0
  88. package/src/decoder/utils.ts +212 -0
  89. package/src/example/usage.ts +172 -0
  90. package/src/index.ts +174 -0
  91. package/src/server/addressResolver.ts +68 -0
  92. package/src/server/caches.ts +209 -0
  93. package/src/server/decodeTransactionSync.ts +156 -0
  94. package/src/server/decodeTransactionsBatch.ts +207 -0
  95. package/src/server/finishDecoding.ts +116 -0
  96. package/src/server/index.ts +81 -0
  97. package/src/server/lsp23Resolver.test.ts +46 -0
  98. package/src/server/lsp23Resolver.ts +419 -0
  99. package/src/server/types.ts +168 -0
  100. package/src/server.ts +22 -0
  101. package/src/shared/addressResolver.ts +651 -0
  102. package/src/shared/cache.ts +144 -0
  103. package/src/shared/constants.ts +21 -0
  104. package/src/stubs/tty.ts +13 -0
  105. package/src/stubs/util.ts +42 -0
  106. package/src/types/index.ts +154 -0
  107. package/src/types/provider.ts +46 -0
  108. package/src/umd.ts +13 -0
  109. package/src/utils/debug.ts +49 -0
  110. package/src/utils/json-bigint.ts +47 -0
@@ -0,0 +1,153 @@
1
+ import { type Address, type Hex, isHex, size } from 'viem'
2
+ import type { ArrayArgs } from '../decoder/types'
3
+ import { getArgByName } from '../decoder/utils'
4
+ import type { DataKey } from '../types'
5
+
6
+ export interface CollectedAddress {
7
+ key: DataKey
8
+ path: Array<string | number>
9
+ parent?: Record<string, unknown>
10
+ root: unknown
11
+ }
12
+
13
+ /**
14
+ * Collect all DataKeys from a data structure
15
+ * This is a simplified version that just returns the keys
16
+ * @param data - The data to analyze
17
+ * @param skipGqlTypes - Whether to skip GraphQL type fields
18
+ * @param existingKeys - Optional existing keys to merge with
19
+ */
20
+ export function collectDataKeys(
21
+ data: unknown,
22
+ skipGqlTypes = true,
23
+ existingKeys?: DataKey[]
24
+ ): DataKey[] {
25
+ const addresses = new Set<string>()
26
+
27
+ // Add existing keys to the set first
28
+ if (existingKeys) {
29
+ for (const key of existingKeys) {
30
+ if (typeof key === 'string') {
31
+ addresses.add(key)
32
+ } else {
33
+ addresses.add(JSON.stringify(key))
34
+ }
35
+ }
36
+ }
37
+
38
+ // Check if this is an LSP8 decoded transaction and collect tokens
39
+ function collectLSP8Tokens(obj: Record<string, unknown>): void {
40
+ if (
41
+ obj.standard !== 'LSP8IdentifiableDigitalAsset' ||
42
+ !obj.to ||
43
+ !obj.args
44
+ ) {
45
+ return
46
+ }
47
+
48
+ const contractAddress = obj.to as string
49
+ const args = obj.args as ArrayArgs
50
+
51
+ // Check for single tokenId
52
+ const tokenId = getArgByName(args, 'tokenId') as string | undefined
53
+ if (tokenId && tokenId !== null && tokenId !== '0x') {
54
+ addresses.add(`${contractAddress}:${tokenId}`)
55
+ }
56
+
57
+ // Check for multiple tokenIds
58
+ const tokenIds = getArgByName(args, 'tokenIds') as string[] | undefined
59
+ if (Array.isArray(tokenIds)) {
60
+ for (const tokenId of tokenIds) {
61
+ // Skip null/undefined/empty tokens
62
+ if (tokenId && tokenId !== null && tokenId !== '0x') {
63
+ addresses.add(`${contractAddress}:${tokenId}`)
64
+ }
65
+ }
66
+ }
67
+ }
68
+
69
+ function collect(
70
+ obj: unknown,
71
+ parent?: Record<string, unknown>,
72
+ visited = new WeakSet(),
73
+ path: string[] = []
74
+ ): void {
75
+ // Circular reference detection
76
+ if (obj && typeof obj === 'object' && visited.has(obj)) {
77
+ return
78
+ }
79
+
80
+ if (obj && typeof obj === 'object') {
81
+ visited.add(obj)
82
+ }
83
+ // Handle string case first
84
+ if (typeof obj === 'string' && obj.startsWith('0x')) {
85
+ // Check if this is a composite address:tokenId format
86
+ if (obj.includes(':')) {
87
+ const [addressPart, tokenIdPart] = obj.split(':')
88
+ // Validate both parts are hex strings
89
+ if (
90
+ addressPart.startsWith('0x') &&
91
+ tokenIdPart.startsWith('0x') &&
92
+ isHex(addressPart) &&
93
+ size(addressPart as Hex) === 20
94
+ ) {
95
+ addresses.add(obj) // Just add the composite string directly
96
+ return
97
+ }
98
+ }
99
+
100
+ // Use regex to detect zero-padded addresses
101
+ const isPaddedAddress = /^0x0*([a-fA-F0-9]{40})$/.test(obj)
102
+
103
+ if (isPaddedAddress || (isHex(obj) && size(obj as Hex) === 20)) {
104
+ // Skip if parent has __gqltype
105
+ if (parent && skipGqlTypes && '__gqltype' in parent) {
106
+ return
107
+ }
108
+
109
+ // Extract the actual address (remove padding if needed)
110
+ const address = isPaddedAddress
111
+ ? (obj.replace(/^0x0*([a-fA-F0-9]{40})$/, '0x$1') as Address)
112
+ : obj
113
+
114
+ // Skip if too many zeros (likely not an address)
115
+ if (
116
+ address
117
+ .slice(2)
118
+ .split('')
119
+ .filter((c: string) => c === '0').length > 10
120
+ ) {
121
+ return
122
+ }
123
+
124
+ addresses.add(address)
125
+ }
126
+ return
127
+ }
128
+
129
+ if (!obj || typeof obj !== 'object') return
130
+
131
+ if (Array.isArray(obj)) {
132
+ for (let i = 0; i < obj.length; i++) {
133
+ collect(obj[i], parent, visited, [...path, `[${i}]`])
134
+ }
135
+ } else {
136
+ const record = obj as Record<string, unknown>
137
+
138
+ // Check if this is an LSP8 transaction at the root level
139
+ if ('standard' in record && 'to' in record && 'args' in record) {
140
+ collectLSP8Tokens(record)
141
+ }
142
+
143
+ for (const [key, value] of Object.entries(record)) {
144
+ collect(value, record, visited, [...path, key])
145
+ }
146
+ }
147
+ }
148
+
149
+ collect(data)
150
+
151
+ // Convert to DataKey array (all as strings)
152
+ return Array.from(addresses) as DataKey[]
153
+ }
@@ -0,0 +1,135 @@
1
+ import type { Chain } from 'viem'
2
+ import { fetchMultipleAddresses } from '../shared/addressResolver'
3
+ import type { AddressIdentityCache } from '../shared/cache'
4
+ import type { DataKey, EnhancedInfo, IDataModel } from '../types'
5
+
6
+ /**
7
+ * Configuration for address resolver
8
+ */
9
+ export interface AddressResolverConfig {
10
+ dataModel: IDataModel
11
+ graphqlEndpoint: string
12
+ chain: Chain
13
+ batchSize?: number
14
+ batchDelay?: number
15
+ cache?: AddressIdentityCache
16
+ }
17
+
18
+ /**
19
+ * Resolve addresses using GraphQL
20
+ * Replaces the old patchValue mechanism
21
+ */
22
+ export class AddressResolver {
23
+ private dataModel: IDataModel
24
+ private graphqlEndpoint: string
25
+ private batchSize: number
26
+ private batchDelay: number
27
+ private pendingAddresses = new Set<string>()
28
+ private batchTimer?: NodeJS.Timeout
29
+ private cache?: AddressIdentityCache
30
+
31
+ constructor(config: AddressResolverConfig) {
32
+ this.dataModel = config.dataModel
33
+ this.graphqlEndpoint = config.graphqlEndpoint
34
+ this.batchSize = config.batchSize || 50
35
+ this.batchDelay = config.batchDelay || 100
36
+ this.cache = config.cache
37
+ }
38
+
39
+ /**
40
+ * Start watching for missing addresses
41
+ */
42
+ startWatching() {
43
+ // Check for missing addresses periodically
44
+ setInterval(() => {
45
+ const missing = this.dataModel.getMissingKeys()
46
+ if (missing.length > 0) {
47
+ this.queueAddresses(missing)
48
+ }
49
+ }, 1000)
50
+ }
51
+
52
+ /**
53
+ * Queue addresses for batch resolution
54
+ */
55
+ queueAddresses(addresses: DataKey[]) {
56
+ // Add to pending set
57
+ for (const addr of addresses) {
58
+ this.pendingAddresses.add(addr)
59
+ }
60
+
61
+ // Clear existing timer
62
+ if (this.batchTimer) {
63
+ clearTimeout(this.batchTimer)
64
+ }
65
+
66
+ // Set new timer
67
+ this.batchTimer = setTimeout(() => {
68
+ this.processBatch()
69
+ }, this.batchDelay)
70
+
71
+ // Process immediately if batch is full
72
+ if (this.pendingAddresses.size >= this.batchSize) {
73
+ clearTimeout(this.batchTimer)
74
+ this.processBatch()
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Process a batch of addresses
80
+ */
81
+ private async processBatch() {
82
+ const batch = Array.from(this.pendingAddresses).slice(0, this.batchSize)
83
+ if (batch.length === 0) return
84
+
85
+ // Remove from pending
86
+ for (const key of batch) {
87
+ this.pendingAddresses.delete(key)
88
+ }
89
+
90
+ // Convert batch keys back to DataKey format
91
+ const dataKeys: DataKey[] = batch.map((key) => {
92
+ return key as DataKey
93
+ })
94
+
95
+ try {
96
+ // Fetch data using shared implementation with cache
97
+ const results = await fetchMultipleAddresses(
98
+ dataKeys,
99
+ this.graphqlEndpoint,
100
+ this.cache
101
+ )
102
+
103
+ // Convert to array for injection
104
+ const enhancedData: EnhancedInfo[] = Array.from(results.values())
105
+
106
+ // Inject data into model
107
+ if (enhancedData.length > 0) {
108
+ this.dataModel.injectData(enhancedData)
109
+ }
110
+ } catch (error) {
111
+ console.error('Failed to resolve addresses:', error)
112
+
113
+ // Mark addresses as having errors
114
+ for (const key of dataKeys) {
115
+ this.dataModel.setError(key, 'Failed to fetch address data')
116
+ }
117
+ }
118
+
119
+ // Continue processing if more pending
120
+ if (this.pendingAddresses.size > 0) {
121
+ this.batchTimer = setTimeout(() => {
122
+ this.processBatch()
123
+ }, this.batchDelay)
124
+ }
125
+ }
126
+
127
+ /**
128
+ * Stop watching for addresses
129
+ */
130
+ stopWatching() {
131
+ if (this.batchTimer) {
132
+ clearTimeout(this.batchTimer)
133
+ }
134
+ }
135
+ }