@orbinum/sdk 0.3.0 → 0.4.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 +570 -22
- package/dist/index.d.mts +1791 -986
- package/dist/index.d.ts +1791 -986
- package/dist/index.js +2225 -491
- package/dist/index.mjs +2207 -489
- package/package.json +5 -1
package/dist/index.mjs
CHANGED
|
@@ -4,10 +4,45 @@ import {
|
|
|
4
4
|
Binary
|
|
5
5
|
} from "polkadot-api";
|
|
6
6
|
import { getWsProvider } from "polkadot-api/ws-provider";
|
|
7
|
+
import { getDynamicBuilder, getLookupFn } from "@polkadot-api/metadata-builders";
|
|
8
|
+
import { decAnyMetadata, unifyMetadata } from "@polkadot-api/substrate-bindings";
|
|
9
|
+
import { AccountId } from "@polkadot-api/substrate-bindings";
|
|
10
|
+
import { getExtrinsicDecoder } from "@polkadot-api/tx-utils";
|
|
11
|
+
|
|
12
|
+
// src/utils/hex.ts
|
|
13
|
+
function toHex(bytes) {
|
|
14
|
+
return "0x" + Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
15
|
+
}
|
|
16
|
+
function fromHex(hex) {
|
|
17
|
+
const clean = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
18
|
+
if (clean.length % 2 !== 0) {
|
|
19
|
+
throw new Error(`Invalid hex string \u2014 odd length: "${hex}"`);
|
|
20
|
+
}
|
|
21
|
+
const bytes = new Uint8Array(clean.length / 2);
|
|
22
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
23
|
+
const byte = parseInt(clean.slice(i * 2, i * 2 + 2), 16);
|
|
24
|
+
if (isNaN(byte)) throw new Error(`Invalid hex character at position ${i * 2}`);
|
|
25
|
+
bytes[i] = byte;
|
|
26
|
+
}
|
|
27
|
+
return bytes;
|
|
28
|
+
}
|
|
29
|
+
function ensureHexPrefix(hex) {
|
|
30
|
+
return hex.startsWith("0x") ? hex : `0x${hex}`;
|
|
31
|
+
}
|
|
32
|
+
function hexToNumber(hex) {
|
|
33
|
+
return parseInt(hex, 16);
|
|
34
|
+
}
|
|
35
|
+
function hexToBigint(hex) {
|
|
36
|
+
return BigInt(hex);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// src/substrate/SubstrateClient.ts
|
|
7
40
|
var SubstrateClient = class _SubstrateClient {
|
|
8
41
|
constructor(_papi) {
|
|
9
42
|
this._papi = _papi;
|
|
10
43
|
}
|
|
44
|
+
_dynamicBuilder = null;
|
|
45
|
+
_extDecoder = null;
|
|
11
46
|
/**
|
|
12
47
|
* Connects to the Orbinum node via WebSocket.
|
|
13
48
|
* Throws if the node does not respond within `timeoutMs`.
|
|
@@ -33,13 +68,145 @@ var SubstrateClient = class _SubstrateClient {
|
|
|
33
68
|
async request(method, params = []) {
|
|
34
69
|
return this._papi._request(method, params);
|
|
35
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* Returns basic chain information from the node.
|
|
73
|
+
* Combines `system_name`, `system_chain`, `system_properties`, and `state_getRuntimeVersion`.
|
|
74
|
+
*/
|
|
75
|
+
async getChainInfo() {
|
|
76
|
+
const [chainName, version, props] = await Promise.all([
|
|
77
|
+
this.request("system_chain", []),
|
|
78
|
+
this.request("state_getRuntimeVersion", []),
|
|
79
|
+
this.request(
|
|
80
|
+
"system_properties",
|
|
81
|
+
[]
|
|
82
|
+
)
|
|
83
|
+
]);
|
|
84
|
+
const rawSymbol = props.tokenSymbol;
|
|
85
|
+
const rawDecimals = props.tokenDecimals;
|
|
86
|
+
return {
|
|
87
|
+
name: chainName,
|
|
88
|
+
version: String(version.specVersion),
|
|
89
|
+
ss58Prefix: version.ss58Prefix ?? 42,
|
|
90
|
+
symbol: Array.isArray(rawSymbol) ? rawSymbol[0] ?? "ORB" : rawSymbol ?? "ORB",
|
|
91
|
+
decimals: Array.isArray(rawDecimals) ? rawDecimals[0] ?? 18 : rawDecimals ?? 18
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Returns the node's peer count and sync status.
|
|
96
|
+
*/
|
|
97
|
+
async getHealth() {
|
|
98
|
+
return this.request("system_health", []);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Returns the node's software version string.
|
|
102
|
+
*/
|
|
103
|
+
async getNodeVersion() {
|
|
104
|
+
return this.request("system_version", []);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Returns the genesis hash hex.
|
|
108
|
+
*/
|
|
109
|
+
async getGenesisHash() {
|
|
110
|
+
return this.request("chain_getBlockHash", [0]);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Returns the block hash for a given block number.
|
|
114
|
+
* Returns null when the block does not exist or has been pruned.
|
|
115
|
+
*/
|
|
116
|
+
async getBlockHash(blockNumber) {
|
|
117
|
+
const hash = await this.request("chain_getBlockHash", [blockNumber]);
|
|
118
|
+
if (!hash || /^0x0+$/.test(hash) || hash === "0x" + "00".repeat(32)) return null;
|
|
119
|
+
return hash;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Fetches a block by hash or number, enriched with timestamp and block author.
|
|
123
|
+
*
|
|
124
|
+
* Uses `chain_getBlock` (works for all non-pruned blocks, unlike PAPI chainHead
|
|
125
|
+
* which only pins recent blocks). Timestamp is read from `Timestamp.Now` storage
|
|
126
|
+
* with a fallback via the `timestamp.set` extrinsic argument. Author is decoded
|
|
127
|
+
* from PreRuntime digest logs using the chain's SS58 prefix.
|
|
128
|
+
*
|
|
129
|
+
* @param hashOrNumber - A `0x`-prefixed block hash or a block number (number or decimal string).
|
|
130
|
+
* @returns `BlockInfo` or `null` if the block is not found.
|
|
131
|
+
*/
|
|
132
|
+
async getBlock(hashOrNumber) {
|
|
133
|
+
try {
|
|
134
|
+
let blockHash;
|
|
135
|
+
if (typeof hashOrNumber === "number" || /^\d+$/.test(String(hashOrNumber))) {
|
|
136
|
+
const num = typeof hashOrNumber === "number" ? hashOrNumber : parseInt(hashOrNumber, 10);
|
|
137
|
+
const h = await this.getBlockHash(num);
|
|
138
|
+
if (!h) return null;
|
|
139
|
+
blockHash = h;
|
|
140
|
+
} else {
|
|
141
|
+
blockHash = hashOrNumber;
|
|
142
|
+
}
|
|
143
|
+
const raw = await this.request("chain_getBlock", [blockHash]);
|
|
144
|
+
if (!raw?.block) return null;
|
|
145
|
+
const { header, extrinsics } = raw.block;
|
|
146
|
+
const builder = await this.getDynamicBuilder().catch(() => null);
|
|
147
|
+
const ss58Prefix = builder?.ss58Prefix ?? 42;
|
|
148
|
+
let timestampMs = null;
|
|
149
|
+
if (builder) {
|
|
150
|
+
try {
|
|
151
|
+
const tsStore = builder.buildStorage("Timestamp", "Now");
|
|
152
|
+
const tsRaw = await this.request("state_getStorage", [
|
|
153
|
+
tsStore.keys.enc(),
|
|
154
|
+
blockHash
|
|
155
|
+
]);
|
|
156
|
+
if (tsRaw) {
|
|
157
|
+
timestampMs = Number(tsStore.value.dec(fromHex(tsRaw)));
|
|
158
|
+
}
|
|
159
|
+
} catch {
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (!timestampMs) {
|
|
163
|
+
const tsHex = extrinsics.find((hex) => {
|
|
164
|
+
try {
|
|
165
|
+
const b = fromHex(hex);
|
|
166
|
+
return b.length > 6 && b[4] === 3 && b[5] === 0;
|
|
167
|
+
} catch {
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
if (tsHex) {
|
|
172
|
+
try {
|
|
173
|
+
const b = fromHex(tsHex);
|
|
174
|
+
const view = new DataView(b.buffer, b.byteOffset + 6, 8);
|
|
175
|
+
const lo = view.getUint32(0, true);
|
|
176
|
+
const hi = view.getUint32(4, true);
|
|
177
|
+
const ms = lo + hi * 4294967296;
|
|
178
|
+
if (ms > 0) timestampMs = ms;
|
|
179
|
+
} catch {
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
const author = _SubstrateClient.extractAuthorFromLogs(header.digest.logs, ss58Prefix);
|
|
184
|
+
return { header, extrinsics, timestampMs, author };
|
|
185
|
+
} catch {
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
36
189
|
/**
|
|
37
190
|
* Returns the underlying PolkadotClient instance.
|
|
38
|
-
* Use for
|
|
191
|
+
* Use for raw metadata access and advanced SCALE operations.
|
|
39
192
|
*/
|
|
40
193
|
get polkadotClient() {
|
|
41
194
|
return this._papi;
|
|
42
195
|
}
|
|
196
|
+
/**
|
|
197
|
+
* Observable that emits a new entry each time a best-block is reported by the node.
|
|
198
|
+
* Delegates to PAPI's `blocks$`.
|
|
199
|
+
*/
|
|
200
|
+
get blocks$() {
|
|
201
|
+
return this._papi.blocks$;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Returns the block header for a given tag or block hash.
|
|
205
|
+
* Delegates to PAPI's `getBlockHeader`.
|
|
206
|
+
*/
|
|
207
|
+
getBlockHeader(...args) {
|
|
208
|
+
return this._papi.getBlockHeader(...args);
|
|
209
|
+
}
|
|
43
210
|
/**
|
|
44
211
|
* Returns the PAPI UnsafeApi for dynamic, metadata-driven transaction building.
|
|
45
212
|
* The first access triggers a metadata fetch from the node.
|
|
@@ -84,34 +251,148 @@ var SubstrateClient = class _SubstrateClient {
|
|
|
84
251
|
destroy() {
|
|
85
252
|
this._papi.destroy();
|
|
86
253
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
254
|
+
/**
|
|
255
|
+
* Fetches and decodes all events for a given block hash.
|
|
256
|
+
* Queries `System.Events` storage via SCALE codec built from on-chain metadata.
|
|
257
|
+
*
|
|
258
|
+
* @param blockHash - The `0x`-prefixed block hash string.
|
|
259
|
+
* @returns Array of `EventRecord` or `null` if unavailable.
|
|
260
|
+
*/
|
|
261
|
+
async queryBlockEvents(blockHash) {
|
|
262
|
+
try {
|
|
263
|
+
const builder = await this.getDynamicBuilder();
|
|
264
|
+
const { keys, value } = builder.buildStorage("System", "Events");
|
|
265
|
+
const raw = await this.request("state_getStorage", [
|
|
266
|
+
keys.enc(),
|
|
267
|
+
blockHash
|
|
268
|
+
]);
|
|
269
|
+
if (!raw) return null;
|
|
270
|
+
const decoded = value.dec(fromHex(raw));
|
|
271
|
+
return _SubstrateClient._toEventRecords(decoded);
|
|
272
|
+
} catch {
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
97
275
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
276
|
+
// ─── Internal helpers ─────────────────────────────────────────────────────
|
|
277
|
+
async getDynamicBuilder() {
|
|
278
|
+
if (this._dynamicBuilder) return this._dynamicBuilder;
|
|
279
|
+
const rawMetadata = await this._papi.getMetadata("best");
|
|
280
|
+
const metadata = decAnyMetadata(rawMetadata);
|
|
281
|
+
const unified = unifyMetadata(metadata);
|
|
282
|
+
const lookup = getLookupFn(unified);
|
|
283
|
+
this._dynamicBuilder = getDynamicBuilder(lookup);
|
|
284
|
+
return this._dynamicBuilder;
|
|
285
|
+
}
|
|
286
|
+
async getExtrinsicDecoder() {
|
|
287
|
+
if (this._extDecoder) return this._extDecoder;
|
|
288
|
+
const rawMetadata = await this._papi.getMetadata("best");
|
|
289
|
+
this._extDecoder = getExtrinsicDecoder(rawMetadata);
|
|
290
|
+
return this._extDecoder;
|
|
291
|
+
}
|
|
292
|
+
static _buildDataProxy(value) {
|
|
293
|
+
const formatValue = (v) => {
|
|
294
|
+
if (v instanceof Uint8Array) return fromHex(v).toString();
|
|
295
|
+
if (typeof v === "bigint") return v.toString();
|
|
296
|
+
return String(v);
|
|
297
|
+
};
|
|
298
|
+
const jsonifyValue = (v) => {
|
|
299
|
+
if (v === null || v === void 0) return v;
|
|
300
|
+
if (typeof v === "bigint") return v.toString();
|
|
301
|
+
if (v instanceof Uint8Array)
|
|
302
|
+
return Array.from(v).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
303
|
+
if (Array.isArray(v)) return v.map(jsonifyValue);
|
|
304
|
+
if (typeof v === "object") {
|
|
305
|
+
return Object.fromEntries(
|
|
306
|
+
Object.entries(v).filter(([, val]) => typeof val !== "function").map(([k, val]) => [k, jsonifyValue(val)])
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
return v;
|
|
310
|
+
};
|
|
311
|
+
const entries = Array.isArray(value) ? value : value !== null && typeof value === "object" ? Object.values(value) : [value];
|
|
312
|
+
const items = entries.map((v) => ({
|
|
313
|
+
toString: () => formatValue(v),
|
|
314
|
+
toJSON: () => jsonifyValue(v),
|
|
315
|
+
toHuman: () => jsonifyValue(v),
|
|
316
|
+
...v !== null && typeof v === "object" ? v : {}
|
|
317
|
+
}));
|
|
318
|
+
return Object.assign(items, {
|
|
319
|
+
toJSON: () => jsonifyValue(value),
|
|
320
|
+
toHuman: () => jsonifyValue(value)
|
|
321
|
+
});
|
|
103
322
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
323
|
+
/**
|
|
324
|
+
* Extracts the block author (validator/collator) from raw digest log hex strings.
|
|
325
|
+
* Looks for a PreRuntime log (tag byte = 6) and decodes the first 32 bytes of the
|
|
326
|
+
* SCALE-compact payload as an SS58 address using the given prefix.
|
|
327
|
+
*
|
|
328
|
+
* Can be used standalone with raw logs from `chain_getBlock` responses.
|
|
329
|
+
*/
|
|
330
|
+
static extractAuthorFromLogs(logs, ss58Prefix) {
|
|
331
|
+
try {
|
|
332
|
+
for (const hex of logs) {
|
|
333
|
+
const bytes = fromHex(hex);
|
|
334
|
+
if (bytes.length < 6 || bytes[0] !== 6) continue;
|
|
335
|
+
const firstLenByte = bytes[5];
|
|
336
|
+
const mode = firstLenByte & 3;
|
|
337
|
+
let payloadStart;
|
|
338
|
+
let payloadLen;
|
|
339
|
+
if (mode === 0) {
|
|
340
|
+
payloadLen = firstLenByte >> 2;
|
|
341
|
+
payloadStart = 6;
|
|
342
|
+
} else if (mode === 1) {
|
|
343
|
+
if (bytes.length < 7) continue;
|
|
344
|
+
payloadLen = firstLenByte >> 2 | bytes[6] << 6;
|
|
345
|
+
payloadStart = 7;
|
|
346
|
+
} else if (mode === 2) {
|
|
347
|
+
if (bytes.length < 9) continue;
|
|
348
|
+
payloadLen = (firstLenByte >> 2 | bytes[6] << 6 | bytes[7] << 14 | bytes[8] << 22) >>> 0;
|
|
349
|
+
payloadStart = 9;
|
|
350
|
+
} else {
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
353
|
+
const payload = bytes.slice(payloadStart, payloadStart + payloadLen);
|
|
354
|
+
if (payload.length >= 32) {
|
|
355
|
+
try {
|
|
356
|
+
return AccountId(ss58Prefix).dec(payload.slice(0, 32));
|
|
357
|
+
} catch {
|
|
358
|
+
return toHex(payload.slice(0, 32));
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
} catch {
|
|
363
|
+
}
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
static _toEventRecords(decoded) {
|
|
367
|
+
return decoded.flatMap((e) => {
|
|
368
|
+
try {
|
|
369
|
+
const raw = e;
|
|
370
|
+
const isApply = raw.phase.type === "ApplyExtrinsic";
|
|
371
|
+
const extIdx = isApply ? raw.phase.value : 0;
|
|
372
|
+
const section = raw.event.type.charAt(0).toLowerCase() + raw.event.type.slice(1);
|
|
373
|
+
const method = raw.event.value.type;
|
|
374
|
+
const record = {
|
|
375
|
+
phase: {
|
|
376
|
+
isApplyExtrinsic: isApply,
|
|
377
|
+
asApplyExtrinsic: {
|
|
378
|
+
eq: (n) => n === extIdx,
|
|
379
|
+
toString: () => String(extIdx),
|
|
380
|
+
toNumber: () => extIdx
|
|
381
|
+
}
|
|
382
|
+
},
|
|
383
|
+
event: {
|
|
384
|
+
section,
|
|
385
|
+
method,
|
|
386
|
+
data: _SubstrateClient._buildDataProxy(raw.event.value.value)
|
|
387
|
+
}
|
|
388
|
+
};
|
|
389
|
+
return [record];
|
|
390
|
+
} catch {
|
|
391
|
+
return [];
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
};
|
|
115
396
|
|
|
116
397
|
// src/evm/EvmClient.ts
|
|
117
398
|
var EvmClient = class {
|
|
@@ -208,77 +489,582 @@ var EvmClient = class {
|
|
|
208
489
|
* Returns a transaction receipt by hash, or null if not yet mined.
|
|
209
490
|
*/
|
|
210
491
|
async getTransactionReceipt(txHash) {
|
|
211
|
-
|
|
492
|
+
const res = await fetch(this.rpcUrl, {
|
|
493
|
+
method: "POST",
|
|
494
|
+
headers: { "Content-Type": "application/json" },
|
|
495
|
+
body: JSON.stringify({
|
|
496
|
+
id: 1,
|
|
497
|
+
jsonrpc: "2.0",
|
|
498
|
+
method: "eth_getTransactionReceipt",
|
|
499
|
+
params: [txHash]
|
|
500
|
+
})
|
|
501
|
+
});
|
|
502
|
+
if (!res.ok) throw new Error(`EVM HTTP ${res.status}: ${res.statusText}`);
|
|
503
|
+
const json = await res.json();
|
|
504
|
+
if (json.error) {
|
|
505
|
+
throw new Error(`EVM RPC [${json.error.code}]: ${json.error.message}`);
|
|
506
|
+
}
|
|
507
|
+
return json.result ?? null;
|
|
212
508
|
}
|
|
213
509
|
};
|
|
214
510
|
|
|
215
|
-
// src/
|
|
216
|
-
var
|
|
217
|
-
|
|
218
|
-
|
|
511
|
+
// src/utils/format.ts
|
|
512
|
+
var LOCALE_DECIMAL_SEP = new Intl.NumberFormat(void 0).formatToParts(1.1).find((p) => p.type === "decimal")?.value ?? ".";
|
|
513
|
+
function formatIntegerLocale(intPart) {
|
|
514
|
+
try {
|
|
515
|
+
return BigInt(intPart || "0").toLocaleString(void 0);
|
|
516
|
+
} catch {
|
|
517
|
+
return (intPart || "0").replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
219
518
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
519
|
+
}
|
|
520
|
+
function normalizeDecimalForDisplay(raw, maxFractionDigits) {
|
|
521
|
+
let value = raw.trim();
|
|
522
|
+
if (!value) return null;
|
|
523
|
+
let sign = "";
|
|
524
|
+
if (value.startsWith("-")) {
|
|
525
|
+
sign = "-";
|
|
526
|
+
value = value.slice(1);
|
|
527
|
+
}
|
|
528
|
+
if (!/^\d*(\.\d*)?$/.test(value)) return null;
|
|
529
|
+
let [integerPart = "0", fractionPart = ""] = value.split(".");
|
|
530
|
+
integerPart = integerPart.replace(/^0+(?=\d)/, "") || "0";
|
|
531
|
+
const limit = Math.max(0, maxFractionDigits);
|
|
532
|
+
fractionPart = fractionPart.slice(0, limit).replace(/0+$/, "");
|
|
533
|
+
const formattedInt = formatIntegerLocale(integerPart);
|
|
534
|
+
return fractionPart ? `${sign}${formattedInt}${LOCALE_DECIMAL_SEP}${fractionPart}` : `${sign}${formattedInt}`;
|
|
535
|
+
}
|
|
536
|
+
function bigintFormatUnits(value, decimals) {
|
|
537
|
+
const negative = value < 0n;
|
|
538
|
+
const abs = negative ? -value : value;
|
|
539
|
+
const divider = 10n ** BigInt(decimals);
|
|
540
|
+
const intPart = abs / divider;
|
|
541
|
+
const fracPart = abs % divider;
|
|
542
|
+
const fracStr = fracPart.toString().padStart(decimals, "0");
|
|
543
|
+
return (negative ? "-" : "") + intPart.toString() + "." + fracStr;
|
|
544
|
+
}
|
|
545
|
+
function isCanonicalDecimal(value) {
|
|
546
|
+
return /^-?(?:\d+\.\d*|\d*\.\d+)$/.test(value);
|
|
547
|
+
}
|
|
548
|
+
function isBigIntLikeInteger(value) {
|
|
549
|
+
return /^-?\d+$/.test(value) || /^0[xX][0-9a-fA-F]+$/.test(value);
|
|
550
|
+
}
|
|
551
|
+
function formatBalance(raw, options = {}) {
|
|
552
|
+
const opts = typeof options === "number" ? { decimals: options } : options;
|
|
553
|
+
const { decimals = 18, symbol = "ORB", showSymbol = true, precision = 6 } = opts;
|
|
554
|
+
const zero = showSymbol ? `0 ${symbol}` : "0";
|
|
555
|
+
if (raw === null || raw === void 0) return zero;
|
|
556
|
+
if (typeof raw === "number" && !Number.isFinite(raw)) return zero;
|
|
557
|
+
const rawStr = String(raw).trim();
|
|
558
|
+
if (!rawStr) return zero;
|
|
559
|
+
if (isCanonicalDecimal(rawStr)) {
|
|
560
|
+
const formatted = normalizeDecimalForDisplay(rawStr, precision);
|
|
561
|
+
if (!formatted || formatted === "0" || formatted === "-0") return zero;
|
|
562
|
+
return showSymbol ? `${formatted} ${symbol}` : formatted;
|
|
563
|
+
}
|
|
564
|
+
if (!isBigIntLikeInteger(rawStr)) return zero;
|
|
565
|
+
try {
|
|
566
|
+
const n = BigInt(rawStr);
|
|
567
|
+
const decimalStr = bigintFormatUnits(n, decimals);
|
|
568
|
+
const formatted = normalizeDecimalForDisplay(decimalStr, precision);
|
|
569
|
+
if (!formatted || formatted === "0" || formatted === "-0") return zero;
|
|
570
|
+
return showSymbol ? `${formatted} ${symbol}` : formatted;
|
|
571
|
+
} catch {
|
|
572
|
+
return zero;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
function formatORB(raw, precision = 6) {
|
|
576
|
+
return formatBalance(raw, { decimals: 18, symbol: "ORB", showSymbol: true, precision });
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
// src/evm-explorer/EvmExplorer.ts
|
|
580
|
+
var EvmExplorer = class _EvmExplorer {
|
|
581
|
+
constructor(evm) {
|
|
582
|
+
this.evm = evm;
|
|
583
|
+
}
|
|
584
|
+
// --- Blocks ---
|
|
585
|
+
async getLatestBlocks(count = 10) {
|
|
586
|
+
const latest = await this.evm.getBlockNumber();
|
|
587
|
+
const nums = Array.from({ length: Math.min(count, latest + 1) }, (_, i) => latest - i);
|
|
588
|
+
const results = await Promise.all(
|
|
589
|
+
nums.map(
|
|
590
|
+
(n) => this.evm.request("eth_getBlockByNumber", [
|
|
591
|
+
`0x${n.toString(16)}`,
|
|
592
|
+
false
|
|
593
|
+
]).catch(() => null)
|
|
594
|
+
)
|
|
227
595
|
);
|
|
228
|
-
return
|
|
229
|
-
root: raw.root,
|
|
230
|
-
treeSize: raw.tree_size,
|
|
231
|
-
depth: raw.depth
|
|
232
|
-
};
|
|
596
|
+
return results.filter((b) => b !== null && !!b.hash).map((b) => this.parseBlock(b));
|
|
233
597
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
async getProof(leafIndex) {
|
|
238
|
-
const raw = await this.substrate.request("shieldedPool_getMerkleProof", [
|
|
239
|
-
leafIndex
|
|
240
|
-
]);
|
|
241
|
-
return {
|
|
242
|
-
root: raw.root,
|
|
243
|
-
leafIndex: raw.leaf_index,
|
|
244
|
-
siblings: raw.siblings
|
|
245
|
-
};
|
|
598
|
+
async getBlock(hashOrNumber) {
|
|
599
|
+
const b = await this.fetchBlock(hashOrNumber, false);
|
|
600
|
+
return b ? this.parseBlock(b) : null;
|
|
246
601
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
602
|
+
async getBlockTransactions(hashOrNumber) {
|
|
603
|
+
try {
|
|
604
|
+
const b = await this.fetchBlock(hashOrNumber, true);
|
|
605
|
+
if (!b || !b.transactions.length) return [];
|
|
606
|
+
const txs = b.transactions;
|
|
607
|
+
const receipts = await this.evm.batchRequest(txs.map((tx) => ({ method: "eth_getTransactionReceipt", params: [tx.hash] }))).catch(() => txs.map(() => null));
|
|
608
|
+
return txs.map((tx, i) => this.parseTx(tx, receipts[i] ?? null));
|
|
609
|
+
} catch {
|
|
610
|
+
return [];
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
// --- Transactions ---
|
|
614
|
+
async getTransaction(hash) {
|
|
615
|
+
try {
|
|
616
|
+
const [tx, receipt] = await Promise.all([
|
|
617
|
+
this.evm.request("eth_getTransactionByHash", [hash]),
|
|
618
|
+
this.evm.request("eth_getTransactionReceipt", [hash]).catch(() => null)
|
|
619
|
+
]);
|
|
620
|
+
if (!tx) return null;
|
|
621
|
+
return this.parseTx(tx, receipt);
|
|
622
|
+
} catch {
|
|
623
|
+
return null;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
async getTransactionsByAddress(address, maxBlocks = 300) {
|
|
627
|
+
const addr = address.toLowerCase();
|
|
628
|
+
const latest = await this.evm.getBlockNumber();
|
|
629
|
+
const from = Math.max(0, latest - maxBlocks + 1);
|
|
630
|
+
const blockNums = Array.from({ length: latest - from + 1 }, (_, i) => latest - i);
|
|
631
|
+
const blocks = await Promise.all(
|
|
632
|
+
blockNums.map(
|
|
633
|
+
(n) => this.evm.request("eth_getBlockByNumber", [
|
|
634
|
+
`0x${n.toString(16)}`,
|
|
635
|
+
true
|
|
636
|
+
]).catch(() => null)
|
|
637
|
+
)
|
|
638
|
+
);
|
|
639
|
+
const matchingTxs = [];
|
|
640
|
+
for (const block of blocks) {
|
|
641
|
+
if (!block?.transactions) continue;
|
|
642
|
+
const blockTimestamp = block.timestamp ? hexToNumber(block.timestamp) : null;
|
|
643
|
+
for (const tx of block.transactions) {
|
|
644
|
+
if (tx.from?.toLowerCase() === addr || tx.to?.toLowerCase() === addr) {
|
|
645
|
+
matchingTxs.push({ tx, timestamp: blockTimestamp });
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
if (!matchingTxs.length) return [];
|
|
650
|
+
const receipts = await this.evm.batchRequest(
|
|
651
|
+
matchingTxs.map(({ tx }) => ({
|
|
652
|
+
method: "eth_getTransactionReceipt",
|
|
653
|
+
params: [tx.hash]
|
|
654
|
+
}))
|
|
655
|
+
).catch(() => matchingTxs.map(() => null));
|
|
656
|
+
const results = matchingTxs.map(({ tx, timestamp }, i) => {
|
|
657
|
+
const receipt = receipts[i] ?? null;
|
|
658
|
+
return {
|
|
659
|
+
hash: tx.hash,
|
|
660
|
+
blockNumber: hexToNumber(tx.blockNumber),
|
|
661
|
+
timestamp,
|
|
662
|
+
from: tx.from,
|
|
663
|
+
to: tx.to,
|
|
664
|
+
value: tx.value ?? "0x0",
|
|
665
|
+
input: tx.input ?? "0x",
|
|
666
|
+
gasUsed: receipt ? hexToNumber(receipt.gasUsed) : hexToNumber(tx.gas),
|
|
667
|
+
gasPrice: tx.gasPrice ?? "0x0",
|
|
668
|
+
status: receipt ? receipt.status === "0x1" : true,
|
|
669
|
+
isContractCreation: !tx.to,
|
|
670
|
+
contractAddress: receipt?.contractAddress ?? null
|
|
671
|
+
};
|
|
672
|
+
});
|
|
673
|
+
results.sort((a, b) => b.blockNumber - a.blockNumber);
|
|
674
|
+
return results;
|
|
675
|
+
}
|
|
676
|
+
// --- Address ---
|
|
677
|
+
async getAddressInfo(address) {
|
|
678
|
+
const latest = await this.evm.getBlockNumber().catch(() => 0);
|
|
679
|
+
const fromBlock = `0x${Math.max(0, latest - 5e3).toString(16)}`;
|
|
680
|
+
const [balance, nonce, code, logs] = await Promise.all([
|
|
681
|
+
this.evm.request("eth_getBalance", [address, "latest"]).catch(() => null),
|
|
682
|
+
this.evm.getTransactionCount(address).catch(() => 0),
|
|
683
|
+
this.evm.request("eth_getCode", [address, "latest"]).catch(() => null),
|
|
684
|
+
this.evm.request("eth_getLogs", [{ fromBlock, toBlock: "latest", address }]).catch(() => [])
|
|
254
685
|
]);
|
|
686
|
+
const codeHex = code ?? "0x";
|
|
687
|
+
const isContract = codeHex !== "0x" && codeHex.length > 2;
|
|
688
|
+
const codeBytes = isContract ? Math.floor((codeHex.length - 2) / 2) : 0;
|
|
689
|
+
const recentLogs = (logs ?? []).slice(-50).map((l) => ({
|
|
690
|
+
address: l.address,
|
|
691
|
+
topics: l.topics,
|
|
692
|
+
data: l.data,
|
|
693
|
+
blockNumber: hexToNumber(l.blockNumber),
|
|
694
|
+
transactionHash: l.transactionHash,
|
|
695
|
+
logIndex: hexToNumber(l.logIndex)
|
|
696
|
+
}));
|
|
255
697
|
return {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
698
|
+
address,
|
|
699
|
+
isContract,
|
|
700
|
+
balance: balance ?? "0x0",
|
|
701
|
+
nonce: typeof nonce === "number" ? nonce : hexToNumber(nonce ?? "0x0"),
|
|
702
|
+
codeSize: codeBytes,
|
|
703
|
+
code: isContract ? codeHex.length > 202 ? `${codeHex.slice(0, 202)}\u2026` : codeHex : "0x",
|
|
704
|
+
recentLogs
|
|
259
705
|
};
|
|
260
706
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
707
|
+
async getBalance(address) {
|
|
708
|
+
try {
|
|
709
|
+
const val = await this.evm.getBalance(address);
|
|
710
|
+
return formatBalance(val, { showSymbol: false, precision: 18 });
|
|
711
|
+
} catch {
|
|
712
|
+
return "0";
|
|
713
|
+
}
|
|
267
714
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
715
|
+
async getNonce(address) {
|
|
716
|
+
try {
|
|
717
|
+
return await this.evm.getTransactionCount(address);
|
|
718
|
+
} catch {
|
|
719
|
+
return 0;
|
|
720
|
+
}
|
|
274
721
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
722
|
+
async getIsContract(address) {
|
|
723
|
+
try {
|
|
724
|
+
const code = await this.evm.request("eth_getCode", [address, "latest"]);
|
|
725
|
+
return code !== "0x" && code !== "0x0" && code.length > 2;
|
|
726
|
+
} catch {
|
|
727
|
+
return false;
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
// --- Tokens ---
|
|
731
|
+
async getTokenInfo(address) {
|
|
732
|
+
const addr = address.toLowerCase();
|
|
733
|
+
const [name, symbol, decimals, totalSupply] = await this.evm.batchRequest([
|
|
734
|
+
{ method: "eth_call", params: [{ to: addr, data: "0x06fdde03" }, "latest"] },
|
|
735
|
+
{ method: "eth_call", params: [{ to: addr, data: "0x95d89b41" }, "latest"] },
|
|
736
|
+
{ method: "eth_call", params: [{ to: addr, data: "0x313ce567" }, "latest"] },
|
|
737
|
+
{ method: "eth_call", params: [{ to: addr, data: "0x18160ddd" }, "latest"] }
|
|
738
|
+
]).catch(() => [null, null, null, null]);
|
|
739
|
+
const isErc20 = !!(totalSupply && totalSupply !== "0x" && symbol && decimals);
|
|
740
|
+
if (!isErc20 && !name && !symbol) return null;
|
|
741
|
+
return {
|
|
742
|
+
address: addr,
|
|
743
|
+
name: name ? _EvmExplorer.decodeAbiString(name) : "",
|
|
744
|
+
symbol: symbol ? _EvmExplorer.decodeAbiString(symbol) : "",
|
|
745
|
+
decimals: decimals ? Number(_EvmExplorer.decodeAbiUint(decimals)) : 18,
|
|
746
|
+
totalSupply: totalSupply ?? "0x0",
|
|
747
|
+
isErc20
|
|
748
|
+
};
|
|
749
|
+
}
|
|
750
|
+
async getTokenTransfers(address, holderAddress) {
|
|
751
|
+
const TRANSFER = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef";
|
|
752
|
+
const latest = await this.evm.getBlockNumber().catch(() => 0);
|
|
753
|
+
const fromBlock = `0x${Math.max(0, latest - 5e3).toString(16)}`;
|
|
754
|
+
let logs;
|
|
755
|
+
if (holderAddress) {
|
|
756
|
+
const padded = `0x${holderAddress.replace(/^0x/, "").toLowerCase().padStart(64, "0")}`;
|
|
757
|
+
const [sent, received] = await Promise.all([
|
|
758
|
+
this.evm.request("eth_getLogs", [{ fromBlock, toBlock: "latest", address, topics: [TRANSFER, padded] }]).catch(() => []),
|
|
759
|
+
this.evm.request("eth_getLogs", [{ fromBlock, toBlock: "latest", address, topics: [TRANSFER, null, padded] }]).catch(() => [])
|
|
760
|
+
]);
|
|
761
|
+
const merged = [...sent ?? [], ...received ?? []];
|
|
762
|
+
merged.sort((a, b) => hexToNumber(b.blockNumber) - hexToNumber(a.blockNumber));
|
|
763
|
+
logs = merged.slice(0, 100);
|
|
764
|
+
} else {
|
|
765
|
+
const all = await this.evm.request("eth_getLogs", [{ fromBlock, toBlock: "latest", address, topics: [TRANSFER] }]).catch(() => []);
|
|
766
|
+
logs = (all ?? []).slice(-100).reverse();
|
|
767
|
+
}
|
|
768
|
+
return logs.map((l) => ({
|
|
769
|
+
transactionHash: l.transactionHash,
|
|
770
|
+
blockNumber: hexToNumber(l.blockNumber),
|
|
771
|
+
from: `0x${(l.topics[1] ?? "").slice(-40)}`,
|
|
772
|
+
to: `0x${(l.topics[2] ?? "").slice(-40)}`,
|
|
773
|
+
value: l.data,
|
|
774
|
+
logIndex: hexToNumber(l.logIndex)
|
|
775
|
+
}));
|
|
776
|
+
}
|
|
777
|
+
async getTokenBalance(tokenAddress, holderAddress) {
|
|
778
|
+
const padded = holderAddress.replace(/^0x/, "").toLowerCase().padStart(64, "0");
|
|
779
|
+
const result = await this.ethCall(tokenAddress, `0x70a08231${padded}`);
|
|
780
|
+
return result ?? "0x0";
|
|
781
|
+
}
|
|
782
|
+
// --- Private: parsers ---
|
|
783
|
+
parseBlock(b) {
|
|
784
|
+
return {
|
|
785
|
+
hash: b.hash,
|
|
786
|
+
number: hexToNumber(b.number),
|
|
787
|
+
timestamp: hexToNumber(b.timestamp),
|
|
788
|
+
transactions: b.transactions.map((tx) => typeof tx === "string" ? tx : tx.hash),
|
|
789
|
+
gasUsed: hexToNumber(b.gasUsed).toString(),
|
|
790
|
+
gasLimit: hexToNumber(b.gasLimit).toString(),
|
|
791
|
+
miner: b.miner,
|
|
792
|
+
parentHash: b.parentHash
|
|
793
|
+
};
|
|
794
|
+
}
|
|
795
|
+
parseTx(tx, receipt) {
|
|
796
|
+
const parsed = {
|
|
797
|
+
hash: tx.hash,
|
|
798
|
+
blockNumber: tx.blockNumber ? hexToNumber(tx.blockNumber) : 0,
|
|
799
|
+
from: tx.from,
|
|
800
|
+
to: tx.to ?? null,
|
|
801
|
+
value: tx.value,
|
|
802
|
+
gasUsed: receipt ? hexToNumber(receipt.gasUsed).toString() : "0",
|
|
803
|
+
gasPrice: _EvmExplorer.hexToDecimalStr(tx.gasPrice),
|
|
804
|
+
nonce: hexToNumber(tx.nonce),
|
|
805
|
+
input: tx.input ?? "0x",
|
|
806
|
+
status: receipt ? hexToNumber(receipt.status) : 0,
|
|
807
|
+
contractAddress: receipt?.contractAddress ?? null,
|
|
808
|
+
timestamp: null
|
|
809
|
+
};
|
|
810
|
+
if (tx.blockHash) parsed.blockHash = tx.blockHash;
|
|
811
|
+
return parsed;
|
|
812
|
+
}
|
|
813
|
+
// --- Private: fetch helpers ---
|
|
814
|
+
async fetchBlock(hashOrNumber, withTxObjects) {
|
|
815
|
+
try {
|
|
816
|
+
if (typeof hashOrNumber === "number" || /^\d+$/.test(String(hashOrNumber))) {
|
|
817
|
+
const hexN = `0x${parseInt(String(hashOrNumber), 10).toString(16)}`;
|
|
818
|
+
return await this.evm.request("eth_getBlockByNumber", [
|
|
819
|
+
hexN,
|
|
820
|
+
withTxObjects
|
|
821
|
+
]);
|
|
822
|
+
}
|
|
823
|
+
return await this.evm.request("eth_getBlockByHash", [
|
|
824
|
+
hashOrNumber,
|
|
825
|
+
withTxObjects
|
|
826
|
+
]);
|
|
827
|
+
} catch {
|
|
828
|
+
return null;
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
async ethCall(to, data) {
|
|
832
|
+
try {
|
|
833
|
+
return await this.evm.call(to, data);
|
|
834
|
+
} catch {
|
|
835
|
+
return null;
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
// --- Private static: ABI decoders ---
|
|
839
|
+
static decodeAbiString(hex) {
|
|
840
|
+
if (!hex || hex === "0x") return "";
|
|
841
|
+
const data = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
842
|
+
if (data.length < 128) return "";
|
|
843
|
+
const length = parseInt(data.slice(64, 128), 16);
|
|
844
|
+
if (!length) return "";
|
|
845
|
+
const strHex = data.slice(128, 128 + length * 2);
|
|
846
|
+
try {
|
|
847
|
+
const bytes = new Uint8Array(strHex.match(/../g)?.map((b) => parseInt(b, 16)) ?? []);
|
|
848
|
+
return new TextDecoder("utf-8", { fatal: false }).decode(bytes).replace(/\0/g, "");
|
|
849
|
+
} catch {
|
|
850
|
+
return "";
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
static decodeAbiUint(hex) {
|
|
854
|
+
if (!hex || hex === "0x") return 0n;
|
|
855
|
+
const clean = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
856
|
+
return BigInt(`0x${clean || "0"}`);
|
|
857
|
+
}
|
|
858
|
+
static hexToDecimalStr(hex) {
|
|
859
|
+
try {
|
|
860
|
+
return BigInt(hex).toString();
|
|
861
|
+
} catch {
|
|
862
|
+
return "0";
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
};
|
|
866
|
+
|
|
867
|
+
// src/indexer/IndexerClient.ts
|
|
868
|
+
var IndexerClient = class {
|
|
869
|
+
baseUrl;
|
|
870
|
+
timeoutMs;
|
|
871
|
+
constructor(config) {
|
|
872
|
+
this.baseUrl = config.baseUrl.replace(/\/$/, "");
|
|
873
|
+
this.timeoutMs = config.timeoutMs ?? 1e4;
|
|
874
|
+
}
|
|
875
|
+
// ─── Internal helpers ──────────────────────────────────────────────────────
|
|
876
|
+
async _fetchResponse(path) {
|
|
877
|
+
const controller = new AbortController();
|
|
878
|
+
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
879
|
+
try {
|
|
880
|
+
return await fetch(`${this.baseUrl}${path}`, { signal: controller.signal });
|
|
881
|
+
} finally {
|
|
882
|
+
clearTimeout(timer);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
async get(path) {
|
|
886
|
+
const res = await this._fetchResponse(path);
|
|
887
|
+
if (!res.ok) {
|
|
888
|
+
throw new Error(`IndexerClient: HTTP ${res.status} for ${path}`);
|
|
889
|
+
}
|
|
890
|
+
return res.json();
|
|
891
|
+
}
|
|
892
|
+
async getOrNull(path) {
|
|
893
|
+
const res = await this._fetchResponse(path);
|
|
894
|
+
if (res.status === 404) return null;
|
|
895
|
+
if (!res.ok) {
|
|
896
|
+
throw new Error(`IndexerClient: HTTP ${res.status} for ${path}`);
|
|
897
|
+
}
|
|
898
|
+
return res.json();
|
|
899
|
+
}
|
|
900
|
+
buildQuery(params) {
|
|
901
|
+
const entries = Object.entries(params).filter(([, v]) => v !== void 0);
|
|
902
|
+
if (entries.length === 0) return "";
|
|
903
|
+
const qs = entries.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`).join("&");
|
|
904
|
+
return `?${qs}`;
|
|
905
|
+
}
|
|
906
|
+
// ─── Commitments ───────────────────────────────────────────────────────────
|
|
907
|
+
/** Returns the total count of shielded commitments. */
|
|
908
|
+
async getCommitmentsCount() {
|
|
909
|
+
const res = await this.get("/shielded/commitments/count");
|
|
910
|
+
return res.total;
|
|
911
|
+
}
|
|
912
|
+
/** Returns a paginated list of shielded commitments. */
|
|
913
|
+
async getCommitments(params) {
|
|
914
|
+
const qs = this.buildQuery({
|
|
915
|
+
page: params?.page,
|
|
916
|
+
limit: params?.limit,
|
|
917
|
+
since_leaf_index: params?.sinceLeafIndex
|
|
918
|
+
});
|
|
919
|
+
return this.get(`/shielded/commitments${qs}`);
|
|
920
|
+
}
|
|
921
|
+
/** Returns a single commitment by its hex string, or null if not found. */
|
|
922
|
+
async getCommitmentByHex(hex) {
|
|
923
|
+
return this.getOrNull(
|
|
924
|
+
`/shielded/commitments/${encodeURIComponent(hex)}`
|
|
925
|
+
);
|
|
926
|
+
}
|
|
927
|
+
// ─── Nullifiers ────────────────────────────────────────────────────────────
|
|
928
|
+
/** Returns a paginated list of spent nullifiers. */
|
|
929
|
+
async getNullifiers(params) {
|
|
930
|
+
const qs = this.buildQuery({ page: params?.page, limit: params?.limit });
|
|
931
|
+
return this.get(`/shielded/nullifiers${qs}`);
|
|
932
|
+
}
|
|
933
|
+
/** Returns the spent/unspent status of a nullifier. */
|
|
934
|
+
async getNullifierStatus(hex) {
|
|
935
|
+
return this.get(
|
|
936
|
+
`/shielded/nullifier/${encodeURIComponent(hex)}/status`
|
|
937
|
+
);
|
|
938
|
+
}
|
|
939
|
+
// ─── Private transfers ─────────────────────────────────────────────────────
|
|
940
|
+
/** Returns a paginated list of private transfer events. */
|
|
941
|
+
async getTransfers(params) {
|
|
942
|
+
const qs = this.buildQuery({ page: params?.page, limit: params?.limit });
|
|
943
|
+
return this.get(`/shielded/transfers${qs}`);
|
|
944
|
+
}
|
|
945
|
+
// ─── Unshields ─────────────────────────────────────────────────────────────
|
|
946
|
+
/** Returns a paginated list of unshield events. */
|
|
947
|
+
async getUnshields(params) {
|
|
948
|
+
const qs = this.buildQuery({ page: params?.page, limit: params?.limit });
|
|
949
|
+
return this.get(`/shielded/unshields${qs}`);
|
|
950
|
+
}
|
|
951
|
+
// ─── Merkle roots ──────────────────────────────────────────────────────────
|
|
952
|
+
/** Returns a paginated list of Merkle root checkpoints. */
|
|
953
|
+
async getMerkleRoots(params) {
|
|
954
|
+
const qs = this.buildQuery({ page: params?.page, limit: params?.limit });
|
|
955
|
+
return this.get(`/shielded/merkle-roots${qs}`);
|
|
956
|
+
}
|
|
957
|
+
/** Returns the latest Merkle root, or null if none exists. */
|
|
958
|
+
async getLatestMerkleRoot() {
|
|
959
|
+
return this.getOrNull("/shielded/merkle-roots/latest");
|
|
960
|
+
}
|
|
961
|
+
// ─── Address activity ──────────────────────────────────────────────────────
|
|
962
|
+
/** Returns a paginated list of extrinsics signed by the given address. */
|
|
963
|
+
async getAddressExtrinsics(address, params) {
|
|
964
|
+
const qs = this.buildQuery({ page: params?.page, limit: params?.limit });
|
|
965
|
+
return this.get(
|
|
966
|
+
`/address/${encodeURIComponent(address.toLowerCase())}/extrinsics${qs}`
|
|
967
|
+
);
|
|
968
|
+
}
|
|
969
|
+
/** Returns a paginated list of EVM transactions filtered by address and/or block number. */
|
|
970
|
+
async getEvmTransactions(params) {
|
|
971
|
+
const qs = this.buildQuery({
|
|
972
|
+
page: params?.page,
|
|
973
|
+
limit: params?.limit,
|
|
974
|
+
address: params?.address?.toLowerCase(),
|
|
975
|
+
blockNumber: params?.blockNumber
|
|
976
|
+
});
|
|
977
|
+
return this.get(`/evm/transactions${qs}`);
|
|
978
|
+
}
|
|
979
|
+
/** Returns a single EVM transaction by hash, or null if not found. */
|
|
980
|
+
async getEvmTransactionByHash(hash) {
|
|
981
|
+
return this.getOrNull(
|
|
982
|
+
`/evm/transactions/${encodeURIComponent(hash.toLowerCase())}`
|
|
983
|
+
);
|
|
984
|
+
}
|
|
985
|
+
// ─── Blocks ────────────────────────────────────────────────────────────────
|
|
986
|
+
/** Returns a paginated list of indexed blocks. */
|
|
987
|
+
async getBlocks(params) {
|
|
988
|
+
const qs = this.buildQuery({ page: params?.page, limit: params?.limit });
|
|
989
|
+
return this.get(`/blocks${qs}`);
|
|
990
|
+
}
|
|
991
|
+
/** Returns a single block by number or hash, or null if not found. */
|
|
992
|
+
async getBlock(numberOrHash) {
|
|
993
|
+
return this.getOrNull(`/blocks/${encodeURIComponent(String(numberOrHash))}`);
|
|
994
|
+
}
|
|
995
|
+
// ─── Address commitments ───────────────────────────────────────────────────
|
|
996
|
+
/** Returns a paginated list of shielded commitments initiated by an address. */
|
|
997
|
+
async getAddressCommitments(address, params) {
|
|
998
|
+
const qs = this.buildQuery({ page: params?.page, limit: params?.limit });
|
|
999
|
+
return this.get(
|
|
1000
|
+
`/address/${encodeURIComponent(address.toLowerCase())}/shielded${qs}`
|
|
1001
|
+
);
|
|
1002
|
+
}
|
|
1003
|
+
/**
|
|
1004
|
+
* Returns a paginated list of all shielded activity (commitments, unshields,
|
|
1005
|
+
* private transfers) associated with the given address.
|
|
1006
|
+
* Each item is tagged with a `kind` discriminant.
|
|
1007
|
+
*/
|
|
1008
|
+
async getAddressShieldedActivity(address, params) {
|
|
1009
|
+
const qs = this.buildQuery({ page: params?.page, limit: params?.limit });
|
|
1010
|
+
return this.get(
|
|
1011
|
+
`/shielded/address/${encodeURIComponent(address.toLowerCase())}${qs}`
|
|
1012
|
+
);
|
|
1013
|
+
}
|
|
1014
|
+
// ─── Stats & Health ────────────────────────────────────────────────────────
|
|
1015
|
+
/** Returns aggregated indexer statistics. */
|
|
1016
|
+
async getStats() {
|
|
1017
|
+
return this.get("/stats");
|
|
1018
|
+
}
|
|
1019
|
+
/** Returns true if the indexer health endpoint responds OK. */
|
|
1020
|
+
async isHealthy() {
|
|
1021
|
+
try {
|
|
1022
|
+
const controller = new AbortController();
|
|
1023
|
+
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
1024
|
+
try {
|
|
1025
|
+
const res = await fetch(`${this.baseUrl}/health`, {
|
|
1026
|
+
signal: controller.signal
|
|
1027
|
+
});
|
|
1028
|
+
return res.ok;
|
|
1029
|
+
} finally {
|
|
1030
|
+
clearTimeout(timer);
|
|
1031
|
+
}
|
|
1032
|
+
} catch {
|
|
1033
|
+
return false;
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
};
|
|
1037
|
+
|
|
1038
|
+
// src/shielded-pool/ShieldedPoolModule.ts
|
|
278
1039
|
import { Binary as Binary2 } from "polkadot-api";
|
|
279
1040
|
|
|
1041
|
+
// src/utils/tx.ts
|
|
1042
|
+
function toTxResult(payload) {
|
|
1043
|
+
const base = {
|
|
1044
|
+
txHash: payload.txHash,
|
|
1045
|
+
blockHash: payload.block.hash,
|
|
1046
|
+
blockNumber: payload.block.number,
|
|
1047
|
+
ok: payload.ok
|
|
1048
|
+
};
|
|
1049
|
+
if (!payload.ok) {
|
|
1050
|
+
return { ...base, error: payload.dispatchError.type };
|
|
1051
|
+
}
|
|
1052
|
+
return base;
|
|
1053
|
+
}
|
|
1054
|
+
function callUnsafeTx(txEntry, ...args) {
|
|
1055
|
+
return txEntry(...args);
|
|
1056
|
+
}
|
|
1057
|
+
function resolveTx(unsafe, pallet, call) {
|
|
1058
|
+
const u = unsafe;
|
|
1059
|
+
const p = u["tx"]?.[pallet];
|
|
1060
|
+
if (p === void 0) throw new Error(`Pallet "${pallet}" not found in runtime metadata`);
|
|
1061
|
+
const entry = p[call];
|
|
1062
|
+
if (entry === void 0)
|
|
1063
|
+
throw new Error(`Call "${pallet}.${call}" not found in runtime metadata`);
|
|
1064
|
+
return entry;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
280
1067
|
// src/shielded-pool/EncryptedMemo.ts
|
|
281
|
-
import { sha256 } from "@noble/hashes/sha2.js";
|
|
282
1068
|
import { chacha20poly1305 } from "@noble/ciphers/chacha.js";
|
|
283
1069
|
import { randomBytes } from "@noble/ciphers/utils.js";
|
|
284
1070
|
|
|
@@ -335,11 +1121,10 @@ function leHexToBigint(hex) {
|
|
|
335
1121
|
return bytesToBigintLE(bytes);
|
|
336
1122
|
}
|
|
337
1123
|
|
|
338
|
-
// src/shielded-pool/
|
|
1124
|
+
// src/shielded-pool/helpers.ts
|
|
1125
|
+
import { sha256 } from "@noble/hashes/sha2.js";
|
|
339
1126
|
var KEY_DOMAIN = new TextEncoder().encode("orbinum-note-encryption-v1");
|
|
340
|
-
var NONCE_SIZE = 12;
|
|
341
1127
|
var MEMO_PLAINTEXT_SIZE = 76;
|
|
342
|
-
var ENCRYPTED_MEMO_SIZE = 104;
|
|
343
1128
|
function serializeMemo(value, ownerPk, blinding, assetId) {
|
|
344
1129
|
const buf = new Uint8Array(MEMO_PLAINTEXT_SIZE);
|
|
345
1130
|
const view = new DataView(buf.buffer);
|
|
@@ -356,6 +1141,22 @@ function deriveEncryptionKey(viewingKey, commitment) {
|
|
|
356
1141
|
h.update(KEY_DOMAIN);
|
|
357
1142
|
return h.digest();
|
|
358
1143
|
}
|
|
1144
|
+
function toBase64(buf) {
|
|
1145
|
+
const bytes = buf instanceof Uint8Array ? buf : new Uint8Array(buf);
|
|
1146
|
+
let str = "";
|
|
1147
|
+
for (const b of bytes) str += String.fromCharCode(b);
|
|
1148
|
+
return btoa(str);
|
|
1149
|
+
}
|
|
1150
|
+
function fromBase64(b64) {
|
|
1151
|
+
const bin = atob(b64);
|
|
1152
|
+
const out = new Uint8Array(bin.length);
|
|
1153
|
+
for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
|
|
1154
|
+
return out;
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
// src/shielded-pool/EncryptedMemo.ts
|
|
1158
|
+
var NONCE_SIZE = 12;
|
|
1159
|
+
var ENCRYPTED_MEMO_SIZE = 104;
|
|
359
1160
|
var EncryptedMemo = {
|
|
360
1161
|
/**
|
|
361
1162
|
* Build and encrypt a memo for a note.
|
|
@@ -501,34 +1302,9 @@ var NoteBuilder = class {
|
|
|
501
1302
|
};
|
|
502
1303
|
|
|
503
1304
|
// src/shielded-pool/ShieldedPoolModule.ts
|
|
504
|
-
function toTxResult(payload) {
|
|
505
|
-
const base = {
|
|
506
|
-
txHash: payload.txHash,
|
|
507
|
-
blockHash: payload.block.hash,
|
|
508
|
-
blockNumber: payload.block.number,
|
|
509
|
-
ok: payload.ok
|
|
510
|
-
};
|
|
511
|
-
if (!payload.ok) {
|
|
512
|
-
return { ...base, error: payload.dispatchError.type };
|
|
513
|
-
}
|
|
514
|
-
return base;
|
|
515
|
-
}
|
|
516
|
-
function callUnsafeTx(txEntry, ...args) {
|
|
517
|
-
return txEntry(...args);
|
|
518
|
-
}
|
|
519
|
-
function resolveTx(unsafe, pallet, call) {
|
|
520
|
-
const u = unsafe;
|
|
521
|
-
const p = u["tx"]?.[pallet];
|
|
522
|
-
if (p === void 0) throw new Error(`Pallet "${pallet}" not found in runtime metadata`);
|
|
523
|
-
const entry = p[call];
|
|
524
|
-
if (entry === void 0)
|
|
525
|
-
throw new Error(`Call "${pallet}.${call}" not found in runtime metadata`);
|
|
526
|
-
return entry;
|
|
527
|
-
}
|
|
528
1305
|
var ShieldedPoolModule = class {
|
|
529
|
-
constructor(substrate
|
|
1306
|
+
constructor(substrate) {
|
|
530
1307
|
this.substrate = substrate;
|
|
531
|
-
this.merkle = merkle;
|
|
532
1308
|
}
|
|
533
1309
|
// ─── Extrinsics ────────────────────────────────────────────────────────────
|
|
534
1310
|
/**
|
|
@@ -620,44 +1396,26 @@ var ShieldedPoolModule = class {
|
|
|
620
1396
|
);
|
|
621
1397
|
return toTxResult(await tx.signAndSubmit(signer));
|
|
622
1398
|
}
|
|
623
|
-
// ─── Queries ───────────────────────────────────────────────────────────────
|
|
624
|
-
/** Returns whether a nullifier has already been spent. */
|
|
625
|
-
async isNullifierSpent(nullifierHex) {
|
|
626
|
-
const raw = await this.substrate.request(
|
|
627
|
-
"privacy_getNullifierStatus",
|
|
628
|
-
[nullifierHex]
|
|
629
|
-
);
|
|
630
|
-
return raw.is_spent;
|
|
631
|
-
}
|
|
632
|
-
/** Returns the full nullifier status object. */
|
|
633
|
-
async getNullifierStatus(nullifierHex) {
|
|
634
|
-
const raw = await this.substrate.request(
|
|
635
|
-
"privacy_getNullifierStatus",
|
|
636
|
-
[nullifierHex]
|
|
637
|
-
);
|
|
638
|
-
return { nullifier: raw.nullifier, isSpent: raw.is_spent };
|
|
639
|
-
}
|
|
640
|
-
/** Returns the total locked balance in the pool for a given asset. */
|
|
641
|
-
async getPoolBalance(assetId) {
|
|
642
|
-
const raw = await this.substrate.request(
|
|
643
|
-
"shieldedPool_getPoolBalance",
|
|
644
|
-
[assetId]
|
|
645
|
-
);
|
|
646
|
-
return { assetId, balance: BigInt(raw.balance) };
|
|
647
|
-
}
|
|
648
1399
|
/**
|
|
649
|
-
*
|
|
650
|
-
*
|
|
1400
|
+
* Deposits multiple notes into the shielded pool in a single extrinsic.
|
|
1401
|
+
* Extrinsic: shieldedPool.shieldBatch(operations) — max 20 items.
|
|
651
1402
|
*/
|
|
652
|
-
async
|
|
653
|
-
const
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
1403
|
+
async shieldBatch(params, signer) {
|
|
1404
|
+
const operations = params.items.map((item) => ({
|
|
1405
|
+
assetId: item.assetId,
|
|
1406
|
+
amount: item.amount.toString(),
|
|
1407
|
+
commitment: Binary2.fromHex(item.commitment),
|
|
1408
|
+
encryptedMemo: Binary2.fromBytes(item.encryptedMemo ?? EncryptedMemo.dummy())
|
|
1409
|
+
}));
|
|
1410
|
+
const entry = resolveTx(this.substrate.unsafe, "shieldedPool", "shieldBatch");
|
|
1411
|
+
const tx = callUnsafeTx(entry, operations);
|
|
1412
|
+
return toTxResult(await tx.signAndSubmit(signer));
|
|
658
1413
|
}
|
|
659
1414
|
};
|
|
660
1415
|
|
|
1416
|
+
// src/account-mapping/AccountMappingModule.ts
|
|
1417
|
+
import { Binary as Binary3 } from "polkadot-api";
|
|
1418
|
+
|
|
661
1419
|
// src/utils/address.ts
|
|
662
1420
|
import { decodeAddress, encodeAddress } from "@polkadot/util-crypto";
|
|
663
1421
|
function normalizeEvmAddress(addr) {
|
|
@@ -688,6 +1446,10 @@ function evmToImplicitSubstrate(evmAddr) {
|
|
|
688
1446
|
}
|
|
689
1447
|
return "0x" + clean.toLowerCase() + "0".repeat(24);
|
|
690
1448
|
}
|
|
1449
|
+
function evmToMappedAccountHex(address) {
|
|
1450
|
+
if (!isEvmAddress(address)) return null;
|
|
1451
|
+
return evmToImplicitSubstrate(address);
|
|
1452
|
+
}
|
|
691
1453
|
function isImplicitEvmAccount(accountHex) {
|
|
692
1454
|
const clean = accountHex.startsWith("0x") ? accountHex.slice(2) : accountHex;
|
|
693
1455
|
if (clean.length !== 64) return false;
|
|
@@ -790,69 +1552,40 @@ function addressToAccountIdHex(addr) {
|
|
|
790
1552
|
return substrateSs58ToAccountIdHex(addr);
|
|
791
1553
|
}
|
|
792
1554
|
|
|
793
|
-
// src/
|
|
794
|
-
|
|
795
|
-
|
|
1555
|
+
// src/account-mapping/helpers.ts
|
|
1556
|
+
function mapRawScheme(raw) {
|
|
1557
|
+
if (raw === "Eip191" || raw === "eip191") return "Eip191";
|
|
1558
|
+
if (raw === "Ed25519" || raw === "ed25519") return "Ed25519";
|
|
1559
|
+
return raw;
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
// src/account-mapping/AccountMappingModule.ts
|
|
1563
|
+
var AccountMappingModule = class {
|
|
1564
|
+
constructor(substrate) {
|
|
796
1565
|
this.substrate = substrate;
|
|
797
|
-
this.evm = evm;
|
|
798
|
-
}
|
|
799
|
-
// ─── Node info ─────────────────────────────────────────────────────────────
|
|
800
|
-
/**
|
|
801
|
-
* Returns basic chain information from the node.
|
|
802
|
-
*/
|
|
803
|
-
async getChainInfo() {
|
|
804
|
-
const [name, version] = await Promise.all([
|
|
805
|
-
this.substrate.request("system_name", []),
|
|
806
|
-
this.substrate.request("state_getRuntimeVersion", [])
|
|
807
|
-
]);
|
|
808
|
-
return {
|
|
809
|
-
name,
|
|
810
|
-
version: String(version.specVersion),
|
|
811
|
-
ss58Prefix: version.ss58Prefix ?? 42
|
|
812
|
-
};
|
|
813
|
-
}
|
|
814
|
-
/**
|
|
815
|
-
* Returns the node's peer count and sync status.
|
|
816
|
-
*/
|
|
817
|
-
async getHealth() {
|
|
818
|
-
return this.substrate.request("system_health", []);
|
|
819
|
-
}
|
|
820
|
-
/**
|
|
821
|
-
* Returns the node's software version string.
|
|
822
|
-
*/
|
|
823
|
-
async getNodeVersion() {
|
|
824
|
-
return this.substrate.request("system_version", []);
|
|
825
|
-
}
|
|
826
|
-
/**
|
|
827
|
-
* Returns the genesis hash hex.
|
|
828
|
-
*/
|
|
829
|
-
async getGenesisHash() {
|
|
830
|
-
return this.substrate.request("chain_getBlockHash", [0]);
|
|
831
1566
|
}
|
|
832
|
-
// ───
|
|
1567
|
+
// ─── Address resolution ─────────────────────────────────────────────────────
|
|
833
1568
|
/**
|
|
834
|
-
*
|
|
835
|
-
*
|
|
1569
|
+
* Returns the explicitly mapped (or fallback) Substrate AccountId32 hex for
|
|
1570
|
+
* an EVM address. `mapped` is set only when `map_account` was called.
|
|
1571
|
+
* `fallback` is always the EeSuffix rule: `H160 ++ [0x00; 12]`.
|
|
836
1572
|
*/
|
|
837
|
-
async
|
|
1573
|
+
async getAccountAddresses(accountId) {
|
|
838
1574
|
try {
|
|
839
1575
|
const raw = await this.substrate.request(
|
|
840
|
-
"
|
|
841
|
-
[
|
|
1576
|
+
"accountMapping_getAccountAddresses",
|
|
1577
|
+
[accountId]
|
|
842
1578
|
);
|
|
843
|
-
return {
|
|
844
|
-
substrateAddress: raw.substrate_address ?? null,
|
|
845
|
-
evmAddress: raw.evm_address ? normalizeEvmAddress(raw.evm_address) : null,
|
|
846
|
-
alias: raw.alias ?? null
|
|
847
|
-
};
|
|
1579
|
+
return { mapped: raw.mapped ?? null, fallback: raw.fallback ?? null };
|
|
848
1580
|
} catch {
|
|
849
|
-
return null;
|
|
1581
|
+
return { mapped: null, fallback: null };
|
|
850
1582
|
}
|
|
851
1583
|
}
|
|
852
1584
|
/**
|
|
853
|
-
* Returns the mapped Substrate
|
|
1585
|
+
* Returns the explicitly mapped Substrate AccountId32 hex for a given EVM
|
|
1586
|
+
* address, or null if no explicit mapping exists.
|
|
854
1587
|
*/
|
|
855
|
-
async
|
|
1588
|
+
async getMappedAccount(evmAddress) {
|
|
856
1589
|
try {
|
|
857
1590
|
return await this.substrate.request("accountMapping_getMappedAccount", [
|
|
858
1591
|
normalizeEvmAddress(evmAddress)
|
|
@@ -861,139 +1594,43 @@ var ChainModule = class {
|
|
|
861
1594
|
return null;
|
|
862
1595
|
}
|
|
863
1596
|
}
|
|
1597
|
+
// ─── Alias queries ──────────────────────────────────────────────────────────
|
|
864
1598
|
/**
|
|
865
|
-
*
|
|
1599
|
+
* Resolves "@alias" to basic info (owner, optional EVM address, link count).
|
|
1600
|
+
* Accepts the alias with or without the leading "@".
|
|
866
1601
|
*/
|
|
867
|
-
async
|
|
1602
|
+
async resolveAlias(alias) {
|
|
868
1603
|
try {
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
1604
|
+
const raw = await this.substrate.request(
|
|
1605
|
+
"accountMapping_resolveAlias",
|
|
1606
|
+
[alias]
|
|
1607
|
+
);
|
|
1608
|
+
if (!raw) return null;
|
|
1609
|
+
return {
|
|
1610
|
+
owner: raw.substrate_account,
|
|
1611
|
+
evmAddress: raw.evm_address ? normalizeEvmAddress(raw.evm_address) : null,
|
|
1612
|
+
chainLinksCount: raw.chain_links_count
|
|
1613
|
+
};
|
|
872
1614
|
} catch {
|
|
873
1615
|
return null;
|
|
874
1616
|
}
|
|
875
1617
|
}
|
|
876
|
-
// ─── EVM helpers ───────────────────────────────────────────────────────────
|
|
877
1618
|
/**
|
|
878
|
-
* Returns
|
|
879
|
-
* to have been provided in `OrbinumClientConfig`.
|
|
1619
|
+
* Returns the alias registered for the given Substrate AccountId32 hex, or null.
|
|
880
1620
|
*/
|
|
881
|
-
async
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
1621
|
+
async getAliasOf(accountId) {
|
|
1622
|
+
try {
|
|
1623
|
+
return await this.substrate.request("accountMapping_getAliasOf", [
|
|
1624
|
+
accountId
|
|
1625
|
+
]);
|
|
1626
|
+
} catch {
|
|
1627
|
+
return null;
|
|
1628
|
+
}
|
|
885
1629
|
}
|
|
1630
|
+
// ─── Full identity ──────────────────────────────────────────────────────────
|
|
886
1631
|
/**
|
|
887
|
-
*
|
|
888
|
-
|
|
889
|
-
async getEvmBlockNumber() {
|
|
890
|
-
if (!this.evm) throw new Error("No EVM RPC URL configured.");
|
|
891
|
-
return this.evm.getBlockNumber();
|
|
892
|
-
}
|
|
893
|
-
};
|
|
894
|
-
|
|
895
|
-
// src/account-mapping/AccountMappingModule.ts
|
|
896
|
-
import { Binary as Binary3 } from "polkadot-api";
|
|
897
|
-
function toTxResult2(payload) {
|
|
898
|
-
const base = {
|
|
899
|
-
txHash: payload.txHash,
|
|
900
|
-
blockHash: payload.block.hash,
|
|
901
|
-
blockNumber: payload.block.number,
|
|
902
|
-
ok: payload.ok
|
|
903
|
-
};
|
|
904
|
-
if (!payload.ok) {
|
|
905
|
-
return { ...base, error: payload.dispatchError.type };
|
|
906
|
-
}
|
|
907
|
-
return base;
|
|
908
|
-
}
|
|
909
|
-
function callUnsafeTx2(txEntry, ...args) {
|
|
910
|
-
return txEntry(...args);
|
|
911
|
-
}
|
|
912
|
-
function resolveTx2(unsafe, pallet, call) {
|
|
913
|
-
const u = unsafe;
|
|
914
|
-
const p = u["tx"]?.[pallet];
|
|
915
|
-
if (p === void 0) throw new Error(`Pallet "${pallet}" not found in runtime metadata`);
|
|
916
|
-
const entry = p[call];
|
|
917
|
-
if (entry === void 0)
|
|
918
|
-
throw new Error(`Call "${pallet}.${call}" not found in runtime metadata`);
|
|
919
|
-
return entry;
|
|
920
|
-
}
|
|
921
|
-
function mapRawScheme(raw) {
|
|
922
|
-
if (raw === "Eip191" || raw === "eip191") return "Eip191";
|
|
923
|
-
if (raw === "Ed25519" || raw === "ed25519") return "Ed25519";
|
|
924
|
-
return raw;
|
|
925
|
-
}
|
|
926
|
-
var AccountMappingModule = class {
|
|
927
|
-
constructor(substrate) {
|
|
928
|
-
this.substrate = substrate;
|
|
929
|
-
}
|
|
930
|
-
// ─── Address resolution ─────────────────────────────────────────────────────
|
|
931
|
-
/**
|
|
932
|
-
* Returns the explicitly mapped (or fallback) Substrate AccountId32 hex for
|
|
933
|
-
* an EVM address. `mapped` is set only when `map_account` was called.
|
|
934
|
-
* `fallback` is always the EeSuffix rule: `H160 ++ [0x00; 12]`.
|
|
935
|
-
*/
|
|
936
|
-
async getAccountAddresses(accountId) {
|
|
937
|
-
try {
|
|
938
|
-
const raw = await this.substrate.request(
|
|
939
|
-
"accountMapping_getAccountAddresses",
|
|
940
|
-
[accountId]
|
|
941
|
-
);
|
|
942
|
-
return { mapped: raw.mapped ?? null, fallback: raw.fallback ?? null };
|
|
943
|
-
} catch {
|
|
944
|
-
return { mapped: null, fallback: null };
|
|
945
|
-
}
|
|
946
|
-
}
|
|
947
|
-
/**
|
|
948
|
-
* Returns the explicitly mapped Substrate AccountId32 hex for a given EVM
|
|
949
|
-
* address, or null if no explicit mapping exists.
|
|
950
|
-
*/
|
|
951
|
-
async getMappedAccount(evmAddress) {
|
|
952
|
-
try {
|
|
953
|
-
return await this.substrate.request("accountMapping_getMappedAccount", [
|
|
954
|
-
normalizeEvmAddress(evmAddress)
|
|
955
|
-
]);
|
|
956
|
-
} catch {
|
|
957
|
-
return null;
|
|
958
|
-
}
|
|
959
|
-
}
|
|
960
|
-
// ─── Alias queries ──────────────────────────────────────────────────────────
|
|
961
|
-
/**
|
|
962
|
-
* Resolves "@alias" to basic info (owner, optional EVM address, link count).
|
|
963
|
-
* Accepts the alias with or without the leading "@".
|
|
964
|
-
*/
|
|
965
|
-
async resolveAlias(alias) {
|
|
966
|
-
try {
|
|
967
|
-
const raw = await this.substrate.request(
|
|
968
|
-
"accountMapping_resolveAlias",
|
|
969
|
-
[alias]
|
|
970
|
-
);
|
|
971
|
-
if (!raw) return null;
|
|
972
|
-
return {
|
|
973
|
-
owner: raw.substrate_account,
|
|
974
|
-
evmAddress: raw.evm_address ? normalizeEvmAddress(raw.evm_address) : null,
|
|
975
|
-
chainLinksCount: raw.chain_links_count
|
|
976
|
-
};
|
|
977
|
-
} catch {
|
|
978
|
-
return null;
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
|
-
/**
|
|
982
|
-
* Returns the alias registered for the given Substrate AccountId32 hex, or null.
|
|
983
|
-
*/
|
|
984
|
-
async getAliasOf(accountId) {
|
|
985
|
-
try {
|
|
986
|
-
return await this.substrate.request("accountMapping_getAliasOf", [
|
|
987
|
-
accountId
|
|
988
|
-
]);
|
|
989
|
-
} catch {
|
|
990
|
-
return null;
|
|
991
|
-
}
|
|
992
|
-
}
|
|
993
|
-
// ─── Full identity ──────────────────────────────────────────────────────────
|
|
994
|
-
/**
|
|
995
|
-
* Resolves "@alias" to its full identity: owner, EVM address, all public
|
|
996
|
-
* chain links, and profile metadata.
|
|
1632
|
+
* Resolves "@alias" to its full identity: owner, EVM address, all public
|
|
1633
|
+
* chain links, and profile metadata.
|
|
997
1634
|
*/
|
|
998
1635
|
async resolveFullIdentity(alias) {
|
|
999
1636
|
try {
|
|
@@ -1162,18 +1799,18 @@ var AccountMappingModule = class {
|
|
|
1162
1799
|
* Extrinsic: accountMapping.mapAccount()
|
|
1163
1800
|
*/
|
|
1164
1801
|
async mapAccount(signer) {
|
|
1165
|
-
const entry =
|
|
1166
|
-
const tx =
|
|
1167
|
-
return
|
|
1802
|
+
const entry = resolveTx(this.substrate.unsafe, "accountMapping", "mapAccount");
|
|
1803
|
+
const tx = callUnsafeTx(entry);
|
|
1804
|
+
return toTxResult(await tx.signAndSubmit(signer));
|
|
1168
1805
|
}
|
|
1169
1806
|
/**
|
|
1170
1807
|
* Removes the EVM → Substrate mapping for the caller.
|
|
1171
1808
|
* Extrinsic: accountMapping.unmapAccount()
|
|
1172
1809
|
*/
|
|
1173
1810
|
async unmapAccount(signer) {
|
|
1174
|
-
const entry =
|
|
1175
|
-
const tx =
|
|
1176
|
-
return
|
|
1811
|
+
const entry = resolveTx(this.substrate.unsafe, "accountMapping", "unmapAccount");
|
|
1812
|
+
const tx = callUnsafeTx(entry);
|
|
1813
|
+
return toTxResult(await tx.signAndSubmit(signer));
|
|
1177
1814
|
}
|
|
1178
1815
|
/**
|
|
1179
1816
|
* Registers a unique @alias for the caller.
|
|
@@ -1181,27 +1818,27 @@ var AccountMappingModule = class {
|
|
|
1181
1818
|
* Extrinsic: accountMapping.registerAlias(alias)
|
|
1182
1819
|
*/
|
|
1183
1820
|
async registerAlias(alias, signer) {
|
|
1184
|
-
const entry =
|
|
1185
|
-
const tx =
|
|
1186
|
-
return
|
|
1821
|
+
const entry = resolveTx(this.substrate.unsafe, "accountMapping", "registerAlias");
|
|
1822
|
+
const tx = callUnsafeTx(entry, Binary3.fromText(alias));
|
|
1823
|
+
return toTxResult(await tx.signAndSubmit(signer));
|
|
1187
1824
|
}
|
|
1188
1825
|
/**
|
|
1189
1826
|
* Releases the caller's alias and recovers the deposit.
|
|
1190
1827
|
* Extrinsic: accountMapping.releaseAlias()
|
|
1191
1828
|
*/
|
|
1192
1829
|
async releaseAlias(signer) {
|
|
1193
|
-
const entry =
|
|
1194
|
-
const tx =
|
|
1195
|
-
return
|
|
1830
|
+
const entry = resolveTx(this.substrate.unsafe, "accountMapping", "releaseAlias");
|
|
1831
|
+
const tx = callUnsafeTx(entry);
|
|
1832
|
+
return toTxResult(await tx.signAndSubmit(signer));
|
|
1196
1833
|
}
|
|
1197
1834
|
/**
|
|
1198
1835
|
* Transfers the caller's alias to another account.
|
|
1199
1836
|
* Extrinsic: accountMapping.transferAlias(newOwner)
|
|
1200
1837
|
*/
|
|
1201
1838
|
async transferAlias(newOwnerHex, signer) {
|
|
1202
|
-
const entry =
|
|
1203
|
-
const tx =
|
|
1204
|
-
return
|
|
1839
|
+
const entry = resolveTx(this.substrate.unsafe, "accountMapping", "transferAlias");
|
|
1840
|
+
const tx = callUnsafeTx(entry, newOwnerHex);
|
|
1841
|
+
return toTxResult(await tx.signAndSubmit(signer));
|
|
1205
1842
|
}
|
|
1206
1843
|
/**
|
|
1207
1844
|
* Adds a verified public link to an external-chain wallet.
|
|
@@ -1214,65 +1851,65 @@ var AccountMappingModule = class {
|
|
|
1214
1851
|
* Extrinsic: accountMapping.addChainLink(chainId, address, signature)
|
|
1215
1852
|
*/
|
|
1216
1853
|
async addChainLink(params, signer) {
|
|
1217
|
-
const entry =
|
|
1218
|
-
const tx =
|
|
1854
|
+
const entry = resolveTx(this.substrate.unsafe, "accountMapping", "addChainLink");
|
|
1855
|
+
const tx = callUnsafeTx(
|
|
1219
1856
|
entry,
|
|
1220
1857
|
params.chainId,
|
|
1221
1858
|
Binary3.fromBytes(params.address),
|
|
1222
1859
|
Binary3.fromBytes(params.signature)
|
|
1223
1860
|
);
|
|
1224
|
-
return
|
|
1861
|
+
return toTxResult(await tx.signAndSubmit(signer));
|
|
1225
1862
|
}
|
|
1226
1863
|
/**
|
|
1227
1864
|
* Removes the external-chain link for the given chain ID.
|
|
1228
1865
|
* Extrinsic: accountMapping.removeChainLink(chainId)
|
|
1229
1866
|
*/
|
|
1230
1867
|
async removeChainLink(chainId, signer) {
|
|
1231
|
-
const entry =
|
|
1232
|
-
const tx =
|
|
1233
|
-
return
|
|
1868
|
+
const entry = resolveTx(this.substrate.unsafe, "accountMapping", "removeChainLink");
|
|
1869
|
+
const tx = callUnsafeTx(entry, chainId);
|
|
1870
|
+
return toTxResult(await tx.signAndSubmit(signer));
|
|
1234
1871
|
}
|
|
1235
1872
|
/**
|
|
1236
1873
|
* Updates the caller's public profile metadata.
|
|
1237
1874
|
* Extrinsic: accountMapping.setAccountMetadata(displayName, bio, avatar)
|
|
1238
1875
|
*/
|
|
1239
1876
|
async setAccountMetadata(params, signer) {
|
|
1240
|
-
const entry =
|
|
1877
|
+
const entry = resolveTx(this.substrate.unsafe, "accountMapping", "setAccountMetadata");
|
|
1241
1878
|
const encode2 = (v) => v != null ? Binary3.fromText(v) : void 0;
|
|
1242
|
-
const tx =
|
|
1879
|
+
const tx = callUnsafeTx(
|
|
1243
1880
|
entry,
|
|
1244
1881
|
encode2(params.displayName),
|
|
1245
1882
|
encode2(params.bio),
|
|
1246
1883
|
encode2(params.avatar)
|
|
1247
1884
|
);
|
|
1248
|
-
return
|
|
1885
|
+
return toTxResult(await tx.signAndSubmit(signer));
|
|
1249
1886
|
}
|
|
1250
1887
|
/**
|
|
1251
1888
|
* Lists the caller's alias for sale on the alias marketplace.
|
|
1252
1889
|
* Extrinsic: accountMapping.putAliasOnSale(price, isPrivate)
|
|
1253
1890
|
*/
|
|
1254
1891
|
async putAliasOnSale(params, signer) {
|
|
1255
|
-
const entry =
|
|
1256
|
-
const tx =
|
|
1257
|
-
return
|
|
1892
|
+
const entry = resolveTx(this.substrate.unsafe, "accountMapping", "putAliasOnSale");
|
|
1893
|
+
const tx = callUnsafeTx(entry, params.price.toString(), params.isPrivate);
|
|
1894
|
+
return toTxResult(await tx.signAndSubmit(signer));
|
|
1258
1895
|
}
|
|
1259
1896
|
/**
|
|
1260
1897
|
* Cancels an active alias sale listing.
|
|
1261
1898
|
* Extrinsic: accountMapping.cancelSale()
|
|
1262
1899
|
*/
|
|
1263
1900
|
async cancelSale(signer) {
|
|
1264
|
-
const entry =
|
|
1265
|
-
const tx =
|
|
1266
|
-
return
|
|
1901
|
+
const entry = resolveTx(this.substrate.unsafe, "accountMapping", "cancelSale");
|
|
1902
|
+
const tx = callUnsafeTx(entry);
|
|
1903
|
+
return toTxResult(await tx.signAndSubmit(signer));
|
|
1267
1904
|
}
|
|
1268
1905
|
/**
|
|
1269
1906
|
* Purchases an alias listed for sale.
|
|
1270
1907
|
* Extrinsic: accountMapping.buyAlias(alias)
|
|
1271
1908
|
*/
|
|
1272
1909
|
async buyAlias(alias, signer) {
|
|
1273
|
-
const entry =
|
|
1274
|
-
const tx =
|
|
1275
|
-
return
|
|
1910
|
+
const entry = resolveTx(this.substrate.unsafe, "accountMapping", "buyAlias");
|
|
1911
|
+
const tx = callUnsafeTx(entry, Binary3.fromText(alias));
|
|
1912
|
+
return toTxResult(await tx.signAndSubmit(signer));
|
|
1276
1913
|
}
|
|
1277
1914
|
/**
|
|
1278
1915
|
* Dispatches an arbitrary call on behalf of a linked external-chain wallet.
|
|
@@ -1286,8 +1923,8 @@ var AccountMappingModule = class {
|
|
|
1286
1923
|
* Extrinsic: accountMapping.dispatchAsLinkedAccount(owner, chainId, address, signature, call)
|
|
1287
1924
|
*/
|
|
1288
1925
|
async dispatchAsLinkedAccount(params, signer) {
|
|
1289
|
-
const entry =
|
|
1290
|
-
const tx =
|
|
1926
|
+
const entry = resolveTx(this.substrate.unsafe, "accountMapping", "dispatchAsLinkedAccount");
|
|
1927
|
+
const tx = callUnsafeTx(
|
|
1291
1928
|
entry,
|
|
1292
1929
|
params.owner,
|
|
1293
1930
|
params.chainId,
|
|
@@ -1295,18 +1932,118 @@ var AccountMappingModule = class {
|
|
|
1295
1932
|
Binary3.fromBytes(params.signature),
|
|
1296
1933
|
Binary3.fromBytes(params.callData)
|
|
1297
1934
|
);
|
|
1298
|
-
return
|
|
1935
|
+
return toTxResult(await tx.signAndSubmit(signer));
|
|
1299
1936
|
}
|
|
1300
1937
|
};
|
|
1301
1938
|
|
|
1302
|
-
// src/
|
|
1939
|
+
// src/rpc-v2/helpers.ts
|
|
1940
|
+
function mapAssetBalance(balance) {
|
|
1941
|
+
return {
|
|
1942
|
+
assetId: balance.asset_id,
|
|
1943
|
+
balance: balance.balance.toString()
|
|
1944
|
+
};
|
|
1945
|
+
}
|
|
1946
|
+
|
|
1947
|
+
// src/rpc-v2/PrivacyModule.ts
|
|
1948
|
+
var PrivacyModule = class {
|
|
1949
|
+
constructor(substrate) {
|
|
1950
|
+
this.substrate = substrate;
|
|
1951
|
+
}
|
|
1952
|
+
/** Returns the current Merkle tree root. */
|
|
1953
|
+
async getMerkleRoot() {
|
|
1954
|
+
return this.substrate.request("privacy_getMerkleRoot", []);
|
|
1955
|
+
}
|
|
1956
|
+
/** Returns the Merkle proof for the given leaf index or commitment hex. */
|
|
1957
|
+
async getMerkleProof(leafIndex) {
|
|
1958
|
+
const raw = await this.substrate.request("privacy_getMerkleProof", [
|
|
1959
|
+
leafIndex
|
|
1960
|
+
]);
|
|
1961
|
+
return {
|
|
1962
|
+
path: raw.path,
|
|
1963
|
+
leafIndex: raw.leaf_index,
|
|
1964
|
+
treeDepth: raw.tree_depth
|
|
1965
|
+
};
|
|
1966
|
+
}
|
|
1967
|
+
/**
|
|
1968
|
+
* Returns the Merkle inclusion proof for a given commitment hex,
|
|
1969
|
+
* bundled with the current Merkle root.
|
|
1970
|
+
*/
|
|
1971
|
+
async getMerkleProofByCommitment(commitmentHex) {
|
|
1972
|
+
const [proof, root] = await Promise.all([
|
|
1973
|
+
this.getMerkleProof(commitmentHex),
|
|
1974
|
+
this.getMerkleRoot()
|
|
1975
|
+
]);
|
|
1976
|
+
return { ...proof, root };
|
|
1977
|
+
}
|
|
1978
|
+
/** Returns the spend status of a nullifier. */
|
|
1979
|
+
async getNullifierStatus(nullifier) {
|
|
1980
|
+
const raw = await this.substrate.request(
|
|
1981
|
+
"privacy_getNullifierStatus",
|
|
1982
|
+
[nullifier]
|
|
1983
|
+
);
|
|
1984
|
+
return {
|
|
1985
|
+
nullifier: raw.nullifier,
|
|
1986
|
+
isSpent: raw.is_spent
|
|
1987
|
+
};
|
|
1988
|
+
}
|
|
1989
|
+
/** Returns aggregated statistics for the shielded pool from `rpc-v2`. */
|
|
1990
|
+
async getPoolStats() {
|
|
1991
|
+
const raw = await this.substrate.request("privacy_getPoolStats", []);
|
|
1992
|
+
return {
|
|
1993
|
+
merkleRoot: raw.merkle_root,
|
|
1994
|
+
commitmentCount: raw.commitment_count,
|
|
1995
|
+
totalBalance: raw.total_balance.toString(),
|
|
1996
|
+
assetBalances: raw.asset_balances.map(mapAssetBalance),
|
|
1997
|
+
treeDepth: raw.tree_depth
|
|
1998
|
+
};
|
|
1999
|
+
}
|
|
2000
|
+
};
|
|
2001
|
+
|
|
2002
|
+
// src/zk-verifier/ZkVerifierModule.ts
|
|
2003
|
+
function mapVkHash(raw) {
|
|
2004
|
+
return { version: raw.version, vkHash: raw.vk_hash };
|
|
2005
|
+
}
|
|
2006
|
+
function mapCircuitVersionInfo(raw) {
|
|
2007
|
+
return {
|
|
2008
|
+
circuitId: raw.circuit_id,
|
|
2009
|
+
activeVersion: raw.active_version,
|
|
2010
|
+
proofSystem: "Groth16",
|
|
2011
|
+
supportedVersions: raw.supported_versions,
|
|
2012
|
+
vkHashes: raw.vk_hashes.map(mapVkHash),
|
|
2013
|
+
historicalVersions: []
|
|
2014
|
+
};
|
|
2015
|
+
}
|
|
2016
|
+
var ZkVerifierModule = class {
|
|
2017
|
+
constructor(substrate) {
|
|
2018
|
+
this.substrate = substrate;
|
|
2019
|
+
}
|
|
2020
|
+
/** Returns basic version info for all registered circuits. */
|
|
2021
|
+
async getAllCircuitVersions() {
|
|
2022
|
+
const raw = await this.substrate.request(
|
|
2023
|
+
"zkVerifier_getAllCircuitVersions",
|
|
2024
|
+
[]
|
|
2025
|
+
);
|
|
2026
|
+
return raw.map(mapCircuitVersionInfo);
|
|
2027
|
+
}
|
|
2028
|
+
/** Returns version info for a specific circuit, or null if not found. */
|
|
2029
|
+
async getCircuitVersionInfo(circuitId) {
|
|
2030
|
+
const raw = await this.substrate.request(
|
|
2031
|
+
"zkVerifier_getCircuitVersionInfo",
|
|
2032
|
+
[circuitId]
|
|
2033
|
+
);
|
|
2034
|
+
return raw ? mapCircuitVersionInfo(raw) : null;
|
|
2035
|
+
}
|
|
2036
|
+
};
|
|
2037
|
+
|
|
2038
|
+
// src/precompiles/helpers.ts
|
|
2039
|
+
var STATIC_TYPES = /* @__PURE__ */ new Set(["uint", "bytes32", "address", "bool"]);
|
|
1303
2040
|
function concat(arrays) {
|
|
1304
|
-
const total = arrays.reduce((
|
|
2041
|
+
const total = arrays.reduce((sum, array) => sum + array.length, 0);
|
|
1305
2042
|
const out = new Uint8Array(total);
|
|
1306
|
-
let
|
|
1307
|
-
for (const
|
|
1308
|
-
out.set(
|
|
1309
|
-
|
|
2043
|
+
let offset = 0;
|
|
2044
|
+
for (const array of arrays) {
|
|
2045
|
+
out.set(array, offset);
|
|
2046
|
+
offset += array.length;
|
|
1310
2047
|
}
|
|
1311
2048
|
return out;
|
|
1312
2049
|
}
|
|
@@ -1317,7 +2054,6 @@ function padTo32Multiple(data) {
|
|
|
1317
2054
|
padded.set(data);
|
|
1318
2055
|
return padded;
|
|
1319
2056
|
}
|
|
1320
|
-
var STATIC_TYPES = /* @__PURE__ */ new Set(["uint", "bytes32", "address", "bool"]);
|
|
1321
2057
|
function encodeStaticParam(param) {
|
|
1322
2058
|
const buf = new Uint8Array(32);
|
|
1323
2059
|
switch (param.type) {
|
|
@@ -1398,6 +2134,8 @@ function encodeDynamicParam(param) {
|
|
|
1398
2134
|
);
|
|
1399
2135
|
}
|
|
1400
2136
|
}
|
|
2137
|
+
|
|
2138
|
+
// src/precompiles/abi.ts
|
|
1401
2139
|
function encode(selector, ...params) {
|
|
1402
2140
|
const n = params.length;
|
|
1403
2141
|
const headSize = n * 32;
|
|
@@ -1922,23 +2660,28 @@ var AccountMappingPrecompile = class {
|
|
|
1922
2660
|
return signer({ to: this.addr, data });
|
|
1923
2661
|
}
|
|
1924
2662
|
/**
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
2663
|
+
* Updates the signer's public profile metadata.
|
|
2664
|
+
* Pass `null` for any field to leave it unchanged.
|
|
2665
|
+
}
|
|
2666
|
+
displayName: string | null,
|
|
2667
|
+
bio: string | null,
|
|
2668
|
+
avatar: string | null,
|
|
2669
|
+
signer: EvmSigner
|
|
2670
|
+
): Promise<string> {
|
|
2671
|
+
const enc = (v: string | null): Uint8Array =>
|
|
2672
|
+
v != null ? new TextEncoder().encode(v) : new Uint8Array(0);
|
|
2673
|
+
const data = encodeHex(
|
|
2674
|
+
AM_SEL.SET_ACCOUNT_METADATA,
|
|
2675
|
+
{ type: 'bytes', value: enc(displayName) },
|
|
2676
|
+
{ type: 'bytes', value: enc(bio) },
|
|
2677
|
+
{ type: 'bytes', value: enc(avatar) }
|
|
2678
|
+
);
|
|
2679
|
+
return signer({ to: this.addr, data });
|
|
2680
|
+
}
|
|
2681
|
+
|
|
2682
|
+
// ─── Calldata builders (for custom signing / batching) ─────────────────────
|
|
2683
|
+
|
|
2684
|
+
/** Returns the raw ABI-encoded calldata for `registerAlias`. */
|
|
1942
2685
|
buildRegisterAliasCalldata(alias) {
|
|
1943
2686
|
return encodeHex(AM_SEL.REGISTER_ALIAS, { type: "string", value: alias });
|
|
1944
2687
|
}
|
|
@@ -2060,30 +2803,44 @@ var CryptoPrecompiles = class {
|
|
|
2060
2803
|
}
|
|
2061
2804
|
};
|
|
2062
2805
|
|
|
2063
|
-
// src/client.ts
|
|
2806
|
+
// src/client/OrbinumClient.ts
|
|
2064
2807
|
var OrbinumClient = class _OrbinumClient {
|
|
2065
2808
|
/** Raw access to the Substrate WebSocket connection and RPC. */
|
|
2066
2809
|
substrate;
|
|
2067
2810
|
/** Raw access to the EVM HTTP JSON-RPC endpoint (if configured). */
|
|
2068
2811
|
evm;
|
|
2812
|
+
/**
|
|
2813
|
+
* High-level EVM block and transaction explorer (if `evmRpc` is configured).
|
|
2814
|
+
* Provides enriched queries for blocks, transactions, addresses, and token transfers.
|
|
2815
|
+
*/
|
|
2816
|
+
evmExplorer;
|
|
2817
|
+
/**
|
|
2818
|
+
* HTTP client for the Orbinum indexer REST API (if `indexerUrl` is configured).
|
|
2819
|
+
* Provides paginated access to indexed blocks, extrinsics, shielded events, and nullifiers.
|
|
2820
|
+
*/
|
|
2821
|
+
indexer;
|
|
2069
2822
|
/** Shielded-pool operations: shield, unshield, privateTransfer, and merkle queries. */
|
|
2070
2823
|
shieldedPool;
|
|
2071
|
-
/** General chain queries: node info, identity resolution. */
|
|
2072
|
-
chain;
|
|
2073
2824
|
/** Account mapping: aliases, chain links, metadata, marketplace, and identity extrinsics. */
|
|
2074
2825
|
accountMapping;
|
|
2826
|
+
/** Typed access to Orbinum `privacy_*` RPC endpoints. */
|
|
2827
|
+
privacy;
|
|
2828
|
+
/** Typed access to zkVerifier_* RPC endpoints. */
|
|
2829
|
+
zkVerifier;
|
|
2075
2830
|
/**
|
|
2076
2831
|
* EVM precompiles: shielded pool + account mapping callable from an EVM wallet.
|
|
2077
2832
|
* Only available when `evmRpc` is configured. Methods throw if `evm` is null.
|
|
2078
2833
|
*/
|
|
2079
2834
|
precompiles;
|
|
2080
|
-
constructor(substrate, evm) {
|
|
2835
|
+
constructor(substrate, evm, indexer) {
|
|
2081
2836
|
this.substrate = substrate;
|
|
2082
2837
|
this.evm = evm;
|
|
2083
|
-
|
|
2084
|
-
this.
|
|
2085
|
-
this.
|
|
2838
|
+
this.evmExplorer = evm ? new EvmExplorer(evm) : null;
|
|
2839
|
+
this.indexer = indexer;
|
|
2840
|
+
this.shieldedPool = new ShieldedPoolModule(substrate);
|
|
2086
2841
|
this.accountMapping = new AccountMappingModule(substrate);
|
|
2842
|
+
this.privacy = new PrivacyModule(substrate);
|
|
2843
|
+
this.zkVerifier = new ZkVerifierModule(substrate);
|
|
2087
2844
|
this.precompiles = evm ? {
|
|
2088
2845
|
shieldedPool: new ShieldedPoolPrecompile(evm),
|
|
2089
2846
|
accountMapping: new AccountMappingPrecompile(evm),
|
|
@@ -2100,13 +2857,8 @@ var OrbinumClient = class _OrbinumClient {
|
|
|
2100
2857
|
config.connectTimeoutMs ?? 15e3
|
|
2101
2858
|
);
|
|
2102
2859
|
const evm = config.evmRpc ? new EvmClient(config.evmRpc) : null;
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
/**
|
|
2106
|
-
* Convenience getter for the Merkle module (shortcut for `shieldedPool.merkle`).
|
|
2107
|
-
*/
|
|
2108
|
-
get merkle() {
|
|
2109
|
-
return this.shieldedPool.merkle;
|
|
2860
|
+
const indexer = config.indexerUrl ? new IndexerClient({ baseUrl: config.indexerUrl }) : null;
|
|
2861
|
+
return new _OrbinumClient(substrate, evm, indexer);
|
|
2110
2862
|
}
|
|
2111
2863
|
/** Closes the WebSocket connection to the Substrate node. */
|
|
2112
2864
|
destroy() {
|
|
@@ -2114,6 +2866,215 @@ var OrbinumClient = class _OrbinumClient {
|
|
|
2114
2866
|
}
|
|
2115
2867
|
};
|
|
2116
2868
|
|
|
2869
|
+
// src/client/OrbinumClientProvider.ts
|
|
2870
|
+
var DEFAULT_CONNECT_TIMEOUT_MS = 8e3;
|
|
2871
|
+
var DEFAULT_HEARTBEAT_INTERVAL_MS = 5e3;
|
|
2872
|
+
var DEFAULT_HEARTBEAT_TIMEOUT_MS = 4e3;
|
|
2873
|
+
var DEFAULT_RECONNECT_BASE_MS = 3e3;
|
|
2874
|
+
var DEFAULT_RECONNECT_MAX_MS = 3e4;
|
|
2875
|
+
var OrbinumClientProvider = class {
|
|
2876
|
+
config;
|
|
2877
|
+
connectTimeoutMs;
|
|
2878
|
+
heartbeatIntervalMs;
|
|
2879
|
+
heartbeatTimeoutMs;
|
|
2880
|
+
reconnectBaseMs;
|
|
2881
|
+
reconnectMaxMs;
|
|
2882
|
+
// ─── State ──────────────────────────────────────────────────────────────
|
|
2883
|
+
_status = "idle";
|
|
2884
|
+
_orbinumClient = null;
|
|
2885
|
+
_connectingPromise = null;
|
|
2886
|
+
// ─── Timers ─────────────────────────────────────────────────────────────
|
|
2887
|
+
_heartbeatTimer = null;
|
|
2888
|
+
_reconnectTimer = null;
|
|
2889
|
+
_reconnectAttempt = 0;
|
|
2890
|
+
// ─── Events ─────────────────────────────────────────────────────────────
|
|
2891
|
+
_listeners = /* @__PURE__ */ new Set();
|
|
2892
|
+
constructor(config) {
|
|
2893
|
+
this.config = config;
|
|
2894
|
+
this.connectTimeoutMs = config.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS;
|
|
2895
|
+
this.heartbeatIntervalMs = config.heartbeatIntervalMs ?? DEFAULT_HEARTBEAT_INTERVAL_MS;
|
|
2896
|
+
this.heartbeatTimeoutMs = config.heartbeatTimeoutMs ?? DEFAULT_HEARTBEAT_TIMEOUT_MS;
|
|
2897
|
+
this.reconnectBaseMs = config.reconnectBaseMs ?? DEFAULT_RECONNECT_BASE_MS;
|
|
2898
|
+
this.reconnectMaxMs = config.reconnectMaxMs ?? DEFAULT_RECONNECT_MAX_MS;
|
|
2899
|
+
}
|
|
2900
|
+
// ─── Status ─────────────────────────────────────────────────────────────
|
|
2901
|
+
get status() {
|
|
2902
|
+
return this._status;
|
|
2903
|
+
}
|
|
2904
|
+
setStatus(status, error) {
|
|
2905
|
+
this._status = status;
|
|
2906
|
+
const event = { status, ...error ? { error } : {} };
|
|
2907
|
+
this._listeners.forEach((fn) => {
|
|
2908
|
+
try {
|
|
2909
|
+
fn(event);
|
|
2910
|
+
} catch {
|
|
2911
|
+
}
|
|
2912
|
+
});
|
|
2913
|
+
}
|
|
2914
|
+
onStatusChange(listener) {
|
|
2915
|
+
this._listeners.add(listener);
|
|
2916
|
+
return () => {
|
|
2917
|
+
this._listeners.delete(listener);
|
|
2918
|
+
};
|
|
2919
|
+
}
|
|
2920
|
+
// ─── Lifecycle ──────────────────────────────────────────────────────────
|
|
2921
|
+
connect() {
|
|
2922
|
+
if (this._status !== "idle") return;
|
|
2923
|
+
this.startConnectAttempt();
|
|
2924
|
+
}
|
|
2925
|
+
reset() {
|
|
2926
|
+
this.cancelReconnect();
|
|
2927
|
+
this.teardownClient();
|
|
2928
|
+
this._reconnectAttempt = 0;
|
|
2929
|
+
this.setStatus("idle");
|
|
2930
|
+
}
|
|
2931
|
+
// ─── Internal connection flow ───────────────────────────────────────────
|
|
2932
|
+
startConnectAttempt() {
|
|
2933
|
+
this.setStatus("connecting");
|
|
2934
|
+
this._connectingPromise = this.attemptConnect();
|
|
2935
|
+
this._connectingPromise.catch(() => {
|
|
2936
|
+
if (this._status !== "idle") this.scheduleReconnect();
|
|
2937
|
+
});
|
|
2938
|
+
}
|
|
2939
|
+
async attemptConnect() {
|
|
2940
|
+
let timeoutId = null;
|
|
2941
|
+
let orphanClient = null;
|
|
2942
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
2943
|
+
timeoutId = setTimeout(
|
|
2944
|
+
() => reject(
|
|
2945
|
+
new Error(
|
|
2946
|
+
`Node unavailable \u2014 could not connect to ${this.config.substrateWs} within ${this.connectTimeoutMs / 1e3}s`
|
|
2947
|
+
)
|
|
2948
|
+
),
|
|
2949
|
+
this.connectTimeoutMs
|
|
2950
|
+
);
|
|
2951
|
+
});
|
|
2952
|
+
try {
|
|
2953
|
+
const connectConfig = {
|
|
2954
|
+
substrateWs: this.config.substrateWs
|
|
2955
|
+
};
|
|
2956
|
+
if (this.config.evmRpc) connectConfig.evmRpc = this.config.evmRpc;
|
|
2957
|
+
if (this.config.indexerUrl) connectConfig.indexerUrl = this.config.indexerUrl;
|
|
2958
|
+
const clientPromise = OrbinumClient.connect(connectConfig);
|
|
2959
|
+
const client = await Promise.race([clientPromise, timeoutPromise]);
|
|
2960
|
+
orphanClient = client;
|
|
2961
|
+
clearTimeout(timeoutId);
|
|
2962
|
+
orphanClient = null;
|
|
2963
|
+
this._orbinumClient = client;
|
|
2964
|
+
this._connectingPromise = null;
|
|
2965
|
+
this._reconnectAttempt = 0;
|
|
2966
|
+
this.setStatus("connected");
|
|
2967
|
+
this.startHeartbeat();
|
|
2968
|
+
return client;
|
|
2969
|
+
} catch (err) {
|
|
2970
|
+
clearTimeout(timeoutId);
|
|
2971
|
+
if (orphanClient) {
|
|
2972
|
+
try {
|
|
2973
|
+
orphanClient.destroy();
|
|
2974
|
+
} catch {
|
|
2975
|
+
}
|
|
2976
|
+
}
|
|
2977
|
+
this._connectingPromise = null;
|
|
2978
|
+
this.setStatus(
|
|
2979
|
+
"disconnected",
|
|
2980
|
+
err instanceof Error ? err.message : "Connection failed"
|
|
2981
|
+
);
|
|
2982
|
+
throw err;
|
|
2983
|
+
}
|
|
2984
|
+
}
|
|
2985
|
+
// ─── Heartbeat ──────────────────────────────────────────────────────────
|
|
2986
|
+
startHeartbeat() {
|
|
2987
|
+
this.stopHeartbeat();
|
|
2988
|
+
this._heartbeatTimer = setInterval(async () => {
|
|
2989
|
+
if (this._status !== "connected" || !this._orbinumClient) return;
|
|
2990
|
+
const alive = await this.probe();
|
|
2991
|
+
if (!alive && this._status === "connected") {
|
|
2992
|
+
this.setStatus("disconnected", "Node is unreachable");
|
|
2993
|
+
this.teardownClient();
|
|
2994
|
+
this.scheduleReconnect();
|
|
2995
|
+
}
|
|
2996
|
+
}, this.heartbeatIntervalMs);
|
|
2997
|
+
}
|
|
2998
|
+
stopHeartbeat() {
|
|
2999
|
+
if (this._heartbeatTimer) {
|
|
3000
|
+
clearInterval(this._heartbeatTimer);
|
|
3001
|
+
this._heartbeatTimer = null;
|
|
3002
|
+
}
|
|
3003
|
+
}
|
|
3004
|
+
async probe() {
|
|
3005
|
+
if (!this._orbinumClient) return false;
|
|
3006
|
+
try {
|
|
3007
|
+
await Promise.race([
|
|
3008
|
+
this._orbinumClient.substrate.request("system_health", []),
|
|
3009
|
+
new Promise(
|
|
3010
|
+
(_, reject) => setTimeout(() => reject(new Error("timeout")), this.heartbeatTimeoutMs)
|
|
3011
|
+
)
|
|
3012
|
+
]);
|
|
3013
|
+
return true;
|
|
3014
|
+
} catch {
|
|
3015
|
+
return false;
|
|
3016
|
+
}
|
|
3017
|
+
}
|
|
3018
|
+
// ─── Reconnection ───────────────────────────────────────────────────────
|
|
3019
|
+
scheduleReconnect() {
|
|
3020
|
+
if (this._reconnectTimer) clearTimeout(this._reconnectTimer);
|
|
3021
|
+
const delay = Math.min(
|
|
3022
|
+
this.reconnectBaseMs * 2 ** this._reconnectAttempt,
|
|
3023
|
+
this.reconnectMaxMs
|
|
3024
|
+
);
|
|
3025
|
+
this._reconnectAttempt++;
|
|
3026
|
+
this.setStatus("reconnecting");
|
|
3027
|
+
this._reconnectTimer = setTimeout(() => {
|
|
3028
|
+
this._reconnectTimer = null;
|
|
3029
|
+
if (this._status !== "idle") this.startConnectAttempt();
|
|
3030
|
+
}, delay);
|
|
3031
|
+
}
|
|
3032
|
+
cancelReconnect() {
|
|
3033
|
+
if (this._reconnectTimer) {
|
|
3034
|
+
clearTimeout(this._reconnectTimer);
|
|
3035
|
+
this._reconnectTimer = null;
|
|
3036
|
+
}
|
|
3037
|
+
}
|
|
3038
|
+
// ─── Client teardown ────────────────────────────────────────────────────
|
|
3039
|
+
teardownClient() {
|
|
3040
|
+
this.stopHeartbeat();
|
|
3041
|
+
try {
|
|
3042
|
+
this._orbinumClient?.destroy();
|
|
3043
|
+
} catch {
|
|
3044
|
+
}
|
|
3045
|
+
this._orbinumClient = null;
|
|
3046
|
+
this._connectingPromise = null;
|
|
3047
|
+
}
|
|
3048
|
+
// ─── Client access ──────────────────────────────────────────────────────
|
|
3049
|
+
async getOrbinumClient() {
|
|
3050
|
+
if (this._orbinumClient) return this._orbinumClient;
|
|
3051
|
+
if (this._connectingPromise) return this._connectingPromise;
|
|
3052
|
+
throw new Error(`OrbinumClientProvider: cannot get client in status '${this._status}'`);
|
|
3053
|
+
}
|
|
3054
|
+
async tryGetOrbinumClient() {
|
|
3055
|
+
try {
|
|
3056
|
+
return await this.getOrbinumClient();
|
|
3057
|
+
} catch {
|
|
3058
|
+
return null;
|
|
3059
|
+
}
|
|
3060
|
+
}
|
|
3061
|
+
// ─── Convenience RPC helpers ────────────────────────────────────────────
|
|
3062
|
+
async rpcSend(method, params = []) {
|
|
3063
|
+
const client = await this.getOrbinumClient();
|
|
3064
|
+
return client.substrate.request(method, params);
|
|
3065
|
+
}
|
|
3066
|
+
async evmRpc(method, params = []) {
|
|
3067
|
+
const client = await this.getOrbinumClient();
|
|
3068
|
+
if (!client.evm) throw new Error("EVM RPC not configured");
|
|
3069
|
+
return client.evm.request(method, params);
|
|
3070
|
+
}
|
|
3071
|
+
async evmRpcBatch(calls) {
|
|
3072
|
+
const client = await this.getOrbinumClient();
|
|
3073
|
+
if (!client.evm) throw new Error("EVM RPC not configured");
|
|
3074
|
+
return client.evm.batchRequest(calls);
|
|
3075
|
+
}
|
|
3076
|
+
};
|
|
3077
|
+
|
|
2117
3078
|
// src/shielded-pool/NoteDecryptor.ts
|
|
2118
3079
|
import { poseidon2 as poseidon22, poseidon4 as poseidon42 } from "poseidon-lite";
|
|
2119
3080
|
function tryDecryptNote(commitment, viewingKey, spendingKey) {
|
|
@@ -2156,7 +3117,11 @@ function tryDecryptNote(commitment, viewingKey, spendingKey) {
|
|
|
2156
3117
|
import { hkdf } from "@noble/hashes/hkdf.js";
|
|
2157
3118
|
import { sha256 as sha2562 } from "@noble/hashes/sha2.js";
|
|
2158
3119
|
import { mulPointEscalar, Base8 } from "@zk-kit/baby-jubjub";
|
|
3120
|
+
|
|
3121
|
+
// src/shielded-pool/constants.ts
|
|
2159
3122
|
var BN254_R = 21888242871839275222246405745257275088548364400416034343698204186575808495617n;
|
|
3123
|
+
|
|
3124
|
+
// src/shielded-pool/PrivacyKeys.ts
|
|
2160
3125
|
var IVK_DOMAIN = new TextEncoder().encode("orbinum-ivk-v1");
|
|
2161
3126
|
function deriveSpendingKeyMessage(chainId, address) {
|
|
2162
3127
|
return `orbinum-spending-key-v1
|
|
@@ -2187,13 +3152,12 @@ function deriveOwnerPk(spendingKey) {
|
|
|
2187
3152
|
}
|
|
2188
3153
|
|
|
2189
3154
|
// src/shielded-pool/PrivacyKeyManager.ts
|
|
2190
|
-
var
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
};
|
|
2196
|
-
var PrivacyKeyManager = {
|
|
3155
|
+
var PrivacyKeyManager = class {
|
|
3156
|
+
_state = {
|
|
3157
|
+
spendingKey: null,
|
|
3158
|
+
viewingKey: null,
|
|
3159
|
+
ownerPk: null
|
|
3160
|
+
};
|
|
2197
3161
|
/**
|
|
2198
3162
|
* Load a spending key into the in-memory session.
|
|
2199
3163
|
* Derives viewingKey and ownerPk immediately.
|
|
@@ -2202,52 +3166,52 @@ var PrivacyKeyManager = {
|
|
|
2202
3166
|
async load(spendingKey) {
|
|
2203
3167
|
const viewingKey = deriveViewingKey(spendingKey);
|
|
2204
3168
|
const ownerPk = deriveOwnerPk(spendingKey);
|
|
2205
|
-
_state = { spendingKey, viewingKey, ownerPk };
|
|
2206
|
-
}
|
|
3169
|
+
this._state = { spendingKey, viewingKey, ownerPk };
|
|
3170
|
+
}
|
|
2207
3171
|
/** Clear all key material from memory. Call on vault lock / sign-out. */
|
|
2208
3172
|
clear() {
|
|
2209
|
-
_state = { spendingKey: null, viewingKey: null, ownerPk: null };
|
|
2210
|
-
}
|
|
3173
|
+
this._state = { spendingKey: null, viewingKey: null, ownerPk: null };
|
|
3174
|
+
}
|
|
2211
3175
|
/** Returns true if a spending key has been loaded. */
|
|
2212
3176
|
isLoaded() {
|
|
2213
|
-
return _state.spendingKey !== null;
|
|
2214
|
-
}
|
|
3177
|
+
return this._state.spendingKey !== null;
|
|
3178
|
+
}
|
|
2215
3179
|
/** Returns the spending key. Throws if not loaded. */
|
|
2216
3180
|
getSpendingKey() {
|
|
2217
|
-
if (_state.spendingKey === null) {
|
|
3181
|
+
if (this._state.spendingKey === null) {
|
|
2218
3182
|
throw new Error("PrivacyKeyManager: no key loaded. Call load() first.");
|
|
2219
3183
|
}
|
|
2220
|
-
return _state.spendingKey;
|
|
2221
|
-
}
|
|
3184
|
+
return this._state.spendingKey;
|
|
3185
|
+
}
|
|
2222
3186
|
/** Returns the 32-byte viewing key. Throws if not loaded. */
|
|
2223
3187
|
getViewingKey() {
|
|
2224
|
-
if (_state.viewingKey === null) {
|
|
3188
|
+
if (this._state.viewingKey === null) {
|
|
2225
3189
|
throw new Error("PrivacyKeyManager: no key loaded. Call load() first.");
|
|
2226
3190
|
}
|
|
2227
|
-
return _state.viewingKey;
|
|
2228
|
-
}
|
|
3191
|
+
return this._state.viewingKey;
|
|
3192
|
+
}
|
|
2229
3193
|
/** Returns the BabyJubJub owner public key (x-coordinate). Throws if not loaded. */
|
|
2230
3194
|
getOwnerPk() {
|
|
2231
|
-
if (_state.ownerPk === null) {
|
|
3195
|
+
if (this._state.ownerPk === null) {
|
|
2232
3196
|
throw new Error("PrivacyKeyManager: no key loaded. Call load() first.");
|
|
2233
3197
|
}
|
|
2234
|
-
return _state.ownerPk;
|
|
2235
|
-
}
|
|
3198
|
+
return this._state.ownerPk;
|
|
3199
|
+
}
|
|
2236
3200
|
/** Returns the spending key as a 32-byte little-endian Uint8Array. Throws if not loaded. */
|
|
2237
3201
|
getSpendingKeyBytes() {
|
|
2238
3202
|
return bigintTo32Le(this.getSpendingKey());
|
|
2239
|
-
}
|
|
3203
|
+
}
|
|
2240
3204
|
/** Exports the spending key as a 0x-prefixed 64-char hex string. Throws if not loaded. */
|
|
2241
3205
|
exportHex() {
|
|
2242
3206
|
return "0x" + this.getSpendingKey().toString(16).padStart(64, "0");
|
|
2243
|
-
}
|
|
3207
|
+
}
|
|
2244
3208
|
/**
|
|
2245
3209
|
* Load a spending key from a 0x-prefixed or bare hex string.
|
|
2246
3210
|
* Validates the key is in the valid range [1, BN254_R).
|
|
2247
3211
|
*/
|
|
2248
3212
|
async importFromHex(hex) {
|
|
2249
3213
|
const key = BigInt(hex.startsWith("0x") ? hex : "0x" + hex);
|
|
2250
|
-
if (key === 0n || key >=
|
|
3214
|
+
if (key === 0n || key >= BN254_R) {
|
|
2251
3215
|
throw new Error("PrivacyKeyManager: invalid spending key \u2014 out of BN254 range.");
|
|
2252
3216
|
}
|
|
2253
3217
|
await this.load(key);
|
|
@@ -2265,18 +3229,6 @@ function vaultReviver(_key, value) {
|
|
|
2265
3229
|
}
|
|
2266
3230
|
return value;
|
|
2267
3231
|
}
|
|
2268
|
-
function toBase64(buf) {
|
|
2269
|
-
const bytes = buf instanceof Uint8Array ? buf : new Uint8Array(buf);
|
|
2270
|
-
let str = "";
|
|
2271
|
-
for (const b of bytes) str += String.fromCharCode(b);
|
|
2272
|
-
return btoa(str);
|
|
2273
|
-
}
|
|
2274
|
-
function fromBase64(b64) {
|
|
2275
|
-
const bin = atob(b64);
|
|
2276
|
-
const out = new Uint8Array(bin.length);
|
|
2277
|
-
for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
|
|
2278
|
-
return out;
|
|
2279
|
-
}
|
|
2280
3232
|
var VAULT_KEY_INFO = new TextEncoder().encode("orbinum-vault-key-v1");
|
|
2281
3233
|
var IV_BYTES = 12;
|
|
2282
3234
|
async function deriveVaultKey(spendingKeyBytes) {
|
|
@@ -2315,71 +3267,70 @@ async function decryptJson(key, iv, ciphertext) {
|
|
|
2315
3267
|
return JSON.parse(new TextDecoder().decode(plainBuf), vaultReviver);
|
|
2316
3268
|
}
|
|
2317
3269
|
|
|
2318
|
-
// src/
|
|
2319
|
-
var
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
3270
|
+
// src/account-mapping/types/index.ts
|
|
3271
|
+
var SignatureScheme = {
|
|
3272
|
+
Eip191: "Eip191",
|
|
3273
|
+
Ed25519: "Ed25519"
|
|
3274
|
+
};
|
|
3275
|
+
var SLIP0044_NAMESPACE = 2147483648;
|
|
3276
|
+
|
|
3277
|
+
// src/precompiles/decode.ts
|
|
3278
|
+
function decodePrecompileCalldata(address, input) {
|
|
3279
|
+
const info = KNOWN_PRECOMPILES[address.toLowerCase()];
|
|
3280
|
+
if (!info || !input || input.length < 10) return null;
|
|
3281
|
+
const selector = input.slice(2, 10).toLowerCase();
|
|
3282
|
+
const fnSig = info.functions[selector];
|
|
3283
|
+
if (!fnSig) return null;
|
|
3284
|
+
if (fnSig.startsWith("registerAlias")) {
|
|
3285
|
+
try {
|
|
3286
|
+
const data = hexToBytes(input.slice(10));
|
|
3287
|
+
const alias = decodeString(data, 0);
|
|
3288
|
+
return { fnSig, args: { alias } };
|
|
3289
|
+
} catch {
|
|
3290
|
+
return { fnSig, args: {} };
|
|
3291
|
+
}
|
|
2325
3292
|
}
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
3293
|
+
if (fnSig.startsWith("shield(")) {
|
|
3294
|
+
try {
|
|
3295
|
+
const data = hexToBytes(input.slice(10));
|
|
3296
|
+
const assetId = decodeUint(data, 0);
|
|
3297
|
+
const amount = decodeUint(data, 32);
|
|
3298
|
+
const commitment = toHex(data.slice(64, 96));
|
|
3299
|
+
return { fnSig, args: { assetId, amount, commitment } };
|
|
3300
|
+
} catch {
|
|
3301
|
+
return { fnSig, args: {} };
|
|
3302
|
+
}
|
|
2334
3303
|
}
|
|
2335
|
-
if (
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
const intPart = abs / divider;
|
|
2348
|
-
const fracPart = abs % divider;
|
|
2349
|
-
const fracStr = fracPart.toString().padStart(decimals, "0");
|
|
2350
|
-
return (negative ? "-" : "") + intPart.toString() + "." + fracStr;
|
|
2351
|
-
}
|
|
2352
|
-
function formatBalance(raw, options = {}) {
|
|
2353
|
-
const opts = typeof options === "number" ? { decimals: options } : options;
|
|
2354
|
-
const { decimals = 18, symbol = "ORB", showSymbol = true, precision = 6 } = opts;
|
|
2355
|
-
const zero = showSymbol ? `0 ${symbol}` : "0";
|
|
2356
|
-
if (raw === null || raw === void 0) return zero;
|
|
2357
|
-
const rawStr = String(raw).trim().replace(/,/g, "");
|
|
2358
|
-
if (!rawStr || rawStr === "0" || rawStr === "0x0") return zero;
|
|
2359
|
-
if (rawStr.includes(".") && !rawStr.startsWith("0x")) {
|
|
2360
|
-
const formatted = normalizeDecimalForDisplay(rawStr, precision);
|
|
2361
|
-
if (!formatted || formatted === "0" || formatted === "-0") return zero;
|
|
2362
|
-
return showSymbol ? `${formatted} ${symbol}` : formatted;
|
|
3304
|
+
if (fnSig.startsWith("unshield(")) {
|
|
3305
|
+
try {
|
|
3306
|
+
const data = hexToBytes(input.slice(10));
|
|
3307
|
+
const root = toHex(data.slice(32, 64));
|
|
3308
|
+
const nullifier = toHex(data.slice(64, 96));
|
|
3309
|
+
const assetId = decodeUint(data, 96);
|
|
3310
|
+
const amount = decodeUint(data, 128);
|
|
3311
|
+
const recipient = toHex(data.slice(160, 192));
|
|
3312
|
+
return { fnSig, args: { root, nullifier, assetId, amount, recipient } };
|
|
3313
|
+
} catch {
|
|
3314
|
+
return { fnSig, args: {} };
|
|
3315
|
+
}
|
|
2363
3316
|
}
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
3317
|
+
if (fnSig.startsWith("privateTransfer(")) {
|
|
3318
|
+
try {
|
|
3319
|
+
const data = hexToBytes(input.slice(10));
|
|
3320
|
+
const root = toHex(data.slice(32, 64));
|
|
3321
|
+
const nullOffset = Number(decodeUint(data, 64));
|
|
3322
|
+
const commOffset = Number(decodeUint(data, 96));
|
|
3323
|
+
const nullifiers = Number(decodeUint(data, nullOffset));
|
|
3324
|
+
const commitments = Number(decodeUint(data, commOffset));
|
|
3325
|
+
return { fnSig, args: { root, nullifiers, commitments } };
|
|
3326
|
+
} catch {
|
|
3327
|
+
return { fnSig, args: {} };
|
|
3328
|
+
}
|
|
2373
3329
|
}
|
|
2374
|
-
}
|
|
2375
|
-
function formatORB(raw, precision = 6) {
|
|
2376
|
-
return formatBalance(raw, { decimals: 18, symbol: "ORB", showSymbol: true, precision });
|
|
3330
|
+
return { fnSig, args: {} };
|
|
2377
3331
|
}
|
|
2378
3332
|
|
|
2379
|
-
// src/types.ts
|
|
2380
|
-
var SLIP0044_NAMESPACE = 2147483648;
|
|
2381
|
-
|
|
2382
|
-
// src/types/pallet-extrinsics/zk-verifier.ts
|
|
3333
|
+
// src/zk-verifier/types/pallet-extrinsics.ts
|
|
2383
3334
|
var CircuitId = {
|
|
2384
3335
|
Transfer: 1,
|
|
2385
3336
|
Unshield: 2,
|
|
@@ -2387,34 +3338,788 @@ var CircuitId = {
|
|
|
2387
3338
|
PrivateLink: 4
|
|
2388
3339
|
};
|
|
2389
3340
|
|
|
3341
|
+
// src/utils/string.ts
|
|
3342
|
+
function truncateMiddle(str, start, end) {
|
|
3343
|
+
if (!str) return "";
|
|
3344
|
+
if (str.length <= start + end + 1) return str;
|
|
3345
|
+
return `${str.slice(0, start)}\u2026${str.slice(-end)}`;
|
|
3346
|
+
}
|
|
3347
|
+
function shortHash(h, start = 8, end = 6) {
|
|
3348
|
+
return truncateMiddle(h, start, end);
|
|
3349
|
+
}
|
|
3350
|
+
|
|
3351
|
+
// src/extrinsic/index.ts
|
|
3352
|
+
function mapExtrinsicArgs(section, method, args) {
|
|
3353
|
+
if (!args || Object.keys(args).length === 0) return args;
|
|
3354
|
+
const s = section.toLowerCase();
|
|
3355
|
+
const m = method.toLowerCase();
|
|
3356
|
+
const get = (idx, name) => {
|
|
3357
|
+
if (name in args) return args[name];
|
|
3358
|
+
const argKey = `arg${idx}`;
|
|
3359
|
+
if (argKey in args) return args[argKey];
|
|
3360
|
+
if (idx in args) return args[idx];
|
|
3361
|
+
const strIdx = idx.toString();
|
|
3362
|
+
if (strIdx in args) return args[strIdx];
|
|
3363
|
+
return void 0;
|
|
3364
|
+
};
|
|
3365
|
+
if (s === "system") {
|
|
3366
|
+
const m_norm = m.replace(/_/g, "");
|
|
3367
|
+
if (m_norm === "remark" || m_norm === "remarkwithevent") {
|
|
3368
|
+
return { remark: get(0, "remark") };
|
|
3369
|
+
}
|
|
3370
|
+
if (m_norm === "setheappages") {
|
|
3371
|
+
return { pages: get(0, "pages") };
|
|
3372
|
+
}
|
|
3373
|
+
if (m_norm === "setcode" || m_norm === "setcodewithoutchecks") {
|
|
3374
|
+
return { code: get(0, "code") };
|
|
3375
|
+
}
|
|
3376
|
+
if (m_norm === "setstorage") {
|
|
3377
|
+
return { items: get(0, "items") };
|
|
3378
|
+
}
|
|
3379
|
+
if (m_norm === "killstorage") {
|
|
3380
|
+
return { keys: get(0, "keys") };
|
|
3381
|
+
}
|
|
3382
|
+
if (m_norm === "killprefix") {
|
|
3383
|
+
return {
|
|
3384
|
+
prefix: get(0, "prefix"),
|
|
3385
|
+
subkeys: get(1, "subkeys")
|
|
3386
|
+
};
|
|
3387
|
+
}
|
|
3388
|
+
if (m_norm === "authorizeupgrade" || m_norm === "authorizeupgradewithoutchecks") {
|
|
3389
|
+
return { code_hash: get(0, "code_hash") };
|
|
3390
|
+
}
|
|
3391
|
+
if (m_norm === "applyauthorizedupgrade") {
|
|
3392
|
+
return { code: get(0, "code") };
|
|
3393
|
+
}
|
|
3394
|
+
}
|
|
3395
|
+
if (s === "timestamp") {
|
|
3396
|
+
if (m === "set") {
|
|
3397
|
+
return { now: get(0, "now") };
|
|
3398
|
+
}
|
|
3399
|
+
}
|
|
3400
|
+
if (s === "balances") {
|
|
3401
|
+
const m_norm = m.replace(/_/g, "");
|
|
3402
|
+
if (m_norm.startsWith("transfer")) {
|
|
3403
|
+
return {
|
|
3404
|
+
recipient: get(0, "dest") || get(0, "destination") || get(0, "recipient"),
|
|
3405
|
+
amount: get(1, "value") || get(1, "amount")
|
|
3406
|
+
};
|
|
3407
|
+
}
|
|
3408
|
+
if (m_norm === "forcetransfer") {
|
|
3409
|
+
return {
|
|
3410
|
+
source: get(0, "source"),
|
|
3411
|
+
dest: get(1, "dest"),
|
|
3412
|
+
value: get(2, "value")
|
|
3413
|
+
};
|
|
3414
|
+
}
|
|
3415
|
+
if (m_norm === "forceunreserve") {
|
|
3416
|
+
return {
|
|
3417
|
+
who: get(0, "who"),
|
|
3418
|
+
amount: get(1, "amount")
|
|
3419
|
+
};
|
|
3420
|
+
}
|
|
3421
|
+
if (m_norm === "upgradeaccounts") {
|
|
3422
|
+
return { who: get(0, "who") };
|
|
3423
|
+
}
|
|
3424
|
+
if (m_norm === "forcesetbalance") {
|
|
3425
|
+
return {
|
|
3426
|
+
who: get(0, "who"),
|
|
3427
|
+
new_free: get(1, "new_free")
|
|
3428
|
+
};
|
|
3429
|
+
}
|
|
3430
|
+
if (m_norm === "forceadjusttotalissuance") {
|
|
3431
|
+
return {
|
|
3432
|
+
direction: get(0, "direction"),
|
|
3433
|
+
delta: get(1, "delta")
|
|
3434
|
+
};
|
|
3435
|
+
}
|
|
3436
|
+
if (m_norm === "burn") {
|
|
3437
|
+
return {
|
|
3438
|
+
value: get(0, "value"),
|
|
3439
|
+
keep_alive: get(1, "keep_alive")
|
|
3440
|
+
};
|
|
3441
|
+
}
|
|
3442
|
+
}
|
|
3443
|
+
if (s === "sudo") {
|
|
3444
|
+
const m_norm = m.replace(/_/g, "");
|
|
3445
|
+
if (m_norm === "sudo") {
|
|
3446
|
+
return { call: get(0, "call") };
|
|
3447
|
+
}
|
|
3448
|
+
if (m_norm === "sudouncheckedweight") {
|
|
3449
|
+
return {
|
|
3450
|
+
call: get(0, "call"),
|
|
3451
|
+
weight: get(1, "weight")
|
|
3452
|
+
};
|
|
3453
|
+
}
|
|
3454
|
+
if (m_norm === "setkey") {
|
|
3455
|
+
return { new: get(0, "new") };
|
|
3456
|
+
}
|
|
3457
|
+
if (m_norm === "sudoas") {
|
|
3458
|
+
return {
|
|
3459
|
+
who: get(0, "who"),
|
|
3460
|
+
call: get(1, "call")
|
|
3461
|
+
};
|
|
3462
|
+
}
|
|
3463
|
+
}
|
|
3464
|
+
if (s === "grandpa") {
|
|
3465
|
+
const m_norm = m.replace(/_/g, "");
|
|
3466
|
+
if (m_norm === "reportequivocation" || m_norm === "reportequivocationunsigned") {
|
|
3467
|
+
return {
|
|
3468
|
+
equivocation_proof: get(0, "equivocation_proof"),
|
|
3469
|
+
key_owner_proof: get(1, "key_owner_proof")
|
|
3470
|
+
};
|
|
3471
|
+
}
|
|
3472
|
+
if (m_norm === "notestalled") {
|
|
3473
|
+
return {
|
|
3474
|
+
delay: get(0, "delay"),
|
|
3475
|
+
best_finalized_block_number: get(1, "best_finalized_block_number")
|
|
3476
|
+
};
|
|
3477
|
+
}
|
|
3478
|
+
}
|
|
3479
|
+
if (s === "shieldedpool") {
|
|
3480
|
+
const m_norm = m.replace(/_/g, "");
|
|
3481
|
+
if (m_norm === "shield") {
|
|
3482
|
+
return {
|
|
3483
|
+
asset_id: get(0, "asset_id"),
|
|
3484
|
+
amount: get(1, "amount"),
|
|
3485
|
+
commitment: get(2, "commitment"),
|
|
3486
|
+
encrypted_memo: get(3, "encrypted_memo")
|
|
3487
|
+
};
|
|
3488
|
+
}
|
|
3489
|
+
if (m_norm === "shieldbatch") {
|
|
3490
|
+
const ops = get(0, "operations") || get(0, "arg0");
|
|
3491
|
+
if (Array.isArray(ops)) {
|
|
3492
|
+
return {
|
|
3493
|
+
operations: ops.map((op) => {
|
|
3494
|
+
if (Array.isArray(op)) {
|
|
3495
|
+
return {
|
|
3496
|
+
asset_id: op[0],
|
|
3497
|
+
amount: op[1],
|
|
3498
|
+
commitment: op[2],
|
|
3499
|
+
encrypted_memo: op[3]
|
|
3500
|
+
};
|
|
3501
|
+
}
|
|
3502
|
+
return op;
|
|
3503
|
+
})
|
|
3504
|
+
};
|
|
3505
|
+
}
|
|
3506
|
+
return { operations: ops };
|
|
3507
|
+
}
|
|
3508
|
+
if (m_norm === "privatetransfer" || m_norm === "transfer") {
|
|
3509
|
+
return {
|
|
3510
|
+
proof: get(0, "proof"),
|
|
3511
|
+
merkle_root: get(1, "merkle_root"),
|
|
3512
|
+
nullifiers: get(2, "nullifiers"),
|
|
3513
|
+
commitments: get(3, "commitments"),
|
|
3514
|
+
encrypted_memos: get(4, "encrypted_memos")
|
|
3515
|
+
};
|
|
3516
|
+
}
|
|
3517
|
+
if (m_norm === "unshield") {
|
|
3518
|
+
return {
|
|
3519
|
+
proof: get(0, "proof"),
|
|
3520
|
+
merkle_root: get(1, "merkle_root"),
|
|
3521
|
+
nullifier: get(2, "nullifier"),
|
|
3522
|
+
asset_id: get(3, "asset_id"),
|
|
3523
|
+
amount: get(4, "amount"),
|
|
3524
|
+
recipient: get(5, "recipient")
|
|
3525
|
+
};
|
|
3526
|
+
}
|
|
3527
|
+
if (m_norm === "setauditpolicy") {
|
|
3528
|
+
return {
|
|
3529
|
+
auditors: get(0, "auditors"),
|
|
3530
|
+
conditions: get(1, "conditions"),
|
|
3531
|
+
max_frequency: get(2, "max_frequency"),
|
|
3532
|
+
valid_until: get(3, "valid_until")
|
|
3533
|
+
};
|
|
3534
|
+
}
|
|
3535
|
+
if (m_norm === "requestdisclosure") {
|
|
3536
|
+
return {
|
|
3537
|
+
target: get(0, "target"),
|
|
3538
|
+
reason: get(1, "reason")
|
|
3539
|
+
};
|
|
3540
|
+
}
|
|
3541
|
+
if (m_norm === "disclose") {
|
|
3542
|
+
return {
|
|
3543
|
+
commitment: get(0, "commitment"),
|
|
3544
|
+
proof_bytes: get(1, "proof_bytes"),
|
|
3545
|
+
public_signals: get(2, "public_signals"),
|
|
3546
|
+
auditor: get(3, "auditor")
|
|
3547
|
+
};
|
|
3548
|
+
}
|
|
3549
|
+
if (m_norm === "rejectdisclosure") {
|
|
3550
|
+
return {
|
|
3551
|
+
auditor: get(0, "auditor"),
|
|
3552
|
+
reason: get(1, "reason")
|
|
3553
|
+
};
|
|
3554
|
+
}
|
|
3555
|
+
if (m_norm === "registerasset") {
|
|
3556
|
+
return {
|
|
3557
|
+
name: get(0, "name"),
|
|
3558
|
+
symbol: get(1, "symbol"),
|
|
3559
|
+
decimals: get(2, "decimals"),
|
|
3560
|
+
contract_address: get(3, "contract_address")
|
|
3561
|
+
};
|
|
3562
|
+
}
|
|
3563
|
+
if (m_norm === "verifyasset") {
|
|
3564
|
+
return { asset_id: get(0, "asset_id") };
|
|
3565
|
+
}
|
|
3566
|
+
if (m_norm === "unverifyasset") {
|
|
3567
|
+
return { asset_id: get(0, "asset_id") };
|
|
3568
|
+
}
|
|
3569
|
+
if (m_norm === "batchsubmitdisclosureproofs") {
|
|
3570
|
+
return { submissions: get(0, "submissions") };
|
|
3571
|
+
}
|
|
3572
|
+
if (m_norm === "pruneexpiredrequest") {
|
|
3573
|
+
return {
|
|
3574
|
+
target: get(0, "target"),
|
|
3575
|
+
auditor: get(1, "auditor")
|
|
3576
|
+
};
|
|
3577
|
+
}
|
|
3578
|
+
if (m_norm === "revokedisclosurerecord") {
|
|
3579
|
+
return { commitment: get(0, "commitment") };
|
|
3580
|
+
}
|
|
3581
|
+
}
|
|
3582
|
+
if (s === "ethereum" && m === "transact") {
|
|
3583
|
+
return { transaction: get(0, "transaction") };
|
|
3584
|
+
}
|
|
3585
|
+
if (s === "evm") {
|
|
3586
|
+
if (m === "withdraw") {
|
|
3587
|
+
return {
|
|
3588
|
+
address: get(0, "address"),
|
|
3589
|
+
value: get(1, "value")
|
|
3590
|
+
};
|
|
3591
|
+
}
|
|
3592
|
+
if (m === "call") {
|
|
3593
|
+
return {
|
|
3594
|
+
source: get(0, "source"),
|
|
3595
|
+
target: get(1, "target"),
|
|
3596
|
+
input: get(2, "input"),
|
|
3597
|
+
value: get(3, "value"),
|
|
3598
|
+
gas_limit: get(4, "gas_limit"),
|
|
3599
|
+
max_fee_per_gas: get(5, "max_fee_per_gas"),
|
|
3600
|
+
max_priority_fee_per_gas: get(6, "max_priority_fee_per_gas"),
|
|
3601
|
+
nonce: get(7, "nonce"),
|
|
3602
|
+
access_list: get(8, "access_list"),
|
|
3603
|
+
authorization_list: get(9, "authorization_list")
|
|
3604
|
+
};
|
|
3605
|
+
}
|
|
3606
|
+
if (m === "create") {
|
|
3607
|
+
return {
|
|
3608
|
+
source: get(0, "source"),
|
|
3609
|
+
init: get(1, "init"),
|
|
3610
|
+
value: get(2, "value"),
|
|
3611
|
+
gas_limit: get(3, "gas_limit"),
|
|
3612
|
+
max_fee_per_gas: get(4, "max_fee_per_gas"),
|
|
3613
|
+
max_priority_fee_per_gas: get(5, "max_priority_fee_per_gas"),
|
|
3614
|
+
nonce: get(6, "nonce"),
|
|
3615
|
+
access_list: get(7, "access_list"),
|
|
3616
|
+
authorization_list: get(8, "authorization_list")
|
|
3617
|
+
};
|
|
3618
|
+
}
|
|
3619
|
+
if (m === "create2") {
|
|
3620
|
+
return {
|
|
3621
|
+
source: get(0, "source"),
|
|
3622
|
+
init: get(1, "init"),
|
|
3623
|
+
salt: get(2, "salt"),
|
|
3624
|
+
value: get(3, "value"),
|
|
3625
|
+
gas_limit: get(4, "gas_limit"),
|
|
3626
|
+
max_fee_per_gas: get(5, "max_fee_per_gas"),
|
|
3627
|
+
max_priority_fee_per_gas: get(6, "max_priority_fee_per_gas"),
|
|
3628
|
+
nonce: get(7, "nonce"),
|
|
3629
|
+
access_list: get(8, "access_list"),
|
|
3630
|
+
authorization_list: get(9, "authorization_list")
|
|
3631
|
+
};
|
|
3632
|
+
}
|
|
3633
|
+
}
|
|
3634
|
+
if (s === "accountmapping") {
|
|
3635
|
+
const m_norm = m.replace(/_/g, "");
|
|
3636
|
+
if (m_norm === "registeralias") {
|
|
3637
|
+
return { alias: get(0, "alias") };
|
|
3638
|
+
}
|
|
3639
|
+
if (m_norm === "transferalias") {
|
|
3640
|
+
return { new_owner: get(0, "new_owner") };
|
|
3641
|
+
}
|
|
3642
|
+
if (m_norm === "putaliasonsale") {
|
|
3643
|
+
return {
|
|
3644
|
+
price: get(0, "price"),
|
|
3645
|
+
allowed_buyers: get(1, "allowed_buyers")
|
|
3646
|
+
};
|
|
3647
|
+
}
|
|
3648
|
+
if (m_norm === "buyalias") {
|
|
3649
|
+
return { alias: get(0, "alias") };
|
|
3650
|
+
}
|
|
3651
|
+
if (m_norm === "addchainlink") {
|
|
3652
|
+
return {
|
|
3653
|
+
chain_id: get(0, "chain_id"),
|
|
3654
|
+
address: get(1, "address"),
|
|
3655
|
+
signature: get(2, "signature")
|
|
3656
|
+
};
|
|
3657
|
+
}
|
|
3658
|
+
if (m_norm === "removechainlink") {
|
|
3659
|
+
return { chain_id: get(0, "chain_id") };
|
|
3660
|
+
}
|
|
3661
|
+
if (m_norm === "setaccountmetadata") {
|
|
3662
|
+
return {
|
|
3663
|
+
display_name: get(0, "display_name"),
|
|
3664
|
+
bio: get(1, "bio"),
|
|
3665
|
+
avatar: get(2, "avatar")
|
|
3666
|
+
};
|
|
3667
|
+
}
|
|
3668
|
+
if (m_norm === "addsupportedchain") {
|
|
3669
|
+
return {
|
|
3670
|
+
chain_id: get(0, "chain_id"),
|
|
3671
|
+
scheme: get(1, "scheme")
|
|
3672
|
+
};
|
|
3673
|
+
}
|
|
3674
|
+
if (m_norm === "removesupportedchain") {
|
|
3675
|
+
return { chain_id: get(0, "chain_id") };
|
|
3676
|
+
}
|
|
3677
|
+
if (m_norm === "dispatchaslinkedaccount") {
|
|
3678
|
+
return {
|
|
3679
|
+
owner: get(0, "owner"),
|
|
3680
|
+
chain_id: get(1, "chain_id"),
|
|
3681
|
+
address: get(2, "address"),
|
|
3682
|
+
signature: get(3, "signature"),
|
|
3683
|
+
call: get(4, "call")
|
|
3684
|
+
};
|
|
3685
|
+
}
|
|
3686
|
+
if (m_norm === "registerprivatelink") {
|
|
3687
|
+
return {
|
|
3688
|
+
chain_id: get(0, "chain_id"),
|
|
3689
|
+
commitment: get(1, "commitment")
|
|
3690
|
+
};
|
|
3691
|
+
}
|
|
3692
|
+
if (m_norm === "removeprivatelink") {
|
|
3693
|
+
return { commitment: get(0, "commitment") };
|
|
3694
|
+
}
|
|
3695
|
+
if (m_norm === "revealprivatelink") {
|
|
3696
|
+
return {
|
|
3697
|
+
commitment: get(0, "commitment"),
|
|
3698
|
+
address: get(1, "address"),
|
|
3699
|
+
blinding: get(2, "blinding"),
|
|
3700
|
+
signature: get(3, "signature")
|
|
3701
|
+
};
|
|
3702
|
+
}
|
|
3703
|
+
if (m_norm === "dispatchasprivatelink") {
|
|
3704
|
+
return {
|
|
3705
|
+
owner: get(0, "owner"),
|
|
3706
|
+
commitment: get(1, "commitment"),
|
|
3707
|
+
zk_proof: get(2, "zk_proof"),
|
|
3708
|
+
call: get(3, "call")
|
|
3709
|
+
};
|
|
3710
|
+
}
|
|
3711
|
+
}
|
|
3712
|
+
if (s === "zkverifier") {
|
|
3713
|
+
const m_norm = m.replace(/_/g, "");
|
|
3714
|
+
if (m_norm === "batchregisterverificationkeys") {
|
|
3715
|
+
const entries = get(0, "entries");
|
|
3716
|
+
if (Array.isArray(entries)) {
|
|
3717
|
+
return {
|
|
3718
|
+
entries: entries.map((e) => ({
|
|
3719
|
+
circuit_id: e["circuit_id"],
|
|
3720
|
+
version: e["version"],
|
|
3721
|
+
verification_key: e["verification_key"],
|
|
3722
|
+
set_active: e["set_active"]
|
|
3723
|
+
}))
|
|
3724
|
+
};
|
|
3725
|
+
}
|
|
3726
|
+
return { entries };
|
|
3727
|
+
}
|
|
3728
|
+
if (m_norm === "registerverificationkey") {
|
|
3729
|
+
return {
|
|
3730
|
+
circuit_id: get(0, "circuit_id"),
|
|
3731
|
+
version: get(1, "version"),
|
|
3732
|
+
verification_key: get(2, "verification_key")
|
|
3733
|
+
};
|
|
3734
|
+
}
|
|
3735
|
+
if (m_norm === "setactiveversion") {
|
|
3736
|
+
return {
|
|
3737
|
+
circuit_id: get(0, "circuit_id"),
|
|
3738
|
+
version: get(1, "version")
|
|
3739
|
+
};
|
|
3740
|
+
}
|
|
3741
|
+
if (m_norm === "removeverificationkey") {
|
|
3742
|
+
return {
|
|
3743
|
+
circuit_id: get(0, "circuit_id"),
|
|
3744
|
+
version: get(1, "version")
|
|
3745
|
+
};
|
|
3746
|
+
}
|
|
3747
|
+
if (m_norm === "verifyproof") {
|
|
3748
|
+
return {
|
|
3749
|
+
circuit_id: get(0, "circuit_id"),
|
|
3750
|
+
proof: get(1, "proof"),
|
|
3751
|
+
public_inputs: get(2, "public_inputs")
|
|
3752
|
+
};
|
|
3753
|
+
}
|
|
3754
|
+
}
|
|
3755
|
+
return args;
|
|
3756
|
+
}
|
|
3757
|
+
function mapZkEventData(method, data) {
|
|
3758
|
+
const m = method.toLowerCase();
|
|
3759
|
+
const get = (idx, name) => {
|
|
3760
|
+
if (name in data) return data[name];
|
|
3761
|
+
const argKey = `arg${idx}`;
|
|
3762
|
+
if (argKey in data) return data[argKey];
|
|
3763
|
+
if (idx in data) return data[idx];
|
|
3764
|
+
const strIdx = idx.toString();
|
|
3765
|
+
if (strIdx in data) return data[strIdx];
|
|
3766
|
+
return void 0;
|
|
3767
|
+
};
|
|
3768
|
+
const formatAmount = (val) => {
|
|
3769
|
+
if (val === void 0 || val === null) return null;
|
|
3770
|
+
return formatBalance(String(val));
|
|
3771
|
+
};
|
|
3772
|
+
if (m === "shielded" || m === "deposit") {
|
|
3773
|
+
return {
|
|
3774
|
+
sender: get(0, "depositor") || get(0, "sender"),
|
|
3775
|
+
amount: formatAmount(get(1, "amount")),
|
|
3776
|
+
commitment: get(2, "commitment"),
|
|
3777
|
+
memo: get(3, "encrypted_memo") || get(3, "memo"),
|
|
3778
|
+
index: get(4, "leaf_index") || get(4, "index")
|
|
3779
|
+
};
|
|
3780
|
+
}
|
|
3781
|
+
if (m === "privatetransfer") {
|
|
3782
|
+
return {
|
|
3783
|
+
nullifiers: get(0, "nullifiers"),
|
|
3784
|
+
commitments: get(1, "commitments"),
|
|
3785
|
+
memos: get(2, "encrypted_memos") || get(2, "memos"),
|
|
3786
|
+
indices: get(3, "leaf_indices") || get(3, "indices")
|
|
3787
|
+
};
|
|
3788
|
+
}
|
|
3789
|
+
if (m === "unshielded" || m === "withdraw") {
|
|
3790
|
+
return {
|
|
3791
|
+
nullifier: get(0, "nullifier"),
|
|
3792
|
+
amount: formatAmount(get(1, "amount")),
|
|
3793
|
+
recipient: get(2, "recipient")
|
|
3794
|
+
};
|
|
3795
|
+
}
|
|
3796
|
+
if (m === "merklerootupdated" || m === "merkleroot") {
|
|
3797
|
+
return {
|
|
3798
|
+
old_root: get(0, "old_root"),
|
|
3799
|
+
new_root: get(1, "new_root"),
|
|
3800
|
+
size: get(2, "tree_size") || get(2, "size")
|
|
3801
|
+
};
|
|
3802
|
+
}
|
|
3803
|
+
const m_norm = m.replace(/_/g, "");
|
|
3804
|
+
if (m_norm === "auditpolicyset") {
|
|
3805
|
+
return {
|
|
3806
|
+
account: get(0, "account"),
|
|
3807
|
+
version: get(1, "version")
|
|
3808
|
+
};
|
|
3809
|
+
}
|
|
3810
|
+
if (m_norm === "disclosed") {
|
|
3811
|
+
return {
|
|
3812
|
+
who: get(0, "who"),
|
|
3813
|
+
commitment: get(1, "commitment"),
|
|
3814
|
+
auditor: get(2, "auditor")
|
|
3815
|
+
};
|
|
3816
|
+
}
|
|
3817
|
+
if (m_norm === "disclosurerequested") {
|
|
3818
|
+
return {
|
|
3819
|
+
target: get(0, "target"),
|
|
3820
|
+
auditor: get(1, "auditor"),
|
|
3821
|
+
reason: get(2, "reason")
|
|
3822
|
+
};
|
|
3823
|
+
}
|
|
3824
|
+
if (m_norm === "disclosurerejected") {
|
|
3825
|
+
return {
|
|
3826
|
+
target: get(0, "target"),
|
|
3827
|
+
auditor: get(1, "auditor"),
|
|
3828
|
+
reason: get(2, "reason")
|
|
3829
|
+
};
|
|
3830
|
+
}
|
|
3831
|
+
if (m_norm === "disclosurerequestexpired") {
|
|
3832
|
+
return {
|
|
3833
|
+
target: get(0, "target"),
|
|
3834
|
+
auditor: get(1, "auditor")
|
|
3835
|
+
};
|
|
3836
|
+
}
|
|
3837
|
+
if (m_norm === "disclosurerecordrevoked") {
|
|
3838
|
+
return {
|
|
3839
|
+
who: get(0, "who"),
|
|
3840
|
+
commitment: get(1, "commitment")
|
|
3841
|
+
};
|
|
3842
|
+
}
|
|
3843
|
+
if (m_norm === "assetregistered") {
|
|
3844
|
+
return { asset_id: get(0, "asset_id") };
|
|
3845
|
+
}
|
|
3846
|
+
if (m_norm === "assetverified") {
|
|
3847
|
+
return { asset_id: get(0, "asset_id") };
|
|
3848
|
+
}
|
|
3849
|
+
if (m_norm === "assetunverified") {
|
|
3850
|
+
return { asset_id: get(0, "asset_id") };
|
|
3851
|
+
}
|
|
3852
|
+
if (m_norm === "accountmapped" || m_norm === "accountunmapped") {
|
|
3853
|
+
return {
|
|
3854
|
+
account: get(0, "account"),
|
|
3855
|
+
address: get(1, "address")
|
|
3856
|
+
};
|
|
3857
|
+
}
|
|
3858
|
+
if (m_norm === "aliasregistered") {
|
|
3859
|
+
return {
|
|
3860
|
+
account: get(0, "account"),
|
|
3861
|
+
alias: get(1, "alias"),
|
|
3862
|
+
evm_address: get(2, "evm_address")
|
|
3863
|
+
};
|
|
3864
|
+
}
|
|
3865
|
+
if (m_norm === "aliasreleased") {
|
|
3866
|
+
return {
|
|
3867
|
+
account: get(0, "account"),
|
|
3868
|
+
alias: get(1, "alias")
|
|
3869
|
+
};
|
|
3870
|
+
}
|
|
3871
|
+
if (m_norm === "aliastransferred") {
|
|
3872
|
+
return {
|
|
3873
|
+
from: get(0, "from"),
|
|
3874
|
+
to: get(1, "to"),
|
|
3875
|
+
alias: get(2, "alias")
|
|
3876
|
+
};
|
|
3877
|
+
}
|
|
3878
|
+
if (m_norm === "aliaslistedforsale") {
|
|
3879
|
+
return {
|
|
3880
|
+
seller: get(0, "seller"),
|
|
3881
|
+
alias: get(1, "alias"),
|
|
3882
|
+
price: get(2, "price"),
|
|
3883
|
+
private: get(3, "private")
|
|
3884
|
+
};
|
|
3885
|
+
}
|
|
3886
|
+
if (m_norm === "aliassalecancelled") {
|
|
3887
|
+
return {
|
|
3888
|
+
seller: get(0, "seller"),
|
|
3889
|
+
alias: get(1, "alias")
|
|
3890
|
+
};
|
|
3891
|
+
}
|
|
3892
|
+
if (m_norm === "aliassold") {
|
|
3893
|
+
return {
|
|
3894
|
+
seller: get(0, "seller"),
|
|
3895
|
+
buyer: get(1, "buyer"),
|
|
3896
|
+
alias: get(2, "alias"),
|
|
3897
|
+
price: get(3, "price")
|
|
3898
|
+
};
|
|
3899
|
+
}
|
|
3900
|
+
if (m_norm === "chainlinkadded") {
|
|
3901
|
+
return {
|
|
3902
|
+
account: get(0, "account"),
|
|
3903
|
+
chain_id: get(1, "chain_id"),
|
|
3904
|
+
address: get(2, "address")
|
|
3905
|
+
};
|
|
3906
|
+
}
|
|
3907
|
+
if (m_norm === "chainlinkremoved") {
|
|
3908
|
+
return {
|
|
3909
|
+
account: get(0, "account"),
|
|
3910
|
+
chain_id: get(1, "chain_id")
|
|
3911
|
+
};
|
|
3912
|
+
}
|
|
3913
|
+
if (m_norm === "metadataupdated") {
|
|
3914
|
+
return { account: get(0, "account") };
|
|
3915
|
+
}
|
|
3916
|
+
if (m_norm === "supportedchainadded") {
|
|
3917
|
+
return {
|
|
3918
|
+
chain_id: get(0, "chain_id"),
|
|
3919
|
+
scheme: get(1, "scheme")
|
|
3920
|
+
};
|
|
3921
|
+
}
|
|
3922
|
+
if (m_norm === "supportedchainremoved") {
|
|
3923
|
+
return { chain_id: get(0, "chain_id") };
|
|
3924
|
+
}
|
|
3925
|
+
if (m_norm === "proxycallexecuted") {
|
|
3926
|
+
return {
|
|
3927
|
+
owner: get(0, "owner"),
|
|
3928
|
+
chain_id: get(1, "chain_id"),
|
|
3929
|
+
address: get(2, "address")
|
|
3930
|
+
};
|
|
3931
|
+
}
|
|
3932
|
+
if (m_norm === "privatechainlinkadded" || m_norm === "privatechainlinkremoved") {
|
|
3933
|
+
return {
|
|
3934
|
+
account: get(0, "account"),
|
|
3935
|
+
chain_id: get(1, "chain_id"),
|
|
3936
|
+
commitment: get(2, "commitment")
|
|
3937
|
+
};
|
|
3938
|
+
}
|
|
3939
|
+
if (m_norm === "privatechainlinkrevealed") {
|
|
3940
|
+
return {
|
|
3941
|
+
account: get(0, "account"),
|
|
3942
|
+
chain_id: get(1, "chain_id"),
|
|
3943
|
+
address: get(2, "address")
|
|
3944
|
+
};
|
|
3945
|
+
}
|
|
3946
|
+
if (m_norm === "privatelinkdispatchexecuted") {
|
|
3947
|
+
return {
|
|
3948
|
+
owner: get(0, "owner"),
|
|
3949
|
+
commitment: get(1, "commitment")
|
|
3950
|
+
};
|
|
3951
|
+
}
|
|
3952
|
+
if (m_norm === "verificationkeyregistered" || m_norm === "activeversionset" || m_norm === "verificationkeyremoved" || m_norm === "proofverified" || m_norm === "proofverificationfailed") {
|
|
3953
|
+
return {
|
|
3954
|
+
circuit_id: get(0, "circuit_id"),
|
|
3955
|
+
version: get(1, "version")
|
|
3956
|
+
};
|
|
3957
|
+
}
|
|
3958
|
+
if (m_norm === "log") {
|
|
3959
|
+
return { log: get(0, "log") };
|
|
3960
|
+
}
|
|
3961
|
+
if (m_norm === "created" || m_norm === "createdfailed" || m_norm === "executed" || m_norm === "executedfailed") {
|
|
3962
|
+
return { address: get(0, "address") };
|
|
3963
|
+
}
|
|
3964
|
+
if (m_norm === "executed") {
|
|
3965
|
+
return {
|
|
3966
|
+
from: get(0, "from"),
|
|
3967
|
+
to: get(1, "to"),
|
|
3968
|
+
transaction_hash: get(2, "transaction_hash"),
|
|
3969
|
+
exit_reason: get(3, "exit_reason")
|
|
3970
|
+
};
|
|
3971
|
+
}
|
|
3972
|
+
if (m_norm === "extrinsicsuccess") {
|
|
3973
|
+
return { dispatch_info: get(0, "dispatch_info") };
|
|
3974
|
+
}
|
|
3975
|
+
if (m_norm === "extrinsicfailed") {
|
|
3976
|
+
return {
|
|
3977
|
+
dispatch_error: get(0, "dispatch_error"),
|
|
3978
|
+
dispatch_info: get(1, "dispatch_info")
|
|
3979
|
+
};
|
|
3980
|
+
}
|
|
3981
|
+
if (m_norm === "newaccount" || m_norm === "killedaccount") {
|
|
3982
|
+
return { account: get(0, "account") };
|
|
3983
|
+
}
|
|
3984
|
+
if (m_norm === "remarked") {
|
|
3985
|
+
return {
|
|
3986
|
+
sender: get(0, "sender"),
|
|
3987
|
+
hash: get(1, "hash")
|
|
3988
|
+
};
|
|
3989
|
+
}
|
|
3990
|
+
if (m_norm === "upgradeauthorized") {
|
|
3991
|
+
return {
|
|
3992
|
+
code_hash: get(0, "code_hash"),
|
|
3993
|
+
check_version: get(1, "check_version")
|
|
3994
|
+
};
|
|
3995
|
+
}
|
|
3996
|
+
if (m_norm === "rejectedinvalidauthorizedupgrade") {
|
|
3997
|
+
return {
|
|
3998
|
+
code_hash: get(0, "code_hash"),
|
|
3999
|
+
error: get(1, "error")
|
|
4000
|
+
};
|
|
4001
|
+
}
|
|
4002
|
+
if (m_norm === "endowed") {
|
|
4003
|
+
return {
|
|
4004
|
+
account: get(0, "account"),
|
|
4005
|
+
free_balance: get(1, "free_balance")
|
|
4006
|
+
};
|
|
4007
|
+
}
|
|
4008
|
+
if (m_norm === "dustlost") {
|
|
4009
|
+
return {
|
|
4010
|
+
account: get(0, "account"),
|
|
4011
|
+
amount: get(1, "amount")
|
|
4012
|
+
};
|
|
4013
|
+
}
|
|
4014
|
+
if (m_norm === "transfer") {
|
|
4015
|
+
return {
|
|
4016
|
+
from: get(0, "from"),
|
|
4017
|
+
to: get(1, "to"),
|
|
4018
|
+
amount: get(2, "amount")
|
|
4019
|
+
};
|
|
4020
|
+
}
|
|
4021
|
+
if (m_norm === "balanceset") {
|
|
4022
|
+
return {
|
|
4023
|
+
who: get(0, "who"),
|
|
4024
|
+
free: get(1, "free")
|
|
4025
|
+
};
|
|
4026
|
+
}
|
|
4027
|
+
if (m_norm === "reserved" || m_norm === "unreserved" || m_norm === "deposit" || m_norm === "slashed" || m_norm === "minted" || m_norm === "burned" || m_norm === "suspended" || m_norm === "restored" || m_norm === "locked" || m_norm === "unlocked" || m_norm === "frozen" || m_norm === "thawed") {
|
|
4028
|
+
return {
|
|
4029
|
+
who: get(0, "who"),
|
|
4030
|
+
amount: get(1, "amount")
|
|
4031
|
+
};
|
|
4032
|
+
}
|
|
4033
|
+
if (m_norm === "reserverepatriated") {
|
|
4034
|
+
return {
|
|
4035
|
+
from: get(0, "from"),
|
|
4036
|
+
to: get(1, "to"),
|
|
4037
|
+
amount: get(2, "amount"),
|
|
4038
|
+
destination_status: get(3, "destination_status")
|
|
4039
|
+
};
|
|
4040
|
+
}
|
|
4041
|
+
if (m_norm === "upgraded") {
|
|
4042
|
+
return { who: get(0, "who") };
|
|
4043
|
+
}
|
|
4044
|
+
if (m_norm === "issued" || m_norm === "rescinded") {
|
|
4045
|
+
return { amount: get(0, "amount") };
|
|
4046
|
+
}
|
|
4047
|
+
if (m_norm === "totalissuanceforced") {
|
|
4048
|
+
return {
|
|
4049
|
+
old: get(0, "old"),
|
|
4050
|
+
new: get(1, "new")
|
|
4051
|
+
};
|
|
4052
|
+
}
|
|
4053
|
+
if (m_norm === "sudid" || m_norm === "sudoasdone") {
|
|
4054
|
+
return { sudo_result: get(0, "sudo_result") };
|
|
4055
|
+
}
|
|
4056
|
+
if (m_norm === "keychanged") {
|
|
4057
|
+
return {
|
|
4058
|
+
old: get(0, "old"),
|
|
4059
|
+
new: get(1, "new")
|
|
4060
|
+
};
|
|
4061
|
+
}
|
|
4062
|
+
if (m_norm === "newauthorities") {
|
|
4063
|
+
return { authority_set: get(0, "authority_set") };
|
|
4064
|
+
}
|
|
4065
|
+
if (m_norm === "transactionfeepaid") {
|
|
4066
|
+
return {
|
|
4067
|
+
who: get(0, "who"),
|
|
4068
|
+
actual_fee: get(1, "actual_fee"),
|
|
4069
|
+
tip: get(2, "tip")
|
|
4070
|
+
};
|
|
4071
|
+
}
|
|
4072
|
+
return data;
|
|
4073
|
+
}
|
|
4074
|
+
|
|
2390
4075
|
// src/index.ts
|
|
4076
|
+
import {
|
|
4077
|
+
Blake2256,
|
|
4078
|
+
AccountId as AccountId2,
|
|
4079
|
+
u128,
|
|
4080
|
+
u64,
|
|
4081
|
+
Storage,
|
|
4082
|
+
Keccak256
|
|
4083
|
+
} from "@polkadot-api/substrate-bindings";
|
|
4084
|
+
import { base58 } from "@scure/base";
|
|
2391
4085
|
import { getPolkadotSigner } from "polkadot-api/signer";
|
|
2392
4086
|
import { getPolkadotSignerFromPjs } from "polkadot-api/pjs-signer";
|
|
4087
|
+
import { getSs58AddressInfo } from "polkadot-api";
|
|
2393
4088
|
export {
|
|
4089
|
+
AccountId2 as AccountId,
|
|
2394
4090
|
AccountMappingModule,
|
|
2395
4091
|
AccountMappingPrecompile,
|
|
2396
|
-
|
|
4092
|
+
Blake2256,
|
|
2397
4093
|
CircuitId,
|
|
2398
4094
|
CryptoPrecompiles,
|
|
2399
4095
|
EncryptedMemo,
|
|
2400
4096
|
EvmClient,
|
|
4097
|
+
EvmExplorer,
|
|
4098
|
+
IndexerClient,
|
|
2401
4099
|
KNOWN_PRECOMPILES,
|
|
2402
|
-
|
|
4100
|
+
Keccak256,
|
|
2403
4101
|
NoteBuilder,
|
|
2404
4102
|
OrbinumClient,
|
|
4103
|
+
OrbinumClientProvider,
|
|
2405
4104
|
PRECOMPILE_ADDR,
|
|
2406
4105
|
PrivacyKeyManager,
|
|
4106
|
+
PrivacyModule,
|
|
2407
4107
|
SLIP0044_NAMESPACE,
|
|
2408
4108
|
ShieldedPoolModule,
|
|
2409
4109
|
ShieldedPoolPrecompile,
|
|
4110
|
+
SignatureScheme,
|
|
4111
|
+
Storage,
|
|
2410
4112
|
SubstrateClient,
|
|
4113
|
+
ZkVerifierModule,
|
|
2411
4114
|
accountIdHexToSs58,
|
|
2412
4115
|
addressToAccountIdHex,
|
|
4116
|
+
base58,
|
|
2413
4117
|
bigintTo32Be,
|
|
2414
4118
|
bigintTo32Le,
|
|
2415
4119
|
bigintTo32LeArr,
|
|
2416
4120
|
bytesToBigintLE,
|
|
2417
4121
|
computePathIndices,
|
|
4122
|
+
decodePrecompileCalldata,
|
|
2418
4123
|
decryptJson,
|
|
2419
4124
|
deriveOwnerPk,
|
|
2420
4125
|
deriveSpendingKeyFromSignature,
|
|
@@ -2425,13 +4130,18 @@ export {
|
|
|
2425
4130
|
ensureHexPrefix,
|
|
2426
4131
|
evmAddressToAccountId,
|
|
2427
4132
|
evmToImplicitSubstrate,
|
|
4133
|
+
evmToMappedAccountHex,
|
|
2428
4134
|
evmToSubstrate,
|
|
2429
4135
|
formatBalance,
|
|
2430
4136
|
formatORB,
|
|
4137
|
+
fromBase64,
|
|
2431
4138
|
fromHex,
|
|
2432
4139
|
getPolkadotSigner,
|
|
2433
4140
|
getPolkadotSignerFromPjs,
|
|
2434
4141
|
getPrecompileLabel,
|
|
4142
|
+
getSs58AddressInfo,
|
|
4143
|
+
hexToBigint,
|
|
4144
|
+
hexToNumber,
|
|
2435
4145
|
implicitSubstrateToEvm,
|
|
2436
4146
|
isEvmAddress,
|
|
2437
4147
|
isImplicitEvmAccount,
|
|
@@ -2439,11 +4149,19 @@ export {
|
|
|
2439
4149
|
isSubstrateAddress,
|
|
2440
4150
|
isUnifiedAddress,
|
|
2441
4151
|
leHexToBigint,
|
|
4152
|
+
mapExtrinsicArgs,
|
|
4153
|
+
mapZkEventData,
|
|
2442
4154
|
normalizeEvmAddress,
|
|
4155
|
+
shortHash,
|
|
2443
4156
|
substrateSs58ToAccountIdHex,
|
|
2444
4157
|
substrateToEvm,
|
|
4158
|
+
toBase64,
|
|
2445
4159
|
toHex,
|
|
4160
|
+
toTxResult,
|
|
4161
|
+
truncateMiddle,
|
|
2446
4162
|
tryDecryptNote,
|
|
4163
|
+
u128,
|
|
4164
|
+
u64,
|
|
2447
4165
|
vaultReplacer,
|
|
2448
4166
|
vaultReviver
|
|
2449
4167
|
};
|