@silvana-one/mina-utils 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +1 -0
- package/dist/node/config.d.ts +4 -0
- package/dist/node/config.js +5 -0
- package/dist/node/config.js.map +1 -0
- package/dist/node/index.cjs +1325 -0
- package/dist/node/index.d.ts +6 -0
- package/dist/node/index.js +7 -0
- package/dist/node/index.js.map +1 -0
- package/dist/node/networks.d.ts +32 -0
- package/dist/node/networks.js +81 -0
- package/dist/node/networks.js.map +1 -0
- package/dist/node/storage/index.d.ts +2 -0
- package/dist/node/storage/index.js +3 -0
- package/dist/node/storage/index.js.map +1 -0
- package/dist/node/storage/ipfs.d.ts +5 -0
- package/dist/node/storage/ipfs.js +16 -0
- package/dist/node/storage/ipfs.js.map +1 -0
- package/dist/node/storage/pinata.d.ts +6 -0
- package/dist/node/storage/pinata.js +40 -0
- package/dist/node/storage/pinata.js.map +1 -0
- package/dist/node/transactions/account.d.ts +4 -0
- package/dist/node/transactions/account.js +44 -0
- package/dist/node/transactions/account.js.map +1 -0
- package/dist/node/transactions/blockberry.d.ts +21 -0
- package/dist/node/transactions/blockberry.js +130 -0
- package/dist/node/transactions/blockberry.js.map +1 -0
- package/dist/node/transactions/chain.d.ts +1 -0
- package/dist/node/transactions/chain.js +2 -0
- package/dist/node/transactions/chain.js.map +1 -0
- package/dist/node/transactions/index.d.ts +8 -0
- package/dist/node/transactions/index.js +9 -0
- package/dist/node/transactions/index.js.map +1 -0
- package/dist/node/transactions/nonce.d.ts +17 -0
- package/dist/node/transactions/nonce.js +91 -0
- package/dist/node/transactions/nonce.js.map +1 -0
- package/dist/node/transactions/send.d.ts +31 -0
- package/dist/node/transactions/send.js +154 -0
- package/dist/node/transactions/send.js.map +1 -0
- package/dist/node/transactions/tiny-contract.d.ts +5 -0
- package/dist/node/transactions/tiny-contract.js +22 -0
- package/dist/node/transactions/tiny-contract.js.map +1 -0
- package/dist/node/transactions/transaction.d.ts +21 -0
- package/dist/node/transactions/transaction.js +222 -0
- package/dist/node/transactions/transaction.js.map +1 -0
- package/dist/node/transactions/txstatus.d.ts +8 -0
- package/dist/node/transactions/txstatus.js +16 -0
- package/dist/node/transactions/txstatus.js.map +1 -0
- package/dist/node/utils/base64-field.d.ts +5 -0
- package/dist/node/utils/base64-field.js +29 -0
- package/dist/node/utils/base64-field.js.map +1 -0
- package/dist/node/utils/base64.d.ts +6 -0
- package/dist/node/utils/base64.js +83 -0
- package/dist/node/utils/base64.js.map +1 -0
- package/dist/node/utils/fee.d.ts +6 -0
- package/dist/node/utils/fee.js +11 -0
- package/dist/node/utils/fee.js.map +1 -0
- package/dist/node/utils/fetch.d.ts +44 -0
- package/dist/node/utils/fetch.js +101 -0
- package/dist/node/utils/fetch.js.map +1 -0
- package/dist/node/utils/fields.d.ts +13 -0
- package/dist/node/utils/fields.js +39 -0
- package/dist/node/utils/fields.js.map +1 -0
- package/dist/node/utils/index.d.ts +8 -0
- package/dist/node/utils/index.js +9 -0
- package/dist/node/utils/index.js.map +1 -0
- package/dist/node/utils/indexed-map.d.ts +32 -0
- package/dist/node/utils/indexed-map.js +124 -0
- package/dist/node/utils/indexed-map.js.map +1 -0
- package/dist/node/utils/mina.d.ts +39 -0
- package/dist/node/utils/mina.js +123 -0
- package/dist/node/utils/mina.js.map +1 -0
- package/dist/node/utils/utils.d.ts +8 -0
- package/dist/node/utils/utils.js +61 -0
- package/dist/node/utils/utils.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/tsconfig.web.tsbuildinfo +1 -0
- package/dist/web/config.d.ts +4 -0
- package/dist/web/config.js +5 -0
- package/dist/web/config.js.map +1 -0
- package/dist/web/index.d.ts +6 -0
- package/dist/web/index.js +7 -0
- package/dist/web/index.js.map +1 -0
- package/dist/web/networks.d.ts +32 -0
- package/dist/web/networks.js +81 -0
- package/dist/web/networks.js.map +1 -0
- package/dist/web/storage/index.d.ts +2 -0
- package/dist/web/storage/index.js +3 -0
- package/dist/web/storage/index.js.map +1 -0
- package/dist/web/storage/ipfs.d.ts +5 -0
- package/dist/web/storage/ipfs.js +16 -0
- package/dist/web/storage/ipfs.js.map +1 -0
- package/dist/web/storage/pinata.d.ts +6 -0
- package/dist/web/storage/pinata.js +40 -0
- package/dist/web/storage/pinata.js.map +1 -0
- package/dist/web/transactions/account.d.ts +4 -0
- package/dist/web/transactions/account.js +44 -0
- package/dist/web/transactions/account.js.map +1 -0
- package/dist/web/transactions/blockberry.d.ts +21 -0
- package/dist/web/transactions/blockberry.js +130 -0
- package/dist/web/transactions/blockberry.js.map +1 -0
- package/dist/web/transactions/chain.d.ts +1 -0
- package/dist/web/transactions/chain.js +2 -0
- package/dist/web/transactions/chain.js.map +1 -0
- package/dist/web/transactions/index.d.ts +8 -0
- package/dist/web/transactions/index.js +9 -0
- package/dist/web/transactions/index.js.map +1 -0
- package/dist/web/transactions/nonce.d.ts +17 -0
- package/dist/web/transactions/nonce.js +91 -0
- package/dist/web/transactions/nonce.js.map +1 -0
- package/dist/web/transactions/send.d.ts +31 -0
- package/dist/web/transactions/send.js +154 -0
- package/dist/web/transactions/send.js.map +1 -0
- package/dist/web/transactions/tiny-contract.d.ts +5 -0
- package/dist/web/transactions/tiny-contract.js +22 -0
- package/dist/web/transactions/tiny-contract.js.map +1 -0
- package/dist/web/transactions/transaction.d.ts +21 -0
- package/dist/web/transactions/transaction.js +222 -0
- package/dist/web/transactions/transaction.js.map +1 -0
- package/dist/web/transactions/txstatus.d.ts +8 -0
- package/dist/web/transactions/txstatus.js +16 -0
- package/dist/web/transactions/txstatus.js.map +1 -0
- package/dist/web/utils/base64-field.d.ts +5 -0
- package/dist/web/utils/base64-field.js +29 -0
- package/dist/web/utils/base64-field.js.map +1 -0
- package/dist/web/utils/base64.d.ts +6 -0
- package/dist/web/utils/base64.js +83 -0
- package/dist/web/utils/base64.js.map +1 -0
- package/dist/web/utils/fee.d.ts +6 -0
- package/dist/web/utils/fee.js +11 -0
- package/dist/web/utils/fee.js.map +1 -0
- package/dist/web/utils/fetch.d.ts +44 -0
- package/dist/web/utils/fetch.js +101 -0
- package/dist/web/utils/fetch.js.map +1 -0
- package/dist/web/utils/fields.d.ts +13 -0
- package/dist/web/utils/fields.js +39 -0
- package/dist/web/utils/fields.js.map +1 -0
- package/dist/web/utils/index.d.ts +8 -0
- package/dist/web/utils/index.js +9 -0
- package/dist/web/utils/index.js.map +1 -0
- package/dist/web/utils/indexed-map.d.ts +32 -0
- package/dist/web/utils/indexed-map.js +124 -0
- package/dist/web/utils/indexed-map.js.map +1 -0
- package/dist/web/utils/mina.d.ts +39 -0
- package/dist/web/utils/mina.js +123 -0
- package/dist/web/utils/mina.js.map +1 -0
- package/dist/web/utils/utils.d.ts +8 -0
- package/dist/web/utils/utils.js +61 -0
- package/dist/web/utils/utils.js.map +1 -0
- package/package.json +62 -0
- package/src/config.ts +5 -0
- package/src/index.ts +6 -0
- package/src/networks.ts +130 -0
- package/src/storage/index.ts +2 -0
- package/src/storage/ipfs.ts +20 -0
- package/src/storage/pinata.ts +56 -0
- package/src/transactions/account.ts +57 -0
- package/src/transactions/blockberry.ts +198 -0
- package/src/transactions/chain.ts +1 -0
- package/src/transactions/index.ts +8 -0
- package/src/transactions/nonce.ts +121 -0
- package/src/transactions/send.ts +228 -0
- package/src/transactions/tiny-contract.ts +9 -0
- package/src/transactions/transaction.ts +319 -0
- package/src/transactions/txstatus.ts +26 -0
- package/src/utils/base64-field.ts +34 -0
- package/src/utils/base64.ts +87 -0
- package/src/utils/fee.ts +11 -0
- package/src/utils/fetch.ts +130 -0
- package/src/utils/fields.ts +39 -0
- package/src/utils/index.ts +8 -0
- package/src/utils/indexed-map.ts +170 -0
- package/src/utils/mina.ts +171 -0
- package/src/utils/utils.ts +79 -0
package/src/utils/fee.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { UInt64 } from "o1js";
|
|
2
|
+
import config from "../config.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Calculate the fee for a transaction
|
|
6
|
+
* @returns the fee for a transaction
|
|
7
|
+
*/
|
|
8
|
+
export async function fee(): Promise<UInt64> {
|
|
9
|
+
//TODO: update after mainnet launch and resolution of the issue https://github.com/o1-labs/o1js/issues/1626
|
|
10
|
+
return UInt64.fromJSON(config.MINAFEE);
|
|
11
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PublicKey,
|
|
3
|
+
Field,
|
|
4
|
+
Mina,
|
|
5
|
+
fetchAccount,
|
|
6
|
+
checkZkappTransaction,
|
|
7
|
+
} from "o1js";
|
|
8
|
+
import { sleep } from "./utils.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Fetches the Mina account for a given public key with error handling
|
|
12
|
+
* @param params the parameters for fetching the account
|
|
13
|
+
* @param params.publicKey the public key of the account
|
|
14
|
+
* @param params.tokenId the token id of the account
|
|
15
|
+
* @param params.force whether to force the fetch - use it only if you are sure the account exists
|
|
16
|
+
* @returns the account object
|
|
17
|
+
*/
|
|
18
|
+
export async function fetchMinaAccount(params: {
|
|
19
|
+
publicKey: string | PublicKey;
|
|
20
|
+
tokenId?: string | Field | undefined;
|
|
21
|
+
force?: boolean;
|
|
22
|
+
}) {
|
|
23
|
+
const { publicKey, tokenId, force = false } = params;
|
|
24
|
+
const timeout = 1000 * 60 * 3; // 3 minutes
|
|
25
|
+
let attempt = 0;
|
|
26
|
+
const startTime = Date.now();
|
|
27
|
+
let result = { account: undefined };
|
|
28
|
+
while (Date.now() - startTime < timeout) {
|
|
29
|
+
try {
|
|
30
|
+
const result = await fetchAccount(
|
|
31
|
+
{
|
|
32
|
+
publicKey,
|
|
33
|
+
tokenId,
|
|
34
|
+
},
|
|
35
|
+
undefined,
|
|
36
|
+
{ timeout: 5 * 1000 }
|
|
37
|
+
);
|
|
38
|
+
return result;
|
|
39
|
+
} catch (error: any) {
|
|
40
|
+
if (force === true)
|
|
41
|
+
console.log("Error in fetchMinaAccount:", {
|
|
42
|
+
error,
|
|
43
|
+
publicKey:
|
|
44
|
+
typeof publicKey === "string" ? publicKey : publicKey.toBase58(),
|
|
45
|
+
tokenId: tokenId?.toString(),
|
|
46
|
+
force,
|
|
47
|
+
});
|
|
48
|
+
else {
|
|
49
|
+
console.log("fetchMinaAccount error", {
|
|
50
|
+
error,
|
|
51
|
+
publicKey:
|
|
52
|
+
typeof publicKey === "string" ? publicKey : publicKey.toBase58(),
|
|
53
|
+
tokenId: tokenId?.toString(),
|
|
54
|
+
force,
|
|
55
|
+
});
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
attempt++;
|
|
60
|
+
await sleep(1000 * 6 * attempt); // to handle rate limit we increase the interval
|
|
61
|
+
}
|
|
62
|
+
if (force === true)
|
|
63
|
+
throw new Error(
|
|
64
|
+
`fetchMinaAccount timeout
|
|
65
|
+
${{
|
|
66
|
+
publicKey:
|
|
67
|
+
typeof publicKey === "string" ? publicKey : publicKey.toBase58(),
|
|
68
|
+
tokenId: tokenId?.toString(),
|
|
69
|
+
force,
|
|
70
|
+
}}`
|
|
71
|
+
);
|
|
72
|
+
else
|
|
73
|
+
console.log(
|
|
74
|
+
"fetchMinaAccount timeout",
|
|
75
|
+
typeof publicKey === "string" ? publicKey : publicKey.toBase58(),
|
|
76
|
+
tokenId?.toString(),
|
|
77
|
+
force
|
|
78
|
+
);
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Fetches the Mina actions for a given public key with error handling
|
|
84
|
+
* @param publicKey the public key of the contract
|
|
85
|
+
* @param fromActionState the starting action state
|
|
86
|
+
* @param endActionState the ending action state
|
|
87
|
+
* @returns the actions array
|
|
88
|
+
*/
|
|
89
|
+
|
|
90
|
+
export async function fetchMinaActions(
|
|
91
|
+
publicKey: PublicKey,
|
|
92
|
+
fromActionState: Field,
|
|
93
|
+
endActionState?: Field
|
|
94
|
+
) {
|
|
95
|
+
const timeout = 1000 * 60 * 600; // 10 hours
|
|
96
|
+
const startTime = Date.now();
|
|
97
|
+
while (Date.now() - startTime < timeout) {
|
|
98
|
+
try {
|
|
99
|
+
let actions = await Mina.fetchActions(publicKey, {
|
|
100
|
+
fromActionState,
|
|
101
|
+
endActionState,
|
|
102
|
+
});
|
|
103
|
+
if (Array.isArray(actions)) return actions;
|
|
104
|
+
else console.log("Cannot fetch actions - wrong format");
|
|
105
|
+
} catch (error: any) {
|
|
106
|
+
console.log(
|
|
107
|
+
"Error in fetchMinaActions",
|
|
108
|
+
error.toString().substring(0, 300)
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
await sleep(1000 * 60 * 2);
|
|
112
|
+
}
|
|
113
|
+
console.log("Timeout in fetchMinaActions");
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Fetches the Mina transaction for a given hash with error handling
|
|
119
|
+
* @param hash the hash of the transaction
|
|
120
|
+
* @returns the transaction object
|
|
121
|
+
*/
|
|
122
|
+
export async function checkMinaZkappTransaction(hash: string) {
|
|
123
|
+
try {
|
|
124
|
+
const result = await checkZkappTransaction(hash);
|
|
125
|
+
return result;
|
|
126
|
+
} catch (error) {
|
|
127
|
+
console.error("Error in checkZkappTransaction:", error);
|
|
128
|
+
return { success: false };
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Field, Poseidon } from "o1js";
|
|
2
|
+
import { fieldToBase64, fieldFromBase64 } from "./base64-field.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Serialize fields to a string using base64 URL-friendly encoding
|
|
6
|
+
* @param fields the fields array to serialize
|
|
7
|
+
* @returns the serialized string
|
|
8
|
+
*/
|
|
9
|
+
export function serializeFields(fields: Field[]): string {
|
|
10
|
+
const hash = Poseidon.hash(fields);
|
|
11
|
+
const value = [Field(fields.length), hash, ...fields];
|
|
12
|
+
//return value.map((f) => f.toBigInt().toString(36)).join(".");
|
|
13
|
+
return value.map((f) => fieldToBase64(f)).join(".");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Deserialize fields from a string using base64 URL-friendly encoding
|
|
18
|
+
* @param s the string to deserialize
|
|
19
|
+
* @returns the deserialized fields array
|
|
20
|
+
*/
|
|
21
|
+
export function deserializeFields(s: string): Field[] {
|
|
22
|
+
try {
|
|
23
|
+
//const value = s.split(".").map((n) => Field(BigInt(convert(n, 36))));
|
|
24
|
+
const value = s.split(".").map((n) => fieldFromBase64(n));
|
|
25
|
+
const length = value[0];
|
|
26
|
+
if (
|
|
27
|
+
Field(value.length - 2)
|
|
28
|
+
.equals(length)
|
|
29
|
+
.toBoolean() === false
|
|
30
|
+
)
|
|
31
|
+
throw new Error("deserializeFields: invalid length");
|
|
32
|
+
const hash = Poseidon.hash(value.slice(2));
|
|
33
|
+
if (hash.equals(value[1]).toBoolean()) {
|
|
34
|
+
return value.slice(2);
|
|
35
|
+
} else throw new Error("deserializeFields: invalid hash: data mismatch");
|
|
36
|
+
} catch (e: any) {
|
|
37
|
+
throw new Error(`deserializeFields: invalid string: ${s}: ${e}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { Experimental, Field } from "o1js";
|
|
2
|
+
import { bigintToBase64, bigintFromBase64 } from "./base64.js";
|
|
3
|
+
import { sleep } from "./utils.js";
|
|
4
|
+
import { pinJSON } from "../storage/pinata.js";
|
|
5
|
+
|
|
6
|
+
const { IndexedMerkleMap } = Experimental;
|
|
7
|
+
type IndexedMerkleMap = Experimental.IndexedMerkleMap;
|
|
8
|
+
|
|
9
|
+
export interface IndexedMapSerialized {
|
|
10
|
+
height: number;
|
|
11
|
+
root: string;
|
|
12
|
+
length: string;
|
|
13
|
+
nodes: string;
|
|
14
|
+
sortedLeaves: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function loadIndexedMerkleMap(params: {
|
|
18
|
+
url: string;
|
|
19
|
+
type: ReturnType<typeof IndexedMerkleMap>;
|
|
20
|
+
timeout?: number;
|
|
21
|
+
attempts?: number;
|
|
22
|
+
}) {
|
|
23
|
+
const { url, type, timeout = 60000, attempts = 5 } = params;
|
|
24
|
+
let attempt = 0;
|
|
25
|
+
const start = Date.now();
|
|
26
|
+
let response = await fetch(url);
|
|
27
|
+
while (!response.ok && attempt < attempts && Date.now() - start < timeout) {
|
|
28
|
+
attempt++;
|
|
29
|
+
await sleep(5000 * attempt); // handle rate limiting
|
|
30
|
+
response = await fetch(url);
|
|
31
|
+
}
|
|
32
|
+
if (!response.ok) {
|
|
33
|
+
throw new Error("Failed to fetch IndexedMerkleMap");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const json = await response.json();
|
|
37
|
+
const serializedIndexedMap = (
|
|
38
|
+
json as unknown as { map: IndexedMapSerialized }
|
|
39
|
+
).map;
|
|
40
|
+
if (!serializedIndexedMap)
|
|
41
|
+
throw new Error("wrong IndexedMerkleMap json format");
|
|
42
|
+
const map = deserializeIndexedMerkleMapInternal({
|
|
43
|
+
serializedIndexedMap,
|
|
44
|
+
type,
|
|
45
|
+
});
|
|
46
|
+
if (!map) {
|
|
47
|
+
throw new Error("Failed to deserialize whitelist");
|
|
48
|
+
}
|
|
49
|
+
return map;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export async function saveIndexedMerkleMap(params: {
|
|
53
|
+
map: IndexedMerkleMap;
|
|
54
|
+
name?: string;
|
|
55
|
+
keyvalues?: { key: string; value: string }[];
|
|
56
|
+
auth: string;
|
|
57
|
+
}): Promise<string | undefined> {
|
|
58
|
+
const { map, name = "indexed-map", keyvalues, auth } = params;
|
|
59
|
+
const serialized = serializeIndexedMap(map);
|
|
60
|
+
const ipfsHash = await pinJSON({
|
|
61
|
+
data: { map: serialized },
|
|
62
|
+
name,
|
|
63
|
+
keyvalues,
|
|
64
|
+
auth,
|
|
65
|
+
});
|
|
66
|
+
return ipfsHash;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function serializeIndexedMap(
|
|
70
|
+
map: IndexedMerkleMap
|
|
71
|
+
): IndexedMapSerialized {
|
|
72
|
+
return {
|
|
73
|
+
height: map.height,
|
|
74
|
+
root: map.root.toJSON(),
|
|
75
|
+
length: map.length.toJSON(),
|
|
76
|
+
nodes: JSON.stringify(map.data.get().nodes, (_, v) =>
|
|
77
|
+
typeof v === "bigint" ? "n" + bigintToBase64(v) : v
|
|
78
|
+
),
|
|
79
|
+
sortedLeaves: JSON.stringify(
|
|
80
|
+
map.data
|
|
81
|
+
.get()
|
|
82
|
+
.sortedLeaves.map((v) => [
|
|
83
|
+
bigintToBase64(v.key),
|
|
84
|
+
bigintToBase64(v.nextKey),
|
|
85
|
+
bigintToBase64(v.value),
|
|
86
|
+
bigintToBase64(BigInt(v.index)),
|
|
87
|
+
])
|
|
88
|
+
),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function deserializeIndexedMerkleMap(params: {
|
|
93
|
+
serializedIndexedMap: IndexedMapSerialized;
|
|
94
|
+
type?: ReturnType<typeof IndexedMerkleMap>;
|
|
95
|
+
}): InstanceType<ReturnType<typeof IndexedMerkleMap>> | undefined {
|
|
96
|
+
try {
|
|
97
|
+
const { serializedIndexedMap, type } = params;
|
|
98
|
+
return deserializeIndexedMerkleMapInternal({
|
|
99
|
+
serializedIndexedMap,
|
|
100
|
+
type: type ?? IndexedMerkleMap(serializedIndexedMap.height),
|
|
101
|
+
});
|
|
102
|
+
} catch (error: any) {
|
|
103
|
+
console.error("Error deserializing map:", error?.message ?? error);
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function parseIndexedMapSerialized(
|
|
109
|
+
serializedMap: string
|
|
110
|
+
): IndexedMapSerialized {
|
|
111
|
+
const json = JSON.parse(serializedMap);
|
|
112
|
+
if (
|
|
113
|
+
json.height === undefined ||
|
|
114
|
+
json.root === undefined ||
|
|
115
|
+
json.length === undefined ||
|
|
116
|
+
json.nodes === undefined ||
|
|
117
|
+
json.sortedLeaves === undefined
|
|
118
|
+
)
|
|
119
|
+
throw new Error("wrong IndexedMerkleMap json format");
|
|
120
|
+
if (typeof json.height !== "number")
|
|
121
|
+
throw new Error("wrong IndexedMerkleMap height format");
|
|
122
|
+
if (typeof json.root !== "string")
|
|
123
|
+
throw new Error("wrong IndexedMerkleMap root format");
|
|
124
|
+
if (typeof json.length !== "string")
|
|
125
|
+
throw new Error("wrong IndexedMerkleMap length format");
|
|
126
|
+
if (typeof json.nodes !== "string")
|
|
127
|
+
throw new Error("wrong IndexedMerkleMap nodes format");
|
|
128
|
+
if (typeof json.sortedLeaves !== "string")
|
|
129
|
+
throw new Error("wrong IndexedMerkleMap sortedLeaves format");
|
|
130
|
+
return json;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function deserializeIndexedMerkleMapInternal(params: {
|
|
134
|
+
serializedIndexedMap: IndexedMapSerialized;
|
|
135
|
+
type: ReturnType<typeof IndexedMerkleMap>;
|
|
136
|
+
}): InstanceType<ReturnType<typeof IndexedMerkleMap>> {
|
|
137
|
+
const { serializedIndexedMap, type } = params;
|
|
138
|
+
const map = new type();
|
|
139
|
+
if (serializedIndexedMap.height !== map.height) {
|
|
140
|
+
throw new Error("wrong IndexedMap height");
|
|
141
|
+
}
|
|
142
|
+
const nodes = JSON.parse(serializedIndexedMap.nodes, (_, v) => {
|
|
143
|
+
// Check if the value is a string that represents a BigInt
|
|
144
|
+
if (typeof v === "string" && v[0] === "n") {
|
|
145
|
+
// Remove the first 'n' and convert the string to a BigInt
|
|
146
|
+
return bigintFromBase64(v.slice(1));
|
|
147
|
+
}
|
|
148
|
+
return v;
|
|
149
|
+
});
|
|
150
|
+
const sortedLeaves = JSON.parse(serializedIndexedMap.sortedLeaves).map(
|
|
151
|
+
(row: any) => {
|
|
152
|
+
return {
|
|
153
|
+
key: bigintFromBase64(row[0]),
|
|
154
|
+
nextKey: bigintFromBase64(row[1]),
|
|
155
|
+
value: bigintFromBase64(row[2]),
|
|
156
|
+
index: Number(bigintFromBase64(row[3])),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
map.root = Field.fromJSON(serializedIndexedMap.root);
|
|
162
|
+
map.length = Field.fromJSON(serializedIndexedMap.length);
|
|
163
|
+
map.data.updateAsProver(() => {
|
|
164
|
+
return {
|
|
165
|
+
nodes: nodes.map((row: any) => [...row]),
|
|
166
|
+
sortedLeaves: [...sortedLeaves],
|
|
167
|
+
};
|
|
168
|
+
});
|
|
169
|
+
return map;
|
|
170
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
export {
|
|
2
|
+
initBlockchain,
|
|
3
|
+
accountBalance,
|
|
4
|
+
accountBalanceMina,
|
|
5
|
+
MinaNetworkInstance,
|
|
6
|
+
currentNetwork,
|
|
7
|
+
getNetworkIdHash,
|
|
8
|
+
getCurrentNetwork,
|
|
9
|
+
getDeployer,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
Mina,
|
|
14
|
+
PublicKey,
|
|
15
|
+
PrivateKey,
|
|
16
|
+
UInt64,
|
|
17
|
+
fetchAccount,
|
|
18
|
+
Field,
|
|
19
|
+
Lightnet,
|
|
20
|
+
CircuitString,
|
|
21
|
+
} from "o1js";
|
|
22
|
+
import { networks, blockchain, MinaNetwork, Local } from "../networks.js";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* MinaNetworkInstance is the data structure for a Mina network instance, keeping track of the keys, network, and network ID hash.
|
|
26
|
+
*/
|
|
27
|
+
interface MinaNetworkInstance {
|
|
28
|
+
/** The keys for the deployers */
|
|
29
|
+
keys: Mina.TestPublicKey[];
|
|
30
|
+
|
|
31
|
+
/** The network */
|
|
32
|
+
network: MinaNetwork;
|
|
33
|
+
|
|
34
|
+
/** The network ID hash */
|
|
35
|
+
networkIdHash: Field;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let currentNetwork: MinaNetworkInstance | undefined = undefined;
|
|
39
|
+
|
|
40
|
+
function getNetworkIdHash(): Field {
|
|
41
|
+
if (currentNetwork === undefined) {
|
|
42
|
+
throw new Error("Network is not initialized");
|
|
43
|
+
}
|
|
44
|
+
return currentNetwork.networkIdHash;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function getCurrentNetwork(): MinaNetworkInstance {
|
|
48
|
+
if (currentNetwork === undefined) {
|
|
49
|
+
throw new Error("Network is not initialized");
|
|
50
|
+
}
|
|
51
|
+
return currentNetwork;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function getDeployer(): Mina.TestPublicKey | undefined {
|
|
55
|
+
if (currentNetwork === undefined) {
|
|
56
|
+
throw new Error("Network is not initialized");
|
|
57
|
+
}
|
|
58
|
+
if (currentNetwork.keys.length < 1) return undefined;
|
|
59
|
+
return currentNetwork.keys[0];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Initializes the Mina blockchain network
|
|
64
|
+
* Due to the limitations of the Mina SDK, only one network can be initialized at a time
|
|
65
|
+
* This function should be called before any other Mina functions
|
|
66
|
+
* @param instance the blockchain instance to initialize
|
|
67
|
+
* @param deployersNumber the number of deployers to use for the network (only for local and lightnet networks)
|
|
68
|
+
* @returns the Mina network instance
|
|
69
|
+
*/
|
|
70
|
+
async function initBlockchain(
|
|
71
|
+
instance: blockchain,
|
|
72
|
+
deployersNumber: number = 0,
|
|
73
|
+
proofsEnabled: boolean = true
|
|
74
|
+
): Promise<MinaNetworkInstance> {
|
|
75
|
+
/*
|
|
76
|
+
if (instance === "mainnet") {
|
|
77
|
+
throw new Error("Mainnet is not supported yet by zkApps");
|
|
78
|
+
}
|
|
79
|
+
*/
|
|
80
|
+
if (currentNetwork !== undefined) {
|
|
81
|
+
if (currentNetwork?.network.chainId === instance) {
|
|
82
|
+
return currentNetwork;
|
|
83
|
+
} else {
|
|
84
|
+
throw new Error(
|
|
85
|
+
`Network is already initialized to different chain ${currentNetwork.network.chainId}, cannot initialize to ${instance}`
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const networkIdHash = CircuitString.fromString(instance).hash();
|
|
90
|
+
|
|
91
|
+
// await used for compatibility with future versions of o1js
|
|
92
|
+
if (instance === "local") {
|
|
93
|
+
const local = await Mina.LocalBlockchain({
|
|
94
|
+
proofsEnabled,
|
|
95
|
+
});
|
|
96
|
+
Mina.setActiveInstance(local);
|
|
97
|
+
if (deployersNumber > local.testAccounts.length)
|
|
98
|
+
throw new Error("Not enough test accounts");
|
|
99
|
+
currentNetwork = {
|
|
100
|
+
keys: local.testAccounts,
|
|
101
|
+
network: Local,
|
|
102
|
+
networkIdHash,
|
|
103
|
+
};
|
|
104
|
+
return currentNetwork;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const network = networks.find((n) => n.chainId === instance);
|
|
108
|
+
if (network === undefined) {
|
|
109
|
+
throw new Error("Unknown network");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const networkInstance = Mina.Network({
|
|
113
|
+
mina: network.mina,
|
|
114
|
+
archive: network.archive,
|
|
115
|
+
lightnetAccountManager: network.accountManager,
|
|
116
|
+
networkId: instance === "mainnet" ? "mainnet" : "testnet",
|
|
117
|
+
});
|
|
118
|
+
Mina.setActiveInstance(networkInstance);
|
|
119
|
+
|
|
120
|
+
const keys: Mina.TestPublicKey[] = [];
|
|
121
|
+
|
|
122
|
+
if (deployersNumber > 0) {
|
|
123
|
+
if (instance === "lightnet") {
|
|
124
|
+
for (let i = 0; i < deployersNumber; i++) {
|
|
125
|
+
const keyPair = await Lightnet.acquireKeyPair();
|
|
126
|
+
const key = Mina.TestPublicKey(keyPair.privateKey);
|
|
127
|
+
keys.push(key);
|
|
128
|
+
}
|
|
129
|
+
} else {
|
|
130
|
+
const deployers = process.env.DEPLOYERS;
|
|
131
|
+
if (
|
|
132
|
+
deployers === undefined ||
|
|
133
|
+
Array.isArray(deployers) === false ||
|
|
134
|
+
deployers.length < deployersNumber
|
|
135
|
+
)
|
|
136
|
+
throw new Error("Deployers are not set");
|
|
137
|
+
for (let i = 0; i < deployersNumber; i++) {
|
|
138
|
+
const privateKey = PrivateKey.fromBase58(deployers[i]);
|
|
139
|
+
const key = Mina.TestPublicKey(privateKey);
|
|
140
|
+
keys.push(key);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
currentNetwork = {
|
|
146
|
+
keys,
|
|
147
|
+
network,
|
|
148
|
+
networkIdHash,
|
|
149
|
+
};
|
|
150
|
+
return currentNetwork;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Fetches the account balance for a given public key
|
|
155
|
+
* @param address the public key
|
|
156
|
+
* @returns the account balance
|
|
157
|
+
*/
|
|
158
|
+
async function accountBalance(address: PublicKey): Promise<UInt64> {
|
|
159
|
+
await fetchAccount({ publicKey: address });
|
|
160
|
+
if (Mina.hasAccount(address)) return Mina.getBalance(address);
|
|
161
|
+
else return UInt64.from(0);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Fetches the account balance for a given public key and returns it in Mina
|
|
166
|
+
* @param address the public key
|
|
167
|
+
* @returns the account balance in MINA
|
|
168
|
+
*/
|
|
169
|
+
async function accountBalanceMina(address: PublicKey): Promise<number> {
|
|
170
|
+
return Number((await accountBalance(address)).toBigInt()) / 1e9;
|
|
171
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
export function sleep(ms: number) {
|
|
2
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function makeString(length: number): string {
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-inferrable-types
|
|
7
|
+
let outString: string = ``;
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/no-inferrable-types
|
|
9
|
+
const inOptions: string = `ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`;
|
|
10
|
+
|
|
11
|
+
for (let i = 0; i < length; i++) {
|
|
12
|
+
outString += inOptions.charAt(Math.floor(Math.random() * inOptions.length));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return outString;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function formatTime(ms: number): string {
|
|
19
|
+
if (ms === undefined) return "";
|
|
20
|
+
if (ms < 1000) return ms.toString() + " ms";
|
|
21
|
+
if (ms < 60 * 1000)
|
|
22
|
+
return parseInt((ms / 1000).toString()).toString() + " sec";
|
|
23
|
+
if (ms < 60 * 60 * 1000) {
|
|
24
|
+
const minutes = parseInt((ms / 1000 / 60).toString());
|
|
25
|
+
const seconds = parseInt(((ms - minutes * 60 * 1000) / 1000).toString());
|
|
26
|
+
return minutes.toString() + " min " + seconds.toString() + " sec";
|
|
27
|
+
} else {
|
|
28
|
+
const hours = parseInt((ms / 1000 / 60 / 60).toString());
|
|
29
|
+
const minutes = parseInt(
|
|
30
|
+
((ms - hours * 60 * 60 * 1000) / 1000 / 60).toString()
|
|
31
|
+
);
|
|
32
|
+
return hours.toString() + " h " + minutes.toString() + " min";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export class Memory {
|
|
37
|
+
// eslint-disable-next-line @typescript-eslint/no-inferrable-types
|
|
38
|
+
static rss: number = 0;
|
|
39
|
+
constructor() {
|
|
40
|
+
Memory.rss = 0;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// eslint-disable-next-line @typescript-eslint/no-inferrable-types
|
|
44
|
+
public static info(description: string = ``, fullInfo: boolean = false) {
|
|
45
|
+
const memoryData = process.memoryUsage();
|
|
46
|
+
const formatMemoryUsage = (data: number) =>
|
|
47
|
+
`${Math.round(data / 1024 / 1024)} MB`;
|
|
48
|
+
const oldRSS = Memory.rss;
|
|
49
|
+
Memory.rss = Math.round(memoryData.rss / 1024 / 1024);
|
|
50
|
+
|
|
51
|
+
const memoryUsage = fullInfo
|
|
52
|
+
? {
|
|
53
|
+
step: `${description}:`,
|
|
54
|
+
rssDelta: `${(oldRSS === 0
|
|
55
|
+
? 0
|
|
56
|
+
: Memory.rss - oldRSS
|
|
57
|
+
).toString()} MB -> Resident Set Size memory change`,
|
|
58
|
+
rss: `${formatMemoryUsage(
|
|
59
|
+
memoryData.rss
|
|
60
|
+
)} -> Resident Set Size - total memory allocated`,
|
|
61
|
+
heapTotal: `${formatMemoryUsage(
|
|
62
|
+
memoryData.heapTotal
|
|
63
|
+
)} -> total size of the allocated heap`,
|
|
64
|
+
heapUsed: `${formatMemoryUsage(
|
|
65
|
+
memoryData.heapUsed
|
|
66
|
+
)} -> actual memory used during the execution`,
|
|
67
|
+
external: `${formatMemoryUsage(
|
|
68
|
+
memoryData.external
|
|
69
|
+
)} -> V8 external memory`,
|
|
70
|
+
}
|
|
71
|
+
: `RSS memory ${description}: ${formatMemoryUsage(memoryData.rss)}${
|
|
72
|
+
oldRSS === 0
|
|
73
|
+
? ``
|
|
74
|
+
: `, changed by ` + (Memory.rss - oldRSS).toString() + ` MB`
|
|
75
|
+
}`;
|
|
76
|
+
|
|
77
|
+
console.log(memoryUsage);
|
|
78
|
+
}
|
|
79
|
+
}
|