@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,776 @@
|
|
|
1
|
+
import {
|
|
2
|
+
consumerModel,
|
|
3
|
+
decodeTransaction
|
|
4
|
+
} from "./chunk-GXZOF3QY.js";
|
|
5
|
+
import {
|
|
6
|
+
fetchMultipleAddresses
|
|
7
|
+
} from "./chunk-GGBHTWJL.js";
|
|
8
|
+
import {
|
|
9
|
+
__name,
|
|
10
|
+
collectDataKeys,
|
|
11
|
+
defaultPlugins,
|
|
12
|
+
defaultSchemaPlugins
|
|
13
|
+
} from "./chunk-XVHJWV5U.js";
|
|
14
|
+
|
|
15
|
+
// src/shared/cache.ts
|
|
16
|
+
function isPromise(value) {
|
|
17
|
+
return value instanceof Promise;
|
|
18
|
+
}
|
|
19
|
+
__name(isPromise, "isPromise");
|
|
20
|
+
function getDataKeyCacheKey(key) {
|
|
21
|
+
return key.toLowerCase();
|
|
22
|
+
}
|
|
23
|
+
__name(getDataKeyCacheKey, "getDataKeyCacheKey");
|
|
24
|
+
function dataKeyToString(dataKey) {
|
|
25
|
+
return dataKey;
|
|
26
|
+
}
|
|
27
|
+
__name(dataKeyToString, "dataKeyToString");
|
|
28
|
+
function parseDataKey(str) {
|
|
29
|
+
return str;
|
|
30
|
+
}
|
|
31
|
+
__name(parseDataKey, "parseDataKey");
|
|
32
|
+
function createMemoryAddressIdentityCache(ttlMs = 1e3 * 60 * 5) {
|
|
33
|
+
const cache = /* @__PURE__ */ new Map();
|
|
34
|
+
return {
|
|
35
|
+
get(key) {
|
|
36
|
+
const cacheKey = getDataKeyCacheKey(key);
|
|
37
|
+
const entry = cache.get(cacheKey);
|
|
38
|
+
if (!entry) return void 0;
|
|
39
|
+
if (Date.now() > entry.expires) {
|
|
40
|
+
cache.delete(cacheKey);
|
|
41
|
+
return void 0;
|
|
42
|
+
}
|
|
43
|
+
return entry.data;
|
|
44
|
+
},
|
|
45
|
+
set(key, value) {
|
|
46
|
+
const cacheKey = getDataKeyCacheKey(key);
|
|
47
|
+
cache.set(cacheKey, {
|
|
48
|
+
data: value,
|
|
49
|
+
expires: Date.now() + ttlMs
|
|
50
|
+
});
|
|
51
|
+
},
|
|
52
|
+
has(key) {
|
|
53
|
+
const cacheKey = getDataKeyCacheKey(key);
|
|
54
|
+
const entry = cache.get(cacheKey);
|
|
55
|
+
if (!entry) return false;
|
|
56
|
+
if (Date.now() > entry.expires) {
|
|
57
|
+
cache.delete(cacheKey);
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
return true;
|
|
61
|
+
},
|
|
62
|
+
getMany(keys) {
|
|
63
|
+
const results = /* @__PURE__ */ new Map();
|
|
64
|
+
for (const key of keys) {
|
|
65
|
+
const data = this.get(key);
|
|
66
|
+
if (data && !isPromise(data)) {
|
|
67
|
+
results.set(key, data);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return results;
|
|
71
|
+
},
|
|
72
|
+
setMany(entries) {
|
|
73
|
+
for (const [key, value] of entries) {
|
|
74
|
+
this.set(key, value);
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
clear() {
|
|
78
|
+
cache.clear();
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
__name(createMemoryAddressIdentityCache, "createMemoryAddressIdentityCache");
|
|
83
|
+
|
|
84
|
+
// src/client/resolveAddresses.ts
|
|
85
|
+
async function resolveAddresses(addresses, chain, options = {}) {
|
|
86
|
+
const {
|
|
87
|
+
endpoint = "/api/resolveAddresses",
|
|
88
|
+
cache,
|
|
89
|
+
batchSize = 100,
|
|
90
|
+
timeout = 1e4
|
|
91
|
+
} = options;
|
|
92
|
+
const results = /* @__PURE__ */ new Map();
|
|
93
|
+
if (addresses.length === 0) {
|
|
94
|
+
return results;
|
|
95
|
+
}
|
|
96
|
+
const uncachedAddresses = [];
|
|
97
|
+
if (cache) {
|
|
98
|
+
for (const addr of addresses) {
|
|
99
|
+
const cached = await cache.get(addr);
|
|
100
|
+
if (cached) {
|
|
101
|
+
results.set(addr, cached);
|
|
102
|
+
} else {
|
|
103
|
+
uncachedAddresses.push(addr);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (uncachedAddresses.length === 0) {
|
|
107
|
+
return results;
|
|
108
|
+
}
|
|
109
|
+
} else {
|
|
110
|
+
uncachedAddresses.push(...addresses);
|
|
111
|
+
}
|
|
112
|
+
const batches = [];
|
|
113
|
+
for (let i = 0; i < uncachedAddresses.length; i += batchSize) {
|
|
114
|
+
batches.push(uncachedAddresses.slice(i, i + batchSize));
|
|
115
|
+
}
|
|
116
|
+
const batchPromises = batches.map(async (batch) => {
|
|
117
|
+
try {
|
|
118
|
+
const apiAddresses = batch;
|
|
119
|
+
const controller = new AbortController();
|
|
120
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
121
|
+
const response = await fetch(endpoint, {
|
|
122
|
+
method: "POST",
|
|
123
|
+
headers: {
|
|
124
|
+
"Content-Type": "application/json"
|
|
125
|
+
},
|
|
126
|
+
body: JSON.stringify({
|
|
127
|
+
chainId: chain.id,
|
|
128
|
+
addresses: apiAddresses
|
|
129
|
+
}),
|
|
130
|
+
signal: controller.signal
|
|
131
|
+
});
|
|
132
|
+
clearTimeout(timeoutId);
|
|
133
|
+
if (!response.ok) {
|
|
134
|
+
console.error(
|
|
135
|
+
`Address resolution failed: ${response.status} ${response.statusText}`
|
|
136
|
+
);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const data = await response.json();
|
|
140
|
+
if (data.success && data.addresses) {
|
|
141
|
+
for (const [cacheKey, enhancedInfo] of Object.entries(data.addresses)) {
|
|
142
|
+
const matchingKey = batch.find(
|
|
143
|
+
(key) => getDataKeyCacheKey(key) === cacheKey
|
|
144
|
+
);
|
|
145
|
+
if (matchingKey) {
|
|
146
|
+
results.set(matchingKey, enhancedInfo);
|
|
147
|
+
if (cache) {
|
|
148
|
+
await cache.set(matchingKey, enhancedInfo);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
} catch (error) {
|
|
154
|
+
console.error("Failed to resolve addresses batch:", error);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
await Promise.all(batchPromises);
|
|
158
|
+
return results;
|
|
159
|
+
}
|
|
160
|
+
__name(resolveAddresses, "resolveAddresses");
|
|
161
|
+
function createApiAddressResolver(chain, options = {}) {
|
|
162
|
+
return async (addresses) => {
|
|
163
|
+
return resolveAddresses(addresses, chain, options);
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
__name(createApiAddressResolver, "createApiAddressResolver");
|
|
167
|
+
|
|
168
|
+
// src/core/addressResolver.ts
|
|
169
|
+
var AddressResolver = class {
|
|
170
|
+
static {
|
|
171
|
+
__name(this, "AddressResolver");
|
|
172
|
+
}
|
|
173
|
+
dataModel;
|
|
174
|
+
graphqlEndpoint;
|
|
175
|
+
batchSize;
|
|
176
|
+
batchDelay;
|
|
177
|
+
pendingAddresses = /* @__PURE__ */ new Set();
|
|
178
|
+
batchTimer;
|
|
179
|
+
cache;
|
|
180
|
+
constructor(config) {
|
|
181
|
+
this.dataModel = config.dataModel;
|
|
182
|
+
this.graphqlEndpoint = config.graphqlEndpoint;
|
|
183
|
+
this.batchSize = config.batchSize || 50;
|
|
184
|
+
this.batchDelay = config.batchDelay || 100;
|
|
185
|
+
this.cache = config.cache;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Start watching for missing addresses
|
|
189
|
+
*/
|
|
190
|
+
startWatching() {
|
|
191
|
+
setInterval(() => {
|
|
192
|
+
const missing = this.dataModel.getMissingKeys();
|
|
193
|
+
if (missing.length > 0) {
|
|
194
|
+
this.queueAddresses(missing);
|
|
195
|
+
}
|
|
196
|
+
}, 1e3);
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Queue addresses for batch resolution
|
|
200
|
+
*/
|
|
201
|
+
queueAddresses(addresses) {
|
|
202
|
+
for (const addr of addresses) {
|
|
203
|
+
this.pendingAddresses.add(addr);
|
|
204
|
+
}
|
|
205
|
+
if (this.batchTimer) {
|
|
206
|
+
clearTimeout(this.batchTimer);
|
|
207
|
+
}
|
|
208
|
+
this.batchTimer = setTimeout(() => {
|
|
209
|
+
this.processBatch();
|
|
210
|
+
}, this.batchDelay);
|
|
211
|
+
if (this.pendingAddresses.size >= this.batchSize) {
|
|
212
|
+
clearTimeout(this.batchTimer);
|
|
213
|
+
this.processBatch();
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Process a batch of addresses
|
|
218
|
+
*/
|
|
219
|
+
async processBatch() {
|
|
220
|
+
const batch = Array.from(this.pendingAddresses).slice(0, this.batchSize);
|
|
221
|
+
if (batch.length === 0) return;
|
|
222
|
+
for (const key of batch) {
|
|
223
|
+
this.pendingAddresses.delete(key);
|
|
224
|
+
}
|
|
225
|
+
const dataKeys = batch.map((key) => {
|
|
226
|
+
return key;
|
|
227
|
+
});
|
|
228
|
+
try {
|
|
229
|
+
const results = await fetchMultipleAddresses(
|
|
230
|
+
dataKeys,
|
|
231
|
+
this.graphqlEndpoint,
|
|
232
|
+
this.cache
|
|
233
|
+
);
|
|
234
|
+
const enhancedData = Array.from(results.values());
|
|
235
|
+
if (enhancedData.length > 0) {
|
|
236
|
+
this.dataModel.injectData(enhancedData);
|
|
237
|
+
}
|
|
238
|
+
} catch (error) {
|
|
239
|
+
console.error("Failed to resolve addresses:", error);
|
|
240
|
+
for (const key of dataKeys) {
|
|
241
|
+
this.dataModel.setError(key, "Failed to fetch address data");
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
if (this.pendingAddresses.size > 0) {
|
|
245
|
+
this.batchTimer = setTimeout(() => {
|
|
246
|
+
this.processBatch();
|
|
247
|
+
}, this.batchDelay);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Stop watching for addresses
|
|
252
|
+
*/
|
|
253
|
+
stopWatching() {
|
|
254
|
+
if (this.batchTimer) {
|
|
255
|
+
clearTimeout(this.batchTimer);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
// src/core/integrateDecoder.ts
|
|
261
|
+
import { effect } from "@preact/signals-core";
|
|
262
|
+
import { lukso } from "viem/chains";
|
|
263
|
+
var DecoderIntegration = class {
|
|
264
|
+
static {
|
|
265
|
+
__name(this, "DecoderIntegration");
|
|
266
|
+
}
|
|
267
|
+
dataModel;
|
|
268
|
+
decoderOptions;
|
|
269
|
+
addressCache;
|
|
270
|
+
constructor(config) {
|
|
271
|
+
this.dataModel = config.dataModel;
|
|
272
|
+
this.addressCache = config.addressCache;
|
|
273
|
+
this.decoderOptions = {
|
|
274
|
+
plugins: defaultPlugins,
|
|
275
|
+
schemaPlugins: defaultSchemaPlugins,
|
|
276
|
+
wrappers: [],
|
|
277
|
+
chain: config.decoderOptions?.chain || lukso,
|
|
278
|
+
...config.decoderOptions
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Add and decode a transaction
|
|
283
|
+
* @param transaction - Raw transaction data
|
|
284
|
+
* @returns Transaction signal that updates as decoding progresses
|
|
285
|
+
*/
|
|
286
|
+
async addAndDecodeTransaction(transaction) {
|
|
287
|
+
const signal = this.dataModel.addTransactions(transaction);
|
|
288
|
+
const transactionOptions = {
|
|
289
|
+
...this.decoderOptions,
|
|
290
|
+
wrappers: []
|
|
291
|
+
// Fresh array for collecting wrappers in this decode hierarchy
|
|
292
|
+
};
|
|
293
|
+
const { signal: decodingSignal } = await decodeTransaction(
|
|
294
|
+
transaction,
|
|
295
|
+
transactionOptions
|
|
296
|
+
);
|
|
297
|
+
effect(() => {
|
|
298
|
+
const state = decodingSignal.value;
|
|
299
|
+
if (state.data) {
|
|
300
|
+
const decodedResult = state.data;
|
|
301
|
+
if (transactionOptions.wrappers.length > 0) {
|
|
302
|
+
if ("wrappers" in decodedResult && typeof decodedResult === "object") {
|
|
303
|
+
;
|
|
304
|
+
decodedResult.wrappers = transactionOptions.wrappers;
|
|
305
|
+
}
|
|
306
|
+
for (const wrapper of transactionOptions.wrappers) {
|
|
307
|
+
this.updateAddressesFromDecoded(wrapper);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
const processedResult = this.flattenBatchTransactions(decodedResult);
|
|
311
|
+
if (transaction.hash) {
|
|
312
|
+
this.dataModel.updateTransactionData(
|
|
313
|
+
transaction.hash,
|
|
314
|
+
processedResult,
|
|
315
|
+
0
|
|
316
|
+
// decoder index
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
this.updateAddressesFromDecoded(processedResult);
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
return signal;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Add and decode multiple transactions
|
|
326
|
+
* @param transactions - Array of raw transactions
|
|
327
|
+
* @returns Array of transaction signals
|
|
328
|
+
*/
|
|
329
|
+
async addAndDecodeTransactions(transactions) {
|
|
330
|
+
const signals = this.dataModel.addTransactions(transactions);
|
|
331
|
+
const decodingPromises = transactions.map(async (tx, index) => {
|
|
332
|
+
const transactionOptions = {
|
|
333
|
+
...this.decoderOptions,
|
|
334
|
+
wrappers: []
|
|
335
|
+
// Fresh array for collecting wrappers in this decode hierarchy
|
|
336
|
+
};
|
|
337
|
+
const { signal: decodingSignal } = await decodeTransaction(
|
|
338
|
+
tx,
|
|
339
|
+
transactionOptions
|
|
340
|
+
);
|
|
341
|
+
effect(() => {
|
|
342
|
+
const state = decodingSignal.value;
|
|
343
|
+
if (state.data) {
|
|
344
|
+
const decodedResult = state.data;
|
|
345
|
+
if (transactionOptions.wrappers.length > 0) {
|
|
346
|
+
if ("wrappers" in decodedResult && typeof decodedResult === "object") {
|
|
347
|
+
;
|
|
348
|
+
decodedResult.wrappers = transactionOptions.wrappers;
|
|
349
|
+
}
|
|
350
|
+
for (const wrapper of transactionOptions.wrappers) {
|
|
351
|
+
this.updateAddressesFromDecoded(wrapper);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
const processedResult = this.flattenBatchTransactions(decodedResult);
|
|
355
|
+
if (tx.hash) {
|
|
356
|
+
this.dataModel.updateTransactionData(
|
|
357
|
+
tx.hash,
|
|
358
|
+
processedResult,
|
|
359
|
+
0
|
|
360
|
+
// decoder index
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
this.updateAddressesFromDecoded(processedResult);
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
return decodingSignal;
|
|
367
|
+
});
|
|
368
|
+
await Promise.all(decodingPromises);
|
|
369
|
+
return signals;
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Extract and register addresses from decoded transaction data
|
|
373
|
+
*/
|
|
374
|
+
async updateAddressesFromDecoded(decodedData) {
|
|
375
|
+
const addresses = collectDataKeys(decodedData);
|
|
376
|
+
for (const address of addresses) {
|
|
377
|
+
if (this.addressCache) {
|
|
378
|
+
const cached = await this.addressCache.get(address);
|
|
379
|
+
if (cached) {
|
|
380
|
+
this.dataModel.updateData(cached);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
this.dataModel.getAddress(address);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Flatten nested batch transactions
|
|
388
|
+
* If a batch contains another batch as a child, flatten all sub-transactions into the parent's children
|
|
389
|
+
*
|
|
390
|
+
* Structure:
|
|
391
|
+
* - Wrappers: The "invisible" execute functions (execute, executeRelayCall, etc.) that wrap the actual transaction
|
|
392
|
+
* - Children: The actual transactions being executed
|
|
393
|
+
*
|
|
394
|
+
* Result:
|
|
395
|
+
* - Single transaction: { resultType: 'execute', wrappers: [...] }
|
|
396
|
+
* - Batch transaction: { resultType: 'executeBatch', children: [flat list], wrappers: [...] }
|
|
397
|
+
*
|
|
398
|
+
* This ensures only ONE level of batch with all transactions flattened
|
|
399
|
+
*/
|
|
400
|
+
flattenBatchTransactions(result) {
|
|
401
|
+
if (result.resultType !== "executeBatch" && result.resultType !== "setDataBatch") {
|
|
402
|
+
return result;
|
|
403
|
+
}
|
|
404
|
+
if (!("children" in result) || !Array.isArray(result.children)) {
|
|
405
|
+
return result;
|
|
406
|
+
}
|
|
407
|
+
const flattenedChildren = [];
|
|
408
|
+
for (const child of result.children) {
|
|
409
|
+
if (typeof child === "object" && child && "resultType" in child) {
|
|
410
|
+
const childResult = child;
|
|
411
|
+
if (childResult.resultType === "executeBatch" || childResult.resultType === "setDataBatch") {
|
|
412
|
+
if ("children" in childResult && Array.isArray(childResult.children)) {
|
|
413
|
+
flattenedChildren.push(...childResult.children);
|
|
414
|
+
}
|
|
415
|
+
} else {
|
|
416
|
+
flattenedChildren.push(child);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
return {
|
|
421
|
+
...result,
|
|
422
|
+
children: flattenedChildren
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Load missing address data
|
|
427
|
+
* This would be called by an external service that fetches address data
|
|
428
|
+
*/
|
|
429
|
+
async loadAddressData(addressData) {
|
|
430
|
+
this.dataModel.injectData(addressData);
|
|
431
|
+
if (this.addressCache) {
|
|
432
|
+
await Promise.all(
|
|
433
|
+
addressData.map((data) => {
|
|
434
|
+
const key = data.tokenId ? `${data.address}:${data.tokenId}` : data.address;
|
|
435
|
+
return this.addressCache?.set(key, data) ?? Promise.resolve();
|
|
436
|
+
})
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Get addresses that need to be fetched
|
|
442
|
+
*/
|
|
443
|
+
getMissingAddresses() {
|
|
444
|
+
return this.dataModel.getMissingKeys();
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Get addresses currently being loaded
|
|
448
|
+
*/
|
|
449
|
+
getLoadingAddresses() {
|
|
450
|
+
return this.dataModel.getLoadingKeys();
|
|
451
|
+
}
|
|
452
|
+
};
|
|
453
|
+
function createMemoryAddressCache() {
|
|
454
|
+
const cache = /* @__PURE__ */ new Map();
|
|
455
|
+
return {
|
|
456
|
+
async get(key) {
|
|
457
|
+
return cache.get(key);
|
|
458
|
+
},
|
|
459
|
+
async set(key, value) {
|
|
460
|
+
cache.set(key, value);
|
|
461
|
+
},
|
|
462
|
+
async has(key) {
|
|
463
|
+
return cache.has(key);
|
|
464
|
+
},
|
|
465
|
+
async delete(key) {
|
|
466
|
+
cache.delete(key);
|
|
467
|
+
},
|
|
468
|
+
async clear() {
|
|
469
|
+
cache.clear();
|
|
470
|
+
}
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
__name(createMemoryAddressCache, "createMemoryAddressCache");
|
|
474
|
+
|
|
475
|
+
// src/server/lsp23Resolver.ts
|
|
476
|
+
import {
|
|
477
|
+
bytesToHex,
|
|
478
|
+
decodeAbiParameters,
|
|
479
|
+
isHex,
|
|
480
|
+
parseAbiParameters
|
|
481
|
+
} from "viem";
|
|
482
|
+
var LSP23_FACTORY_ADDRESS = "0x2300000a84d25df63081feaa37ba6b62c4c89a30";
|
|
483
|
+
var DEPLOY_ERC1167_PROXIES_SELECTOR = "0x6a66a753";
|
|
484
|
+
function decodeDeploymentCalldata(input) {
|
|
485
|
+
try {
|
|
486
|
+
const params = `0x${input.slice(10)}`;
|
|
487
|
+
const decoded = decodeAbiParameters(
|
|
488
|
+
parseAbiParameters(
|
|
489
|
+
"(bytes32,uint256,address,bytes), (uint256,address,bytes,bool,bytes), address, bytes"
|
|
490
|
+
),
|
|
491
|
+
params
|
|
492
|
+
);
|
|
493
|
+
const [
|
|
494
|
+
primaryDeployment,
|
|
495
|
+
secondaryDeployment,
|
|
496
|
+
postDeploymentModule,
|
|
497
|
+
postDeploymentModuleCalldata
|
|
498
|
+
] = decoded;
|
|
499
|
+
const [salt, , primaryImplementation] = primaryDeployment;
|
|
500
|
+
const [, secondaryImplementation] = secondaryDeployment;
|
|
501
|
+
if (!primaryImplementation || !secondaryImplementation) {
|
|
502
|
+
return null;
|
|
503
|
+
}
|
|
504
|
+
return {
|
|
505
|
+
salt,
|
|
506
|
+
primaryImplementation,
|
|
507
|
+
secondaryImplementation,
|
|
508
|
+
postDeploymentModule,
|
|
509
|
+
initializationCalldata: postDeploymentModuleCalldata
|
|
510
|
+
};
|
|
511
|
+
} catch (error) {
|
|
512
|
+
console.error("Failed to decode LSP23 deployment calldata:", error);
|
|
513
|
+
return null;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
__name(decodeDeploymentCalldata, "decodeDeploymentCalldata");
|
|
517
|
+
function decodeDeploymentOutput(output) {
|
|
518
|
+
try {
|
|
519
|
+
const decoded = decodeAbiParameters(
|
|
520
|
+
parseAbiParameters("address, address"),
|
|
521
|
+
output
|
|
522
|
+
);
|
|
523
|
+
return {
|
|
524
|
+
profileAddress: decoded[0],
|
|
525
|
+
urdAddress: decoded[1]
|
|
526
|
+
};
|
|
527
|
+
} catch (error) {
|
|
528
|
+
console.error("Failed to decode LSP23 deployment output:", error);
|
|
529
|
+
return null;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
__name(decodeDeploymentOutput, "decodeDeploymentOutput");
|
|
533
|
+
function extractControllersFromInitCalldata(initializationCalldata) {
|
|
534
|
+
try {
|
|
535
|
+
if (!initializationCalldata || initializationCalldata === "0x") {
|
|
536
|
+
return [];
|
|
537
|
+
}
|
|
538
|
+
const decoded = decodeAbiParameters(
|
|
539
|
+
parseAbiParameters("bytes32[], bytes[]"),
|
|
540
|
+
initializationCalldata
|
|
541
|
+
);
|
|
542
|
+
const [dataKeys, dataValues] = decoded;
|
|
543
|
+
const controllers = [];
|
|
544
|
+
const ADDRESS_PERMISSIONS_ARRAY_PREFIX = "0xdf30dba06db6a30e65354d9a64c60986";
|
|
545
|
+
for (let i = 0; i < dataKeys.length; i++) {
|
|
546
|
+
const keyStr = dataKeys[i].toLowerCase();
|
|
547
|
+
if (keyStr.startsWith(ADDRESS_PERMISSIONS_ARRAY_PREFIX)) {
|
|
548
|
+
const value = dataValues[i];
|
|
549
|
+
const valueHex = isHex(value) ? value : bytesToHex(value);
|
|
550
|
+
if (valueHex.length === 42) {
|
|
551
|
+
const addr = valueHex;
|
|
552
|
+
if (addr !== "0x0000000000000000000000000000000000000000" && !controllers.some((c) => c.toLowerCase() === addr.toLowerCase())) {
|
|
553
|
+
controllers.push(addr);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
return controllers;
|
|
559
|
+
} catch (error) {
|
|
560
|
+
console.error("Failed to extract controllers from init calldata:", error);
|
|
561
|
+
return [];
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
__name(extractControllersFromInitCalldata, "extractControllersFromInitCalldata");
|
|
565
|
+
function buildLSP23DeploymentQuery(config) {
|
|
566
|
+
const {
|
|
567
|
+
controllerAddresses,
|
|
568
|
+
profileAddresses,
|
|
569
|
+
fromBlock = 0,
|
|
570
|
+
toBlock,
|
|
571
|
+
chainId
|
|
572
|
+
} = config;
|
|
573
|
+
if (profileAddresses && profileAddresses.length > 0) {
|
|
574
|
+
return {
|
|
575
|
+
from_block: fromBlock,
|
|
576
|
+
to_block: toBlock,
|
|
577
|
+
// Query CREATE2 traces where the created address is one of our profiles
|
|
578
|
+
traces: [
|
|
579
|
+
{
|
|
580
|
+
type: ["create2"],
|
|
581
|
+
to: profileAddresses.map((addr) => addr.toLowerCase())
|
|
582
|
+
}
|
|
583
|
+
],
|
|
584
|
+
// Also get the transactions to verify they're to the LSP23 factory
|
|
585
|
+
transactions: [
|
|
586
|
+
{
|
|
587
|
+
to: [LSP23_FACTORY_ADDRESS.toLowerCase()]
|
|
588
|
+
}
|
|
589
|
+
],
|
|
590
|
+
field_selection: {
|
|
591
|
+
transaction: ["hash", "from", "to", "input", "output", "block_number"],
|
|
592
|
+
trace: ["transaction_hash", "type", "from", "to"],
|
|
593
|
+
block: ["number", "timestamp"]
|
|
594
|
+
},
|
|
595
|
+
include_all_blocks: false
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
if (controllerAddresses && controllerAddresses.length > 0) {
|
|
599
|
+
return {
|
|
600
|
+
from_block: fromBlock,
|
|
601
|
+
to_block: toBlock,
|
|
602
|
+
// Query transactions to the LSP23 factory from our controllers
|
|
603
|
+
transactions: [
|
|
604
|
+
{
|
|
605
|
+
from: controllerAddresses.map((addr) => addr.toLowerCase()),
|
|
606
|
+
to: [LSP23_FACTORY_ADDRESS.toLowerCase()]
|
|
607
|
+
}
|
|
608
|
+
],
|
|
609
|
+
// Also get traces to see the CREATE2 operations
|
|
610
|
+
traces: [
|
|
611
|
+
{
|
|
612
|
+
type: ["create2"]
|
|
613
|
+
// No filter on 'to' - we'll match by transaction hash
|
|
614
|
+
}
|
|
615
|
+
],
|
|
616
|
+
field_selection: {
|
|
617
|
+
transaction: ["hash", "from", "to", "input", "output", "block_number"],
|
|
618
|
+
trace: ["transaction_hash", "type", "from", "to"],
|
|
619
|
+
block: ["number", "timestamp"]
|
|
620
|
+
},
|
|
621
|
+
include_all_blocks: false
|
|
622
|
+
};
|
|
623
|
+
}
|
|
624
|
+
throw new Error(
|
|
625
|
+
"Either profileAddresses or controllerAddresses must be provided"
|
|
626
|
+
);
|
|
627
|
+
}
|
|
628
|
+
__name(buildLSP23DeploymentQuery, "buildLSP23DeploymentQuery");
|
|
629
|
+
function parseLSP23DeploymentsFromHypersync(response, chainId, controllerAddresses) {
|
|
630
|
+
const deployments = [];
|
|
631
|
+
if (!response?.data) {
|
|
632
|
+
return deployments;
|
|
633
|
+
}
|
|
634
|
+
const blockTimestamps = /* @__PURE__ */ new Map();
|
|
635
|
+
for (const block of response.data.blocks || []) {
|
|
636
|
+
blockTimestamps.set(block.number, block.timestamp);
|
|
637
|
+
}
|
|
638
|
+
const txMap = /* @__PURE__ */ new Map();
|
|
639
|
+
for (const tx of response.data.transactions || []) {
|
|
640
|
+
if (tx.to?.toLowerCase() === LSP23_FACTORY_ADDRESS.toLowerCase() && tx.input?.startsWith(DEPLOY_ERC1167_PROXIES_SELECTOR)) {
|
|
641
|
+
txMap.set(tx.hash.toLowerCase(), tx);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
const create2Traces = /* @__PURE__ */ new Map();
|
|
645
|
+
for (const trace of response.data.traces || []) {
|
|
646
|
+
if (trace.type === "create2" && trace.to) {
|
|
647
|
+
create2Traces.set(
|
|
648
|
+
trace.transaction_hash.toLowerCase(),
|
|
649
|
+
trace.to
|
|
650
|
+
);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
const controllerSet = controllerAddresses ? new Set(controllerAddresses.map((addr) => addr.toLowerCase())) : null;
|
|
654
|
+
for (const [txHash, profileAddress] of create2Traces) {
|
|
655
|
+
const tx = txMap.get(txHash);
|
|
656
|
+
if (!tx) continue;
|
|
657
|
+
if (controllerSet && !controllerSet.has(tx.from.toLowerCase())) {
|
|
658
|
+
continue;
|
|
659
|
+
}
|
|
660
|
+
const decodedInput = decodeDeploymentCalldata(tx.input);
|
|
661
|
+
const decodedOutput = tx.output ? decodeDeploymentOutput(tx.output) : null;
|
|
662
|
+
if (!decodedInput || !decodedOutput) continue;
|
|
663
|
+
const blockTimestamp = blockTimestamps.get(tx.block_number) || 0;
|
|
664
|
+
deployments.push({
|
|
665
|
+
profileAddress: decodedOutput.profileAddress,
|
|
666
|
+
urdAddress: decodedOutput.urdAddress,
|
|
667
|
+
deployerAddress: tx.from,
|
|
668
|
+
// The controller that deployed this profile
|
|
669
|
+
salt: decodedInput.salt,
|
|
670
|
+
primaryImplementation: decodedInput.primaryImplementation,
|
|
671
|
+
secondaryImplementation: decodedInput.secondaryImplementation,
|
|
672
|
+
postDeploymentModule: decodedInput.postDeploymentModule,
|
|
673
|
+
initializationCalldata: decodedInput.initializationCalldata,
|
|
674
|
+
deploymentCalldata: tx.input,
|
|
675
|
+
// Full calldata to deployERC1167Proxies
|
|
676
|
+
transactionHash: tx.hash,
|
|
677
|
+
blockNumber: BigInt(tx.block_number),
|
|
678
|
+
blockTimestamp,
|
|
679
|
+
// Unix timestamp of the block
|
|
680
|
+
chainId
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
return deployments;
|
|
684
|
+
}
|
|
685
|
+
__name(parseLSP23DeploymentsFromHypersync, "parseLSP23DeploymentsFromHypersync");
|
|
686
|
+
|
|
687
|
+
// src/utils/json-bigint.ts
|
|
688
|
+
var JSONbigString = {
|
|
689
|
+
/**
|
|
690
|
+
* Stringify an object, converting BigInt values to strings with 'n' suffix
|
|
691
|
+
*/
|
|
692
|
+
stringify: /* @__PURE__ */ __name((obj, replacer, space) => {
|
|
693
|
+
return JSON.stringify(
|
|
694
|
+
obj,
|
|
695
|
+
(key, value) => {
|
|
696
|
+
if (typeof value === "bigint") {
|
|
697
|
+
return value.toString() + "n";
|
|
698
|
+
}
|
|
699
|
+
return value;
|
|
700
|
+
},
|
|
701
|
+
space
|
|
702
|
+
);
|
|
703
|
+
}, "stringify"),
|
|
704
|
+
/**
|
|
705
|
+
* Parse a JSON string, converting strings ending with 'n' back to BigInt
|
|
706
|
+
*/
|
|
707
|
+
parse: /* @__PURE__ */ __name((text) => {
|
|
708
|
+
return JSON.parse(text, (key, value) => {
|
|
709
|
+
if (typeof value === "string" && /^\d+n$/.test(value)) {
|
|
710
|
+
return BigInt(value.slice(0, -1));
|
|
711
|
+
}
|
|
712
|
+
return value;
|
|
713
|
+
});
|
|
714
|
+
}, "parse")
|
|
715
|
+
};
|
|
716
|
+
|
|
717
|
+
// src/index.ts
|
|
718
|
+
var getTransaction = consumerModel.getTransaction.bind(consumerModel);
|
|
719
|
+
var getTransactionByKey = consumerModel.getTransactionByKey.bind(consumerModel);
|
|
720
|
+
var getTransactionsByIndex = consumerModel.getTransactionsByIndex.bind(consumerModel);
|
|
721
|
+
var getTransactionHashByIndex = consumerModel.getTransactionHashByIndex.bind(consumerModel);
|
|
722
|
+
var getTransactionCount = consumerModel.getTransactionCount.bind(consumerModel);
|
|
723
|
+
var getDecodedCount = consumerModel.getDecodedCount.bind(consumerModel);
|
|
724
|
+
var getDecodedTransactions = consumerModel.getDecodedTransactions.bind(consumerModel);
|
|
725
|
+
var getTransactionsInOrder = consumerModel.getTransactionsInOrder.bind(consumerModel);
|
|
726
|
+
var getAddress = consumerModel.getAddress.bind(consumerModel);
|
|
727
|
+
var getSignal = consumerModel.getSignal.bind(consumerModel);
|
|
728
|
+
var subscribe = consumerModel.subscribe.bind(consumerModel);
|
|
729
|
+
var getState = consumerModel.getState.bind(consumerModel);
|
|
730
|
+
var hasData = consumerModel.hasData.bind(consumerModel);
|
|
731
|
+
var getData = consumerModel.getData.bind(consumerModel);
|
|
732
|
+
var isLoading = consumerModel.isLoading.bind(consumerModel);
|
|
733
|
+
var getError = consumerModel.getError.bind(consumerModel);
|
|
734
|
+
var getAllKeys = consumerModel.getAllKeys.bind(consumerModel);
|
|
735
|
+
var getAllData = consumerModel.getAllData.bind(consumerModel);
|
|
736
|
+
var getAllTransactions = consumerModel.getAllTransactions.bind(consumerModel);
|
|
737
|
+
|
|
738
|
+
export {
|
|
739
|
+
getDataKeyCacheKey,
|
|
740
|
+
dataKeyToString,
|
|
741
|
+
parseDataKey,
|
|
742
|
+
createMemoryAddressIdentityCache,
|
|
743
|
+
resolveAddresses,
|
|
744
|
+
createApiAddressResolver,
|
|
745
|
+
AddressResolver,
|
|
746
|
+
DecoderIntegration,
|
|
747
|
+
createMemoryAddressCache,
|
|
748
|
+
LSP23_FACTORY_ADDRESS,
|
|
749
|
+
DEPLOY_ERC1167_PROXIES_SELECTOR,
|
|
750
|
+
decodeDeploymentCalldata,
|
|
751
|
+
decodeDeploymentOutput,
|
|
752
|
+
extractControllersFromInitCalldata,
|
|
753
|
+
buildLSP23DeploymentQuery,
|
|
754
|
+
parseLSP23DeploymentsFromHypersync,
|
|
755
|
+
JSONbigString,
|
|
756
|
+
getTransaction,
|
|
757
|
+
getTransactionByKey,
|
|
758
|
+
getTransactionsByIndex,
|
|
759
|
+
getTransactionHashByIndex,
|
|
760
|
+
getTransactionCount,
|
|
761
|
+
getDecodedCount,
|
|
762
|
+
getDecodedTransactions,
|
|
763
|
+
getTransactionsInOrder,
|
|
764
|
+
getAddress,
|
|
765
|
+
getSignal,
|
|
766
|
+
subscribe,
|
|
767
|
+
getState,
|
|
768
|
+
hasData,
|
|
769
|
+
getData,
|
|
770
|
+
isLoading,
|
|
771
|
+
getError,
|
|
772
|
+
getAllKeys,
|
|
773
|
+
getAllData,
|
|
774
|
+
getAllTransactions
|
|
775
|
+
};
|
|
776
|
+
//# sourceMappingURL=chunk-LJ6ES5XF.js.map
|