@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,192 @@
1
+ import {
2
+ type Abi,
3
+ AbiDecodingDataSizeTooSmallError,
4
+ AbiEventSignatureEmptyTopicsError,
5
+ AbiEventSignatureNotFoundError,
6
+ type AbiParameter,
7
+ BaseError,
8
+ type Chain,
9
+ type ContractEventName,
10
+ type DecodeEventLogParameters,
11
+ type DecodeEventLogReturnType,
12
+ DecodeLogDataMismatch,
13
+ DecodeLogTopicsMismatch,
14
+ decodeAbiParameters,
15
+ type EventDefinition,
16
+ type Hex,
17
+ type Log,
18
+ size,
19
+ toEventSelector,
20
+ } from 'viem'
21
+ import { formatAbiItem } from 'viem/utils'
22
+ import type { ArrayArgs, DecodeEventResult } from './types'
23
+ import { createNamedArgs } from './utils'
24
+
25
+ const docsPath = '/docs/contract/decodeEventLog'
26
+
27
+ function decodeTopic({ param, value }: { param: AbiParameter; value: Hex }) {
28
+ if (
29
+ param.type === 'string' ||
30
+ param.type === 'bytes' ||
31
+ param.type === 'tuple' ||
32
+ param.type.match(/^(.*)\[(\d+)?\]$/)
33
+ )
34
+ return value
35
+ const decodedArg = decodeAbiParameters([param], value) || []
36
+ return decodedArg[0]
37
+ }
38
+
39
+ export type PositionOutOfBoundsErrorType = PositionOutOfBoundsError & {
40
+ name: 'PositionOutOfBoundsError'
41
+ }
42
+ export class PositionOutOfBoundsError extends BaseError {
43
+ constructor({ length, position }: { length: number; position: number }) {
44
+ super(
45
+ `Position \`${position}\` is out of bounds (\`0 < position < ${length}\`).`,
46
+ { name: 'PositionOutOfBoundsError' }
47
+ )
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Custom copy of decodeEventLog which can assemble named args.
53
+ * @param parameters
54
+ * @returns
55
+ */
56
+ export function customDecodeEventLog<
57
+ const abi extends Abi | readonly unknown[],
58
+ eventName extends ContractEventName<abi> | undefined = undefined,
59
+ topics extends Hex[] = Hex[],
60
+ data extends Hex | undefined = undefined,
61
+ strict extends boolean = true,
62
+ >(
63
+ parameters: DecodeEventLogParameters<abi, eventName, topics, data, strict>
64
+ ): DecodeEventLogReturnType<abi, eventName, topics, data, strict> {
65
+ const {
66
+ abi,
67
+ data,
68
+ strict: strict_,
69
+ topics,
70
+ } = parameters as DecodeEventLogParameters
71
+
72
+ const strict = strict_ ?? true
73
+ const [signature, ...argTopics] = topics
74
+ if (!signature) throw new AbiEventSignatureEmptyTopicsError({ docsPath })
75
+
76
+ const abiItem = (() => {
77
+ if (abi.length === 1) return abi[0]
78
+ return abi.find(
79
+ (x) =>
80
+ x.type === 'event' &&
81
+ signature === toEventSelector(formatAbiItem(x) as EventDefinition)
82
+ )
83
+ })()
84
+
85
+ if (!(abiItem && 'name' in abiItem) || abiItem.type !== 'event')
86
+ throw new AbiEventSignatureNotFoundError(signature, { docsPath })
87
+
88
+ const { name, inputs } = abiItem
89
+ const isUnnamed = inputs?.some((x) => !('name' in x && x.name))
90
+
91
+ let args: unknown[] | Record<string, unknown> = isUnnamed ? [] : {}
92
+
93
+ // Decode topics (indexed args).
94
+ const indexedInputs = inputs.filter((x) => 'indexed' in x && x.indexed)
95
+ for (let i = 0; i < indexedInputs.length; i++) {
96
+ const param = indexedInputs[i]
97
+ const topic = argTopics[i]
98
+ if (!topic)
99
+ throw new DecodeLogTopicsMismatch({
100
+ abiItem,
101
+ param: param as AbiParameter & { indexed: boolean },
102
+ })
103
+ if (isUnnamed && Array.isArray(args)) {
104
+ args[i] = decodeTopic({ param, value: topic })
105
+ } else if (!isUnnamed && !Array.isArray(args)) {
106
+ args[param.name || i] = decodeTopic({ param, value: topic })
107
+ }
108
+ }
109
+
110
+ // Decode data (non-indexed args).
111
+ const nonIndexedInputs = inputs.filter((x) => !('indexed' in x && x.indexed))
112
+ if (nonIndexedInputs.length > 0) {
113
+ if (data && data !== '0x') {
114
+ try {
115
+ const decodedData = decodeAbiParameters(nonIndexedInputs, data)
116
+ if (decodedData) {
117
+ if (isUnnamed && Array.isArray(args)) {
118
+ args = [...args, ...decodedData]
119
+ } else if (!isUnnamed && !Array.isArray(args)) {
120
+ for (let i = 0; i < nonIndexedInputs.length; i++) {
121
+ const name = nonIndexedInputs[i].name
122
+ if (name) {
123
+ args[name] = decodedData[i]
124
+ }
125
+ }
126
+ }
127
+ }
128
+ } catch (err) {
129
+ if (strict) {
130
+ if (
131
+ err instanceof AbiDecodingDataSizeTooSmallError ||
132
+ (err as { name?: string }).name === 'PositionOutOfBoundsError' // Unfortunately, this is not exported from viem
133
+ )
134
+ throw new DecodeLogDataMismatch({
135
+ abiItem,
136
+ data: data,
137
+ params: nonIndexedInputs,
138
+ size: size(data),
139
+ })
140
+ throw err
141
+ }
142
+ }
143
+ } else if (strict) {
144
+ throw new DecodeLogDataMismatch({
145
+ abiItem,
146
+ data: '0x',
147
+ params: nonIndexedInputs,
148
+ size: 0,
149
+ })
150
+ }
151
+ }
152
+ const { args: namedArgs } = createNamedArgs(
153
+ Array.isArray(args) ? args : Object.values(args),
154
+ inputs
155
+ )
156
+ return {
157
+ eventName: name,
158
+ args: namedArgs,
159
+ } as unknown as DecodeEventLogReturnType<abi, eventName, topics, data, strict>
160
+ }
161
+
162
+ /**
163
+ * Decode events
164
+ *
165
+ * @param log Transaction to decode (should have data/input)
166
+ * @returns Promise<ResultType>
167
+ */
168
+ export function decodeEvent<abi extends Abi | readonly unknown[] = Abi>(
169
+ chain: Chain,
170
+ abi: abi,
171
+ log: DecodeEventResult
172
+ ):
173
+ | ({
174
+ eventName: string
175
+ args: ArrayArgs
176
+ } & DecodeEventResult)
177
+ | undefined {
178
+ const { data: _data, address, ...rest } = log as Log
179
+
180
+ let lastError: Error | undefined
181
+ try {
182
+ const result = customDecodeEventLog({
183
+ abi,
184
+ data: _data,
185
+ topics: (log as Log).topics || [],
186
+ })
187
+ return { ...log, ...result } as unknown as {
188
+ eventName: string
189
+ args: ArrayArgs
190
+ } & DecodeEventResult
191
+ } catch {}
192
+ }
@@ -0,0 +1,344 @@
1
+ import {
2
+ type Abi,
3
+ type AbiParameter,
4
+ type Address,
5
+ type Chain,
6
+ decodeAbiParameters,
7
+ encodeAbiParameters,
8
+ getAddress,
9
+ isAddress,
10
+ isAddressEqual,
11
+ parseAbiParameters,
12
+ zeroAddress,
13
+ } from 'viem'
14
+ import { CacheKeyPrefix, makeCacheKey } from './cache'
15
+ import { FUNCTION_DICTIONARY_URL, OPENCHAIN_DICTIONARY_URL } from './constants'
16
+ import { createLRUCache } from './lruCache'
17
+ import type { DecoderOptions, ResultType } from './types'
18
+ import { createNamedArgs, customDecodeFunctionData } from './utils'
19
+
20
+ // Default cache for backward compatibility
21
+ const defaultCache = createLRUCache({
22
+ max: 500,
23
+ ttl: 60 * 1000, // 1 minute
24
+ errorTTL: 30 * 1000, // 30 seconds
25
+ })
26
+
27
+ /**
28
+ * Decode function parameter types from a function signature
29
+ *
30
+ * @param signature Function signature
31
+ * @returns Array of parameter types
32
+ * @throws Error if the signature is invalid
33
+ */
34
+ function generateNamedAbiParameters(signature: string): AbiParameter[] {
35
+ const start = signature.indexOf('(')
36
+ const end = signature.lastIndexOf(')')
37
+ if (start === -1 || end === -1 || end <= start) {
38
+ throw new Error(`Invalid signature: ${signature}`)
39
+ }
40
+
41
+ const paramString = signature.slice(start + 1, end)
42
+
43
+ const rawParams = parseAbiParameters(paramString) as AbiParameter[]
44
+
45
+ const assignNames = (params: AbiParameter[], prefix: string) => {
46
+ return params.map((param: AbiParameter, index: number) => {
47
+ const name = `${prefix}${index + 1}`
48
+ if (param.type === 'tuple' && 'components' in param) {
49
+ const components: AbiParameter[] = assignNames(
50
+ param.components as AbiParameter[],
51
+ `${name}_`
52
+ )
53
+ return { ...param, name, components } as AbiParameter
54
+ }
55
+ return { ...param, name } as AbiParameter
56
+ })
57
+ }
58
+
59
+ return assignNames(rawParams, 'arg')
60
+ }
61
+
62
+ export async function fetchAbi(
63
+ chain: Chain,
64
+ address: Address,
65
+ options?: DecoderOptions
66
+ ) {
67
+ const explorer = chain.blockExplorers?.default?.apiUrl
68
+ if (!explorer) return undefined
69
+
70
+ const cache = options?.cache ?? defaultCache
71
+ let key = getAddress(address)
72
+ const cacheKey = makeCacheKey(CacheKeyPrefix.ABI, key, String(chain.id))
73
+
74
+ return cache.getOrSet(
75
+ cacheKey,
76
+ async (signal) => {
77
+ let isProxy = false
78
+ let decoderVerifiedContract = false
79
+ let factoryName: string | undefined
80
+ const originalKey = key
81
+
82
+ const addressUrl = new URL(`/api/v2/addresses/${key}`, explorer)
83
+ const addressRes = await fetch(addressUrl, { signal })
84
+ if (addressRes.ok) {
85
+ const data = (await addressRes.json()) as {
86
+ implementations?: { address?: Address; address_hash?: Address }[]
87
+ is_contract?: boolean
88
+ is_verified?: boolean
89
+ proxy_type?: string
90
+ name?: string
91
+ }
92
+ const {
93
+ implementations: [
94
+ { address: _address, address_hash: _addressHash } = {},
95
+ ] = [],
96
+ is_contract,
97
+ is_verified: __decoderVerifiedContract,
98
+ proxy_type,
99
+ name: __factoryName,
100
+ } = data
101
+ const address = _address || _addressHash
102
+ factoryName = __factoryName
103
+ decoderVerifiedContract = Boolean(__decoderVerifiedContract || false)
104
+ if (
105
+ address &&
106
+ is_contract &&
107
+ proxy_type !== 'null' &&
108
+ proxy_type != null
109
+ ) {
110
+ key = address as `0x${string}`
111
+ isProxy = true // We resolved from proxy to implementation
112
+ }
113
+ }
114
+
115
+ if (!decoderVerifiedContract) {
116
+ // If the address is not a verified contract, return undefined
117
+ return undefined
118
+ }
119
+
120
+ const url = new URL(`/api/v2/smart-contracts/${key}`, explorer)
121
+ const res = await fetch(url, { signal })
122
+
123
+ if (!res.ok) {
124
+ return undefined
125
+ }
126
+
127
+ const result = await res.json()
128
+ const {
129
+ name = factoryName || 'UnknownName',
130
+ abi,
131
+ is_verified,
132
+ } = result || {}
133
+
134
+ if (abi && is_verified) {
135
+ return {
136
+ abi,
137
+ __decoderVerifiedContract: decoderVerifiedContract, // If we have an ABI, treat it as verified
138
+ __decoderIsProxy: isProxy,
139
+ name,
140
+ explorer,
141
+ }
142
+ }
143
+ return undefined
144
+ },
145
+ { signal: options?.signal }
146
+ ) as Promise<
147
+ | {
148
+ abi: Abi
149
+ __decoderVerifiedContract: boolean
150
+ __decoderIsProxy: boolean
151
+ name: string
152
+ explorer: string
153
+ }
154
+ | undefined
155
+ >
156
+ }
157
+
158
+ /**
159
+ * Gets a function signature. Returns an empty string if hexSignature
160
+ * is not provided or an error is thrown.
161
+ * If hexSignature is provided, it checks the cache storage.
162
+ * If the signature is not found, it fetches 4bytes dictionary and stores
163
+ * the result in the cache storage.
164
+ *
165
+ * @param string hexSignature - first 4 bytes of a payload
166
+ * @param boolean preferError - if true, prefer error signatures
167
+ * @returns function signature as a string
168
+ */
169
+ export const getFunctionSignature = async (
170
+ chain: Chain,
171
+ input?: `0x${string}`,
172
+ to?: `0x${string}`,
173
+ preferError = false,
174
+ options?: DecoderOptions
175
+ ): Promise<
176
+ ResultType & {
177
+ __decoder: string
178
+ __decoderVerifiedContract?: boolean
179
+ __decoderIsProxy?: boolean
180
+ standard?: string
181
+ }
182
+ > => {
183
+ // Remove 0x prefix
184
+ if (to && isAddress(to) && isAddressEqual(to, zeroAddress)) {
185
+ return {
186
+ __decoder: 'none',
187
+ standard: 'unknown',
188
+ to,
189
+ input,
190
+ resultType: 'raw',
191
+ }
192
+ }
193
+ const data = input?.slice(2) as string
194
+ // Get the first 8 chars (4 bytes) of the data
195
+ const selector = data.slice(0, 8)
196
+ if (selector) {
197
+ if (to) {
198
+ // Wait for cached or new promise to resolve
199
+ const info = await fetchAbi(chain, to, options)
200
+ if (info) {
201
+ // The explorer returned it as a verified abi.
202
+ // Use the returned abi to decode the function signature.
203
+ const decoded = customDecodeFunctionData({
204
+ abi: info.abi,
205
+ data: input || '0x',
206
+ }) as ResultType & {
207
+ sig?: `0x${string}`
208
+ functionName?: string
209
+ args: readonly unknown[]
210
+ }
211
+ if (decoded) {
212
+ return {
213
+ ...decoded,
214
+ __decoder: info.explorer,
215
+ __decoderVerifiedContract: info.__decoderVerifiedContract,
216
+ __decoderIsProxy: info.__decoderIsProxy,
217
+ standard: info.name,
218
+ }
219
+ }
220
+ }
221
+ }
222
+ // If we didn't resolve it yet, then try to fetch from one of the 4bytes dictionaries.
223
+ const cache = options?.cache ?? defaultCache
224
+ const cacheKey = makeCacheKey(CacheKeyPrefix.FUNCTION_SIGNATURE, selector)
225
+
226
+ const signatureEntry = cache.getOrSet(
227
+ cacheKey,
228
+ async (signal) => {
229
+ // Try our proxy first.
230
+ const url = `${OPENCHAIN_DICTIONARY_URL}?function=0x${selector}`
231
+ let __decoder = new URL(OPENCHAIN_DICTIONARY_URL).hostname
232
+
233
+ try {
234
+ const res = await fetch(url, { signal })
235
+ if (res.ok) {
236
+ const result = await res.json()
237
+ if (result) {
238
+ result.__decoder = __decoder
239
+ return result
240
+ }
241
+ }
242
+ } catch {
243
+ // Continue to fallback
244
+ }
245
+
246
+ // Fallback to function dictionary
247
+ __decoder = new URL(FUNCTION_DICTIONARY_URL).hostname
248
+ const fallbackRes = await fetch(
249
+ `${FUNCTION_DICTIONARY_URL}/${selector}`,
250
+ { signal }
251
+ )
252
+ if (!fallbackRes.ok) {
253
+ return undefined
254
+ }
255
+ const fallbackResult = await fallbackRes.json()
256
+ if (fallbackResult) {
257
+ fallbackResult.__decoder = __decoder
258
+ }
259
+ return fallbackResult
260
+ },
261
+ { signal: options?.signal }
262
+ )
263
+ // Wait for cached or new promise to resolve
264
+ // biome-ignore lint/suspicious/noExplicitAny: any is easier in this particular case
265
+ const methods = (await signatureEntry) as any
266
+ if (methods?.results?.length > 0) {
267
+ // We got one or more results.
268
+ let search = methods.results.reverse()
269
+ if (preferError) {
270
+ // In case we're preferring Errors,
271
+ // then look for all methods containing Error
272
+ // and put them first.
273
+ const withError = search.filter((result: Record<string, unknown>) =>
274
+ /Error/.test(result.text_signature as string)
275
+ )
276
+ const withoutError = search.filter(
277
+ (result: Record<string, unknown>) =>
278
+ !/Error/.test(result.text_signature as string)
279
+ )
280
+ search = [...withError, ...withoutError]
281
+ }
282
+ // Go through each one and try to encode/decode the data
283
+ // to make sure it works.
284
+ for (const result of search) {
285
+ try {
286
+ const params: AbiParameter[] = generateNamedAbiParameters(
287
+ result.text_signature || result.name
288
+ )
289
+ // Decode arguments according to function spec
290
+ const args = decodeAbiParameters(params, `0x${data.slice(8)}`)
291
+
292
+ // Build arg list (if there are bool values which are no 0 or 1 we can assume it's invalid)
293
+ // Other values are validated in encodeParameters.
294
+ const encodeArgs = Array.from({ length: params.length }).map(
295
+ (_val, index) => {
296
+ if (params[index].type === 'bool') {
297
+ const val = args[`${index}`]
298
+ if (val !== 1 && val !== 0 && val !== true && val !== false) {
299
+ // Due to javascript truthyness any non-empty or non-zero value is encoded as true without a problem.
300
+ // The output packet won't match but there is really no reason to even try.
301
+ throw new Error('Invalid boolean value')
302
+ }
303
+ }
304
+ if (params[index].type === 'address') {
305
+ const val = args[`${index}`] as `0x${string}`
306
+ if (!isAddress(val)) {
307
+ throw new Error(`Invalid address value ${val}`)
308
+ }
309
+ }
310
+ return args[`${index}`] ?? '0x'
311
+ }
312
+ )
313
+
314
+ // Re-encode according to function spec.
315
+ const newData = encodeAbiParameters(
316
+ params,
317
+ encodeArgs as never
318
+ ).slice(2)
319
+
320
+ if (data.slice(8) === newData) {
321
+ return {
322
+ resultType: 'execute',
323
+ standard: 'unknown',
324
+ sig: `0x${selector}`,
325
+ functionName: result.text_signature.replace(/\(.*$/, ''),
326
+ ...(args
327
+ ? {
328
+ ...createNamedArgs(encodeArgs, params),
329
+ }
330
+ : {}),
331
+ __decoder: methods.__decoder || FUNCTION_DICTIONARY_URL,
332
+ } as ResultType & {
333
+ __decoder: string
334
+ __decoderVerifiedContract?: boolean
335
+ }
336
+ }
337
+ } catch (error) {
338
+ // Ignore to try next record
339
+ }
340
+ }
341
+ }
342
+ }
343
+ return undefined
344
+ }