@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.
Files changed (174) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +1 -0
  3. package/dist/node/config.d.ts +4 -0
  4. package/dist/node/config.js +5 -0
  5. package/dist/node/config.js.map +1 -0
  6. package/dist/node/index.cjs +1325 -0
  7. package/dist/node/index.d.ts +6 -0
  8. package/dist/node/index.js +7 -0
  9. package/dist/node/index.js.map +1 -0
  10. package/dist/node/networks.d.ts +32 -0
  11. package/dist/node/networks.js +81 -0
  12. package/dist/node/networks.js.map +1 -0
  13. package/dist/node/storage/index.d.ts +2 -0
  14. package/dist/node/storage/index.js +3 -0
  15. package/dist/node/storage/index.js.map +1 -0
  16. package/dist/node/storage/ipfs.d.ts +5 -0
  17. package/dist/node/storage/ipfs.js +16 -0
  18. package/dist/node/storage/ipfs.js.map +1 -0
  19. package/dist/node/storage/pinata.d.ts +6 -0
  20. package/dist/node/storage/pinata.js +40 -0
  21. package/dist/node/storage/pinata.js.map +1 -0
  22. package/dist/node/transactions/account.d.ts +4 -0
  23. package/dist/node/transactions/account.js +44 -0
  24. package/dist/node/transactions/account.js.map +1 -0
  25. package/dist/node/transactions/blockberry.d.ts +21 -0
  26. package/dist/node/transactions/blockberry.js +130 -0
  27. package/dist/node/transactions/blockberry.js.map +1 -0
  28. package/dist/node/transactions/chain.d.ts +1 -0
  29. package/dist/node/transactions/chain.js +2 -0
  30. package/dist/node/transactions/chain.js.map +1 -0
  31. package/dist/node/transactions/index.d.ts +8 -0
  32. package/dist/node/transactions/index.js +9 -0
  33. package/dist/node/transactions/index.js.map +1 -0
  34. package/dist/node/transactions/nonce.d.ts +17 -0
  35. package/dist/node/transactions/nonce.js +91 -0
  36. package/dist/node/transactions/nonce.js.map +1 -0
  37. package/dist/node/transactions/send.d.ts +31 -0
  38. package/dist/node/transactions/send.js +154 -0
  39. package/dist/node/transactions/send.js.map +1 -0
  40. package/dist/node/transactions/tiny-contract.d.ts +5 -0
  41. package/dist/node/transactions/tiny-contract.js +22 -0
  42. package/dist/node/transactions/tiny-contract.js.map +1 -0
  43. package/dist/node/transactions/transaction.d.ts +21 -0
  44. package/dist/node/transactions/transaction.js +222 -0
  45. package/dist/node/transactions/transaction.js.map +1 -0
  46. package/dist/node/transactions/txstatus.d.ts +8 -0
  47. package/dist/node/transactions/txstatus.js +16 -0
  48. package/dist/node/transactions/txstatus.js.map +1 -0
  49. package/dist/node/utils/base64-field.d.ts +5 -0
  50. package/dist/node/utils/base64-field.js +29 -0
  51. package/dist/node/utils/base64-field.js.map +1 -0
  52. package/dist/node/utils/base64.d.ts +6 -0
  53. package/dist/node/utils/base64.js +83 -0
  54. package/dist/node/utils/base64.js.map +1 -0
  55. package/dist/node/utils/fee.d.ts +6 -0
  56. package/dist/node/utils/fee.js +11 -0
  57. package/dist/node/utils/fee.js.map +1 -0
  58. package/dist/node/utils/fetch.d.ts +44 -0
  59. package/dist/node/utils/fetch.js +101 -0
  60. package/dist/node/utils/fetch.js.map +1 -0
  61. package/dist/node/utils/fields.d.ts +13 -0
  62. package/dist/node/utils/fields.js +39 -0
  63. package/dist/node/utils/fields.js.map +1 -0
  64. package/dist/node/utils/index.d.ts +8 -0
  65. package/dist/node/utils/index.js +9 -0
  66. package/dist/node/utils/index.js.map +1 -0
  67. package/dist/node/utils/indexed-map.d.ts +32 -0
  68. package/dist/node/utils/indexed-map.js +124 -0
  69. package/dist/node/utils/indexed-map.js.map +1 -0
  70. package/dist/node/utils/mina.d.ts +39 -0
  71. package/dist/node/utils/mina.js +123 -0
  72. package/dist/node/utils/mina.js.map +1 -0
  73. package/dist/node/utils/utils.d.ts +8 -0
  74. package/dist/node/utils/utils.js +61 -0
  75. package/dist/node/utils/utils.js.map +1 -0
  76. package/dist/tsconfig.tsbuildinfo +1 -0
  77. package/dist/tsconfig.web.tsbuildinfo +1 -0
  78. package/dist/web/config.d.ts +4 -0
  79. package/dist/web/config.js +5 -0
  80. package/dist/web/config.js.map +1 -0
  81. package/dist/web/index.d.ts +6 -0
  82. package/dist/web/index.js +7 -0
  83. package/dist/web/index.js.map +1 -0
  84. package/dist/web/networks.d.ts +32 -0
  85. package/dist/web/networks.js +81 -0
  86. package/dist/web/networks.js.map +1 -0
  87. package/dist/web/storage/index.d.ts +2 -0
  88. package/dist/web/storage/index.js +3 -0
  89. package/dist/web/storage/index.js.map +1 -0
  90. package/dist/web/storage/ipfs.d.ts +5 -0
  91. package/dist/web/storage/ipfs.js +16 -0
  92. package/dist/web/storage/ipfs.js.map +1 -0
  93. package/dist/web/storage/pinata.d.ts +6 -0
  94. package/dist/web/storage/pinata.js +40 -0
  95. package/dist/web/storage/pinata.js.map +1 -0
  96. package/dist/web/transactions/account.d.ts +4 -0
  97. package/dist/web/transactions/account.js +44 -0
  98. package/dist/web/transactions/account.js.map +1 -0
  99. package/dist/web/transactions/blockberry.d.ts +21 -0
  100. package/dist/web/transactions/blockberry.js +130 -0
  101. package/dist/web/transactions/blockberry.js.map +1 -0
  102. package/dist/web/transactions/chain.d.ts +1 -0
  103. package/dist/web/transactions/chain.js +2 -0
  104. package/dist/web/transactions/chain.js.map +1 -0
  105. package/dist/web/transactions/index.d.ts +8 -0
  106. package/dist/web/transactions/index.js +9 -0
  107. package/dist/web/transactions/index.js.map +1 -0
  108. package/dist/web/transactions/nonce.d.ts +17 -0
  109. package/dist/web/transactions/nonce.js +91 -0
  110. package/dist/web/transactions/nonce.js.map +1 -0
  111. package/dist/web/transactions/send.d.ts +31 -0
  112. package/dist/web/transactions/send.js +154 -0
  113. package/dist/web/transactions/send.js.map +1 -0
  114. package/dist/web/transactions/tiny-contract.d.ts +5 -0
  115. package/dist/web/transactions/tiny-contract.js +22 -0
  116. package/dist/web/transactions/tiny-contract.js.map +1 -0
  117. package/dist/web/transactions/transaction.d.ts +21 -0
  118. package/dist/web/transactions/transaction.js +222 -0
  119. package/dist/web/transactions/transaction.js.map +1 -0
  120. package/dist/web/transactions/txstatus.d.ts +8 -0
  121. package/dist/web/transactions/txstatus.js +16 -0
  122. package/dist/web/transactions/txstatus.js.map +1 -0
  123. package/dist/web/utils/base64-field.d.ts +5 -0
  124. package/dist/web/utils/base64-field.js +29 -0
  125. package/dist/web/utils/base64-field.js.map +1 -0
  126. package/dist/web/utils/base64.d.ts +6 -0
  127. package/dist/web/utils/base64.js +83 -0
  128. package/dist/web/utils/base64.js.map +1 -0
  129. package/dist/web/utils/fee.d.ts +6 -0
  130. package/dist/web/utils/fee.js +11 -0
  131. package/dist/web/utils/fee.js.map +1 -0
  132. package/dist/web/utils/fetch.d.ts +44 -0
  133. package/dist/web/utils/fetch.js +101 -0
  134. package/dist/web/utils/fetch.js.map +1 -0
  135. package/dist/web/utils/fields.d.ts +13 -0
  136. package/dist/web/utils/fields.js +39 -0
  137. package/dist/web/utils/fields.js.map +1 -0
  138. package/dist/web/utils/index.d.ts +8 -0
  139. package/dist/web/utils/index.js +9 -0
  140. package/dist/web/utils/index.js.map +1 -0
  141. package/dist/web/utils/indexed-map.d.ts +32 -0
  142. package/dist/web/utils/indexed-map.js +124 -0
  143. package/dist/web/utils/indexed-map.js.map +1 -0
  144. package/dist/web/utils/mina.d.ts +39 -0
  145. package/dist/web/utils/mina.js +123 -0
  146. package/dist/web/utils/mina.js.map +1 -0
  147. package/dist/web/utils/utils.d.ts +8 -0
  148. package/dist/web/utils/utils.js +61 -0
  149. package/dist/web/utils/utils.js.map +1 -0
  150. package/package.json +62 -0
  151. package/src/config.ts +5 -0
  152. package/src/index.ts +6 -0
  153. package/src/networks.ts +130 -0
  154. package/src/storage/index.ts +2 -0
  155. package/src/storage/ipfs.ts +20 -0
  156. package/src/storage/pinata.ts +56 -0
  157. package/src/transactions/account.ts +57 -0
  158. package/src/transactions/blockberry.ts +198 -0
  159. package/src/transactions/chain.ts +1 -0
  160. package/src/transactions/index.ts +8 -0
  161. package/src/transactions/nonce.ts +121 -0
  162. package/src/transactions/send.ts +228 -0
  163. package/src/transactions/tiny-contract.ts +9 -0
  164. package/src/transactions/transaction.ts +319 -0
  165. package/src/transactions/txstatus.ts +26 -0
  166. package/src/utils/base64-field.ts +34 -0
  167. package/src/utils/base64.ts +87 -0
  168. package/src/utils/fee.ts +11 -0
  169. package/src/utils/fetch.ts +130 -0
  170. package/src/utils/fields.ts +39 -0
  171. package/src/utils/index.ts +8 -0
  172. package/src/utils/indexed-map.ts +170 -0
  173. package/src/utils/mina.ts +171 -0
  174. package/src/utils/utils.ts +79 -0
@@ -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,8 @@
1
+ export * from "./base64-field.js";
2
+ export * from "./base64.js";
3
+ export * from "./fetch.js";
4
+ export * from "./fields.js";
5
+ export * from "./fee.js";
6
+ export * from "./mina.js";
7
+ export * from "./indexed-map.js";
8
+ export * from "./utils.js";
@@ -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
+ }