@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.
- package/LICENSE +201 -0
- package/README.md +486 -0
- package/dist/browser.cjs +6912 -0
- package/dist/browser.cjs.map +1 -0
- package/dist/browser.d.cts +6 -0
- package/dist/browser.d.ts +6 -0
- package/dist/browser.js +131 -0
- package/dist/browser.js.map +1 -0
- package/dist/cdn/transaction-decoder.global.js +296 -0
- package/dist/cdn/transaction-decoder.global.js.map +1 -0
- package/dist/chunk-GGBHTWJL.js +437 -0
- package/dist/chunk-GGBHTWJL.js.map +1 -0
- package/dist/chunk-GXZOF3QY.js +839 -0
- package/dist/chunk-GXZOF3QY.js.map +1 -0
- package/dist/chunk-LJ6ES5XF.js +776 -0
- package/dist/chunk-LJ6ES5XF.js.map +1 -0
- package/dist/chunk-XVHJWV5U.js +4925 -0
- package/dist/chunk-XVHJWV5U.js.map +1 -0
- package/dist/data.cjs +5518 -0
- package/dist/data.cjs.map +1 -0
- package/dist/data.d.cts +43 -0
- package/dist/data.d.ts +43 -0
- package/dist/data.js +55 -0
- package/dist/data.js.map +1 -0
- package/dist/index-BzXh7poJ.d.cts +524 -0
- package/dist/index-BzXh7poJ.d.ts +524 -0
- package/dist/index.cjs +6912 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +756 -0
- package/dist/index.d.ts +756 -0
- package/dist/index.js +131 -0
- package/dist/index.js.map +1 -0
- package/dist/server.cjs +5644 -0
- package/dist/server.cjs.map +1 -0
- package/dist/server.d.cts +217 -0
- package/dist/server.d.ts +217 -0
- package/dist/server.js +644 -0
- package/dist/server.js.map +1 -0
- package/dist/utils-CBAkjQh3.d.cts +108 -0
- package/dist/utils-xT9-km0r.d.ts +108 -0
- package/package.json +101 -0
- package/src/browser.ts +13 -0
- package/src/client/resolveAddresses.ts +157 -0
- package/src/core/addressCollector.ts +153 -0
- package/src/core/addressResolver.ts +135 -0
- package/src/core/dataModel.ts +888 -0
- package/src/core/instance.ts +33 -0
- package/src/core/integrateDecoder.ts +325 -0
- package/src/data.ts +70 -0
- package/src/decoder/GENERATOR_PROPOSAL.md +182 -0
- package/src/decoder/THREE_PHASE_EXAMPLE.md +108 -0
- package/src/decoder/aggregation.ts +218 -0
- package/src/decoder/browserCache.ts +237 -0
- package/src/decoder/cache/README.md +126 -0
- package/src/decoder/cache/index.ts +44 -0
- package/src/decoder/cache.ts +139 -0
- package/src/decoder/constants.ts +125 -0
- package/src/decoder/decodeTransaction.ts +292 -0
- package/src/decoder/errors.ts +95 -0
- package/src/decoder/events.ts +192 -0
- package/src/decoder/functionSignature.ts +344 -0
- package/src/decoder/getDataFromExternalSources.ts +248 -0
- package/src/decoder/graphqlWS.ts +22 -0
- package/src/decoder/interfaces.ts +185 -0
- package/src/decoder/keyValue.ts +5 -0
- package/src/decoder/kvCache.ts +241 -0
- package/src/decoder/lruCache.ts +184 -0
- package/src/decoder/lsp7Mint.test.ts +179 -0
- package/src/decoder/lsp7TransferBatch.test.ts +105 -0
- package/src/decoder/plugins/RegistryAbi.ts +562 -0
- package/src/decoder/plugins/enhanceBurntPix.ts +132 -0
- package/src/decoder/plugins/enhanceGraffiti.ts +70 -0
- package/src/decoder/plugins/enhanceLSP0ERC725Account.ts +179 -0
- package/src/decoder/plugins/enhanceLSP26FollowerSystem.ts +88 -0
- package/src/decoder/plugins/enhanceLSP6KeyManager.ts +231 -0
- package/src/decoder/plugins/enhanceLSP7DigitalAsset.ts +165 -0
- package/src/decoder/plugins/enhanceLSP8IdentifiableDigitalAsset.ts +170 -0
- package/src/decoder/plugins/enhanceLSP9Vault.ts +57 -0
- package/src/decoder/plugins/enhanceRetrieveAbi.ts +85 -0
- package/src/decoder/plugins/enhanceSetData.ts +135 -0
- package/src/decoder/plugins/index.ts +99 -0
- package/src/decoder/plugins/schemaDefault.ts +318 -0
- package/src/decoder/plugins/standardPlugin.ts +202 -0
- package/src/decoder/registry.ts +322 -0
- package/src/decoder/singleGQL.ts +293 -0
- package/src/decoder/transaction.ts +198 -0
- package/src/decoder/types.ts +465 -0
- package/src/decoder/utils.ts +212 -0
- package/src/example/usage.ts +172 -0
- package/src/index.ts +174 -0
- package/src/server/addressResolver.ts +68 -0
- package/src/server/caches.ts +209 -0
- package/src/server/decodeTransactionSync.ts +156 -0
- package/src/server/decodeTransactionsBatch.ts +207 -0
- package/src/server/finishDecoding.ts +116 -0
- package/src/server/index.ts +81 -0
- package/src/server/lsp23Resolver.test.ts +46 -0
- package/src/server/lsp23Resolver.ts +419 -0
- package/src/server/types.ts +168 -0
- package/src/server.ts +22 -0
- package/src/shared/addressResolver.ts +651 -0
- package/src/shared/cache.ts +144 -0
- package/src/shared/constants.ts +21 -0
- package/src/stubs/tty.ts +13 -0
- package/src/stubs/util.ts +42 -0
- package/src/types/index.ts +154 -0
- package/src/types/provider.ts +46 -0
- package/src/umd.ts +13 -0
- package/src/utils/debug.ts +49 -0
- package/src/utils/json-bigint.ts +47 -0
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type DecodeDataOutput,
|
|
3
|
+
decodeData,
|
|
4
|
+
decodeMappingKey,
|
|
5
|
+
decodePermissions,
|
|
6
|
+
decodeValueContent,
|
|
7
|
+
type ERC725JSONSchema,
|
|
8
|
+
isDynamicKeyName,
|
|
9
|
+
type Permissions,
|
|
10
|
+
} from '@erc725/erc725.js'
|
|
11
|
+
import { type Hex, isHex } from 'viem'
|
|
12
|
+
import { ARRAY_MAX, defaultSchema, IPFS_GATEWAY } from '../constants'
|
|
13
|
+
import { getDataFromExternalSources } from '../getDataFromExternalSources'
|
|
14
|
+
import type { Info } from '../types'
|
|
15
|
+
|
|
16
|
+
export const schemaDefaultPlugin = decodeKeyValuePlugin(defaultSchema)
|
|
17
|
+
export default schemaDefaultPlugin
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Decode key/value pair as per erc725 schema
|
|
21
|
+
* @param key
|
|
22
|
+
* @param value
|
|
23
|
+
* @returns
|
|
24
|
+
*/
|
|
25
|
+
export function decodeKeyValuePlugin(
|
|
26
|
+
defaultSchema: ERC725JSONSchema[],
|
|
27
|
+
process?: (output: Info) => Promise<Info>
|
|
28
|
+
) {
|
|
29
|
+
const preProcess = async (key: Hex, value: Hex): Promise<Info> => {
|
|
30
|
+
// Search for the schema entry.
|
|
31
|
+
const schema =
|
|
32
|
+
defaultSchema.find((item) => {
|
|
33
|
+
if (key === item.key) {
|
|
34
|
+
return true
|
|
35
|
+
}
|
|
36
|
+
const index = item.key.indexOf('<')
|
|
37
|
+
if (index !== -1) {
|
|
38
|
+
return key.slice(0, index) === item.key.slice(0, index)
|
|
39
|
+
}
|
|
40
|
+
return false
|
|
41
|
+
}) ||
|
|
42
|
+
defaultSchema.find((item) => {
|
|
43
|
+
if (key.slice(0, 34) === item.key.slice(0, 34)) {
|
|
44
|
+
return true
|
|
45
|
+
}
|
|
46
|
+
return false
|
|
47
|
+
})
|
|
48
|
+
if (schema) {
|
|
49
|
+
try {
|
|
50
|
+
// Get the raw name.
|
|
51
|
+
const name = schema.name.replace(/[:\[\]]|<.*?>/g, '')
|
|
52
|
+
if (schema.keyType === 'Array') {
|
|
53
|
+
if (schema.key === key) {
|
|
54
|
+
// Convert hex string to Uint8Array without using Buffer
|
|
55
|
+
const hexString = value.slice(2)
|
|
56
|
+
const all = new Uint8Array(hexString.length / 2)
|
|
57
|
+
for (let i = 0; i < hexString.length; i += 2) {
|
|
58
|
+
all[i / 2] = Number.parseInt(hexString.substring(i, i + 2), 16)
|
|
59
|
+
}
|
|
60
|
+
// Figure out the first and last byte of the value (this is to allow
|
|
61
|
+
// the older and newer ways to store the array length i.e. uint256, uint128 and so on.)
|
|
62
|
+
const [{ start, end } = { start: 0, end: 0 }] = all.reduce(
|
|
63
|
+
(
|
|
64
|
+
acc: Array<{ isZero: boolean; start: number; end: number }>,
|
|
65
|
+
byte,
|
|
66
|
+
index_
|
|
67
|
+
) => {
|
|
68
|
+
let isZero = byte === 0 || index_ === 0
|
|
69
|
+
const last = acc.at(-1)
|
|
70
|
+
let index = index_
|
|
71
|
+
if (
|
|
72
|
+
!last ||
|
|
73
|
+
last.isZero !== isZero ||
|
|
74
|
+
index === all.length - 1
|
|
75
|
+
) {
|
|
76
|
+
if (index === all.length - 1) {
|
|
77
|
+
index = all.length
|
|
78
|
+
} else if (index === 0) {
|
|
79
|
+
isZero = true
|
|
80
|
+
}
|
|
81
|
+
if (last) {
|
|
82
|
+
last.end = index
|
|
83
|
+
last.isZero = isZero
|
|
84
|
+
}
|
|
85
|
+
if (isZero) {
|
|
86
|
+
acc.push({
|
|
87
|
+
isZero,
|
|
88
|
+
start: index,
|
|
89
|
+
end: index === 0 ? index + 1 : index,
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return acc
|
|
94
|
+
},
|
|
95
|
+
[]
|
|
96
|
+
)
|
|
97
|
+
const picked =
|
|
98
|
+
Math.abs(end - all.length + 1) <= 4
|
|
99
|
+
? all.length + 1
|
|
100
|
+
: Math.abs(end - all.length / 2 + 1) <= 4
|
|
101
|
+
? all.length / 2
|
|
102
|
+
: end
|
|
103
|
+
const segment = value.slice(0, picked * 2 + 2)
|
|
104
|
+
const length = BigInt(segment)
|
|
105
|
+
if (length > ARRAY_MAX) {
|
|
106
|
+
// We don't support arrays larger than 1000. Inside of the indexer it's a problem because of a single array column
|
|
107
|
+
// and we had to pick some kind of maximum size to prevent the SQL from crashing.
|
|
108
|
+
return {
|
|
109
|
+
...schema,
|
|
110
|
+
type: 'Error',
|
|
111
|
+
key,
|
|
112
|
+
value: 'Array length too large',
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
...schema,
|
|
117
|
+
type: 'ArrayLength',
|
|
118
|
+
pretty: name,
|
|
119
|
+
value: Number(length),
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// Extract array index.
|
|
123
|
+
const index = BigInt(`0x${key.slice(34)}`)
|
|
124
|
+
if (index > ARRAY_MAX) {
|
|
125
|
+
return {
|
|
126
|
+
...schema,
|
|
127
|
+
type: 'Error',
|
|
128
|
+
key,
|
|
129
|
+
value: 'Array index too large',
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
let data =
|
|
133
|
+
value !== '0x'
|
|
134
|
+
? decodeValueContent(schema.valueContent, value)
|
|
135
|
+
: undefined
|
|
136
|
+
if (schema.valueContent.startsWith('0x')) {
|
|
137
|
+
data = data === schema.valueContent
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
...schema,
|
|
141
|
+
type: 'ArrayItem',
|
|
142
|
+
pretty: name,
|
|
143
|
+
dynamic: Number(index),
|
|
144
|
+
value: data,
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// Decode dynamic parts.
|
|
148
|
+
let dynamicKeyParts: string[] | string | undefined = undefined
|
|
149
|
+
if (isDynamicKeyName(schema.name)) {
|
|
150
|
+
dynamicKeyParts = decodeMappingKey(key, schema).map(({ value }) =>
|
|
151
|
+
isHex(value) ? (value as string).toLowerCase() : `${value}`
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
// Decode value
|
|
155
|
+
let rawData =
|
|
156
|
+
value !== '0x'
|
|
157
|
+
? (decodeData(
|
|
158
|
+
[
|
|
159
|
+
dynamicKeyParts
|
|
160
|
+
? {
|
|
161
|
+
keyName: schema.name,
|
|
162
|
+
dynamicKeyParts,
|
|
163
|
+
value,
|
|
164
|
+
}
|
|
165
|
+
: { keyName: schema.name, value },
|
|
166
|
+
],
|
|
167
|
+
defaultSchema
|
|
168
|
+
) as unknown as Record<string, unknown>[])
|
|
169
|
+
: [{ value: undefined }]
|
|
170
|
+
type Params = Parameters<typeof getDataFromExternalSources>
|
|
171
|
+
let data = rawData?.[0]?.value
|
|
172
|
+
// Some special cases.
|
|
173
|
+
if (schema.name === 'LSP8TokenMetadataBaseURI') {
|
|
174
|
+
const { url: _url } = (data as { url: string | undefined }) || {}
|
|
175
|
+
const url = _url?.replace(/\0*$/g, '')
|
|
176
|
+
if (!url && url?.includes('\0')) {
|
|
177
|
+
return {
|
|
178
|
+
...schema,
|
|
179
|
+
pretty: name,
|
|
180
|
+
type: 'Error',
|
|
181
|
+
key,
|
|
182
|
+
value: 'Invalid URL (contains \\0)',
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return { ...schema, type: 'Value', name, value: url }
|
|
186
|
+
}
|
|
187
|
+
if (data && typeof data === 'object' && !Array.isArray(data)) {
|
|
188
|
+
const { url: _url } = (data as { url: string | undefined }) || {}
|
|
189
|
+
const url = _url?.replace(/\0*$/g, '')
|
|
190
|
+
if (!url || url?.includes('\0')) {
|
|
191
|
+
const newURL = url?.replace(/\0/g, '\\0')
|
|
192
|
+
const { error, data, method } = rawData?.[0] as {
|
|
193
|
+
error: string
|
|
194
|
+
data?: string
|
|
195
|
+
method?: string
|
|
196
|
+
url?: string
|
|
197
|
+
}
|
|
198
|
+
return {
|
|
199
|
+
...schema,
|
|
200
|
+
pretty: name,
|
|
201
|
+
type: 'Error',
|
|
202
|
+
key,
|
|
203
|
+
value: `${error ? `${error} ` : ''}Invalid URL (contains \\0 ${newURL})`,
|
|
204
|
+
data,
|
|
205
|
+
method,
|
|
206
|
+
url: newURL,
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
const newURL = (data as { url: string }).url.replace(
|
|
210
|
+
'https://2eff.lukso.dev/ipfs/',
|
|
211
|
+
'ipfs://'
|
|
212
|
+
)
|
|
213
|
+
if (newURL !== (data as { url: string }).url) {
|
|
214
|
+
;(data as { url: string }).url = newURL
|
|
215
|
+
}
|
|
216
|
+
rawData = (await getDataFromExternalSources(
|
|
217
|
+
defaultSchema,
|
|
218
|
+
rawData as unknown as DecodeDataOutput[],
|
|
219
|
+
IPFS_GATEWAY,
|
|
220
|
+
false
|
|
221
|
+
)) as unknown as Record<string, unknown>[]
|
|
222
|
+
if (rawData?.[0]?.error) {
|
|
223
|
+
const { error, data, method, url } = rawData?.[0] as {
|
|
224
|
+
error: string
|
|
225
|
+
data?: string
|
|
226
|
+
method?: string
|
|
227
|
+
url?: string
|
|
228
|
+
}
|
|
229
|
+
return {
|
|
230
|
+
...schema,
|
|
231
|
+
type: 'Error',
|
|
232
|
+
pretty: name,
|
|
233
|
+
value: error,
|
|
234
|
+
data,
|
|
235
|
+
method,
|
|
236
|
+
url,
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
data =
|
|
240
|
+
(rawData?.[0]?.value as Record<string, unknown>)?.[schema.name] ||
|
|
241
|
+
(rawData?.[0]?.value as Record<string, unknown>)
|
|
242
|
+
} else if (schema.valueContent.startsWith('0x')) {
|
|
243
|
+
data = data === schema.valueContent
|
|
244
|
+
}
|
|
245
|
+
const {
|
|
246
|
+
data: _data,
|
|
247
|
+
method,
|
|
248
|
+
src,
|
|
249
|
+
url,
|
|
250
|
+
} = rawData?.[0] as {
|
|
251
|
+
data?: string
|
|
252
|
+
method?: string
|
|
253
|
+
url?: string
|
|
254
|
+
src?: string
|
|
255
|
+
}
|
|
256
|
+
if (schema.name === 'AddressPermissions:Permissions:<address>') {
|
|
257
|
+
let _value: string | object = data as string | object
|
|
258
|
+
try {
|
|
259
|
+
const {
|
|
260
|
+
ERC4337_PERMISSION: _ignore1,
|
|
261
|
+
ALL_PERMISSIONS: _ignore2,
|
|
262
|
+
...rest
|
|
263
|
+
} = decodePermissions(data as Hex) as unknown as Permissions & {
|
|
264
|
+
ISRECOVERY?: boolean
|
|
265
|
+
}
|
|
266
|
+
if (Object.keys('rest').length === 1 && rest.ADDCONTROLLER) {
|
|
267
|
+
rest.ISRECOVERY = true
|
|
268
|
+
}
|
|
269
|
+
_value = rest
|
|
270
|
+
} catch {
|
|
271
|
+
// Ignore
|
|
272
|
+
}
|
|
273
|
+
return {
|
|
274
|
+
...schema,
|
|
275
|
+
type: 'Value',
|
|
276
|
+
pretty: name,
|
|
277
|
+
value: _value,
|
|
278
|
+
dynamic:
|
|
279
|
+
dynamicKeyParts?.length === 1
|
|
280
|
+
? dynamicKeyParts[0]
|
|
281
|
+
: dynamicKeyParts,
|
|
282
|
+
data: _data,
|
|
283
|
+
method,
|
|
284
|
+
src,
|
|
285
|
+
url,
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
return {
|
|
289
|
+
...schema,
|
|
290
|
+
type: 'Value',
|
|
291
|
+
pretty: name,
|
|
292
|
+
value: data,
|
|
293
|
+
dynamic:
|
|
294
|
+
dynamicKeyParts?.length === 1
|
|
295
|
+
? dynamicKeyParts[0]
|
|
296
|
+
: dynamicKeyParts,
|
|
297
|
+
data: _data,
|
|
298
|
+
method,
|
|
299
|
+
src,
|
|
300
|
+
url,
|
|
301
|
+
}
|
|
302
|
+
} catch (error) {
|
|
303
|
+
return { ...schema, type: 'Error', key, value: error as Error }
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
return { type: 'Undecoded', name: undefined, key, value }
|
|
307
|
+
}
|
|
308
|
+
return async (key: Hex, value: Hex) => {
|
|
309
|
+
try {
|
|
310
|
+
const result = await preProcess(key, value)
|
|
311
|
+
if (process) {
|
|
312
|
+
return await process(result)
|
|
313
|
+
}
|
|
314
|
+
return result
|
|
315
|
+
} catch {}
|
|
316
|
+
return undefined
|
|
317
|
+
}
|
|
318
|
+
}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import type { ERC725JSONSchema } from '@erc725/erc725.js'
|
|
2
|
+
import type { Abi, AbiParameter, Hex, Log, Transaction } from 'viem'
|
|
3
|
+
import { pluginRegistry } from '../registry'
|
|
4
|
+
import type {
|
|
5
|
+
Aggregation,
|
|
6
|
+
DecodeEventCallback,
|
|
7
|
+
DecodeEventResult,
|
|
8
|
+
DecoderOptions,
|
|
9
|
+
DecoderPlugin,
|
|
10
|
+
DecoderResult,
|
|
11
|
+
EnhancerAggregationKeyCallback,
|
|
12
|
+
EnhancerCallback,
|
|
13
|
+
EnhancerSummarizeCallback,
|
|
14
|
+
Info,
|
|
15
|
+
PluginOptions,
|
|
16
|
+
ResultType,
|
|
17
|
+
SchemaPlugin,
|
|
18
|
+
} from '../types'
|
|
19
|
+
import { customDecodeFunctionData } from '../utils'
|
|
20
|
+
import { decodeKeyValuePlugin } from './schemaDefault'
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Helper to create aggregation keys with plugin prefix
|
|
24
|
+
*/
|
|
25
|
+
export function createAggregationKey(
|
|
26
|
+
pluginOptions: PluginOptions,
|
|
27
|
+
key: string
|
|
28
|
+
): string {
|
|
29
|
+
return `${pluginOptions.name || pluginOptions.decoderName || 'unknown'}:${key}`
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
*
|
|
34
|
+
* @param abi abi to use for decoding
|
|
35
|
+
* @param pluginOptions options to name abi, decoder or module (optional since the enhancer can provide some or all)
|
|
36
|
+
* @param enhance callback to do the actual enhancement once the abi function was decoded.
|
|
37
|
+
* @returns enhanced transaction
|
|
38
|
+
*/
|
|
39
|
+
export function standardPlugin<T extends Abi | readonly unknown[]>(
|
|
40
|
+
abi: T,
|
|
41
|
+
pluginOptions: PluginOptions,
|
|
42
|
+
callbacks: {
|
|
43
|
+
enhance: EnhancerCallback
|
|
44
|
+
decodeEvent: DecodeEventCallback
|
|
45
|
+
overrideEnhance?: EnhancerCallback
|
|
46
|
+
getAggregationKey?: EnhancerAggregationKeyCallback
|
|
47
|
+
summarize?: EnhancerSummarizeCallback
|
|
48
|
+
aggregations?: Aggregation[]
|
|
49
|
+
}
|
|
50
|
+
): DecoderPlugin {
|
|
51
|
+
const {
|
|
52
|
+
abiName,
|
|
53
|
+
decoderName = 'unknown',
|
|
54
|
+
moduleHint,
|
|
55
|
+
required,
|
|
56
|
+
priority,
|
|
57
|
+
name,
|
|
58
|
+
usesAsync,
|
|
59
|
+
} = pluginOptions
|
|
60
|
+
const plugin: DecoderPlugin = {
|
|
61
|
+
enhance: async (transaction: DecoderResult, options: DecoderOptions) => {
|
|
62
|
+
if (callbacks.overrideEnhance) {
|
|
63
|
+
return await callbacks.overrideEnhance(
|
|
64
|
+
transaction,
|
|
65
|
+
pluginOptions,
|
|
66
|
+
options
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
const { preferError } = options
|
|
70
|
+
const {
|
|
71
|
+
to: _to,
|
|
72
|
+
from: _from,
|
|
73
|
+
value: _value,
|
|
74
|
+
input,
|
|
75
|
+
blockNumber: _blockNumber,
|
|
76
|
+
// logs,
|
|
77
|
+
} = transaction as Partial<Transaction> & {
|
|
78
|
+
data?: `0x${string}`
|
|
79
|
+
logs?: Log[]
|
|
80
|
+
}
|
|
81
|
+
const to = _to || undefined
|
|
82
|
+
const from = _from || undefined
|
|
83
|
+
const value = _value ? BigInt(_value) : 0n
|
|
84
|
+
const decoded = customDecodeFunctionData(
|
|
85
|
+
{
|
|
86
|
+
abi,
|
|
87
|
+
data: input || '0x',
|
|
88
|
+
},
|
|
89
|
+
preferError
|
|
90
|
+
)
|
|
91
|
+
if (!decoded) {
|
|
92
|
+
// Most of the time decoded will through an error,
|
|
93
|
+
// but if the result is undefined, then assume it also
|
|
94
|
+
// didn't work.
|
|
95
|
+
return
|
|
96
|
+
}
|
|
97
|
+
const { functionName, sig, args } = decoded as ResultType & {
|
|
98
|
+
sig?: `0x${string}`
|
|
99
|
+
functionName?: string
|
|
100
|
+
args: Array<AbiParameter & { value?: unknown }>
|
|
101
|
+
}
|
|
102
|
+
const output: DecoderResult = {
|
|
103
|
+
isDecoded: true,
|
|
104
|
+
...transaction,
|
|
105
|
+
resultType: 'execute',
|
|
106
|
+
functionName,
|
|
107
|
+
sig,
|
|
108
|
+
input,
|
|
109
|
+
__decoder: decoderName,
|
|
110
|
+
standard: abiName || 'unknown',
|
|
111
|
+
moduleHint,
|
|
112
|
+
args,
|
|
113
|
+
to,
|
|
114
|
+
from,
|
|
115
|
+
value,
|
|
116
|
+
} as DecoderResult
|
|
117
|
+
const enhanced = await callbacks.enhance(output, pluginOptions, options)
|
|
118
|
+
if (enhanced) {
|
|
119
|
+
return enhanced
|
|
120
|
+
}
|
|
121
|
+
return // This enhancement was denied by the enhancer so we need to re-try.
|
|
122
|
+
},
|
|
123
|
+
decodeEvent: async (log: DecodeEventResult, options: DecoderOptions) => {
|
|
124
|
+
return callbacks.decodeEvent(log, options)
|
|
125
|
+
},
|
|
126
|
+
getAggregationKey: async (result, pluginOptions, options) => {
|
|
127
|
+
if (!callbacks.getAggregationKey) {
|
|
128
|
+
return
|
|
129
|
+
}
|
|
130
|
+
return callbacks.getAggregationKey(result, pluginOptions, options)
|
|
131
|
+
},
|
|
132
|
+
summarize: async (aggregationKey, result, pluginOptions, options) => {
|
|
133
|
+
if (!callbacks.summarize) {
|
|
134
|
+
return
|
|
135
|
+
}
|
|
136
|
+
return callbacks.summarize(aggregationKey, result, pluginOptions, options)
|
|
137
|
+
},
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Add optional properties to the plugin
|
|
141
|
+
if (name !== undefined) {
|
|
142
|
+
plugin.name = name
|
|
143
|
+
}
|
|
144
|
+
if (required !== undefined) {
|
|
145
|
+
plugin.required = required
|
|
146
|
+
}
|
|
147
|
+
if (priority !== undefined) {
|
|
148
|
+
plugin.priority = priority
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (usesAsync !== undefined) {
|
|
152
|
+
plugin.usesAsync = usesAsync
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (callbacks.aggregations !== undefined) {
|
|
156
|
+
plugin.aggregations = callbacks.aggregations
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Freeze the plugin to prevent modifications
|
|
160
|
+
const frozenPlugin = Object.freeze(plugin)
|
|
161
|
+
|
|
162
|
+
// Auto-register the plugin if it has a name
|
|
163
|
+
// Use direct import of registry to avoid circular dependency
|
|
164
|
+
if (name) {
|
|
165
|
+
pluginRegistry.register(name, frozenPlugin, {
|
|
166
|
+
priority,
|
|
167
|
+
required,
|
|
168
|
+
usesAsync, // Include async flag for registration
|
|
169
|
+
})
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return frozenPlugin
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Creates a standard schema plugin from ERC725 schemas
|
|
177
|
+
* @param schemas Array of ERC725JSONSchema objects
|
|
178
|
+
* @param pluginOptions Options including name, required, priority
|
|
179
|
+
* @param process Optional post-processing function
|
|
180
|
+
* @returns SchemaPlugin
|
|
181
|
+
*/
|
|
182
|
+
export function standardSchemaPlugin(
|
|
183
|
+
schemas: ERC725JSONSchema[],
|
|
184
|
+
pluginOptions?: {
|
|
185
|
+
name?: string
|
|
186
|
+
required?: boolean
|
|
187
|
+
priority?: number
|
|
188
|
+
},
|
|
189
|
+
process?: (output: Info) => Promise<Info>
|
|
190
|
+
): SchemaPlugin {
|
|
191
|
+
const basePlugin = decodeKeyValuePlugin(schemas, process)
|
|
192
|
+
|
|
193
|
+
// Create a proper SchemaPlugin by assigning properties to the function
|
|
194
|
+
const plugin = Object.assign(basePlugin, {
|
|
195
|
+
name: pluginOptions?.name,
|
|
196
|
+
required: pluginOptions?.required,
|
|
197
|
+
priority: pluginOptions?.priority ?? 50,
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
// Freeze the plugin to prevent modifications
|
|
201
|
+
return Object.freeze(plugin)
|
|
202
|
+
}
|