@d9-network/ink 1.0.2 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +96 -0
- package/dist/chunk-BiucMVzj.mjs +18 -0
- package/dist/index-DgYVGyHC.d.cts +593 -0
- package/dist/index-Doyoeg38.d.mts +591 -0
- package/dist/index.cjs +456 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +426 -127
- package/dist/index.d.mts +426 -127
- package/dist/index.mjs +437 -13
- package/dist/index.mjs.map +1 -1
- package/dist/indexer/index.cjs +11 -0
- package/dist/indexer/index.d.cts +2 -0
- package/dist/indexer/index.d.mts +2 -0
- package/dist/indexer/index.mjs +3 -0
- package/dist/indexer-Buc6flPW.cjs +572 -0
- package/dist/indexer-Buc6flPW.cjs.map +1 -0
- package/dist/indexer-C-EZviUx.mjs +449 -0
- package/dist/indexer-C-EZviUx.mjs.map +1 -0
- package/package.json +18 -2
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
import { t as __exportAll } from "./chunk-BiucMVzj.mjs";
|
|
2
|
+
import { ss58Encode } from "@polkadot-labs/hdkd-helpers";
|
|
3
|
+
import { blake2b } from "@noble/hashes/blake2.js";
|
|
4
|
+
import { D9_SS58_PREFIX, bytesToHex, hexToBytes, toD9Address } from "@d9-network/spec";
|
|
5
|
+
|
|
6
|
+
//#region src/selectors.ts
|
|
7
|
+
/**
|
|
8
|
+
* PSP22 standard selectors for quick reference
|
|
9
|
+
*
|
|
10
|
+
* These are derived from the PSP22 standard and are consistent across implementations.
|
|
11
|
+
* Use these when you need to quickly check if call data matches a specific PSP22 method.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* import { PSP22_SELECTORS, extractSelectorHex } from "@d9-network/ink";
|
|
16
|
+
*
|
|
17
|
+
* const selectorHex = extractSelectorHex(callData);
|
|
18
|
+
* if (selectorHex === PSP22_SELECTORS.transfer) {
|
|
19
|
+
* // This is a PSP22::transfer call
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
const PSP22_SELECTORS = {
|
|
24
|
+
totalSupply: "162df8c2",
|
|
25
|
+
balanceOf: "6568382f",
|
|
26
|
+
allowance: "4d47d921",
|
|
27
|
+
transfer: "db20f9f5",
|
|
28
|
+
transferFrom: "54b3c76e",
|
|
29
|
+
approve: "b20f1bbd",
|
|
30
|
+
increaseAllowance: "96d6b57a",
|
|
31
|
+
decreaseAllowance: "fecb57d5"
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Build a selector lookup map from contract metadata
|
|
35
|
+
*
|
|
36
|
+
* @param metadata - Contract metadata
|
|
37
|
+
* @returns Map of selector hex (without 0x) -> SelectorInfo
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* import { contracts } from "@d9-network/spec";
|
|
42
|
+
* import { buildSelectorMap } from "@d9-network/ink";
|
|
43
|
+
*
|
|
44
|
+
* const selectors = buildSelectorMap(contracts.usdt.metadata);
|
|
45
|
+
* const info = selectors.get("db20f9f5");
|
|
46
|
+
* if (info) {
|
|
47
|
+
* console.log(info.label); // "PSP22::transfer"
|
|
48
|
+
* }
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
function buildSelectorMap(metadata) {
|
|
52
|
+
const map = /* @__PURE__ */ new Map();
|
|
53
|
+
const messages = metadata.spec.messages;
|
|
54
|
+
for (const message of messages) {
|
|
55
|
+
const selectorHex = message.selector.startsWith("0x") ? message.selector.slice(2).toLowerCase() : message.selector.toLowerCase();
|
|
56
|
+
const selector = hexToBytes$1(selectorHex);
|
|
57
|
+
map.set(selectorHex, {
|
|
58
|
+
label: message.label,
|
|
59
|
+
selector,
|
|
60
|
+
selectorHex,
|
|
61
|
+
mutates: message.mutates,
|
|
62
|
+
payable: message.payable
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return map;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Build a reverse lookup map (label -> selector info)
|
|
69
|
+
*
|
|
70
|
+
* @param metadata - Contract metadata
|
|
71
|
+
* @returns Map of label -> SelectorInfo
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```ts
|
|
75
|
+
* const labelMap = buildLabelMap(contracts.usdt.metadata);
|
|
76
|
+
* const info = labelMap.get("PSP22::transfer");
|
|
77
|
+
* console.log(info?.selectorHex); // "db20f9f5"
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
function buildLabelMap(metadata) {
|
|
81
|
+
const map = /* @__PURE__ */ new Map();
|
|
82
|
+
const selectorMap = buildSelectorMap(metadata);
|
|
83
|
+
for (const info of selectorMap.values()) map.set(info.label, info);
|
|
84
|
+
return map;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Get selector for a message label
|
|
88
|
+
*
|
|
89
|
+
* @param metadata - Contract metadata
|
|
90
|
+
* @param label - Message label (e.g., "PSP22::transfer")
|
|
91
|
+
* @returns Selector info or null if not found
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```ts
|
|
95
|
+
* const info = getSelectorForLabel(contracts.usdt.metadata, "PSP22::transfer");
|
|
96
|
+
* console.log(info?.selectorHex); // "db20f9f5"
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
function getSelectorForLabel(metadata, label) {
|
|
100
|
+
return buildLabelMap(metadata).get(label) ?? null;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Get message label for a selector
|
|
104
|
+
*
|
|
105
|
+
* @param metadata - Contract metadata
|
|
106
|
+
* @param selector - Selector as Uint8Array or hex string (with or without 0x)
|
|
107
|
+
* @returns Selector info or null if not found
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```ts
|
|
111
|
+
* const info = getLabelForSelector(contracts.usdt.metadata, "db20f9f5");
|
|
112
|
+
* console.log(info?.label); // "PSP22::transfer"
|
|
113
|
+
*
|
|
114
|
+
* // Also works with Uint8Array
|
|
115
|
+
* const info2 = getLabelForSelector(contracts.usdt.metadata, callData.slice(0, 4));
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
function getLabelForSelector(metadata, selector) {
|
|
119
|
+
const selectorHex = normalizeSelector(selector);
|
|
120
|
+
return buildSelectorMap(metadata).get(selectorHex) ?? null;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Check if call data matches a specific message
|
|
124
|
+
*
|
|
125
|
+
* @param metadata - Contract metadata
|
|
126
|
+
* @param callData - Call data bytes or hex string
|
|
127
|
+
* @param label - Message label to check
|
|
128
|
+
* @returns True if the call data selector matches the label
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```ts
|
|
132
|
+
* if (isMessageCall(contracts.usdt.metadata, callData, "PSP22::transfer")) {
|
|
133
|
+
* // This is a transfer call
|
|
134
|
+
* }
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
137
|
+
function isMessageCall(metadata, callData, label) {
|
|
138
|
+
const bytes = typeof callData === "string" ? hexToBytes$1(callData) : callData;
|
|
139
|
+
if (bytes.length < 4) return false;
|
|
140
|
+
const callSelectorHex = bytesToHex$1(bytes.slice(0, 4));
|
|
141
|
+
const info = getSelectorForLabel(metadata, label);
|
|
142
|
+
return info !== null && info.selectorHex === callSelectorHex;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Check if call data matches a PSP22 method
|
|
146
|
+
*
|
|
147
|
+
* @param callData - Call data bytes or hex string
|
|
148
|
+
* @param method - PSP22 method name (e.g., "transfer", "transferFrom")
|
|
149
|
+
* @returns True if the call data selector matches the PSP22 method
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* ```ts
|
|
153
|
+
* if (isPSP22Call(callData, "transfer")) {
|
|
154
|
+
* // This is a PSP22::transfer call
|
|
155
|
+
* }
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
158
|
+
function isPSP22Call(callData, method) {
|
|
159
|
+
const bytes = typeof callData === "string" ? hexToBytes$1(callData) : callData;
|
|
160
|
+
if (bytes.length < 4) return false;
|
|
161
|
+
return bytesToHex$1(bytes.slice(0, 4)) === PSP22_SELECTORS[method];
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Get all selectors from contract metadata
|
|
165
|
+
*
|
|
166
|
+
* @param metadata - Contract metadata
|
|
167
|
+
* @returns Array of SelectorInfo for all messages
|
|
168
|
+
*/
|
|
169
|
+
function getAllSelectors(metadata) {
|
|
170
|
+
const selectorMap = buildSelectorMap(metadata);
|
|
171
|
+
return Array.from(selectorMap.values());
|
|
172
|
+
}
|
|
173
|
+
function normalizeSelector(selector) {
|
|
174
|
+
if (selector instanceof Uint8Array) return bytesToHex$1(selector);
|
|
175
|
+
return selector.startsWith("0x") ? selector.slice(2).toLowerCase() : selector.toLowerCase();
|
|
176
|
+
}
|
|
177
|
+
function hexToBytes$1(hex) {
|
|
178
|
+
const clean = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
179
|
+
const bytes = new Uint8Array(clean.length / 2);
|
|
180
|
+
for (let i = 0; i < bytes.length; i++) bytes[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);
|
|
181
|
+
return bytes;
|
|
182
|
+
}
|
|
183
|
+
function bytesToHex$1(bytes) {
|
|
184
|
+
let hex = "";
|
|
185
|
+
for (let i = 0; i < bytes.length; i++) hex += bytes[i].toString(16).padStart(2, "0");
|
|
186
|
+
return hex;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
//#endregion
|
|
190
|
+
//#region src/indexer/extrinsic-utils.ts
|
|
191
|
+
/**
|
|
192
|
+
* Extrinsic utilities for indexers
|
|
193
|
+
*
|
|
194
|
+
* Provides functions for computing extrinsic hashes and parsing contract calls
|
|
195
|
+
* from raw hex data, eliminating the need for manual hex manipulation.
|
|
196
|
+
*/
|
|
197
|
+
/**
|
|
198
|
+
* Compute the blake2b-256 hash of an extrinsic
|
|
199
|
+
*
|
|
200
|
+
* This is the standard way to compute extrinsic hashes on Substrate chains.
|
|
201
|
+
*
|
|
202
|
+
* @param extrinsicHex - The raw extrinsic as a hex string (with or without 0x prefix)
|
|
203
|
+
* @returns The extrinsic hash as a hex string with 0x prefix
|
|
204
|
+
*
|
|
205
|
+
* @example
|
|
206
|
+
* ```ts
|
|
207
|
+
* import { computeExtrinsicHash } from "@d9-network/ink/indexer";
|
|
208
|
+
*
|
|
209
|
+
* const extrinsicHex = "0x..."; // from getBlockBody()
|
|
210
|
+
* const hash = computeExtrinsicHash(extrinsicHex);
|
|
211
|
+
* // hash is "0xabcd..." (64 hex chars)
|
|
212
|
+
* ```
|
|
213
|
+
*/
|
|
214
|
+
function computeExtrinsicHash(extrinsicHex) {
|
|
215
|
+
return bytesToHex(blake2b(hexToBytes(extrinsicHex), { dkLen: 32 }));
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Attempt to find and extract contract call data from a raw extrinsic hex
|
|
219
|
+
*
|
|
220
|
+
* This function searches the extrinsic hex for patterns that look like
|
|
221
|
+
* contract call data (selector followed by SCALE-encoded arguments).
|
|
222
|
+
*
|
|
223
|
+
* @param extrinsicHex - The raw extrinsic hex
|
|
224
|
+
* @param selector - The 4-byte selector hex to search for (without 0x)
|
|
225
|
+
* @returns The call data starting from the selector, or null if not found
|
|
226
|
+
*/
|
|
227
|
+
function extractCallDataFromHex(extrinsicHex, selector) {
|
|
228
|
+
const hex = extrinsicHex.startsWith("0x") ? extrinsicHex.slice(2).toLowerCase() : extrinsicHex.toLowerCase();
|
|
229
|
+
const selectorLower = selector.toLowerCase();
|
|
230
|
+
const index = hex.indexOf(selectorLower);
|
|
231
|
+
if (index === -1) return null;
|
|
232
|
+
const callDataHex = hex.slice(index);
|
|
233
|
+
const bytes = new Uint8Array(callDataHex.length / 2);
|
|
234
|
+
for (let i = 0; i < bytes.length; i++) bytes[i] = parseInt(callDataHex.slice(i * 2, i * 2 + 2), 16);
|
|
235
|
+
return bytes;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Parse a contract call from raw hex extrinsic data
|
|
239
|
+
*
|
|
240
|
+
* This is useful for indexers that receive extrinsics as raw hex strings
|
|
241
|
+
* from `getBlockBody()` and need to decode specific contract calls.
|
|
242
|
+
*
|
|
243
|
+
* @param extrinsicHex - The raw extrinsic hex
|
|
244
|
+
* @param callParser - A ContractCallParser instance for the target contract
|
|
245
|
+
* @param options - Additional options and metadata
|
|
246
|
+
* @returns Parsed contract call or null if parsing fails
|
|
247
|
+
*
|
|
248
|
+
* @example
|
|
249
|
+
* ```ts
|
|
250
|
+
* import { parseContractCallFromHex, ContractCallParser } from "@d9-network/ink/indexer";
|
|
251
|
+
* import { contracts } from "@d9-network/spec";
|
|
252
|
+
*
|
|
253
|
+
* const parser = new ContractCallParser(contracts.usdt);
|
|
254
|
+
* const call = parseContractCallFromHex(extrinsicHex, parser, {
|
|
255
|
+
* contractAddress: USDT_ADDRESS,
|
|
256
|
+
* caller: signerAddress,
|
|
257
|
+
* });
|
|
258
|
+
*
|
|
259
|
+
* if (call?.type === "PSP22::transfer") {
|
|
260
|
+
* console.log(call.args.to, call.args.value);
|
|
261
|
+
* }
|
|
262
|
+
* ```
|
|
263
|
+
*/
|
|
264
|
+
function parseContractCallFromHex(extrinsicHex, callParser, options = {}) {
|
|
265
|
+
const selectorMap = callParser.getSelectorMap();
|
|
266
|
+
for (const [selectorHex] of selectorMap) {
|
|
267
|
+
const callData = extractCallDataFromHex(extrinsicHex, selectorHex);
|
|
268
|
+
if (!callData) continue;
|
|
269
|
+
const raw = {
|
|
270
|
+
data: callData,
|
|
271
|
+
contractAddress: options.contractAddress ? toD9Address(options.contractAddress) : void 0,
|
|
272
|
+
txHash: options.txHash,
|
|
273
|
+
blockNumber: options.blockNumber,
|
|
274
|
+
blockHash: options.blockHash
|
|
275
|
+
};
|
|
276
|
+
const result = callParser.parseCall(raw);
|
|
277
|
+
if (result) return result;
|
|
278
|
+
}
|
|
279
|
+
return null;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Extract selector hex from call data
|
|
283
|
+
*
|
|
284
|
+
* @param callData - Raw call data (Uint8Array or hex string)
|
|
285
|
+
* @returns 4-byte selector as hex string without 0x prefix, or null if too short
|
|
286
|
+
*/
|
|
287
|
+
function extractSelectorFromCallData(callData) {
|
|
288
|
+
let bytes;
|
|
289
|
+
if (callData instanceof Uint8Array) bytes = callData;
|
|
290
|
+
else {
|
|
291
|
+
const hex = callData.startsWith("0x") ? callData.slice(2) : callData;
|
|
292
|
+
if (hex.length < 8) return null;
|
|
293
|
+
return hex.slice(0, 8).toLowerCase();
|
|
294
|
+
}
|
|
295
|
+
if (bytes.length < 4) return null;
|
|
296
|
+
let result = "";
|
|
297
|
+
for (let i = 0; i < 4; i++) result += bytes[i].toString(16).padStart(2, "0");
|
|
298
|
+
return result;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Check if extrinsic contains a specific selector
|
|
302
|
+
*
|
|
303
|
+
* @param extrinsicHex - Raw extrinsic hex
|
|
304
|
+
* @param selector - Selector to check for (with or without 0x)
|
|
305
|
+
* @returns True if selector is found in the extrinsic
|
|
306
|
+
*/
|
|
307
|
+
function hasSelector(extrinsicHex, selector) {
|
|
308
|
+
const hex = extrinsicHex.startsWith("0x") ? extrinsicHex.slice(2).toLowerCase() : extrinsicHex.toLowerCase();
|
|
309
|
+
const selectorLower = selector.startsWith("0x") ? selector.slice(2).toLowerCase() : selector.toLowerCase();
|
|
310
|
+
return hex.includes(selectorLower);
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Check if extrinsic contains a PSP22 call
|
|
314
|
+
*
|
|
315
|
+
* @param extrinsicHex - Raw extrinsic hex
|
|
316
|
+
* @returns The PSP22 method name if found, null otherwise
|
|
317
|
+
*/
|
|
318
|
+
function findPSP22Selector(extrinsicHex) {
|
|
319
|
+
for (const [method, selector] of Object.entries(PSP22_SELECTORS)) if (hasSelector(extrinsicHex, selector)) return method;
|
|
320
|
+
return null;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
//#endregion
|
|
324
|
+
//#region src/indexer/psp22.ts
|
|
325
|
+
/**
|
|
326
|
+
* Decode a PSP22 transfer or transfer_from call from raw extrinsic hex
|
|
327
|
+
*
|
|
328
|
+
* This function handles the common case of extracting PSP22 token transfers
|
|
329
|
+
* from raw blockchain data without needing the full contract metadata.
|
|
330
|
+
*
|
|
331
|
+
* PSP22::transfer args: (to: AccountId, value: u128, data: Vec<u8>)
|
|
332
|
+
* PSP22::transfer_from args: (from: AccountId, to: AccountId, value: u128, data: Vec<u8>)
|
|
333
|
+
*
|
|
334
|
+
* @param extrinsicHex - The raw extrinsic hex
|
|
335
|
+
* @param caller - The transaction signer (used as 'from' for transfer)
|
|
336
|
+
* @param options - Decoding options
|
|
337
|
+
* @returns Decoded transfer or null if not a PSP22 transfer
|
|
338
|
+
*
|
|
339
|
+
* @example
|
|
340
|
+
* ```ts
|
|
341
|
+
* import { decodePSP22Transfer } from "@d9-network/ink/indexer";
|
|
342
|
+
*
|
|
343
|
+
* const transfer = decodePSP22Transfer(extrinsicHex, signerAddress);
|
|
344
|
+
* if (transfer) {
|
|
345
|
+
* console.log(`${transfer.from} -> ${transfer.to}: ${transfer.value}`);
|
|
346
|
+
* }
|
|
347
|
+
* ```
|
|
348
|
+
*/
|
|
349
|
+
function decodePSP22Transfer(extrinsicHex, caller, options = {}) {
|
|
350
|
+
const ss58Prefix = options.ss58Prefix ?? D9_SS58_PREFIX;
|
|
351
|
+
let callData = extractCallDataFromHex(extrinsicHex, PSP22_SELECTORS.transfer);
|
|
352
|
+
if (callData) return decodeTransfer(callData, caller, ss58Prefix);
|
|
353
|
+
callData = extractCallDataFromHex(extrinsicHex, PSP22_SELECTORS.transferFrom);
|
|
354
|
+
if (callData) return decodeTransferFrom(callData, ss58Prefix);
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Check if an extrinsic contains a PSP22 transfer call
|
|
359
|
+
*
|
|
360
|
+
* @param extrinsicHex - Raw extrinsic hex
|
|
361
|
+
* @returns True if contains PSP22::transfer or PSP22::transfer_from
|
|
362
|
+
*/
|
|
363
|
+
function isPSP22TransferExtrinsic(extrinsicHex) {
|
|
364
|
+
const hex = extrinsicHex.startsWith("0x") ? extrinsicHex.slice(2).toLowerCase() : extrinsicHex.toLowerCase();
|
|
365
|
+
return hex.includes(PSP22_SELECTORS.transfer) || hex.includes(PSP22_SELECTORS.transferFrom);
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Get the PSP22 transfer type from extrinsic hex
|
|
369
|
+
*
|
|
370
|
+
* @param extrinsicHex - Raw extrinsic hex
|
|
371
|
+
* @returns "transfer", "transfer_from", or null
|
|
372
|
+
*/
|
|
373
|
+
function getPSP22TransferType(extrinsicHex) {
|
|
374
|
+
const hex = extrinsicHex.startsWith("0x") ? extrinsicHex.slice(2).toLowerCase() : extrinsicHex.toLowerCase();
|
|
375
|
+
if (hex.includes(PSP22_SELECTORS.transferFrom)) return "transfer_from";
|
|
376
|
+
if (hex.includes(PSP22_SELECTORS.transfer)) return "transfer";
|
|
377
|
+
return null;
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Decode PSP22::transfer call data
|
|
381
|
+
* Args: (to: AccountId, value: u128, data: Vec<u8>)
|
|
382
|
+
*/
|
|
383
|
+
function decodeTransfer(callData, caller, ss58Prefix) {
|
|
384
|
+
if (callData.length < 52) return null;
|
|
385
|
+
try {
|
|
386
|
+
let offset = 4;
|
|
387
|
+
const toBytes = callData.slice(offset, offset + 32);
|
|
388
|
+
offset += 32;
|
|
389
|
+
const value = bytesToU128LE(callData.slice(offset, offset + 16));
|
|
390
|
+
return {
|
|
391
|
+
type: "transfer",
|
|
392
|
+
from: caller,
|
|
393
|
+
to: ss58Encode(toBytes, ss58Prefix),
|
|
394
|
+
value
|
|
395
|
+
};
|
|
396
|
+
} catch {
|
|
397
|
+
return null;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Decode PSP22::transfer_from call data
|
|
402
|
+
* Args: (from: AccountId, to: AccountId, value: u128, data: Vec<u8>)
|
|
403
|
+
*/
|
|
404
|
+
function decodeTransferFrom(callData, ss58Prefix) {
|
|
405
|
+
if (callData.length < 84) return null;
|
|
406
|
+
try {
|
|
407
|
+
let offset = 4;
|
|
408
|
+
const fromBytes = callData.slice(offset, offset + 32);
|
|
409
|
+
offset += 32;
|
|
410
|
+
const toBytes = callData.slice(offset, offset + 32);
|
|
411
|
+
offset += 32;
|
|
412
|
+
const value = bytesToU128LE(callData.slice(offset, offset + 16));
|
|
413
|
+
return {
|
|
414
|
+
type: "transfer_from",
|
|
415
|
+
from: ss58Encode(fromBytes, ss58Prefix),
|
|
416
|
+
to: ss58Encode(toBytes, ss58Prefix),
|
|
417
|
+
value
|
|
418
|
+
};
|
|
419
|
+
} catch {
|
|
420
|
+
return null;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Convert 16 bytes (little-endian) to bigint
|
|
425
|
+
*/
|
|
426
|
+
function bytesToU128LE(bytes) {
|
|
427
|
+
if (bytes.length !== 16) throw new Error("Expected 16 bytes for u128");
|
|
428
|
+
let result = 0n;
|
|
429
|
+
for (let i = 0; i < 16; i++) result |= BigInt(bytes[i]) << BigInt(i * 8);
|
|
430
|
+
return result;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
//#endregion
|
|
434
|
+
//#region src/indexer/index.ts
|
|
435
|
+
var indexer_exports = /* @__PURE__ */ __exportAll({
|
|
436
|
+
computeExtrinsicHash: () => computeExtrinsicHash,
|
|
437
|
+
decodePSP22Transfer: () => decodePSP22Transfer,
|
|
438
|
+
extractCallDataFromHex: () => extractCallDataFromHex,
|
|
439
|
+
extractSelectorFromCallData: () => extractSelectorFromCallData,
|
|
440
|
+
findPSP22Selector: () => findPSP22Selector,
|
|
441
|
+
getPSP22TransferType: () => getPSP22TransferType,
|
|
442
|
+
hasSelector: () => hasSelector,
|
|
443
|
+
isPSP22TransferExtrinsic: () => isPSP22TransferExtrinsic,
|
|
444
|
+
parseContractCallFromHex: () => parseContractCallFromHex
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
//#endregion
|
|
448
|
+
export { isMessageCall as _, computeExtrinsicHash as a, findPSP22Selector as c, PSP22_SELECTORS as d, buildLabelMap as f, getSelectorForLabel as g, getLabelForSelector as h, isPSP22TransferExtrinsic as i, hasSelector as l, getAllSelectors as m, decodePSP22Transfer as n, extractCallDataFromHex as o, buildSelectorMap as p, getPSP22TransferType as r, extractSelectorFromCallData as s, indexer_exports as t, parseContractCallFromHex as u, isPSP22Call as v };
|
|
449
|
+
//# sourceMappingURL=indexer-C-EZviUx.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"indexer-C-EZviUx.mjs","names":["hexToBytes","bytesToHex","raw: RawContractCall","bytes: Uint8Array"],"sources":["../src/selectors.ts","../src/indexer/extrinsic-utils.ts","../src/indexer/psp22.ts","../src/indexer/index.ts"],"sourcesContent":["/**\n * Selector utilities for ink! contracts\n *\n * Provides functions for looking up selectors by message label and vice versa,\n * as well as commonly used PSP22 standard selectors.\n */\n\nimport type { InkMetadata } from \"@polkadot-api/ink-contracts\";\n\n/**\n * Information about a contract message selector\n */\nexport interface SelectorInfo {\n /** Message label (e.g., \"PSP22::transfer\") */\n label: string;\n /** 4-byte selector */\n selector: Uint8Array;\n /** Hex string without 0x prefix (e.g., \"db20f9f5\") */\n selectorHex: string;\n /** Whether the message mutates state */\n mutates: boolean;\n /** Whether the message is payable */\n payable: boolean;\n}\n\n/**\n * PSP22 standard selectors for quick reference\n *\n * These are derived from the PSP22 standard and are consistent across implementations.\n * Use these when you need to quickly check if call data matches a specific PSP22 method.\n *\n * @example\n * ```ts\n * import { PSP22_SELECTORS, extractSelectorHex } from \"@d9-network/ink\";\n *\n * const selectorHex = extractSelectorHex(callData);\n * if (selectorHex === PSP22_SELECTORS.transfer) {\n * // This is a PSP22::transfer call\n * }\n * ```\n */\nexport const PSP22_SELECTORS = {\n /** PSP22::total_supply - 0x162df8c2 */\n totalSupply: \"162df8c2\",\n /** PSP22::balance_of - 0x6568382f */\n balanceOf: \"6568382f\",\n /** PSP22::allowance - 0x4d47d921 */\n allowance: \"4d47d921\",\n /** PSP22::transfer - 0xdb20f9f5 */\n transfer: \"db20f9f5\",\n /** PSP22::transfer_from - 0x54b3c76e */\n transferFrom: \"54b3c76e\",\n /** PSP22::approve - 0xb20f1bbd */\n approve: \"b20f1bbd\",\n /** PSP22::increase_allowance - 0x96d6b57a */\n increaseAllowance: \"96d6b57a\",\n /** PSP22::decrease_allowance - 0xfecb57d5 */\n decreaseAllowance: \"fecb57d5\",\n} as const;\n\n/**\n * PSP22 selector type for type safety\n */\nexport type PSP22SelectorKey = keyof typeof PSP22_SELECTORS;\n\n/**\n * Build a selector lookup map from contract metadata\n *\n * @param metadata - Contract metadata\n * @returns Map of selector hex (without 0x) -> SelectorInfo\n *\n * @example\n * ```ts\n * import { contracts } from \"@d9-network/spec\";\n * import { buildSelectorMap } from \"@d9-network/ink\";\n *\n * const selectors = buildSelectorMap(contracts.usdt.metadata);\n * const info = selectors.get(\"db20f9f5\");\n * if (info) {\n * console.log(info.label); // \"PSP22::transfer\"\n * }\n * ```\n */\nexport function buildSelectorMap(metadata: InkMetadata): Map<string, SelectorInfo> {\n const map = new Map<string, SelectorInfo>();\n\n const messages = metadata.spec.messages as Array<{\n label: string;\n selector: string;\n mutates: boolean;\n payable: boolean;\n }>;\n\n for (const message of messages) {\n const selectorHex = message.selector.startsWith(\"0x\")\n ? message.selector.slice(2).toLowerCase()\n : message.selector.toLowerCase();\n\n const selector = hexToBytes(selectorHex);\n\n map.set(selectorHex, {\n label: message.label,\n selector,\n selectorHex,\n mutates: message.mutates,\n payable: message.payable,\n });\n }\n\n return map;\n}\n\n/**\n * Build a reverse lookup map (label -> selector info)\n *\n * @param metadata - Contract metadata\n * @returns Map of label -> SelectorInfo\n *\n * @example\n * ```ts\n * const labelMap = buildLabelMap(contracts.usdt.metadata);\n * const info = labelMap.get(\"PSP22::transfer\");\n * console.log(info?.selectorHex); // \"db20f9f5\"\n * ```\n */\nexport function buildLabelMap(metadata: InkMetadata): Map<string, SelectorInfo> {\n const map = new Map<string, SelectorInfo>();\n const selectorMap = buildSelectorMap(metadata);\n\n for (const info of selectorMap.values()) {\n map.set(info.label, info);\n }\n\n return map;\n}\n\n/**\n * Get selector for a message label\n *\n * @param metadata - Contract metadata\n * @param label - Message label (e.g., \"PSP22::transfer\")\n * @returns Selector info or null if not found\n *\n * @example\n * ```ts\n * const info = getSelectorForLabel(contracts.usdt.metadata, \"PSP22::transfer\");\n * console.log(info?.selectorHex); // \"db20f9f5\"\n * ```\n */\nexport function getSelectorForLabel(\n metadata: InkMetadata,\n label: string\n): SelectorInfo | null {\n const labelMap = buildLabelMap(metadata);\n return labelMap.get(label) ?? null;\n}\n\n/**\n * Get message label for a selector\n *\n * @param metadata - Contract metadata\n * @param selector - Selector as Uint8Array or hex string (with or without 0x)\n * @returns Selector info or null if not found\n *\n * @example\n * ```ts\n * const info = getLabelForSelector(contracts.usdt.metadata, \"db20f9f5\");\n * console.log(info?.label); // \"PSP22::transfer\"\n *\n * // Also works with Uint8Array\n * const info2 = getLabelForSelector(contracts.usdt.metadata, callData.slice(0, 4));\n * ```\n */\nexport function getLabelForSelector(\n metadata: InkMetadata,\n selector: Uint8Array | string\n): SelectorInfo | null {\n const selectorHex = normalizeSelector(selector);\n const selectorMap = buildSelectorMap(metadata);\n return selectorMap.get(selectorHex) ?? null;\n}\n\n/**\n * Check if call data matches a specific message\n *\n * @param metadata - Contract metadata\n * @param callData - Call data bytes or hex string\n * @param label - Message label to check\n * @returns True if the call data selector matches the label\n *\n * @example\n * ```ts\n * if (isMessageCall(contracts.usdt.metadata, callData, \"PSP22::transfer\")) {\n * // This is a transfer call\n * }\n * ```\n */\nexport function isMessageCall(\n metadata: InkMetadata,\n callData: Uint8Array | string,\n label: string\n): boolean {\n const bytes = typeof callData === \"string\" ? hexToBytes(callData) : callData;\n if (bytes.length < 4) return false;\n\n const callSelectorHex = bytesToHex(bytes.slice(0, 4));\n const info = getSelectorForLabel(metadata, label);\n\n return info !== null && info.selectorHex === callSelectorHex;\n}\n\n/**\n * Check if call data matches a PSP22 method\n *\n * @param callData - Call data bytes or hex string\n * @param method - PSP22 method name (e.g., \"transfer\", \"transferFrom\")\n * @returns True if the call data selector matches the PSP22 method\n *\n * @example\n * ```ts\n * if (isPSP22Call(callData, \"transfer\")) {\n * // This is a PSP22::transfer call\n * }\n * ```\n */\nexport function isPSP22Call(\n callData: Uint8Array | string,\n method: PSP22SelectorKey\n): boolean {\n const bytes = typeof callData === \"string\" ? hexToBytes(callData) : callData;\n if (bytes.length < 4) return false;\n\n const callSelectorHex = bytesToHex(bytes.slice(0, 4));\n return callSelectorHex === PSP22_SELECTORS[method];\n}\n\n/**\n * Get all selectors from contract metadata\n *\n * @param metadata - Contract metadata\n * @returns Array of SelectorInfo for all messages\n */\nexport function getAllSelectors(metadata: InkMetadata): SelectorInfo[] {\n const selectorMap = buildSelectorMap(metadata);\n return Array.from(selectorMap.values());\n}\n\n// Internal helpers\n\nfunction normalizeSelector(selector: Uint8Array | string): string {\n if (selector instanceof Uint8Array) {\n return bytesToHex(selector);\n }\n // Remove 0x prefix if present and lowercase\n return selector.startsWith(\"0x\")\n ? selector.slice(2).toLowerCase()\n : selector.toLowerCase();\n}\n\nfunction hexToBytes(hex: string): Uint8Array {\n const clean = hex.startsWith(\"0x\") ? hex.slice(2) : hex;\n const bytes = new Uint8Array(clean.length / 2);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);\n }\n return bytes;\n}\n\nfunction bytesToHex(bytes: Uint8Array): string {\n let hex = \"\";\n for (let i = 0; i < bytes.length; i++) {\n hex += bytes[i]!.toString(16).padStart(2, \"0\");\n }\n return hex;\n}\n","/**\n * Extrinsic utilities for indexers\n *\n * Provides functions for computing extrinsic hashes and parsing contract calls\n * from raw hex data, eliminating the need for manual hex manipulation.\n */\n\nimport { blake2b } from \"@noble/hashes/blake2.js\";\nimport type { HexString, SS58String } from \"polkadot-api\";\nimport { hexToBytes, bytesToHex, toD9Address } from \"@d9-network/spec\";\nimport { PSP22_SELECTORS } from \"../selectors\";\nimport type { ContractCallParser } from \"../calls\";\nimport type { TypedContractCall, RawContractCall } from \"../call-types\";\nimport type { InkCallableDescriptor } from \"@polkadot-api/ink-contracts\";\n\n/**\n * Compute the blake2b-256 hash of an extrinsic\n *\n * This is the standard way to compute extrinsic hashes on Substrate chains.\n *\n * @param extrinsicHex - The raw extrinsic as a hex string (with or without 0x prefix)\n * @returns The extrinsic hash as a hex string with 0x prefix\n *\n * @example\n * ```ts\n * import { computeExtrinsicHash } from \"@d9-network/ink/indexer\";\n *\n * const extrinsicHex = \"0x...\"; // from getBlockBody()\n * const hash = computeExtrinsicHash(extrinsicHex);\n * // hash is \"0xabcd...\" (64 hex chars)\n * ```\n */\nexport function computeExtrinsicHash(extrinsicHex: HexString | string): HexString {\n const bytes = hexToBytes(extrinsicHex as HexString);\n const hash = blake2b(bytes, { dkLen: 32 });\n return bytesToHex(hash);\n}\n\n/**\n * Options for parseContractCallFromHex\n */\nexport interface ParseContractCallOptions {\n /** Contract address to include in the raw call metadata */\n contractAddress?: SS58String;\n /** Caller/signer address */\n caller?: SS58String;\n /** Block number */\n blockNumber?: number;\n /** Block hash */\n blockHash?: string;\n /** Extrinsic hash */\n txHash?: string;\n}\n\n/**\n * Search parameters for finding contract call data in an extrinsic\n */\nexport interface ContractCallSearchParams {\n /** Target contract address (to match dest field) */\n targetContract?: SS58String;\n /** Known selector to search for (4 bytes hex without 0x) */\n selector?: string;\n}\n\n/**\n * Attempt to find and extract contract call data from a raw extrinsic hex\n *\n * This function searches the extrinsic hex for patterns that look like\n * contract call data (selector followed by SCALE-encoded arguments).\n *\n * @param extrinsicHex - The raw extrinsic hex\n * @param selector - The 4-byte selector hex to search for (without 0x)\n * @returns The call data starting from the selector, or null if not found\n */\nexport function extractCallDataFromHex(\n extrinsicHex: HexString | string,\n selector: string\n): Uint8Array | null {\n const hex = extrinsicHex.startsWith(\"0x\")\n ? extrinsicHex.slice(2).toLowerCase()\n : extrinsicHex.toLowerCase();\n const selectorLower = selector.toLowerCase();\n\n // Search for the selector in the hex string\n const index = hex.indexOf(selectorLower);\n if (index === -1) {\n return null;\n }\n\n // Extract from selector to end of extrinsic\n // This includes the selector and all subsequent bytes (arguments)\n const callDataHex = hex.slice(index);\n\n // Convert to Uint8Array\n const bytes = new Uint8Array(callDataHex.length / 2);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = parseInt(callDataHex.slice(i * 2, i * 2 + 2), 16);\n }\n\n return bytes;\n}\n\n/**\n * Parse a contract call from raw hex extrinsic data\n *\n * This is useful for indexers that receive extrinsics as raw hex strings\n * from `getBlockBody()` and need to decode specific contract calls.\n *\n * @param extrinsicHex - The raw extrinsic hex\n * @param callParser - A ContractCallParser instance for the target contract\n * @param options - Additional options and metadata\n * @returns Parsed contract call or null if parsing fails\n *\n * @example\n * ```ts\n * import { parseContractCallFromHex, ContractCallParser } from \"@d9-network/ink/indexer\";\n * import { contracts } from \"@d9-network/spec\";\n *\n * const parser = new ContractCallParser(contracts.usdt);\n * const call = parseContractCallFromHex(extrinsicHex, parser, {\n * contractAddress: USDT_ADDRESS,\n * caller: signerAddress,\n * });\n *\n * if (call?.type === \"PSP22::transfer\") {\n * console.log(call.args.to, call.args.value);\n * }\n * ```\n */\nexport function parseContractCallFromHex<M extends InkCallableDescriptor>(\n extrinsicHex: HexString | string,\n callParser: ContractCallParser<any, M, any, any>,\n options: ParseContractCallOptions = {}\n): TypedContractCall<M> | null {\n // Get all selectors from the parser\n const selectorMap = callParser.getSelectorMap();\n\n // Try to find any known selector in the hex\n for (const [selectorHex] of selectorMap) {\n const callData = extractCallDataFromHex(extrinsicHex, selectorHex);\n if (!callData) continue;\n\n // Try to parse the call data\n const raw: RawContractCall = {\n data: callData,\n contractAddress: options.contractAddress\n ? toD9Address(options.contractAddress)\n : undefined,\n txHash: options.txHash,\n blockNumber: options.blockNumber,\n blockHash: options.blockHash,\n };\n\n const result = callParser.parseCall(raw);\n if (result) {\n return result;\n }\n }\n\n return null;\n}\n\n/**\n * Extract selector hex from call data\n *\n * @param callData - Raw call data (Uint8Array or hex string)\n * @returns 4-byte selector as hex string without 0x prefix, or null if too short\n */\nexport function extractSelectorFromCallData(callData: Uint8Array | HexString | string): string | null {\n let bytes: Uint8Array;\n\n if (callData instanceof Uint8Array) {\n bytes = callData;\n } else {\n const hex = callData.startsWith(\"0x\") ? callData.slice(2) : callData;\n if (hex.length < 8) return null;\n return hex.slice(0, 8).toLowerCase();\n }\n\n if (bytes.length < 4) return null;\n\n let result = \"\";\n for (let i = 0; i < 4; i++) {\n result += bytes[i]!.toString(16).padStart(2, \"0\");\n }\n return result;\n}\n\n/**\n * Check if extrinsic contains a specific selector\n *\n * @param extrinsicHex - Raw extrinsic hex\n * @param selector - Selector to check for (with or without 0x)\n * @returns True if selector is found in the extrinsic\n */\nexport function hasSelector(extrinsicHex: HexString | string, selector: string): boolean {\n const hex = extrinsicHex.startsWith(\"0x\")\n ? extrinsicHex.slice(2).toLowerCase()\n : extrinsicHex.toLowerCase();\n const selectorLower = selector.startsWith(\"0x\")\n ? selector.slice(2).toLowerCase()\n : selector.toLowerCase();\n\n return hex.includes(selectorLower);\n}\n\n/**\n * Check if extrinsic contains a PSP22 call\n *\n * @param extrinsicHex - Raw extrinsic hex\n * @returns The PSP22 method name if found, null otherwise\n */\nexport function findPSP22Selector(extrinsicHex: HexString | string): keyof typeof PSP22_SELECTORS | null {\n for (const [method, selector] of Object.entries(PSP22_SELECTORS)) {\n if (hasSelector(extrinsicHex, selector)) {\n return method as keyof typeof PSP22_SELECTORS;\n }\n }\n return null;\n}\n","/**\n * PSP22 utilities for indexers\n *\n * Provides specialized functions for decoding PSP22 token transfers from\n * raw extrinsic data, the most common indexer use case.\n */\n\nimport type { HexString, SS58String } from \"polkadot-api\";\nimport { ss58Encode } from \"@polkadot-labs/hdkd-helpers\";\nimport { D9_SS58_PREFIX, hexToBytes } from \"@d9-network/spec\";\nimport { PSP22_SELECTORS } from \"../selectors\";\nimport { extractCallDataFromHex, extractSelectorFromCallData } from \"./extrinsic-utils\";\n\n/**\n * Decoded PSP22 transfer result\n */\nexport interface DecodedPSP22Transfer {\n /** Transfer type */\n type: \"transfer\" | \"transfer_from\";\n /** Source address (D9 format) */\n from: SS58String;\n /** Destination address (D9 format) */\n to: SS58String;\n /** Transfer amount */\n value: bigint;\n}\n\n/**\n * Options for PSP22 decoding\n */\nexport interface DecodePSP22Options {\n /**\n * SS58 prefix for returned addresses.\n * Defaults to D9_SS58_PREFIX (9).\n */\n ss58Prefix?: number;\n}\n\n/**\n * Decode a PSP22 transfer or transfer_from call from raw extrinsic hex\n *\n * This function handles the common case of extracting PSP22 token transfers\n * from raw blockchain data without needing the full contract metadata.\n *\n * PSP22::transfer args: (to: AccountId, value: u128, data: Vec<u8>)\n * PSP22::transfer_from args: (from: AccountId, to: AccountId, value: u128, data: Vec<u8>)\n *\n * @param extrinsicHex - The raw extrinsic hex\n * @param caller - The transaction signer (used as 'from' for transfer)\n * @param options - Decoding options\n * @returns Decoded transfer or null if not a PSP22 transfer\n *\n * @example\n * ```ts\n * import { decodePSP22Transfer } from \"@d9-network/ink/indexer\";\n *\n * const transfer = decodePSP22Transfer(extrinsicHex, signerAddress);\n * if (transfer) {\n * console.log(`${transfer.from} -> ${transfer.to}: ${transfer.value}`);\n * }\n * ```\n */\nexport function decodePSP22Transfer(\n extrinsicHex: HexString | string,\n caller: SS58String,\n options: DecodePSP22Options = {}\n): DecodedPSP22Transfer | null {\n const ss58Prefix = options.ss58Prefix ?? D9_SS58_PREFIX;\n\n // Try to find transfer selector\n let callData = extractCallDataFromHex(extrinsicHex, PSP22_SELECTORS.transfer);\n if (callData) {\n return decodeTransfer(callData, caller, ss58Prefix);\n }\n\n // Try to find transfer_from selector\n callData = extractCallDataFromHex(extrinsicHex, PSP22_SELECTORS.transferFrom);\n if (callData) {\n return decodeTransferFrom(callData, ss58Prefix);\n }\n\n return null;\n}\n\n/**\n * Check if an extrinsic contains a PSP22 transfer call\n *\n * @param extrinsicHex - Raw extrinsic hex\n * @returns True if contains PSP22::transfer or PSP22::transfer_from\n */\nexport function isPSP22TransferExtrinsic(extrinsicHex: HexString | string): boolean {\n const hex = extrinsicHex.startsWith(\"0x\")\n ? extrinsicHex.slice(2).toLowerCase()\n : extrinsicHex.toLowerCase();\n\n return (\n hex.includes(PSP22_SELECTORS.transfer) ||\n hex.includes(PSP22_SELECTORS.transferFrom)\n );\n}\n\n/**\n * Get the PSP22 transfer type from extrinsic hex\n *\n * @param extrinsicHex - Raw extrinsic hex\n * @returns \"transfer\", \"transfer_from\", or null\n */\nexport function getPSP22TransferType(\n extrinsicHex: HexString | string\n): \"transfer\" | \"transfer_from\" | null {\n const hex = extrinsicHex.startsWith(\"0x\")\n ? extrinsicHex.slice(2).toLowerCase()\n : extrinsicHex.toLowerCase();\n\n if (hex.includes(PSP22_SELECTORS.transferFrom)) {\n return \"transfer_from\";\n }\n if (hex.includes(PSP22_SELECTORS.transfer)) {\n return \"transfer\";\n }\n return null;\n}\n\n// Internal helpers\n\n/**\n * Decode PSP22::transfer call data\n * Args: (to: AccountId, value: u128, data: Vec<u8>)\n */\nfunction decodeTransfer(\n callData: Uint8Array,\n caller: SS58String,\n ss58Prefix: number\n): DecodedPSP22Transfer | null {\n // Skip 4-byte selector\n if (callData.length < 4 + 32 + 16) {\n return null;\n }\n\n try {\n let offset = 4;\n\n // AccountId is 32 bytes\n const toBytes = callData.slice(offset, offset + 32);\n offset += 32;\n\n // u128 is 16 bytes (little-endian)\n const valueBytes = callData.slice(offset, offset + 16);\n const value = bytesToU128LE(valueBytes);\n\n const to = ss58Encode(toBytes, ss58Prefix) as SS58String;\n\n return {\n type: \"transfer\",\n from: caller,\n to,\n value,\n };\n } catch {\n return null;\n }\n}\n\n/**\n * Decode PSP22::transfer_from call data\n * Args: (from: AccountId, to: AccountId, value: u128, data: Vec<u8>)\n */\nfunction decodeTransferFrom(\n callData: Uint8Array,\n ss58Prefix: number\n): DecodedPSP22Transfer | null {\n // Skip 4-byte selector\n if (callData.length < 4 + 32 + 32 + 16) {\n return null;\n }\n\n try {\n let offset = 4;\n\n // First AccountId (from)\n const fromBytes = callData.slice(offset, offset + 32);\n offset += 32;\n\n // Second AccountId (to)\n const toBytes = callData.slice(offset, offset + 32);\n offset += 32;\n\n // u128 is 16 bytes (little-endian)\n const valueBytes = callData.slice(offset, offset + 16);\n const value = bytesToU128LE(valueBytes);\n\n const from = ss58Encode(fromBytes, ss58Prefix) as SS58String;\n const to = ss58Encode(toBytes, ss58Prefix) as SS58String;\n\n return {\n type: \"transfer_from\",\n from,\n to,\n value,\n };\n } catch {\n return null;\n }\n}\n\n/**\n * Convert 16 bytes (little-endian) to bigint\n */\nfunction bytesToU128LE(bytes: Uint8Array): bigint {\n if (bytes.length !== 16) {\n throw new Error(\"Expected 16 bytes for u128\");\n }\n\n let result = 0n;\n for (let i = 0; i < 16; i++) {\n result |= BigInt(bytes[i]!) << BigInt(i * 8);\n }\n return result;\n}\n","/**\n * Indexer utilities for D9 Ink SDK\n *\n * This module provides specialized tools for blockchain indexers to process\n * contract transactions and events from raw chain data.\n *\n * @module @d9-network/ink/indexer\n *\n * @example\n * ```ts\n * import {\n * computeExtrinsicHash,\n * parseContractCallFromHex,\n * decodePSP22Transfer,\n * } from \"@d9-network/ink/indexer\";\n *\n * // Compute extrinsic hash\n * const hash = computeExtrinsicHash(extrinsicHex);\n *\n * // Decode PSP22 transfer\n * const transfer = decodePSP22Transfer(extrinsicHex, signerAddress);\n * if (transfer) {\n * console.log(`${transfer.from} -> ${transfer.to}: ${transfer.value}`);\n * }\n * ```\n */\n\n// Extrinsic utilities\nexport {\n computeExtrinsicHash,\n extractCallDataFromHex,\n parseContractCallFromHex,\n extractSelectorFromCallData,\n hasSelector,\n findPSP22Selector,\n type ParseContractCallOptions,\n type ContractCallSearchParams,\n} from \"./extrinsic-utils\";\n\n// PSP22 utilities\nexport {\n decodePSP22Transfer,\n isPSP22TransferExtrinsic,\n getPSP22TransferType,\n type DecodedPSP22Transfer,\n type DecodePSP22Options,\n} from \"./psp22\";\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@d9-network/ink",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"private": false,
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "D9 Network, Inc.",
|
|
8
|
+
"email": "support@d9network.com",
|
|
9
|
+
"url": "https://d9network.com"
|
|
10
|
+
},
|
|
5
11
|
"files": [
|
|
6
12
|
"dist"
|
|
7
13
|
],
|
|
@@ -20,6 +26,16 @@
|
|
|
20
26
|
"default": "./dist/index.cjs"
|
|
21
27
|
}
|
|
22
28
|
},
|
|
29
|
+
"./indexer": {
|
|
30
|
+
"import": {
|
|
31
|
+
"types": "./dist/indexer/index.d.mts",
|
|
32
|
+
"default": "./dist/indexer/index.mjs"
|
|
33
|
+
},
|
|
34
|
+
"require": {
|
|
35
|
+
"types": "./dist/indexer/index.d.cts",
|
|
36
|
+
"default": "./dist/indexer/index.cjs"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
23
39
|
"./package.json": "./package.json"
|
|
24
40
|
},
|
|
25
41
|
"scripts": {
|
|
@@ -29,7 +45,7 @@
|
|
|
29
45
|
"prepublishOnly": "bun update && bun run build"
|
|
30
46
|
},
|
|
31
47
|
"dependencies": {
|
|
32
|
-
"@d9-network/spec": "^1.0
|
|
48
|
+
"@d9-network/spec": "^1.1.0",
|
|
33
49
|
"@noble/hashes": "^2.0.1",
|
|
34
50
|
"@polkadot-api/ink-contracts": "^0.4.6",
|
|
35
51
|
"@polkadot-api/substrate-bindings": "^0.16.6",
|