@cloak.ag/sdk 1.0.6 → 1.0.7
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/dist/chunk-QDMAIFO4.js +389 -0
- package/dist/index.cjs +2867 -3126
- package/dist/index.d.cts +160 -282
- package/dist/index.d.ts +160 -282
- package/dist/index.js +2509 -3147
- package/dist/onchain-proof-CY7AWF43.js +10 -0
- package/package.json +11 -2
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
// src/utils/crypto.ts
|
|
9
|
+
import { buildPoseidon } from "circomlibjs";
|
|
10
|
+
var poseidon = null;
|
|
11
|
+
async function getPoseidon() {
|
|
12
|
+
if (!poseidon) {
|
|
13
|
+
poseidon = await buildPoseidon();
|
|
14
|
+
}
|
|
15
|
+
return poseidon;
|
|
16
|
+
}
|
|
17
|
+
async function poseidonHash(inputs) {
|
|
18
|
+
const p = await getPoseidon();
|
|
19
|
+
const hash = p(inputs.map((x) => p.F.e(x)));
|
|
20
|
+
return p.F.toObject(hash);
|
|
21
|
+
}
|
|
22
|
+
function splitTo2Limbs(value) {
|
|
23
|
+
const mask = (1n << 128n) - 1n;
|
|
24
|
+
const lo = value & mask;
|
|
25
|
+
const hi = value >> 128n;
|
|
26
|
+
return [lo, hi];
|
|
27
|
+
}
|
|
28
|
+
function pubkeyToLimbs(pubkey) {
|
|
29
|
+
const bytes = typeof pubkey.toBytes === "function" ? pubkey.toBytes() : pubkey;
|
|
30
|
+
const value = BigInt("0x" + Buffer.from(bytes).toString("hex"));
|
|
31
|
+
return splitTo2Limbs(value);
|
|
32
|
+
}
|
|
33
|
+
async function computeMerkleRoot(leaf, pathElements, pathIndices) {
|
|
34
|
+
let current = leaf;
|
|
35
|
+
for (let i = 0; i < pathElements.length; i++) {
|
|
36
|
+
if (pathIndices[i] === 0) {
|
|
37
|
+
current = await poseidonHash([current, pathElements[i]]);
|
|
38
|
+
} else {
|
|
39
|
+
current = await poseidonHash([pathElements[i], current]);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return current;
|
|
43
|
+
}
|
|
44
|
+
function hexToBigint(hex) {
|
|
45
|
+
const cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
46
|
+
return BigInt("0x" + cleanHex);
|
|
47
|
+
}
|
|
48
|
+
async function computeCommitment(amount, r, sk_spend) {
|
|
49
|
+
const [sk0, sk1] = splitTo2Limbs(sk_spend);
|
|
50
|
+
const [r0, r1] = splitTo2Limbs(r);
|
|
51
|
+
const pk_spend = await poseidonHash([sk0, sk1]);
|
|
52
|
+
return await poseidonHash([amount, r0, r1, pk_spend]);
|
|
53
|
+
}
|
|
54
|
+
async function generateCommitmentAsync(amountLamports, r, skSpend) {
|
|
55
|
+
const amount = BigInt(amountLamports);
|
|
56
|
+
const rValue = hexToBigint(bytesToHex(r));
|
|
57
|
+
const skValue = hexToBigint(bytesToHex(skSpend));
|
|
58
|
+
return await computeCommitment(amount, rValue, skValue);
|
|
59
|
+
}
|
|
60
|
+
function generateCommitment(_amountLamports, _r, _skSpend) {
|
|
61
|
+
throw new Error("generateCommitment is deprecated. Use generateCommitmentAsync instead.");
|
|
62
|
+
}
|
|
63
|
+
async function computeNullifier(sk_spend, leafIndex) {
|
|
64
|
+
const [sk0, sk1] = splitTo2Limbs(sk_spend);
|
|
65
|
+
return await poseidonHash([sk0, sk1, leafIndex]);
|
|
66
|
+
}
|
|
67
|
+
async function computeNullifierAsync(skSpend, leafIndex) {
|
|
68
|
+
const skValue = typeof skSpend === "string" ? hexToBigint(skSpend) : hexToBigint(bytesToHex(skSpend));
|
|
69
|
+
return await computeNullifier(skValue, BigInt(leafIndex));
|
|
70
|
+
}
|
|
71
|
+
function computeNullifierSync(_skSpend, _leafIndex) {
|
|
72
|
+
throw new Error("computeNullifierSync is deprecated. Use computeNullifierAsync instead.");
|
|
73
|
+
}
|
|
74
|
+
async function computeOutputsHashAsync(outputs) {
|
|
75
|
+
let hash = 0n;
|
|
76
|
+
for (const output of outputs) {
|
|
77
|
+
const [lo, hi] = pubkeyToLimbs(output.recipient);
|
|
78
|
+
hash = await poseidonHash([hash, lo, hi, BigInt(output.amount)]);
|
|
79
|
+
}
|
|
80
|
+
return hash;
|
|
81
|
+
}
|
|
82
|
+
async function computeOutputsHash(outAddr, outAmount, outFlags) {
|
|
83
|
+
let hash = 0n;
|
|
84
|
+
for (let i = 0; i < 5; i++) {
|
|
85
|
+
if (outFlags[i] === 1) {
|
|
86
|
+
hash = await poseidonHash([hash, outAddr[i][0], outAddr[i][1], outAmount[i]]);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return hash;
|
|
90
|
+
}
|
|
91
|
+
function computeOutputsHashSync(_outputs) {
|
|
92
|
+
throw new Error("computeOutputsHashSync is deprecated. Use computeOutputsHashAsync instead.");
|
|
93
|
+
}
|
|
94
|
+
async function computeSwapOutputsHash(inputMintLimbs, outputMintLimbs, recipientAtaLimbs, minOutputAmount, publicAmount) {
|
|
95
|
+
return await poseidonHash([
|
|
96
|
+
inputMintLimbs[0],
|
|
97
|
+
inputMintLimbs[1],
|
|
98
|
+
outputMintLimbs[0],
|
|
99
|
+
outputMintLimbs[1],
|
|
100
|
+
recipientAtaLimbs[0],
|
|
101
|
+
recipientAtaLimbs[1],
|
|
102
|
+
minOutputAmount,
|
|
103
|
+
publicAmount
|
|
104
|
+
]);
|
|
105
|
+
}
|
|
106
|
+
async function computeSwapOutputsHashAsync(inputMint, outputMint, recipientAta, minOutputAmount, amount) {
|
|
107
|
+
const inputMintLimbs = pubkeyToLimbs(inputMint);
|
|
108
|
+
const outputMintLimbs = pubkeyToLimbs(outputMint);
|
|
109
|
+
const recipientAtaLimbs = pubkeyToLimbs(recipientAta);
|
|
110
|
+
return await computeSwapOutputsHash(
|
|
111
|
+
inputMintLimbs,
|
|
112
|
+
outputMintLimbs,
|
|
113
|
+
recipientAtaLimbs,
|
|
114
|
+
BigInt(minOutputAmount),
|
|
115
|
+
BigInt(amount)
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
function computeSwapOutputsHashSync(_outputMint, _recipientAta, _minOutputAmount, _amount) {
|
|
119
|
+
throw new Error("computeSwapOutputsHashSync is deprecated. Use computeSwapOutputsHashAsync instead.");
|
|
120
|
+
}
|
|
121
|
+
function bigintToBytes32(n) {
|
|
122
|
+
const hex = n.toString(16).padStart(64, "0");
|
|
123
|
+
const bytes = new Uint8Array(32);
|
|
124
|
+
for (let i = 0; i < 32; i++) {
|
|
125
|
+
bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
126
|
+
}
|
|
127
|
+
return bytes;
|
|
128
|
+
}
|
|
129
|
+
function hexToBytes(hex) {
|
|
130
|
+
const cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
131
|
+
const bytes = new Uint8Array(cleanHex.length / 2);
|
|
132
|
+
for (let i = 0; i < cleanHex.length; i += 2) {
|
|
133
|
+
bytes[i / 2] = parseInt(cleanHex.substr(i, 2), 16);
|
|
134
|
+
}
|
|
135
|
+
return bytes;
|
|
136
|
+
}
|
|
137
|
+
function bytesToHex(bytes, prefix = false) {
|
|
138
|
+
const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
139
|
+
return prefix ? `0x${hex}` : hex;
|
|
140
|
+
}
|
|
141
|
+
function randomBytes(length) {
|
|
142
|
+
const bytes = new Uint8Array(length);
|
|
143
|
+
const g = globalThis;
|
|
144
|
+
try {
|
|
145
|
+
const cryptoObj = g?.crypto || g?.window?.crypto || g?.self?.crypto;
|
|
146
|
+
if (cryptoObj && typeof cryptoObj.getRandomValues === "function") {
|
|
147
|
+
cryptoObj.getRandomValues(bytes);
|
|
148
|
+
return bytes;
|
|
149
|
+
}
|
|
150
|
+
} catch {
|
|
151
|
+
}
|
|
152
|
+
try {
|
|
153
|
+
const nodeCrypto = __require("crypto");
|
|
154
|
+
if (nodeCrypto?.randomBytes) {
|
|
155
|
+
const buffer = nodeCrypto.randomBytes(length);
|
|
156
|
+
bytes.set(buffer);
|
|
157
|
+
return bytes;
|
|
158
|
+
}
|
|
159
|
+
if (nodeCrypto?.webcrypto?.getRandomValues) {
|
|
160
|
+
nodeCrypto.webcrypto.getRandomValues(bytes);
|
|
161
|
+
return bytes;
|
|
162
|
+
}
|
|
163
|
+
} catch {
|
|
164
|
+
}
|
|
165
|
+
for (let i = 0; i < length; i++) bytes[i] = Math.floor(Math.random() * 256);
|
|
166
|
+
return bytes;
|
|
167
|
+
}
|
|
168
|
+
function isValidHex(hex, expectedLength) {
|
|
169
|
+
const cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
170
|
+
if (!/^[0-9a-f]*$/i.test(cleanHex)) {
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
if (cleanHex.length % 2 !== 0) {
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
if (expectedLength !== void 0) {
|
|
177
|
+
return cleanHex.length === expectedLength * 2;
|
|
178
|
+
}
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
var BN254_MODULUS = BigInt("0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47");
|
|
182
|
+
function proofToBytes(proof) {
|
|
183
|
+
const pi_a_x = BigInt(proof.pi_a[0]);
|
|
184
|
+
const pi_a_y = BigInt(proof.pi_a[1]);
|
|
185
|
+
const pi_a_y_neg = (BN254_MODULUS - pi_a_y) % BN254_MODULUS;
|
|
186
|
+
const pi_a_x_le = bigintToBytes32LE(pi_a_x);
|
|
187
|
+
const pi_a_y_neg_le = bigintToBytes32LE(pi_a_y_neg);
|
|
188
|
+
const pi_a_le = new Uint8Array(64);
|
|
189
|
+
pi_a_le.set(pi_a_x_le, 0);
|
|
190
|
+
pi_a_le.set(pi_a_y_neg_le, 32);
|
|
191
|
+
const pi_a_be = convertEndianness32(pi_a_le);
|
|
192
|
+
const pi_b_x1 = BigInt(proof.pi_b[0][0]);
|
|
193
|
+
const pi_b_x2 = BigInt(proof.pi_b[0][1]);
|
|
194
|
+
const pi_b_y1 = BigInt(proof.pi_b[1][0]);
|
|
195
|
+
const pi_b_y2 = BigInt(proof.pi_b[1][1]);
|
|
196
|
+
const pi_b_x1_le = bigintToBytes32LE(pi_b_x1);
|
|
197
|
+
const pi_b_x2_le = bigintToBytes32LE(pi_b_x2);
|
|
198
|
+
const pi_b_y1_le = bigintToBytes32LE(pi_b_y1);
|
|
199
|
+
const pi_b_y2_le = bigintToBytes32LE(pi_b_y2);
|
|
200
|
+
const pi_b_le = new Uint8Array(128);
|
|
201
|
+
pi_b_le.set(pi_b_x1_le, 0);
|
|
202
|
+
pi_b_le.set(pi_b_x2_le, 32);
|
|
203
|
+
pi_b_le.set(pi_b_y1_le, 64);
|
|
204
|
+
pi_b_le.set(pi_b_y2_le, 96);
|
|
205
|
+
const pi_b_be = convertEndianness64(pi_b_le);
|
|
206
|
+
const pi_c_x = BigInt(proof.pi_c[0]);
|
|
207
|
+
const pi_c_y = BigInt(proof.pi_c[1]);
|
|
208
|
+
const pi_c_x_le = bigintToBytes32LE(pi_c_x);
|
|
209
|
+
const pi_c_y_le = bigintToBytes32LE(pi_c_y);
|
|
210
|
+
const pi_c_le = new Uint8Array(64);
|
|
211
|
+
pi_c_le.set(pi_c_x_le, 0);
|
|
212
|
+
pi_c_le.set(pi_c_y_le, 32);
|
|
213
|
+
const pi_c_be = convertEndianness32(pi_c_le);
|
|
214
|
+
const result = new Uint8Array(256);
|
|
215
|
+
result.set(pi_a_be, 0);
|
|
216
|
+
result.set(pi_b_be, 64);
|
|
217
|
+
result.set(pi_c_be, 192);
|
|
218
|
+
return result;
|
|
219
|
+
}
|
|
220
|
+
function bigintToBytes32LE(n) {
|
|
221
|
+
const bytes = new Uint8Array(32);
|
|
222
|
+
let value = n % BN254_MODULUS;
|
|
223
|
+
if (value < 0) {
|
|
224
|
+
value = (value + BN254_MODULUS) % BN254_MODULUS;
|
|
225
|
+
}
|
|
226
|
+
for (let i = 0; i < 32; i++) {
|
|
227
|
+
bytes[i] = Number(value & BigInt(255));
|
|
228
|
+
value = value >> BigInt(8);
|
|
229
|
+
}
|
|
230
|
+
return bytes;
|
|
231
|
+
}
|
|
232
|
+
function convertEndianness32(bytes) {
|
|
233
|
+
if (bytes.length !== 64) {
|
|
234
|
+
throw new Error("convertEndianness32 expects 64 bytes");
|
|
235
|
+
}
|
|
236
|
+
const result = new Uint8Array(64);
|
|
237
|
+
for (let i = 0; i < 32; i++) {
|
|
238
|
+
result[i] = bytes[31 - i];
|
|
239
|
+
}
|
|
240
|
+
for (let i = 0; i < 32; i++) {
|
|
241
|
+
result[32 + i] = bytes[63 - i];
|
|
242
|
+
}
|
|
243
|
+
return result;
|
|
244
|
+
}
|
|
245
|
+
function convertEndianness64(bytes) {
|
|
246
|
+
if (bytes.length !== 128) {
|
|
247
|
+
throw new Error("convertEndianness64 expects 128 bytes");
|
|
248
|
+
}
|
|
249
|
+
const result = new Uint8Array(128);
|
|
250
|
+
for (let i = 0; i < 64; i++) {
|
|
251
|
+
result[i] = bytes[63 - i];
|
|
252
|
+
}
|
|
253
|
+
for (let i = 0; i < 64; i++) {
|
|
254
|
+
result[64 + i] = bytes[127 - i];
|
|
255
|
+
}
|
|
256
|
+
return result;
|
|
257
|
+
}
|
|
258
|
+
function buildPublicInputsBytes(root, nullifier, outputsHash, publicAmount) {
|
|
259
|
+
const result = new Uint8Array(104);
|
|
260
|
+
result.set(bigintToBytes32(root), 0);
|
|
261
|
+
result.set(bigintToBytes32(nullifier), 32);
|
|
262
|
+
result.set(bigintToBytes32(outputsHash), 64);
|
|
263
|
+
const amountBytes = new Uint8Array(8);
|
|
264
|
+
let amt = publicAmount;
|
|
265
|
+
for (let i = 7; i >= 0; i--) {
|
|
266
|
+
amountBytes[i] = Number(amt & 0xffn);
|
|
267
|
+
amt = amt >> 8n;
|
|
268
|
+
}
|
|
269
|
+
result.set(amountBytes, 96);
|
|
270
|
+
return result;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// src/utils/onchain-proof.ts
|
|
274
|
+
var MERKLE_TREE_HEIGHT = 32;
|
|
275
|
+
var SUBTREES_OFFSET = 40;
|
|
276
|
+
var ROOT_OFFSET = 40 + MERKLE_TREE_HEIGHT * 32;
|
|
277
|
+
var POSEIDON_ZERO_VALUES = [
|
|
278
|
+
"0000000000000000000000000000000000000000000000000000000000000000"
|
|
279
|
+
// level 0
|
|
280
|
+
];
|
|
281
|
+
var zeroValuesComputed = false;
|
|
282
|
+
async function ensureZeroValues() {
|
|
283
|
+
if (zeroValuesComputed) return;
|
|
284
|
+
for (let i = 1; i <= MERKLE_TREE_HEIGHT; i++) {
|
|
285
|
+
const prevZeroHex = POSEIDON_ZERO_VALUES[i - 1];
|
|
286
|
+
const prevZeroBigInt = BigInt("0x" + prevZeroHex);
|
|
287
|
+
const hash = await poseidonHash([prevZeroBigInt, prevZeroBigInt]);
|
|
288
|
+
POSEIDON_ZERO_VALUES[i] = hash.toString(16).padStart(64, "0");
|
|
289
|
+
}
|
|
290
|
+
zeroValuesComputed = true;
|
|
291
|
+
}
|
|
292
|
+
async function readMerkleTreeState(connection, merkleTreePDA) {
|
|
293
|
+
const accountInfo = await connection.getAccountInfo(merkleTreePDA);
|
|
294
|
+
if (!accountInfo) {
|
|
295
|
+
throw new Error("Merkle tree account not found");
|
|
296
|
+
}
|
|
297
|
+
const data = accountInfo.data;
|
|
298
|
+
const nextIndex = Number(data.readBigUInt64LE(32));
|
|
299
|
+
const subtrees = [];
|
|
300
|
+
for (let i = 0; i < MERKLE_TREE_HEIGHT; i++) {
|
|
301
|
+
const offset = SUBTREES_OFFSET + i * 32;
|
|
302
|
+
const subtree = data.slice(offset, offset + 32);
|
|
303
|
+
subtrees.push(Buffer.from(subtree).toString("hex"));
|
|
304
|
+
}
|
|
305
|
+
const root = Buffer.from(data.slice(ROOT_OFFSET, ROOT_OFFSET + 32)).toString("hex");
|
|
306
|
+
return { nextIndex, root, subtrees };
|
|
307
|
+
}
|
|
308
|
+
async function computeProofFromChain(connection, merkleTreePDA, leafIndex) {
|
|
309
|
+
await ensureZeroValues();
|
|
310
|
+
const { nextIndex, root, subtrees } = await readMerkleTreeState(connection, merkleTreePDA);
|
|
311
|
+
if (leafIndex >= nextIndex) {
|
|
312
|
+
throw new Error(`Leaf index ${leafIndex} is beyond next_index ${nextIndex}`);
|
|
313
|
+
}
|
|
314
|
+
const pathElements = [];
|
|
315
|
+
const pathIndices = [];
|
|
316
|
+
let index = leafIndex;
|
|
317
|
+
for (let level = 0; level < MERKLE_TREE_HEIGHT; level++) {
|
|
318
|
+
pathIndices.push(index % 2);
|
|
319
|
+
if (index % 2 === 0) {
|
|
320
|
+
const siblingIndex = index + 1;
|
|
321
|
+
const levelNextIndex = Math.ceil(nextIndex / (1 << level));
|
|
322
|
+
if (siblingIndex >= levelNextIndex) {
|
|
323
|
+
pathElements.push(POSEIDON_ZERO_VALUES[level]);
|
|
324
|
+
} else {
|
|
325
|
+
pathElements.push(POSEIDON_ZERO_VALUES[level]);
|
|
326
|
+
}
|
|
327
|
+
} else {
|
|
328
|
+
pathElements.push(subtrees[level]);
|
|
329
|
+
}
|
|
330
|
+
index = Math.floor(index / 2);
|
|
331
|
+
}
|
|
332
|
+
return { pathElements, pathIndices, root };
|
|
333
|
+
}
|
|
334
|
+
async function computeProofForLatestDeposit(connection, merkleTreePDA) {
|
|
335
|
+
await ensureZeroValues();
|
|
336
|
+
const { nextIndex, root, subtrees } = await readMerkleTreeState(connection, merkleTreePDA);
|
|
337
|
+
if (nextIndex === 0) {
|
|
338
|
+
throw new Error("No leaves in tree");
|
|
339
|
+
}
|
|
340
|
+
const leafIndex = nextIndex - 1;
|
|
341
|
+
const proof = await computeProofInternal(leafIndex, nextIndex, subtrees);
|
|
342
|
+
return { ...proof, root, leafIndex };
|
|
343
|
+
}
|
|
344
|
+
async function computeProofInternal(leafIndex, _nextIndex, subtrees) {
|
|
345
|
+
const pathElements = [];
|
|
346
|
+
const pathIndices = [];
|
|
347
|
+
let index = leafIndex;
|
|
348
|
+
for (let level = 0; level < MERKLE_TREE_HEIGHT; level++) {
|
|
349
|
+
pathIndices.push(index % 2);
|
|
350
|
+
if (index % 2 === 0) {
|
|
351
|
+
pathElements.push(POSEIDON_ZERO_VALUES[level]);
|
|
352
|
+
} else {
|
|
353
|
+
pathElements.push(subtrees[level]);
|
|
354
|
+
}
|
|
355
|
+
index = Math.floor(index / 2);
|
|
356
|
+
}
|
|
357
|
+
return { pathElements, pathIndices };
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
export {
|
|
361
|
+
__require,
|
|
362
|
+
poseidonHash,
|
|
363
|
+
splitTo2Limbs,
|
|
364
|
+
pubkeyToLimbs,
|
|
365
|
+
computeMerkleRoot,
|
|
366
|
+
hexToBigint,
|
|
367
|
+
computeCommitment,
|
|
368
|
+
generateCommitmentAsync,
|
|
369
|
+
generateCommitment,
|
|
370
|
+
computeNullifier,
|
|
371
|
+
computeNullifierAsync,
|
|
372
|
+
computeNullifierSync,
|
|
373
|
+
computeOutputsHashAsync,
|
|
374
|
+
computeOutputsHash,
|
|
375
|
+
computeOutputsHashSync,
|
|
376
|
+
computeSwapOutputsHash,
|
|
377
|
+
computeSwapOutputsHashAsync,
|
|
378
|
+
computeSwapOutputsHashSync,
|
|
379
|
+
bigintToBytes32,
|
|
380
|
+
hexToBytes,
|
|
381
|
+
bytesToHex,
|
|
382
|
+
randomBytes,
|
|
383
|
+
isValidHex,
|
|
384
|
+
proofToBytes,
|
|
385
|
+
buildPublicInputsBytes,
|
|
386
|
+
readMerkleTreeState,
|
|
387
|
+
computeProofFromChain,
|
|
388
|
+
computeProofForLatestDeposit
|
|
389
|
+
};
|