@effectstream/midnight-contracts 0.103.0 → 0.103.2
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 +15 -0
- package/package.json +2 -2
- package/src/dust-state.ts +73 -0
- package/src/get-wallet-info.ts +13 -61
- package/src/mod.ts +5 -2
package/README.md
CHANGED
|
@@ -123,6 +123,21 @@ The circuit list is enumerated automatically from the contract's compiled `keys/
|
|
|
123
123
|
- `deployMidnightContractPhased(...)`: the phased deploy routine `deployMidnightContract` delegates to when `phasedVerifierKeys` is set. Exported for advanced callers that already have built providers and a wallet.
|
|
124
124
|
- `DeployConfig`, `NetworkUrls`: input types.
|
|
125
125
|
|
|
126
|
+
Wallet and dust helpers, exported from the package root:
|
|
127
|
+
|
|
128
|
+
- `buildWalletFacade(...)`: builds the wallet facade the deploy and batcher paths run on.
|
|
129
|
+
- `registerNightForDust(...)`, `getInitialDustState(...)`: register NIGHT to generate dust and read the starting state.
|
|
130
|
+
- `waitForDustFunds(wallet, opts)` / `waitForDustFundsWithRetry(...)`: block until a wallet has spendable dust — the step that makes a freshly funded wallet usable.
|
|
131
|
+
- `saveDustState(...)` / `loadDustState(...)`: persist and restore dust state across restarts, avoiding a re-sync.
|
|
132
|
+
- `resolveFacadeDustBalance(...)`: current dust balance for a facade.
|
|
133
|
+
|
|
134
|
+
Other subpaths:
|
|
135
|
+
|
|
136
|
+
- `@effectstream/midnight-contracts/wallet-info` - wallet inspection plus the dust-state persistence helpers above, and `resolveWalletSyncTimeoutMs()`.
|
|
137
|
+
- `@effectstream/midnight-contracts/midnight-env` - `midnightNetworkConfig` (the resolved `{ id, indexer, indexerWS, node, proofServer }` endpoints, env-overridable), `MidnightNetworkConfig`, and `isExternalProofServerConfigured`.
|
|
138
|
+
- `@effectstream/midnight-contracts/ledger-from-tx-state` - `midnightLedgerFromTxStateHex(...)` and the `MidnightLedgerFn` / `MidnightContractStateDeserializer` types, for decoding contract ledger state from a serialized transaction state.
|
|
139
|
+
- `@effectstream/midnight-contracts/types` - shared types.
|
|
140
|
+
|
|
126
141
|
## Examples
|
|
127
142
|
|
|
128
143
|
End-to-end usage in templates:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effectstream/midnight-contracts",
|
|
3
|
-
"version": "0.103.
|
|
3
|
+
"version": "0.103.2",
|
|
4
4
|
"license": "(MIT OR Apache-2.0)",
|
|
5
5
|
"homepage": "https://effectstream.github.io/docs/",
|
|
6
6
|
"repository": {
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"./types": "./src/types.ts"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@effectstream/utils": "0.103.
|
|
24
|
+
"@effectstream/utils": "0.103.2",
|
|
25
25
|
"@scure/bip39": "^2.0.1",
|
|
26
26
|
"dotenv": "^16.4.7",
|
|
27
27
|
"rxjs": "^7.8.2",
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// Dust-state persistence — the ONLY disk I/O behind the `./wallet-info`
|
|
2
|
+
// subpath, split into its own module so it stays out of browser bundles.
|
|
3
|
+
//
|
|
4
|
+
// `get-wallet-info.ts` is reachable from browsers (MidnightLocal.connectFromSeed
|
|
5
|
+
// imports it to build the wallet facade), and previously carried these
|
|
6
|
+
// functions along with their `node:fs` import. Bundlers shim `node:fs` to an
|
|
7
|
+
// empty/null module, which once crashed the whole entry at import time and,
|
|
8
|
+
// after that was patched, still shipped dead fs/path polyfills to the client.
|
|
9
|
+
// Here the functions are reached only via a lazy `await import()` inside
|
|
10
|
+
// `waitForDustFundsWithRetry` — a node-side flow — so `node:fs`/`node:path`
|
|
11
|
+
// never enter the browser's static graph at all.
|
|
12
|
+
import * as path from "node:path";
|
|
13
|
+
import * as fs from "node:fs";
|
|
14
|
+
|
|
15
|
+
const log = console;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Build the dust state file path from network + seed.
|
|
19
|
+
* Uses first 16 hex chars of the seed as a stable identifier — the seed
|
|
20
|
+
* deterministically maps to a dust address, so this is a unique key per wallet
|
|
21
|
+
* that is available before building the facade.
|
|
22
|
+
*/
|
|
23
|
+
export function getDustStatePath(baseDir: string, networkId: string, seed: string): string {
|
|
24
|
+
const seedKey = seed.slice(0, 16);
|
|
25
|
+
return path.join(baseDir, `${networkId}-${seedKey}.json`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function isUndeployedNetwork(networkId: string): boolean {
|
|
29
|
+
return networkId.toLowerCase() === "undeployed";
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Save serialized dust wallet state to disk.
|
|
34
|
+
* No-ops for "undeployed" networks (chain resets make cached state invalid).
|
|
35
|
+
* @param seed - Wallet seed hex string (used to derive stable file path)
|
|
36
|
+
*/
|
|
37
|
+
export function saveDustState(
|
|
38
|
+
baseDir: string,
|
|
39
|
+
networkId: string,
|
|
40
|
+
seed: string,
|
|
41
|
+
serializedState: string,
|
|
42
|
+
): string | null {
|
|
43
|
+
if (isUndeployedNetwork(networkId)) return null;
|
|
44
|
+
const filePath = getDustStatePath(baseDir, networkId, seed);
|
|
45
|
+
try {
|
|
46
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
47
|
+
fs.writeFileSync(filePath, serializedState, "utf-8");
|
|
48
|
+
log.info(`Dust state saved to ${filePath}`);
|
|
49
|
+
return filePath;
|
|
50
|
+
} catch (e) {
|
|
51
|
+
log.warn(`Failed to save dust state to ${filePath}: ${e instanceof Error ? e.message : String(e)}`);
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Load previously saved dust wallet state from disk.
|
|
58
|
+
* Always returns null for "undeployed" networks.
|
|
59
|
+
* @param seed - Wallet seed hex string (used to derive stable file path)
|
|
60
|
+
*/
|
|
61
|
+
export function loadDustState(
|
|
62
|
+
baseDir: string,
|
|
63
|
+
networkId: string,
|
|
64
|
+
seed: string,
|
|
65
|
+
): string | null {
|
|
66
|
+
if (isUndeployedNetwork(networkId)) return null;
|
|
67
|
+
const filePath = getDustStatePath(baseDir, networkId, seed);
|
|
68
|
+
try {
|
|
69
|
+
return fs.readFileSync(filePath, "utf-8");
|
|
70
|
+
} catch {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
package/src/get-wallet-info.ts
CHANGED
|
@@ -38,77 +38,24 @@ import {
|
|
|
38
38
|
TransactionHistoryStorage,
|
|
39
39
|
} from "@midnightntwrk/wallet-sdk-abstractions";
|
|
40
40
|
import { MidnightBech32m } from "@midnightntwrk/wallet-sdk-address-format";
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
// No node:fs / node:path here — this module is reachable from BROWSER bundles
|
|
42
|
+
// (MidnightLocal.connectFromSeed imports `./wallet-info` to build the wallet
|
|
43
|
+
// facade), and browser bundlers shim those to empty/null modules. All disk I/O
|
|
44
|
+
// (dust-state persistence) lives in dust-state.ts, loaded lazily inside
|
|
45
|
+
// waitForDustFundsWithRetry so it never enters the browser's static graph.
|
|
43
46
|
import { CONSTANTS } from "./constants.ts";
|
|
44
47
|
import type { NetworkUrls, WalletResult } from "./types.ts";
|
|
45
48
|
import { midnightNetworkConfig } from "./midnight-env.ts";
|
|
46
49
|
import { getEnv, args as getArgs, exit, isNotFoundError } from "@effectstream/utils/runtime";
|
|
47
50
|
|
|
48
51
|
// ============================================================================
|
|
49
|
-
// Dust State Persistence
|
|
52
|
+
// Dust State Persistence — moved to dust-state.ts (node-only; disk I/O).
|
|
53
|
+
// Re-exported from mod.ts for node consumers; NOT re-exported here, since a
|
|
54
|
+
// static re-export would pull node:fs right back into the browser graph.
|
|
50
55
|
// ============================================================================
|
|
51
56
|
|
|
52
57
|
const DEFAULT_DUST_STATE_DIR = "dust-state";
|
|
53
58
|
|
|
54
|
-
/**
|
|
55
|
-
* Build the dust state file path from network + seed.
|
|
56
|
-
* Uses first 16 hex chars of the seed as a stable identifier — the seed
|
|
57
|
-
* deterministically maps to a dust address, so this is a unique key per wallet
|
|
58
|
-
* that is available before building the facade.
|
|
59
|
-
*/
|
|
60
|
-
function getDustStatePath(baseDir: string, networkId: string, seed: string): string {
|
|
61
|
-
const seedKey = seed.slice(0, 16);
|
|
62
|
-
return path.join(baseDir, `${networkId}-${seedKey}.json`);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function isUndeployedNetwork(networkId: string): boolean {
|
|
66
|
-
return networkId.toLowerCase() === "undeployed";
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Save serialized dust wallet state to disk.
|
|
71
|
-
* No-ops for "undeployed" networks (chain resets make cached state invalid).
|
|
72
|
-
* @param seed - Wallet seed hex string (used to derive stable file path)
|
|
73
|
-
*/
|
|
74
|
-
export function saveDustState(
|
|
75
|
-
baseDir: string,
|
|
76
|
-
networkId: string,
|
|
77
|
-
seed: string,
|
|
78
|
-
serializedState: string,
|
|
79
|
-
): string | null {
|
|
80
|
-
if (isUndeployedNetwork(networkId)) return null;
|
|
81
|
-
const filePath = getDustStatePath(baseDir, networkId, seed);
|
|
82
|
-
try {
|
|
83
|
-
mkdirSync(path.dirname(filePath), { recursive: true });
|
|
84
|
-
writeFileSync(filePath, serializedState, "utf-8");
|
|
85
|
-
log.info(`Dust state saved to ${filePath}`);
|
|
86
|
-
return filePath;
|
|
87
|
-
} catch (e) {
|
|
88
|
-
log.warn(`Failed to save dust state to ${filePath}: ${e instanceof Error ? e.message : String(e)}`);
|
|
89
|
-
return null;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Load previously saved dust wallet state from disk.
|
|
95
|
-
* Always returns null for "undeployed" networks.
|
|
96
|
-
* @param seed - Wallet seed hex string (used to derive stable file path)
|
|
97
|
-
*/
|
|
98
|
-
export function loadDustState(
|
|
99
|
-
baseDir: string,
|
|
100
|
-
networkId: string,
|
|
101
|
-
seed: string,
|
|
102
|
-
): string | null {
|
|
103
|
-
if (isUndeployedNetwork(networkId)) return null;
|
|
104
|
-
const filePath = getDustStatePath(baseDir, networkId, seed);
|
|
105
|
-
try {
|
|
106
|
-
return readFileSync(filePath, "utf-8");
|
|
107
|
-
} catch {
|
|
108
|
-
return null;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
59
|
// ============================================================================
|
|
113
60
|
// Key Derivation
|
|
114
61
|
// ============================================================================
|
|
@@ -554,6 +501,11 @@ export async function waitForDustFundsWithRetry(
|
|
|
554
501
|
|
|
555
502
|
const networkIdStr = String(networkId);
|
|
556
503
|
|
|
504
|
+
// Lazy import keeps node:fs out of the browser's static graph — this retry
|
|
505
|
+
// flow is node-side (long-running dust sync with disk caching), while the
|
|
506
|
+
// module as a whole is bundled for browsers via `./wallet-info`.
|
|
507
|
+
const { loadDustState, saveDustState, getDustStatePath } = await import("./dust-state.ts");
|
|
508
|
+
|
|
557
509
|
// Pre-load cached state from disk before building any wallet.
|
|
558
510
|
// Uses seed-based path so we don't need the dust address yet.
|
|
559
511
|
const cachedState: string | null = loadDustState(dustStateDir, networkIdStr, seed);
|
package/src/mod.ts
CHANGED
|
@@ -18,9 +18,12 @@ export {
|
|
|
18
18
|
getInitialDustState,
|
|
19
19
|
waitForDustFunds,
|
|
20
20
|
waitForDustFundsWithRetry,
|
|
21
|
-
saveDustState,
|
|
22
|
-
loadDustState,
|
|
23
21
|
} from "./get-wallet-info.ts";
|
|
22
|
+
// Disk-backed dust persistence lives in its own node-only module so the
|
|
23
|
+
// browser-reachable ./wallet-info subpath carries no node:fs. This barrel is
|
|
24
|
+
// node-only anyway (deploy.ts imports node:fs/promises), so a static
|
|
25
|
+
// re-export here is fine and keeps the public API unchanged.
|
|
26
|
+
export { saveDustState, loadDustState } from "./dust-state.ts";
|
|
24
27
|
export type {
|
|
25
28
|
WalletSyncMode,
|
|
26
29
|
DustSyncWithRetryOptions,
|