@effectstream/midnight-contracts 0.100.28 → 0.101.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/package.json +2 -2
- package/src/deploy.ts +24 -21
- package/src/get-wallet-info-cli.ts +213 -0
- package/src/get-wallet-info.ts +1 -189
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effectstream/midnight-contracts",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.101.0",
|
|
4
4
|
"license": "MIT",
|
|
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.
|
|
24
|
+
"@effectstream/utils": "0.101.0",
|
|
25
25
|
"@scure/bip39": "^2.0.1",
|
|
26
26
|
"dotenv": "^16.4.7",
|
|
27
27
|
"@midnight-ntwrk/zswap": "4.0.0",
|
package/src/deploy.ts
CHANGED
|
@@ -92,6 +92,7 @@ export async function deployMidnightContract(
|
|
|
92
92
|
config: DeployConfig,
|
|
93
93
|
networkUrls?: NetworkUrls,
|
|
94
94
|
seedOrMnemonic?: { seed: string; mnemonic: string },
|
|
95
|
+
opts?: { walletResult?: WalletResult },
|
|
95
96
|
): Promise<string> {
|
|
96
97
|
checkEnvVariables();
|
|
97
98
|
|
|
@@ -141,30 +142,32 @@ export async function deployMidnightContract(
|
|
|
141
142
|
|
|
142
143
|
setNetworkId(resolvedNetworkId);
|
|
143
144
|
|
|
144
|
-
let walletResult: WalletResult | null = null;
|
|
145
|
+
let walletResult: WalletResult | null = opts?.walletResult ?? null;
|
|
145
146
|
let providers: ReturnType<typeof configureMidnightNodeProviders> | null = null;
|
|
146
147
|
|
|
147
148
|
try {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
149
|
+
if (!walletResult) {
|
|
150
|
+
log.info("Building wallet...");
|
|
151
|
+
let seed;
|
|
152
|
+
if (seedOrMnemonic?.seed) {
|
|
153
|
+
seed = seedOrMnemonic.seed;
|
|
154
|
+
} else if (seedOrMnemonic?.mnemonic) {
|
|
155
|
+
seed = Buffer.from(
|
|
156
|
+
await mnemonicToSeed(seedOrMnemonic.mnemonic),
|
|
157
|
+
).toString("hex");
|
|
158
|
+
} else {
|
|
159
|
+
seed = midnightNetworkConfig.walletSeed;
|
|
160
|
+
}
|
|
161
|
+
if (!seed) {
|
|
162
|
+
throw new Error("No seed or mnemonic provided");
|
|
163
|
+
}
|
|
162
164
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
165
|
+
walletResult = await buildWalletAndWaitForFunds(
|
|
166
|
+
resolvedNetworkUrls,
|
|
167
|
+
seed,
|
|
168
|
+
resolvedNetworkId,
|
|
169
|
+
);
|
|
170
|
+
}
|
|
168
171
|
|
|
169
172
|
const {
|
|
170
173
|
wallet,
|
|
@@ -174,7 +177,7 @@ export async function deployMidnightContract(
|
|
|
174
177
|
walletDustSecretKey,
|
|
175
178
|
dustAddress,
|
|
176
179
|
unshieldedKeystore,
|
|
177
|
-
} = walletResult
|
|
180
|
+
} = walletResult!;
|
|
178
181
|
const resolvedDustReceiverAddress =
|
|
179
182
|
getEnv("MIDNIGHT_DUST_RECEIVER_ADDRESS") ?? dustAddress;
|
|
180
183
|
if (resolvedDustReceiverAddress === dustAddress) {
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
// CLI entry for inspecting a Midnight wallet (prints addresses, optional balances).
|
|
2
|
+
//
|
|
3
|
+
// Split out of get-wallet-info.ts so that module stays browser-bundle-safe:
|
|
4
|
+
// `parseArgs` (node:util) and `dotenv` are Node-only, top-level imports. Because
|
|
5
|
+
// get-wallet-info.ts is reachable from frontends (via @effectstream/wallets →
|
|
6
|
+
// @effectstream/midnight-contracts/wallet-info → buildWalletFacade), those
|
|
7
|
+
// imports broke the browser bundle ("No matching export ... for import parseArgs").
|
|
8
|
+
// The reusable wallet/dust helpers stay in get-wallet-info.ts; only this CLI lives here.
|
|
9
|
+
//
|
|
10
|
+
// Run: bun run src/get-wallet-info-cli.ts [--seed <hex>] [--balance]
|
|
11
|
+
import dotenv from "dotenv";
|
|
12
|
+
import { parseArgs } from "node:util";
|
|
13
|
+
import { shieldedToken } from "@midnight-ntwrk/ledger-v8";
|
|
14
|
+
import { setNetworkId } from "@midnight-ntwrk/midnight-js-network-id";
|
|
15
|
+
import { NetworkId } from "@midnight-ntwrk/wallet-sdk-abstractions";
|
|
16
|
+
import * as Rx from "rxjs";
|
|
17
|
+
import type { NetworkUrls } from "./types.ts";
|
|
18
|
+
import { midnightNetworkConfig } from "./midnight-env.ts";
|
|
19
|
+
import { getEnv, args as getArgs, exit, isNotFoundError } from "@effectstream/utils/runtime";
|
|
20
|
+
import {
|
|
21
|
+
buildWalletFacade,
|
|
22
|
+
getInitialShieldedState,
|
|
23
|
+
getInitialUnshieldedState,
|
|
24
|
+
resolveWalletSyncTimeoutMs,
|
|
25
|
+
syncAndWaitForFunds,
|
|
26
|
+
resolveFacadeDustBalance,
|
|
27
|
+
waitForDustFunds,
|
|
28
|
+
registerNightForDust,
|
|
29
|
+
} from "./get-wallet-info.ts";
|
|
30
|
+
|
|
31
|
+
const log = console;
|
|
32
|
+
|
|
33
|
+
async function main() {
|
|
34
|
+
const { values: parsedArgs } = parseArgs({
|
|
35
|
+
args: getArgs(),
|
|
36
|
+
options: {
|
|
37
|
+
seed: { type: "string" },
|
|
38
|
+
balance: { type: "boolean", default: false },
|
|
39
|
+
},
|
|
40
|
+
strict: false,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const result = dotenv.config({ path: ".env.testnet", override: true });
|
|
44
|
+
if (result.error) {
|
|
45
|
+
if (!isNotFoundError(result.error)) {
|
|
46
|
+
log.warn(`Failed to load .env.testnet: ${result.error}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const envSeed = getEnv("MIDNIGHT_WALLET_SEED");
|
|
51
|
+
const argSeed = parsedArgs.seed;
|
|
52
|
+
let seed = argSeed || envSeed;
|
|
53
|
+
|
|
54
|
+
if (!seed) {
|
|
55
|
+
log.info("No seed provided. Generating a new random 32-byte hex seed...");
|
|
56
|
+
const randomBytes = new Uint8Array(32);
|
|
57
|
+
crypto.getRandomValues(randomBytes);
|
|
58
|
+
seed = Array.from(randomBytes)
|
|
59
|
+
.map((b) => b.toString(16).padStart(2, "0"))
|
|
60
|
+
.join("");
|
|
61
|
+
log.info("==========================================");
|
|
62
|
+
log.info(`GENERATED SEED: ${seed}`);
|
|
63
|
+
log.info("SAVE THIS SEED! YOU WILL NEED IT TO RESTORE THIS WALLET.");
|
|
64
|
+
log.info("==========================================");
|
|
65
|
+
} else {
|
|
66
|
+
log.info("Using provided seed: " + seed);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (seed?.startsWith("000000000000000000000000000000000000000000000000000000000000000")) {
|
|
70
|
+
log.warn("⚠️ Genesis seeds (0x000...001, 0x000...002, etc.) only have funds on 'undeployed' local networks!");
|
|
71
|
+
log.warn("⚠️ For testnet/preview networks, you need to:");
|
|
72
|
+
log.warn(" 1. Generate a new wallet seed, OR");
|
|
73
|
+
log.warn(" 2. Request funds from a faucet for this wallet");
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const indexer = getEnv("MIDNIGHT_INDEXER_URL") || midnightNetworkConfig.indexer;
|
|
77
|
+
const indexerWS = getEnv("MIDNIGHT_INDEXER_WS_URL") || midnightNetworkConfig.indexerWS;
|
|
78
|
+
const node = getEnv("MIDNIGHT_NODE_URL") || midnightNetworkConfig.node;
|
|
79
|
+
const proofServer = getEnv("MIDNIGHT_PROOF_SERVER_URL") || midnightNetworkConfig.proofServer;
|
|
80
|
+
|
|
81
|
+
const networkUrls: Required<NetworkUrls> = {
|
|
82
|
+
id: "placeholder-value",
|
|
83
|
+
indexer,
|
|
84
|
+
indexerWS,
|
|
85
|
+
node,
|
|
86
|
+
proofServer
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const networkIdRaw = getEnv("MIDNIGHT_NETWORK_ID") || "undeployed";
|
|
90
|
+
|
|
91
|
+
let networkId: NetworkId.NetworkId;
|
|
92
|
+
switch (networkIdRaw.toLowerCase()) {
|
|
93
|
+
case "undeployed":
|
|
94
|
+
networkId = NetworkId.NetworkId.Undeployed;
|
|
95
|
+
break;
|
|
96
|
+
case "testnet":
|
|
97
|
+
case "testnet-02":
|
|
98
|
+
networkId = NetworkId.NetworkId.TestNet;
|
|
99
|
+
break;
|
|
100
|
+
case "devnet":
|
|
101
|
+
case "qanet":
|
|
102
|
+
networkId = NetworkId.NetworkId.DevNet;
|
|
103
|
+
break;
|
|
104
|
+
case "preview":
|
|
105
|
+
networkId = "preview" as NetworkId.NetworkId;
|
|
106
|
+
log.info(`Using preview network (addresses will have mn_addr_preview prefix)`);
|
|
107
|
+
break;
|
|
108
|
+
default:
|
|
109
|
+
log.warn(`Unknown network ID "${networkIdRaw}", using as-is. Valid values: undeployed, testnet, devnet, preview`);
|
|
110
|
+
networkId = networkIdRaw as NetworkId.NetworkId;
|
|
111
|
+
}
|
|
112
|
+
networkUrls.id = networkId;
|
|
113
|
+
|
|
114
|
+
log.info(`Using network ID: ${networkId}`);
|
|
115
|
+
log.info(`Indexer: ${indexer}`);
|
|
116
|
+
log.info(`Indexer WS: ${indexerWS}`);
|
|
117
|
+
log.info(`Node: ${node}`);
|
|
118
|
+
setNetworkId(networkId);
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
log.info("Building wallet...");
|
|
122
|
+
const walletResult = await buildWalletFacade(networkUrls, seed, networkId);
|
|
123
|
+
|
|
124
|
+
const initialState = await getInitialShieldedState(walletResult.wallet.shielded);
|
|
125
|
+
const shieldedAddress = initialState.address.coinPublicKeyString();
|
|
126
|
+
|
|
127
|
+
log.info("==========================================");
|
|
128
|
+
log.info("Wallet Addresses");
|
|
129
|
+
log.info("==========================================");
|
|
130
|
+
log.info(`Shielded Address: ${shieldedAddress}`);
|
|
131
|
+
log.info(`Unshielded Address: ${walletResult.unshieldedAddress}`);
|
|
132
|
+
log.info(`Dust Address: ${walletResult.dustAddress}`);
|
|
133
|
+
log.info("==========================================");
|
|
134
|
+
|
|
135
|
+
if (parsedArgs.balance) {
|
|
136
|
+
log.info("==========================================");
|
|
137
|
+
log.info("Fetching Balances...");
|
|
138
|
+
log.info("==========================================");
|
|
139
|
+
|
|
140
|
+
let shieldedBalance = 0n;
|
|
141
|
+
let unshieldedBalance = 0n;
|
|
142
|
+
let dustBalance = 0n;
|
|
143
|
+
|
|
144
|
+
const tokenId = shieldedToken().tag;
|
|
145
|
+
shieldedBalance = initialState.balances[tokenId] ?? 0n;
|
|
146
|
+
|
|
147
|
+
const syncTimeoutMs = resolveWalletSyncTimeoutMs();
|
|
148
|
+
|
|
149
|
+
if (shieldedBalance === 0n) {
|
|
150
|
+
log.info("Shielded balance is 0. Waiting for wallet sync to confirm funds...");
|
|
151
|
+
try {
|
|
152
|
+
const synced = await syncAndWaitForFunds(walletResult.wallet);
|
|
153
|
+
shieldedBalance = synced.shieldedBalance;
|
|
154
|
+
unshieldedBalance = synced.unshieldedBalance;
|
|
155
|
+
dustBalance = synced.dustBalance;
|
|
156
|
+
} catch (e) {
|
|
157
|
+
log.warn(`Sync timed out or failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
158
|
+
}
|
|
159
|
+
} else {
|
|
160
|
+
try {
|
|
161
|
+
const unshieldedState = await getInitialUnshieldedState((walletResult.wallet as any).unshielded);
|
|
162
|
+
const uBalances = (unshieldedState?.balances ?? {}) as Record<string, bigint>;
|
|
163
|
+
unshieldedBalance = Object.values(uBalances).reduce(
|
|
164
|
+
(acc: bigint, v) => acc + (v ?? 0n),
|
|
165
|
+
0n
|
|
166
|
+
);
|
|
167
|
+
} catch(_e) { /* ignore */ }
|
|
168
|
+
|
|
169
|
+
try {
|
|
170
|
+
const state = await Rx.firstValueFrom(walletResult.wallet.state());
|
|
171
|
+
dustBalance = resolveFacadeDustBalance(state, new Date());
|
|
172
|
+
|
|
173
|
+
if (dustBalance === 0n) {
|
|
174
|
+
log.info("Dust balance is 0. Attempting to sync dust wallet...");
|
|
175
|
+
try {
|
|
176
|
+
dustBalance = await waitForDustFunds(walletResult.wallet, { timeoutMs: syncTimeoutMs });
|
|
177
|
+
} catch(_e) {
|
|
178
|
+
log.warn("Dust sync timed out or returned no funds.");
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (dustBalance === 0n && unshieldedBalance > 0n) {
|
|
183
|
+
log.info("Dust is 0 but unshielded funds available. Registering for dust generation...");
|
|
184
|
+
const success = await registerNightForDust(walletResult);
|
|
185
|
+
if (success) {
|
|
186
|
+
dustBalance = await waitForDustFunds(walletResult.wallet, { timeoutMs: 30000 });
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
} catch (_e) {
|
|
190
|
+
// ignore
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
log.info("==========================================");
|
|
195
|
+
log.info("Balances");
|
|
196
|
+
log.info("==========================================");
|
|
197
|
+
log.info(`Shielded Balance: ${shieldedBalance} NIGHT`);
|
|
198
|
+
log.info(`Dust Balance: ${dustBalance} DUST`);
|
|
199
|
+
log.info(`Unshielded Balance: ${unshieldedBalance} NIGHT`);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
log.info("==========================================");
|
|
203
|
+
|
|
204
|
+
await walletResult.wallet.stop();
|
|
205
|
+
} catch (error) {
|
|
206
|
+
log.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
207
|
+
exit(1);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (import.meta.main) {
|
|
212
|
+
main();
|
|
213
|
+
}
|
package/src/get-wallet-info.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import dotenv from "dotenv";
|
|
2
|
-
import { parseArgs } from "node:util";
|
|
3
1
|
// graphql-ws has a dangling promise in its subscribe flow: when a subscription ends,
|
|
4
2
|
// the socket closes normally (code 1000) but the internal throwOnClose promise rejects
|
|
5
3
|
// with no handler. In Bun, unhandled rejections crash the process (exit 1).
|
|
@@ -969,7 +967,7 @@ export function getInitialShieldedState(
|
|
|
969
967
|
/**
|
|
970
968
|
* Get initial state of unshielded wallet
|
|
971
969
|
*/
|
|
972
|
-
function getInitialUnshieldedState(
|
|
970
|
+
export function getInitialUnshieldedState(
|
|
973
971
|
unshieldedWallet: any
|
|
974
972
|
): Promise<any> {
|
|
975
973
|
if (!unshieldedWallet) return Promise.resolve(null);
|
|
@@ -1055,189 +1053,3 @@ export async function registerNightForDust(
|
|
|
1055
1053
|
return false;
|
|
1056
1054
|
}
|
|
1057
1055
|
}
|
|
1058
|
-
|
|
1059
|
-
// ============================================================================
|
|
1060
|
-
// Main
|
|
1061
|
-
// ============================================================================
|
|
1062
|
-
|
|
1063
|
-
async function main() {
|
|
1064
|
-
const { values: parsedArgs } = parseArgs({
|
|
1065
|
-
args: getArgs(),
|
|
1066
|
-
options: {
|
|
1067
|
-
seed: { type: "string" },
|
|
1068
|
-
balance: { type: "boolean", default: false },
|
|
1069
|
-
},
|
|
1070
|
-
strict: false,
|
|
1071
|
-
});
|
|
1072
|
-
|
|
1073
|
-
const result = dotenv.config({ path: ".env.testnet", override: true });
|
|
1074
|
-
if (result.error) {
|
|
1075
|
-
if (!isNotFoundError(result.error)) {
|
|
1076
|
-
log.warn(`Failed to load .env.testnet: ${result.error}`);
|
|
1077
|
-
}
|
|
1078
|
-
}
|
|
1079
|
-
|
|
1080
|
-
const envSeed = getEnv("MIDNIGHT_WALLET_SEED");
|
|
1081
|
-
const argSeed = parsedArgs.seed;
|
|
1082
|
-
let seed = argSeed || envSeed;
|
|
1083
|
-
|
|
1084
|
-
if (!seed) {
|
|
1085
|
-
log.info("No seed provided. Generating a new random 32-byte hex seed...");
|
|
1086
|
-
const randomBytes = new Uint8Array(32);
|
|
1087
|
-
crypto.getRandomValues(randomBytes);
|
|
1088
|
-
seed = Array.from(randomBytes)
|
|
1089
|
-
.map((b) => b.toString(16).padStart(2, "0"))
|
|
1090
|
-
.join("");
|
|
1091
|
-
log.info("==========================================");
|
|
1092
|
-
log.info(`GENERATED SEED: ${seed}`);
|
|
1093
|
-
log.info("SAVE THIS SEED! YOU WILL NEED IT TO RESTORE THIS WALLET.");
|
|
1094
|
-
log.info("==========================================");
|
|
1095
|
-
} else {
|
|
1096
|
-
log.info("Using provided seed: " + seed);
|
|
1097
|
-
}
|
|
1098
|
-
|
|
1099
|
-
if (seed?.startsWith("000000000000000000000000000000000000000000000000000000000000000")) {
|
|
1100
|
-
log.warn("⚠️ Genesis seeds (0x000...001, 0x000...002, etc.) only have funds on 'undeployed' local networks!");
|
|
1101
|
-
log.warn("⚠️ For testnet/preview networks, you need to:");
|
|
1102
|
-
log.warn(" 1. Generate a new wallet seed, OR");
|
|
1103
|
-
log.warn(" 2. Request funds from a faucet for this wallet");
|
|
1104
|
-
}
|
|
1105
|
-
|
|
1106
|
-
const indexer = getEnv("MIDNIGHT_INDEXER_URL") || midnightNetworkConfig.indexer;
|
|
1107
|
-
const indexerWS = getEnv("MIDNIGHT_INDEXER_WS_URL") || midnightNetworkConfig.indexerWS;
|
|
1108
|
-
const node = getEnv("MIDNIGHT_NODE_URL") || midnightNetworkConfig.node;
|
|
1109
|
-
const proofServer = getEnv("MIDNIGHT_PROOF_SERVER_URL") || midnightNetworkConfig.proofServer;
|
|
1110
|
-
|
|
1111
|
-
const networkUrls: Required<NetworkUrls> = {
|
|
1112
|
-
id: "placeholder-value",
|
|
1113
|
-
indexer,
|
|
1114
|
-
indexerWS,
|
|
1115
|
-
node,
|
|
1116
|
-
proofServer
|
|
1117
|
-
};
|
|
1118
|
-
|
|
1119
|
-
const networkIdRaw = getEnv("MIDNIGHT_NETWORK_ID") || "undeployed";
|
|
1120
|
-
|
|
1121
|
-
let networkId: NetworkId.NetworkId;
|
|
1122
|
-
switch (networkIdRaw.toLowerCase()) {
|
|
1123
|
-
case "undeployed":
|
|
1124
|
-
networkId = NetworkId.NetworkId.Undeployed;
|
|
1125
|
-
break;
|
|
1126
|
-
case "testnet":
|
|
1127
|
-
case "testnet-02":
|
|
1128
|
-
networkId = NetworkId.NetworkId.TestNet;
|
|
1129
|
-
break;
|
|
1130
|
-
case "devnet":
|
|
1131
|
-
case "qanet":
|
|
1132
|
-
networkId = NetworkId.NetworkId.DevNet;
|
|
1133
|
-
break;
|
|
1134
|
-
case "preview":
|
|
1135
|
-
networkId = "preview" as NetworkId.NetworkId;
|
|
1136
|
-
log.info(`Using preview network (addresses will have mn_addr_preview prefix)`);
|
|
1137
|
-
break;
|
|
1138
|
-
default:
|
|
1139
|
-
log.warn(`Unknown network ID "${networkIdRaw}", using as-is. Valid values: undeployed, testnet, devnet, preview`);
|
|
1140
|
-
networkId = networkIdRaw as NetworkId.NetworkId;
|
|
1141
|
-
}
|
|
1142
|
-
networkUrls.id = networkId;
|
|
1143
|
-
|
|
1144
|
-
log.info(`Using network ID: ${networkId}`);
|
|
1145
|
-
log.info(`Indexer: ${indexer}`);
|
|
1146
|
-
log.info(`Indexer WS: ${indexerWS}`);
|
|
1147
|
-
log.info(`Node: ${node}`);
|
|
1148
|
-
setNetworkId(networkId);
|
|
1149
|
-
|
|
1150
|
-
try {
|
|
1151
|
-
log.info("Building wallet...");
|
|
1152
|
-
const walletResult = await buildWalletFacade(networkUrls, seed, networkId);
|
|
1153
|
-
|
|
1154
|
-
const initialState = await getInitialShieldedState(walletResult.wallet.shielded);
|
|
1155
|
-
const shieldedAddress = initialState.address.coinPublicKeyString();
|
|
1156
|
-
|
|
1157
|
-
log.info("==========================================");
|
|
1158
|
-
log.info("Wallet Addresses");
|
|
1159
|
-
log.info("==========================================");
|
|
1160
|
-
log.info(`Shielded Address: ${shieldedAddress}`);
|
|
1161
|
-
log.info(`Unshielded Address: ${walletResult.unshieldedAddress}`);
|
|
1162
|
-
log.info(`Dust Address: ${walletResult.dustAddress}`);
|
|
1163
|
-
log.info("==========================================");
|
|
1164
|
-
|
|
1165
|
-
if (parsedArgs.balance) {
|
|
1166
|
-
log.info("==========================================");
|
|
1167
|
-
log.info("Fetching Balances...");
|
|
1168
|
-
log.info("==========================================");
|
|
1169
|
-
|
|
1170
|
-
let shieldedBalance = 0n;
|
|
1171
|
-
let unshieldedBalance = 0n;
|
|
1172
|
-
let dustBalance = 0n;
|
|
1173
|
-
|
|
1174
|
-
const tokenId = shieldedToken().tag;
|
|
1175
|
-
shieldedBalance = initialState.balances[tokenId] ?? 0n;
|
|
1176
|
-
|
|
1177
|
-
const syncTimeoutMs = resolveWalletSyncTimeoutMs();
|
|
1178
|
-
|
|
1179
|
-
if (shieldedBalance === 0n) {
|
|
1180
|
-
log.info("Shielded balance is 0. Waiting for wallet sync to confirm funds...");
|
|
1181
|
-
try {
|
|
1182
|
-
const synced = await syncAndWaitForFunds(walletResult.wallet);
|
|
1183
|
-
shieldedBalance = synced.shieldedBalance;
|
|
1184
|
-
unshieldedBalance = synced.unshieldedBalance;
|
|
1185
|
-
dustBalance = synced.dustBalance;
|
|
1186
|
-
} catch (e) {
|
|
1187
|
-
log.warn(`Sync timed out or failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
1188
|
-
}
|
|
1189
|
-
} else {
|
|
1190
|
-
try {
|
|
1191
|
-
const unshieldedState = await getInitialUnshieldedState((walletResult.wallet as any).unshielded);
|
|
1192
|
-
const uBalances = (unshieldedState?.balances ?? {}) as Record<string, bigint>;
|
|
1193
|
-
unshieldedBalance = Object.values(uBalances).reduce(
|
|
1194
|
-
(acc: bigint, v) => acc + (v ?? 0n),
|
|
1195
|
-
0n
|
|
1196
|
-
);
|
|
1197
|
-
} catch(_e) { /* ignore */ }
|
|
1198
|
-
|
|
1199
|
-
try {
|
|
1200
|
-
const state = await Rx.firstValueFrom(walletResult.wallet.state());
|
|
1201
|
-
dustBalance = resolveFacadeDustBalance(state, new Date());
|
|
1202
|
-
|
|
1203
|
-
if (dustBalance === 0n) {
|
|
1204
|
-
log.info("Dust balance is 0. Attempting to sync dust wallet...");
|
|
1205
|
-
try {
|
|
1206
|
-
dustBalance = await waitForDustFunds(walletResult.wallet, { timeoutMs: syncTimeoutMs });
|
|
1207
|
-
} catch(_e) {
|
|
1208
|
-
log.warn("Dust sync timed out or returned no funds.");
|
|
1209
|
-
}
|
|
1210
|
-
}
|
|
1211
|
-
|
|
1212
|
-
if (dustBalance === 0n && unshieldedBalance > 0n) {
|
|
1213
|
-
log.info("Dust is 0 but unshielded funds available. Registering for dust generation...");
|
|
1214
|
-
const success = await registerNightForDust(walletResult);
|
|
1215
|
-
if (success) {
|
|
1216
|
-
dustBalance = await waitForDustFunds(walletResult.wallet, { timeoutMs: 30000 });
|
|
1217
|
-
}
|
|
1218
|
-
}
|
|
1219
|
-
} catch (_e) {
|
|
1220
|
-
// ignore
|
|
1221
|
-
}
|
|
1222
|
-
}
|
|
1223
|
-
|
|
1224
|
-
log.info("==========================================");
|
|
1225
|
-
log.info("Balances");
|
|
1226
|
-
log.info("==========================================");
|
|
1227
|
-
log.info(`Shielded Balance: ${shieldedBalance} NIGHT`);
|
|
1228
|
-
log.info(`Dust Balance: ${dustBalance} DUST`);
|
|
1229
|
-
log.info(`Unshielded Balance: ${unshieldedBalance} NIGHT`);
|
|
1230
|
-
}
|
|
1231
|
-
|
|
1232
|
-
log.info("==========================================");
|
|
1233
|
-
|
|
1234
|
-
await walletResult.wallet.stop();
|
|
1235
|
-
} catch (error) {
|
|
1236
|
-
log.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
1237
|
-
exit(1);
|
|
1238
|
-
}
|
|
1239
|
-
}
|
|
1240
|
-
|
|
1241
|
-
if (import.meta.main) {
|
|
1242
|
-
main();
|
|
1243
|
-
}
|