midnight-wallet-cli 0.6.0-rc.2 → 0.6.0-rc.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/mcp-server.js +459 -456
- package/dist/wallet.js +535 -523
- package/package.json +1 -1
package/dist/mcp-server.js
CHANGED
|
@@ -1,73 +1,73 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{createRequire as
|
|
2
|
+
import{createRequire as Xu}from"node:module";var qu=Object.defineProperty;var zu=(e)=>e;function Yu(e,t){this[e]=zu.bind(null,t)}var he=(e,t)=>{for(var r in t)qu(e,r,{get:t[r],enumerable:!0,configurable:!0,set:Yu.bind(t,r)})};var T=(e,t,r)=>()=>{if(e)try{t=e(e=0)}catch(n){r=[n]}if(r)throw r[0];return t};var ii=Xu(import.meta.url);function x(e,t){let r=e.flags[t];if(r===void 0||r===!0)return;return r}function R(e,t){return t in e.flags}function je(e){return R(e,"verbose")}function pt(e){return R(e,on)&&!R(e,Sr)}function jt(e){if(R(e,"no-cache"))throw Error(`--no-cache is not supported on write commands (transfer, airdrop, dust register, serve).
|
|
3
3
|
`+`Writes always use the cache — the SDK's fresh-sync is too slow on hosted networks.
|
|
4
|
-
`+"To reset: midnight cache clear --wallet <name> --network <name>")}function
|
|
5
|
-
`;if(
|
|
6
|
-
`,{mode:
|
|
7
|
-
Valid keys: ${
|
|
8
|
-
Valid networks: preprod, preview, undeployed`);
|
|
9
|
-
Wallet name must be a simple name (no path separators, .json suffix, or special characters).`);
|
|
10
|
-
Must start with http://, https://, ws://, or wss://`);let
|
|
11
|
-
Valid keys: ${
|
|
12
|
-
Valid keys: ${
|
|
13
|
-
`)){if(!n)continue;let[s="",o=""]=n.split("|"),i=(a)=>[...o.matchAll(new RegExp(`:(\\d+)->${a}/tcp`,"g"))].map((c)=>parseInt(c[1],10));if(s.includes("indexer"))i(8088).forEach((a)=>t.indexer.add(a));if(s.includes("midnight-node"))i(9944).forEach((a)=>t.node.add(a));if(s.includes("proof-server"))i(6300).forEach((a)=>t.proofServer.add(a))}let r=(n)=>[...n].sort((s,o)=>s-o);return{node:r(t.node),indexer:r(t.indexer),proofServer:r(t.proofServer)}}function
|
|
14
|
-
Pick one per command: --node ws://localhost:<port> --indexer-ws ws://localhost:<port>${
|
|
4
|
+
`+"To reset: midnight cache clear --wallet <name> --network <name>")}function an(e,t,r){let n=x(e,t);if(n===void 0)throw Error(`Missing required flag: --${t} <${r}>`);return n}var on="_minimal",Sr="_full";function gs(e){ms=e}function D(e){let t=JSON.stringify(e)+`
|
|
5
|
+
`;if(ms)ms(t);else process.stdout.write(t)}var ms=null;function ai(e){return e instanceof U}var U;var Oe=T(()=>{U=class U extends Error{constructor(e){super(e);this.name="UsageError",Object.setPrototypeOf(this,U.prototype)}}});function Ct(e){if(!e||e!==e.trim())return!1;if(/[\/\\]/.test(e))return!1;if(e.endsWith(".json"))return!1;if(e==="."||e==="..")return!1;if(/[\x00-\x1f]/.test(e))return!1;return!0}var rt="0000000000000000000000000000000000000000000000000000000000000001",br="0000000000000000000000000000000000000000000000000000000000000000",vr="/api/v4/graphql",Gt="/api/v4/graphql/ws",ys=6,Ss=1e6,pi=300000000000000n,fi=5,kr=900000000000000n,mi=5000000000n,gi=8267n,hi=10800n,wi=300000,ln=30000,yi=1e4,bs=120000,un=300000,vs=60000,Si=16384,bi=0.7,vi=512,pn=10,ki=3,xi=600000,ks=15000,Ci=115,ie=".midnight",fn="wallet.json",Ei="config.json",Te=448,Ne=384,xs="localnet",Cs=2,Me="cache",mn="wallets",Es="default",xr=10,As=3000,Ai=120000,Cr=9932,gn="https://midnight-comp-tracker.vercel.app";import*as nt from"fs";import*as Ns from"path";import{homedir as pp}from"os";function Rs(e){return fp[e]??e}function mp(e){return/^(https?|wss?):\/\/\S+/.test(e)}function Ri(e){return e??Ns.join(pp(),ie)}function Di(e){return Ns.join(Ri(e),Ei)}function gp(e){let t=Ri(e);if(!nt.existsSync(t))nt.mkdirSync(t,{recursive:!0,mode:Te})}function Ie(e){let t=Di(e);if(!nt.existsSync(t))return{...Er};let r;try{r=nt.readFileSync(t,"utf-8")}catch{return{...Er}}let n;try{n=JSON.parse(r)}catch{return{...Er}}let s={network:n.network&&be(n.network)?n.network:Er.network};if(n["proof-server"]&&typeof n["proof-server"]==="string")s["proof-server"]=n["proof-server"];if(n.node&&typeof n.node==="string")s.node=n.node;if(n["indexer-ws"]&&typeof n["indexer-ws"]==="string")s["indexer-ws"]=n["indexer-ws"];if(n.wallet&&typeof n.wallet==="string")s.wallet=n.wallet;if(n.networks&&typeof n.networks==="object"){let o={};for(let[i,a]of Object.entries(n.networks)){if(!be(i)||!a||typeof a!=="object")continue;let c={};for(let d of Et){let u=a[d];if(u&&typeof u==="string")c[d]=u}if(Object.keys(c).length>0)o[i]=c}if(Object.keys(o).length>0)s.networks=o}return s}function Ar(e,t){let r=e.networks?.[t]??{},n=t===e.network;return{"proof-server":r["proof-server"]??(n?e["proof-server"]:void 0),node:r.node??(n?e.node:void 0),"indexer-ws":r["indexer-ws"]??(n?e["indexer-ws"]:void 0)}}function wn(e,t){gp(t);let r=Di(t);nt.writeFileSync(r,JSON.stringify(e,null,2)+`
|
|
6
|
+
`,{mode:Ne})}function Ii(e,t,r){let n=Rs(e),s=Ie(t);if(Ds(n,r),n==="network")return s.network;if(n==="wallet")return s.wallet??"(not set)";if(Et.has(n)){let i=Ar(s,r??s.network)[n];return typeof i==="string"?i:"(not set)"}throw Error(`Unknown config key: "${e}"
|
|
7
|
+
Valid keys: ${hn.join(", ")}`)}function hp(e,t){let r={...e.networks?.[t]??{}},n=!1;for(let s of Et){let o=s,i=e[o];if(i&&typeof i==="string"){if(!r[o])r[o]=i;delete e[o],n=!0}}if(n)e.networks={...e.networks??{},[t]:r}}function $i(e,t,r,n){let s=Rs(e),o=Ie(r);if(Ds(s,n),s==="network"){if(!be(t))throw Error(`Invalid network: "${t}"
|
|
8
|
+
Valid networks: preprod, preview, undeployed`);hp(o,o.network),o.network=t}else if(s==="wallet"){if(!Ct(t))throw Error(`Invalid wallet name: "${t}"
|
|
9
|
+
Wallet name must be a simple name (no path separators, .json suffix, or special characters).`);o.wallet=t}else if(Et.has(s)){if(!mp(t))throw Error(`Invalid URL for "${e}": "${t}"
|
|
10
|
+
Must start with http://, https://, ws://, or wss://`);let i=s,a=n??o.network,c={...o.networks?.[a]??{}};if(c[i]=t,o.networks={...o.networks??{},[a]:c},a===o.network)delete o[i]}else throw Error(`Unknown config key: "${e}"
|
|
11
|
+
Valid keys: ${hn.join(", ")}`);wn(o,r)}function Pi(e,t,r){let n=Rs(e),s=Ie(t);if(Ds(n,r),n==="network")s.network=Er.network;else if(n==="wallet")delete s.wallet;else if(Et.has(n)){let o=n,i=r??s.network;if(i===s.network)delete s[o];let a=s.networks?.[i];if(a){if(delete a[o],Object.keys(a).length===0){if(delete s.networks[i],Object.keys(s.networks).length===0)delete s.networks}}}else throw Error(`Unknown config key: "${e}"
|
|
12
|
+
Valid keys: ${hn.join(", ")}`);wn(s,t)}function Ds(e,t){if(t!==void 0&&!Et.has(e))throw new U(`--network only applies to the endpoint keys (${[...Et].join(", ")}), not "${e}".`)}function Is(){return hn}var Er,hn,fp,Et;var Kt=T(()=>{me();Oe();Er={network:"undeployed"},hn=["network","proof-server","node","indexer-ws","wallet"],fp={"network-id":"network"};Et=new Set(["proof-server","node","indexer-ws"])});import{execSync as wp}from"child_process";import{ProtocolVersion as yp}from"@midnightntwrk/wallet-sdk";function be(e){return _i.includes(e)}function Tr(e){return{...Sp[e]}}function Nr(){return _i}function bp(e){let t={node:new Set,indexer:new Set,proofServer:new Set};for(let n of e.split(`
|
|
13
|
+
`)){if(!n)continue;let[s="",o=""]=n.split("|"),i=(a)=>[...o.matchAll(new RegExp(`:(\\d+)->${a}/tcp`,"g"))].map((c)=>parseInt(c[1],10));if(s.includes("indexer"))i(8088).forEach((a)=>t.indexer.add(a));if(s.includes("midnight-node"))i(9944).forEach((a)=>t.node.add(a));if(s.includes("proof-server"))i(6300).forEach((a)=>t.proofServer.add(a))}let r=(n)=>[...n].sort((s,o)=>s-o);return{node:r(t.node),indexer:r(t.indexer),proofServer:r(t.proofServer)}}function kp(e,t=vp){if(t.node&&e.node.length>1||t.indexer&&e.indexer.length>1||t.proofServer&&e.proofServer.length>1)throw new Oi(e);return{nodePort:t.node?e.node[0]:void 0,indexerPort:t.indexer?e.indexer[0]:void 0,proofServerPort:t.proofServer?e.proofServer[0]:void 0}}function xp(){if(process.env.MN_NO_LOCAL_DETECT==="1")return{node:[],indexer:[],proofServer:[]};try{return bp(wp('docker ps --format "{{.Image}}|{{.Ports}}"',{encoding:"utf-8",timeout:5000}))}catch{return{node:[],indexer:[],proofServer:[]}}}function Mi(e,t={}){let r=Tr(e),n=t.given??{},s={node:n.node===void 0,indexer:n.indexerWS===void 0,proofServer:n.proofServer===void 0};if(e==="undeployed"&&(s.node||s.indexer||s.proofServer)){let o=kp((t.detect??xp)(),s);if(o.indexerPort)r.indexer=`http://localhost:${o.indexerPort}${vr}`,r.indexerWS=`ws://localhost:${o.indexerPort}${Gt}`;if(o.nodePort)r.node=`ws://localhost:${o.nodePort}`;if(o.proofServerPort)r.proofServer=`http://localhost:${o.proofServerPort}`}if(n.node!==void 0)r.node=n.node;if(n.proofServer!==void 0)r.proofServer=n.proofServer;if(n.indexerWS!==void 0)r.indexerWS=n.indexerWS,r.indexer=Fi(n.indexerWS);return r}function Fi(e){return e.replace(/^wss:/,"https:").replace(/^ws:/,"http:").replace(/\/ws$/,"")}function yn(e){let t={};if(e.node!==void 0)t.node=e.node;if(e.indexerWS!==void 0)t["indexer-ws"]=e.indexerWS;if(e.proofServer!==void 0)t["proof-server"]=e.proofServer;return t}function $e(e,t,r,n){let s=Ie(n),o=Ar(s,r);if(e.proofServer=t.proofServer??o["proof-server"]??e.proofServer,e.node=t.node??o.node??e.node,e.indexerWS=t.indexerWS??o["indexer-ws"]??e.indexerWS,t.indexerWS??o["indexer-ws"])e.indexer=Fi(e.indexerWS);return e}var st,Sp,_i,Oi,vp;var me=T(()=>{Kt();st=yp.V9NativeForkSchedule,Sp={preprod:{indexer:`https://indexer.preprod.midnight.network${vr}`,indexerWS:`wss://indexer.preprod.midnight.network${Gt}`,node:"wss://rpc.preprod.midnight.network",proofServer:"http://localhost:6300",networkId:"PreProd"},preview:{indexer:`https://indexer.preview.midnight.network${vr}`,indexerWS:`wss://indexer.preview.midnight.network${Gt}`,node:"wss://rpc.preview.midnight.network",proofServer:"http://localhost:6300",networkId:"Preview"},undeployed:{indexer:`http://localhost:8088${vr}`,indexerWS:`ws://localhost:8088${Gt}`,node:"ws://localhost:9944",proofServer:"http://localhost:6300",networkId:"Undeployed"}},_i=["preprod","preview","undeployed"];Oi=class Oi extends Error{code="AMBIGUOUS_LOCAL_STACKS";constructor(e){super(`Several local Midnight stacks are running (node ${e.node.join(", ")}; indexer ${e.indexer.join(", ")}; proof-server ${e.proofServer.join(", ")}), and mn won't guess which one to use.
|
|
14
|
+
Pick one per command: --node ws://localhost:<port> --indexer-ws ws://localhost:<port>${Gt} --proof-server http://localhost:<port>
|
|
15
15
|
or once: midnight config set network undeployed, then midnight config set node / indexer-ws / proof-server <url>
|
|
16
|
-
Commands without endpoint flags (cache, test, dev) use the saved config. MN_NO_LOCAL_DETECT=1 turns detection off.`);this.name="AmbiguousLocalStacksError"}};
|
|
17
|
-
Valid networks: ${
|
|
18
|
-
`,{mode:
|
|
19
|
-
Wallet name must be a simple name (no path separators, .json suffix, or special characters).`);let t=
|
|
20
|
-
Run "midnight wallet list" to see available wallets.`);let r=Ie();r.wallet=e,
|
|
21
|
-
Wallet name must be a simple name (no path separators, .json suffix, or special characters).`);let t=
|
|
22
|
-
Run "midnight wallet list" to see available wallets.`);let n=
|
|
23
|
-
Switch to another wallet first: midnight wallet use <other-wallet>`);if(
|
|
24
|
-
`+"Create another wallet first: midnight wallet generate <name>");
|
|
25
|
-
Generate a wallet first: midnight wallet generate <name> --network <name>`);let r;try{r=
|
|
26
|
-
${c.message}`)}let n;try{n=JSON.parse(r)}catch{throw Error(`Invalid JSON in wallet file: ${t}`)}if(!n.seed||!n.createdAt){let c=["seed","createdAt"];if(!n.addresses)c.push("address");let d=c.filter((u)=>!n[u]);if(d.length>0)throw Error(`Wallet file is missing required fields (${d.join(", ")}): ${t}`)}if(!/^[0-9a-fA-F]+$/.test(n.seed))throw Error(`Invalid seed format in wallet file (expected hex string): ${t}`);if(!n.addresses){if(!n.address)throw Error(`Wallet file is missing required fields (address): ${t}`);let c=Buffer.from(n.seed,"hex"),d=
|
|
27
|
-
`,{mode:
|
|
28
|
-
`,{mode:
|
|
29
|
-
`,{mode:
|
|
16
|
+
Commands without endpoint flags (cache, test, dev) use the saved config. MN_NO_LOCAL_DETECT=1 turns detection off.`);this.name="AmbiguousLocalStacksError"}};vp={node:!0,indexer:!0,proofServer:!0}});import{HDWallet as Cp,Roles as $s}from"@midnightntwrk/wallet-sdk/hd";function Ps(e,t){let r=Cp.fromSeed(e);if(r.type!=="seedOk")throw Error("Invalid seed for HD wallet");let n=r.hdWallet.selectAccount(0).selectRole(t).deriveKeyAt(0);if(n.type==="keyOutOfBounds")throw Error("Key derivation out of bounds");return n.key}function At(e){return Ps(e,$s.Zswap)}function Li(e){return Ps(e,$s.NightExternal)}function ft(e){return Ps(e,$s.Dust)}var Tt=()=>{};import{NetworkId as Vt}from"@midnightntwrk/wallet-sdk";function Fe(e){let t=Ep[e];if(t===void 0)throw Error(`Unknown networkId: ${e}`);return t}function _s(e){return Ap[e]}var Ep,Ap;var mt=T(()=>{Ep={PreProd:Vt.NetworkId.PreProd,Preview:Vt.NetworkId.Preview,Undeployed:Vt.NetworkId.Undeployed},Ap={preprod:Vt.NetworkId.PreProd,preview:Vt.NetworkId.Preview,undeployed:Vt.NetworkId.Undeployed}});import{HDWallet as Tp,Roles as Np}from"@midnightntwrk/wallet-sdk/hd";import{createKeystore as Rp,PublicKey as Dp}from"@midnightntwrk/wallet-sdk/unshielded";import{MidnightBech32m as Ip,ShieldedAddress as $p,ShieldedCoinPublicKey as Pp,ShieldedEncryptionPublicKey as _p}from"@midnightntwrk/wallet-sdk/address-format";import*as Ui from"@midnightntwrk/ledger-v9";function ve(e,t,r=0){let n=_s(t),s=Tp.fromSeed(e);if(s.type!=="seedOk")throw Error("Invalid seed for HD wallet");let o=s.hdWallet.selectAccount(0).selectRole(Np.NightExternal).deriveKeyAt(r);if(o.type==="keyOutOfBounds")throw Error(`Key index ${r} out of bounds`);let i=Rp({kind:"schnorr",secret:o.key},n);return Dp.fromKeyStore(i).address}function Nt(e,t=0){let r={};for(let n of Nr())r[n]=ve(e,n,t);return r}function Rr(e){let t=Dr(e),r={};for(let n of Nr()){let s=_s(n);r[n]=Ip.encode(s,t).asString()}return r}function Dr(e){let t=At(e),r=Ui.ZswapSecretKeys.fromSeed(t);return new $p(new Pp(Buffer.from(r.coinPublicKey,"hex")),new _p(Buffer.from(r.encryptionPublicKey,"hex")))}var He=T(()=>{me();Tt();mt()});function we(e){let t=x(e.args,"network");if(t!==void 0){if(!be(t))throw Error(`Invalid network: "${t}"
|
|
17
|
+
Valid networks: ${Nr().join(", ")}`);return t}let r=Ie(e.configDir);if(r.network&&be(r.network))return r.network;return"undeployed"}function le(e){let t=we(e),r=Ar(Ie(e.configDir),t),n={node:x(e.args,"node")??r.node,indexerWS:x(e.args,"indexer-ws")??r["indexer-ws"],proofServer:x(e.args,"proof-server")??r["proof-server"]},s=Mi(t,{given:n});return{name:t,config:s}}var ke=T(()=>{me();Kt()});import*as Q from"fs";import*as xe from"path";import{homedir as Op}from"os";function Jt(e,t,r){let n=xe.resolve(e);if(!Q.existsSync(n))return;try{let s=JSON.parse(Q.readFileSync(n,"utf-8")),o=s.shieldedAddresses&&typeof s.shieldedAddresses==="object"?s.shieldedAddresses:{};if(o[t]=r,s.shieldedAddresses=o,s.shieldedAddress&&s.shieldedAddress===r)delete s.shieldedAddress;Q.writeFileSync(n,JSON.stringify(s,null,2)+`
|
|
18
|
+
`,{mode:Ne})}catch{}}function Os(){return xe.join(Op(),ie)}function Ir(){return xe.join(Os(),mn)}function Bi(){return xe.join(Os(),fn)}function Mp(){let e=Os();if(!Q.existsSync(e))Q.mkdirSync(e,{recursive:!0,mode:Te})}function Fp(e){return e.includes("/")||e.includes("\\")||e.endsWith(".json")}function re(e){if(e!==void 0){if(Fp(e))return xe.resolve(e);return xe.join(Ir(),`${e}.json`)}let r=Ie().wallet??Es;return xe.join(Ir(),`${r}.json`)}function qt(){return Ie().wallet??Es}function Ms(e){if(!Ct(e))throw Error(`Invalid wallet name: "${e}"
|
|
19
|
+
Wallet name must be a simple name (no path separators, .json suffix, or special characters).`);let t=xe.join(Ir(),`${e}.json`);if(!Q.existsSync(t))throw Error(`Wallet "${e}" not found.
|
|
20
|
+
Run "midnight wallet list" to see available wallets.`);let r=Ie();r.wallet=e,wn(r)}function Fs(){let e=Ir();if(!Q.existsSync(e))return[];let t=qt();return Q.readdirSync(e).filter((n)=>n.endsWith(".json")).sort().map((n)=>{let s=n.replace(/\.json$/,""),o=xe.join(e,n);try{let i=JSON.parse(Q.readFileSync(o,"utf-8")),a;if(i.addresses)a=i.addresses;else if(i.address&&i.seed)try{let d=Buffer.from(i.seed,"hex");a=Nt(d)}catch{a={undeployed:i.address,preprod:"(unknown)",preview:"(unknown)"}}else a={undeployed:"(unknown)",preprod:"(unknown)",preview:"(unknown)"};let c;if(i.shieldedAddresses&&typeof i.shieldedAddresses==="object")c=i.shieldedAddresses;else if(i.seed)try{c=Rr(Buffer.from(i.seed,"hex"))}catch{}return{name:s,addresses:a,shieldedAddresses:c,isActive:s===t,createdAt:typeof i.createdAt==="string"?i.createdAt:void 0,file:o}}catch{return{name:s,addresses:{undeployed:"(invalid)",preprod:"(invalid)",preview:"(invalid)"},isActive:s===t,file:o}}})}function Lp(e,t){for(let r of e){for(let[n,s]of Object.entries(r.addresses))if(s===t)return{wallet:r,network:n};if(r.shieldedAddresses){for(let[n,s]of Object.entries(r.shieldedAddresses))if(s===t)return{wallet:r,network:n}}}return}function ji(e){return Lp(Fs(),e)}function Hi(e){if(!Ct(e))throw Error(`Invalid wallet name: "${e}"
|
|
21
|
+
Wallet name must be a simple name (no path separators, .json suffix, or special characters).`);let t=Ir(),r=xe.join(t,`${e}.json`);if(!Q.existsSync(r))throw Error(`Wallet "${e}" not found.
|
|
22
|
+
Run "midnight wallet list" to see available wallets.`);let n=qt();if(e===n)throw Error(`Cannot remove the active wallet "${e}".
|
|
23
|
+
Switch to another wallet first: midnight wallet use <other-wallet>`);if(Q.readdirSync(t).filter((o)=>o.endsWith(".json")).length<=1)throw Error(`Cannot remove "${e}" — it is the only wallet.
|
|
24
|
+
`+"Create another wallet first: midnight wallet generate <name>");Q.unlinkSync(r)}function ae(e){let t=e?xe.resolve(e):Bi();if(!Q.existsSync(t))throw Error(`Wallet file not found: ${t}
|
|
25
|
+
Generate a wallet first: midnight wallet generate <name> --network <name>`);let r;try{r=Q.readFileSync(t,"utf-8")}catch(c){throw Error(`Failed to read wallet file: ${t}
|
|
26
|
+
${c.message}`)}let n;try{n=JSON.parse(r)}catch{throw Error(`Invalid JSON in wallet file: ${t}`)}if(!n.seed||!n.createdAt){let c=["seed","createdAt"];if(!n.addresses)c.push("address");let d=c.filter((u)=>!n[u]);if(d.length>0)throw Error(`Wallet file is missing required fields (${d.join(", ")}): ${t}`)}if(!/^[0-9a-fA-F]+$/.test(n.seed))throw Error(`Invalid seed format in wallet file (expected hex string): ${t}`);if(!n.addresses){if(!n.address)throw Error(`Wallet file is missing required fields (address): ${t}`);let c=Buffer.from(n.seed,"hex"),d=Nt(c),u={seed:n.seed,addresses:d,createdAt:n.createdAt};if(n.mnemonic)u.mnemonic=n.mnemonic;let l=Wi(n,c);if(l)u.shieldedAddresses=l;let f={...n,addresses:d};if(l)f.shieldedAddresses=l,delete f.shieldedAddress;return Q.writeFileSync(t,JSON.stringify(f,null,2)+`
|
|
27
|
+
`,{mode:Ne}),u}if(typeof n.addresses!=="object")throw Error(`Wallet file has invalid addresses field: ${t}`);let s={seed:n.seed,addresses:n.addresses,createdAt:n.createdAt};if(n.mnemonic)s.mnemonic=n.mnemonic;let o=Buffer.from(n.seed,"hex"),i=Wi(n,o);if(i)s.shieldedAddresses=i;if(i&&(!n.shieldedAddresses||typeof n.shieldedAddresses!=="object"||Object.keys(n.shieldedAddresses).length<Object.keys(i).length))try{let c={...n,shieldedAddresses:i};delete c.shieldedAddress,Q.writeFileSync(t,JSON.stringify(c,null,2)+`
|
|
28
|
+
`,{mode:Ne})}catch{}return s}function Wi(e,t){let r;try{r=Rr(t)}catch{}let n=e.shieldedAddresses,s=n&&typeof n==="object"?n:null,o=s?Object.fromEntries(Object.entries(s).filter(([,i])=>typeof i==="string"&&i.length>0)):{};if(!r)return Object.keys(o).length>0?o:void 0;return{...r,...o}}function Sn(e,t){let r=t?xe.resolve(t):Bi();if(!t)Mp();else{let n=xe.dirname(r);if(!Q.existsSync(n))Q.mkdirSync(n,{recursive:!0,mode:Te})}return Q.writeFileSync(r,JSON.stringify(e,null,2)+`
|
|
29
|
+
`,{mode:Ne}),r}var Le=T(()=>{Kt();He()});function $r(e,t){let r=e.trim().replace(/^0x/,"");if(r.length!==64&&r.length!==128||!/^[0-9a-fA-F]+$/.test(r))throw new U(`${t} must be 64 or 128 hex characters (a 32-byte seed, or a 64-byte BIP-39 seed)`);return Buffer.from(r,"hex")}function Ls(e,t={}){let r=x(e,"seed"),n=r??process.env.MN_SEED;if(n)return{seed:$r(n,r?"--seed":"MN_SEED"),walletPath:null,config:null};let s=x(e,"wallet");if(s===void 0&&t.requireExplicit)throw new U(`${t.label??"This command"} needs a seed source. Provide one of:
|
|
30
30
|
--seed <hex> seed as 64 hex chars (32-byte) or 128 (64-byte BIP-39)
|
|
31
31
|
MN_SEED=<hex> same seed via env (kept off the process list)
|
|
32
|
-
--wallet <name> derive from a saved wallet`);let o=re(s),i=
|
|
33
|
-
`);for(let p of f)o.push(...
|
|
34
|
-
`)}function
|
|
35
|
-
`)}var
|
|
36
|
-
Use --force to overwrite, or --output <file> to save to a different path.`);let c,d;if(o!==void 0)c
|
|
32
|
+
--wallet <name> derive from a saved wallet`);let o=re(s),i=ae(o);return{seed:Buffer.from(i.seed,"hex"),walletPath:o,config:i}}function bn(e,t){return Ls(e,t).seed}var zt=T(()=>{Oe();Le()});function Pr(){return!("NO_COLOR"in process.env)}function _r(e,t){if(!Pr())return e;return`\x1B[38;5;${t}m${e}\x1B[0m`}function P(e){if(!Pr())return e;return`\x1B[1m${e}\x1B[0m`}function g(e){if(!Pr())return e;return`\x1B[2m${e}\x1B[0m`}function G(e){return _r(e,38)}function ce(e){return _r(e,196)}function W(e){return _r(e,40)}function Z(e){return _r(e,226)}function Or(e){return _r(e,245)}function B(e,t=Ki){let r=` ${e} `,n=t-r.length;if(n<=0)return P(r);let s=Math.floor(n/2),o=n-s;return P("═".repeat(s)+r+"═".repeat(o))}function J(e=Ki){return g("─".repeat(e))}function C(e,t,r=16){let n=(e+":").padEnd(r);return` ${Or(n)}${t}`}function Rt(e){let t=e<0n,r=t?-e:e,n=BigInt(10**ys),s=r/n,i=(r%n).toString().padStart(ys,"0");return`${t?"-":""}${s}.${i}`}function vn(e){return`${Rt(e)} NIGHT`}function de(e){let t=e<0n,r=t?-e:e,n=10n**BigInt(Gi),s=r/n,a=(r%n).toString().padStart(Gi,"0").replace(/0+$/,"").padEnd(6,"0");return`${t?"-":""}${s}.${a}`}function Mr(e){return`${de(e)} DUST`}function ee(e,t=!1){let r=t&&e.length>20?e.slice(0,10)+"…"+e.slice(-8):e;return G(r)}function Up(e,t){let r=[],n="",s=0,o=!1,i=0;while(i<e.length){let a=/^\x1b\[[0-9;]*m/.exec(e.slice(i));if(a){n+=a[0],o=!0,i+=a[0].length;continue}if(s===t)r.push(o?n+"\x1B[0m":n),n="",s=0,o=!1;n+=e[i],s+=1,i+=1}if(n.length>0)r.push(o?n+"\x1B[0m":n);return r}function Wp(e,t){if(Yt(e).length<=t)return[e];let n=e.split(/(\s+)/).flatMap((a)=>Yt(a).length>t?Up(a,t):[a]),s=[],o="",i=0;for(let a of n){let c=Yt(a).length;if(i+c>t&&i>0)s.push(o),o=a.trimStart(),i=Yt(o).length;else o+=a,i+=c}if(o.length>0)s.push(o);return s}function Vi(e,t="light",r=70){let n=t==="heavy"?{tl:"╔",tr:"╗",bl:"╚",br:"╝",h:"═",v:"║"}:{tl:"┌",tr:"┐",bl:"└",br:"┘",h:"─",v:"│"},s=r-4,o=[];for(let l of e){let f=l.split(`
|
|
33
|
+
`);for(let p of f)o.push(...Wp(p,s))}let i=Math.max(...o.map((l)=>Yt(l).length)),a=Math.max(i+2,20),c=n.tl+n.h.repeat(a)+n.tr,d=n.bl+n.h.repeat(a)+n.br,u=o.map((l)=>{let f=Yt(l).length,p=a-f-2;return`${n.v} ${l}${" ".repeat(Math.max(0,p))} ${n.v}`});return[c,...u,d].join(`
|
|
34
|
+
`)}function gt(e,t){let n=[`${W("✓")} ${e}`];if(t)n.push(C("Transaction",G(t)));return n.join(`
|
|
35
|
+
`)}var Ki=60,Gi=15,Yt=(e)=>e.replace(/\x1b\[[0-9;]*m/g,"");var ue=()=>{};var Xi={};he(Xi,{default:()=>Yi});import*as zi from"fs";import*as kn from"path";import{homedir as Bp}from"os";import{generateMnemonic as jp,mnemonicToSeedSync as Ji,validateMnemonic as Hp}from"@scure/bip39";import{wordlist as qi}from"@scure/bip39/wordlists/english.js";async function Yi(e){let t=we({args:e}),r=x(e,"output"),n=x(e,"seed"),s=process.env.MN_SEED?.trim(),o=n??(s?s:void 0),i=x(e,"mnemonic");if(o!==void 0&&i!==void 0)throw Error("Cannot specify both --seed and --mnemonic. Use one or the other.");let a=r?kn.resolve(r):kn.join(Bp(),ie,fn);if(zi.existsSync(a)&&!R(e,"force"))throw Error(`Wallet file already exists: ${a}
|
|
36
|
+
Use --force to overwrite, or --output <file> to save to a different path.`);let c,d;if(o!==void 0)c=$r(o,n!==void 0?"--seed":"MN_SEED");else if(i!==void 0){if(!Hp(i,qi))throw Error("Invalid BIP-39 mnemonic. Expected 12 or 24 words from the English wordlist.");d=i,c=Buffer.from(Ji(d))}else d=jp(qi,256),c=Buffer.from(Ji(d));let u=Nt(c),l=u[t],f={seed:c.toString("hex"),addresses:u,createdAt:new Date().toISOString()};if(d)f.mnemonic=d;let p=Sn(f,r);if(R(e,"json")){let m={addresses:u,activeAddress:l,activeNetwork:t,seed:c.toString("hex"),file:p,createdAt:f.createdAt};if(d)m.mnemonic=d;D(m);return}if(process.stdout.write(l+`
|
|
37
37
|
`),process.stderr.write(`
|
|
38
|
-
`+
|
|
38
|
+
`+B("Wallet Generated")+`
|
|
39
39
|
|
|
40
|
-
`),process.stderr.write(
|
|
41
|
-
`),process.stderr.write(
|
|
42
|
-
`),process.stderr.write(
|
|
40
|
+
`),process.stderr.write(C("Network",t)+`
|
|
41
|
+
`),process.stderr.write(C("Address",ee(l))+`
|
|
42
|
+
`),process.stderr.write(C("File",p)+`
|
|
43
43
|
`),process.stderr.write(`
|
|
44
|
-
`),d)process.stderr.write(
|
|
44
|
+
`),d)process.stderr.write(Z(P(" MNEMONIC (save securely!):"))+`
|
|
45
45
|
`),process.stderr.write(` ${d}
|
|
46
46
|
|
|
47
|
-
`);process.stderr.write(
|
|
47
|
+
`);process.stderr.write(Z(P(" SEED (hex):"))+`
|
|
48
48
|
`),process.stderr.write(` ${c.toString("hex")}
|
|
49
49
|
|
|
50
|
-
`),process.stderr.write(
|
|
50
|
+
`),process.stderr.write(J()+`
|
|
51
51
|
`),process.stderr.write(g(" Next: midnight info | midnight balance")+`
|
|
52
52
|
|
|
53
|
-
`),process.stderr.write(
|
|
54
|
-
`)}var
|
|
53
|
+
`),process.stderr.write(W("✓")+` Wallet saved
|
|
54
|
+
`)}var Zi=T(()=>{He();ke();Le();zt();ue()});var ea={};he(ea,{default:()=>Qi});async function Qi(e){let t=re(x(e,"wallet")),r=ae(t),n=we({args:e}),s=r.addresses[n];if(R(e,"json")){let i={addresses:r.addresses,activeNetwork:n,activeAddress:s,createdAt:r.createdAt,file:t};if(r.shieldedAddresses)i.shieldedAddresses=r.shieldedAddresses;D(i);return}process.stdout.write(s+`
|
|
55
55
|
`),process.stderr.write(`
|
|
56
|
-
`+
|
|
56
|
+
`+B("Wallet Info")+`
|
|
57
57
|
|
|
58
|
-
`);let o=Object.keys(r.addresses);for(let i=0;i<o.length;i++){let a=o[i],c=a===n,d=r.addresses[a],u=r.shieldedAddresses?.[a],l=c?
|
|
59
|
-
`),process.stderr.write(` ${g("unshielded")} ${
|
|
60
|
-
`),u)process.stderr.write(` ${g("shielded ")} ${
|
|
58
|
+
`);let o=Object.keys(r.addresses);for(let i=0;i<o.length;i++){let a=o[i],c=a===n,d=r.addresses[a],u=r.shieldedAddresses?.[a],l=c?P(G(a))+g(" (active)"):a;if(process.stderr.write(` ${l}
|
|
59
|
+
`),process.stderr.write(` ${g("unshielded")} ${ee(d)}
|
|
60
|
+
`),u)process.stderr.write(` ${g("shielded ")} ${ee(u)}
|
|
61
61
|
`);else process.stderr.write(` ${g("shielded ")} ${g("(unavailable)")}
|
|
62
62
|
`);if(i<o.length-1)process.stderr.write(`
|
|
63
63
|
`)}process.stderr.write(`
|
|
64
|
-
`+
|
|
64
|
+
`+J()+`
|
|
65
65
|
|
|
66
66
|
`),process.stderr.write(` ${g("created")} ${r.createdAt}
|
|
67
67
|
`),process.stderr.write(` ${g("file ")} ${t}
|
|
68
68
|
|
|
69
|
-
`)}var
|
|
70
|
-
`)}var
|
|
69
|
+
`)}var ta=T(()=>{Le();ke();ue();ue()});function Ge(){ra=!0}function F(e,t){if(!ra)return;let r=new Date().toISOString().slice(11,23);process.stderr.write(g(` [${r}] ${e}: ${t}`)+`
|
|
70
|
+
`)}var ra=!1;var ht=()=>{};function Kp(e){return!Gp.includes(e)}function xn(e,t=!1){return Kp(e)||t}function Cn(e){return`Shielded is unavailable on ${e} (no faucet). Use --force-shielded to sync anyway, or --network undeployed.`}var Gp;var Us=T(()=>{Gp=["preview","preprod"]});import Vp from"ws";function Xt(e,t,r){return new Promise((n,s)=>{let o=new Vp(t,["graphql-transport-ws"]),i=new Map,a=0,c=0,d=0,u=!1,l=!1,f,p=()=>{let w=new Map,y=0,S=0,v=0;for(let A of i.values())if(!A.spent){y++;let N=w.get(A.tokenType)??0n;if(w.set(A.tokenType,N+A.value),A.tokenType===br)if(A.registeredForDustGeneration)S++;else v++}return{balances:w,utxoCount:y,txCount:a,highestTxId:c,registeredUtxos:S,unregisteredUtxos:v}},m=()=>{clearTimeout(f)},h=()=>{if(!l&&u&&(c===0||d>=c))l=!0,m(),o.send(JSON.stringify({id:"1",type:"complete"})),o.close(),n(p())};o.on("open",()=>{o.send(JSON.stringify({type:"connection_init"}))}),o.on("message",(w)=>{let y=JSON.parse(w.toString());switch(y.type){case"connection_ack":o.send(JSON.stringify({id:"1",type:"subscribe",payload:{query:Jp,variables:{address:e}}}));break;case"next":{if(y.payload?.errors){let v=y.payload.errors[0]?.message||"Unknown GraphQL error";if(!l)l=!0,m(),o.close(),s(Error(`GraphQL error: ${v}`));return}let S=y.payload?.data?.unshieldedTransactions;if(!S)return;if(S.__typename==="UnshieldedTransaction"){a++;let v=S;d=Math.max(d,v.transaction.id);for(let A of v.createdUtxos){let N=`${A.intentHash}:${A.outputIndex}`;i.set(N,{value:BigInt(A.value),tokenType:A.tokenType,spent:!1,registeredForDustGeneration:A.registeredForDustGeneration===!0})}for(let A of v.spentUtxos){let N=`${A.intentHash}:${A.outputIndex}`,L=i.get(N);if(L)L.spent=!0}if(r)r(d,c);h()}else if(S.__typename==="UnshieldedTransactionsProgress")c=S.highestTransactionId,u=!0,h();break}case"error":if(!l)l=!0,m(),o.close(),s(Error(`GraphQL subscription error: ${JSON.stringify(y.payload)}`));break;case"complete":break}}),o.on("error",(w)=>{if(!l){l=!0,m();let y=w.message?.trim()?w.message:`unable to reach ${t} (connection refused, DNS, or TLS error). Is the indexer running?`;s(Error(`WebSocket connection failed: ${y}`))}}),o.on("close",()=>{if(!l)l=!0,m(),s(Error(`Indexer closed the connection before balance sync completed. Indexer: ${t}`))}),f=setTimeout(()=>{if(!l)l=!0,o.close(),s(Error(`Balance check timed out after ${vs/1000}s. Indexer: ${t}`))},vs)})}function Fr(e){return e===br}var Jp=`
|
|
71
71
|
subscription UnshieldedTransactions($address: UnshieldedAddress!) {
|
|
72
72
|
unshieldedTransactions(address: $address) {
|
|
73
73
|
__typename
|
|
@@ -81,14 +81,14 @@ Use --force to overwrite, or --output <file> to save to a different path.`);let
|
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
|
-
`;var
|
|
85
|
-
`),p=await d()}}else F("facade","No cache, building fresh"),p=await d();if(!a||!c)throw Error("Wallet facade was built without its shielded or dust wallet");return{facade:p,keystore:o,seeds:s,seedStartable:{shielded:a,dust:c},restoredFromCache:f,indexerHttpUrl:t.indexer}}async function
|
|
84
|
+
`;var Lr=()=>{};import{existsSync as Ur,mkdirSync as qp,writeFileSync as zp,readFileSync as na,unlinkSync as En,readdirSync as Ws,renameSync as Yp}from"node:fs";import{join as Dt,dirname as Xp}from"node:path";import{homedir as sa}from"node:os";import{randomBytes as Zp}from"node:crypto";import*as An from"@midnightntwrk/ledger-v9";function Bs(e){return e.toString(16).padStart(64,"0")}function Xe(e){let t=ft(e),r=An.DustSecretKey.fromSeed(t);return Bs(r.publicKey)}function js(e,t){let r=t??Dt(sa(),ie,Me);return Dt(r,e)}function Hs(e,t,r){let n=t.slice(0,20);return Dt(js(e,r),`dust-${n}.json`)}function Wr(e,t,r){let n=Hs(e,t,r);if(!Ur(n))return null;try{let s=JSON.parse(na(n,"utf-8"));if(s.version!==oa)return null;if(s.network!==e)return null;if(s.dustPublicKeyHex!==t)return null;if(typeof s.lastAppliedEventId!=="number")return null;if(typeof s.dustState!=="string")return null;if(!Array.isArray(s.ownedGenerationIndices))return null;if(typeof s.generationFrontier!=="number")return null;let o=Buffer.from(s.dustState,"hex");return{state:An.DustLocalState.deserialize(o),lastAppliedEventId:s.lastAppliedEventId,retention:{ownedGenerationIndices:s.ownedGenerationIndices,generationFrontier:s.generationFrontier}}}catch{return null}}function Gs(e,t,r,n,s,o,i=Qp){let a={version:oa,network:e,dustPublicKeyHex:t,lastAppliedEventId:n,timestamp:new Date().toISOString(),dustState:Buffer.from(r.serialize()).toString("hex"),ownedGenerationIndices:i.ownedGenerationIndices,generationFrontier:i.generationFrontier,...o?{chainId:o}:{}},c=Hs(e,t,s),d=Xp(c);if(!Ur(d))qp(d,{recursive:!0,mode:Te});let u=c+`.tmp.${Zp(4).toString("hex")}`;try{zp(u,JSON.stringify(a),{mode:Ne}),Yp(u,c)}catch(l){try{En(u)}catch{}throw l}}function ia(e,t,r){if(!t)return[];let n=js(e,r);if(!Ur(n))return[];let s=[],o;try{o=Ws(n)}catch{return[]}for(let i of o){if(!i.startsWith("dust-")||!i.endsWith(".json"))continue;let a=Dt(n,i);try{let c=JSON.parse(na(a,"utf-8"));if(!c.chainId)continue;if(c.chainId!==t)En(a),s.push(a)}catch{}}return s}function ot(e,t,r){let n=r??Dt(sa(),ie,Me);if(e&&t){let o=Hs(e,t,r);try{En(o)}catch{}return}let s=(o)=>{if(!Ur(o))return;try{for(let i of Ws(o))if(i.startsWith("dust-")&&i.endsWith(".json"))try{En(Dt(o,i))}catch{}}catch{}};if(e){s(js(e,r));return}if(!Ur(n))return;try{for(let o of Ws(n))s(Dt(n,o))}catch{}}var oa=3,Qp;var It=T(()=>{Tt();Qp={ownedGenerationIndices:[],generationFrontier:0}});import{ShieldedWallet as aa}from"@midnightntwrk/wallet-sdk/shielded";import{UnshieldedWallet as ca,createKeystore as ef,PublicKey as tf}from"@midnightntwrk/wallet-sdk/unshielded";import{DustWallet as da}from"@midnightntwrk/wallet-sdk/dust";import{WalletFacade as la,WalletEntrySchema as rf,mergeWalletEntries as nf}from"@midnightntwrk/wallet-sdk/facade";import*as ua from"@midnightntwrk/ledger-v9";import{InMemoryTransactionHistoryStorage as sf}from"@midnightntwrk/wallet-sdk";import*as Pe from"rxjs";async function Ze(e,t,r){let n=Fe(t.networkId);F("facade",`Building facade for network ${t.networkId}`),F("facade",`Node: ${t.node}`),F("facade",`Indexer: ${t.indexerWS}`),F("facade",`Proof server: ${t.proofServer}`);let s={shielded:At(e),unshielded:Li(e),dust:ft(e)},o=ef({kind:"schnorr",secret:s.unshielded},n),i={networkId:n,forks:st,indexerClientConnection:{indexerHttpUrl:t.indexer,indexerWsUrl:t.indexerWS},costParameters:{additionalFeeOverhead:pi,feeBlocksMargin:fi},txHistoryStorage:new sf(rf,nf),provingServerUrl:new URL(t.proofServer),relayURL:new URL(t.node)},a,c,d=()=>la.init({configuration:i,shielded:async(m)=>a=await aa(m).startWithSeed(s.shielded),unshielded:(m)=>ca(m).startWithPublicKey(tf.fromKeyStore(o)),dust:async(m)=>c=await da(m).startWithSeed(s.dust)}),u=ua.DustSecretKey.fromSeed(s.dust).publicKey,l=r?af(r,t,u):null,f=!1,p;if(l){F("facade","Restoring from cache...");try{p=await la.init({configuration:i,shielded:(m)=>a=aa(m).restore(l.shielded),unshielded:(m)=>ca(m).restore(l.unshielded),dust:(m)=>c=da(m).restore(l.dust)}),f=!0,F("facade","Cache restore successful")}catch(m){F("facade",`Cache restore failed: ${m.message}`),process.stderr.write(` Cache restore failed, building from scratch: ${m.message}
|
|
85
|
+
`),p=await d()}}else F("facade","No cache, building fresh"),p=await d();if(!a||!c)throw Error("Wallet facade was built without its shielded or dust wallet");return{facade:p,keystore:o,seeds:s,seedStartable:{shielded:a,dust:c},restoredFromCache:f,indexerHttpUrl:t.indexer}}async function of(e){let{facade:t,seeds:r,seedStartable:n}=e;if(!e.restoredFromCache){await t.start(r);return}await Promise.all([n.shielded.startWithSeed(r.shielded),t.unshielded.start(),n.dust.startWithSeed(r.dust),t.pendingTransactionsService.start()])}function Vs(e,t){let r=JSON.parse(e);if(BigInt(r.protocolVersion)<st.v9)throw Error(`Can't put a ledger-9 dust state into a snapshot at protocol version ${r.protocolVersion}: the wallet would read it as ledger 8 (fork at ${st.v9}).`);return r.state=Buffer.from(t.state.serialize()).toString("hex"),r.offset=t.lastAppliedEventId.toString(),JSON.stringify(r)}function af(e,t,r){try{let n=t.networkId.toLowerCase(),s=Bs(r),o=Wr(n,s);if(!o)return e;let i=JSON.parse(e.dust),a=i.offset!==void 0?Number(i.offset):-1;if(a>=o.lastAppliedEventId)return F("facade",`Facade dust offset=${a} >= dust-direct offset=${o.lastAppliedEventId}; skipping bridge`),e;return F("facade",`Bridged dust-direct cache (facade offset ${a} → dust-direct offset ${o.lastAppliedEventId})`),{...e,dust:Vs(e.dust,o)}}catch(n){return F("facade",`Dust-direct bridge skipped: ${n.message}`),e}}function pa(e,t){if(e.isStrictlyComplete())return!0;if(e.highestRelevantWalletIndex>0n&&e.appliedIndex>=e.highestRelevantWalletIndex)return!0;return fa(e)&&t}function fa(e){return e.highestRelevantWalletIndex===0n&&e.appliedIndex===0n}function Ks(e,t="full"){let r=e.unshielded.progress.isStrictlyComplete(),n=t==="no-dust"||pa(e.dust.progress,r);if(t==="lite")return r&&n;let s=e.shielded.progress;return(s.isStrictlyComplete()||r&&fa(s))&&r&&n}function cf(e){return!pa(e.dust.progress,e.unshielded.progress.isStrictlyComplete())}async function wt(e,t={}){let{onProgress:r,onSyncDetail:n,timeoutMs:s,syncMode:o="full",requireStrictSync:i=!1}=t,{facade:a}=e;F("sync","Starting facade (connecting to node and indexer)..."),await of(e),F("sync","Facade started, subscribing to state...");let c=s??wi;F("sync",`Sync timeout: ${c/1000}s, mode: ${o}`);let d=!i&&e.restoredFromCache,u=Date.now();return new Promise((l,f)=>{let p=!1,m=0,h="",w=null,y=setTimeout(()=>{if(!p){if(F("sync",`Sync timed out after ${c/1000}s (${m} emissions)`),w)try{let S=w.unshielded.progress;F("sync",` unshielded: applied=${S.appliedId} highest=${S.highestTransactionId} complete=${S.isStrictlyComplete()}`);let v=w.dust.progress;if(F("sync",` dust: applied=${v.appliedIndex} highest=${v.highestRelevantWalletIndex} complete=${v.isStrictlyComplete()} connected=${v.isConnected}`),o==="full"){let A=w.shielded.progress;F("sync",` shielded: complete=${A.isStrictlyComplete()}`)}}catch{}f(Error("Wallet sync timed out"))}},c);e.keepAlive=a.state().subscribe({next:(S)=>{if(p)return;if(m++,w=S,e.restoredFromCache){let A=lf(S);if(A){p=!0,clearTimeout(y),F("sync",`Stale cache detected: ${A}`),f(new Tn(A));return}}if(r){let A=S.unshielded.progress;if(A){let N=Number(A.appliedId),L=Number(A.highestTransactionId);r(Math.min(N,L),L)}}let v=[];try{if((o==="full"||o==="no-dust")&&!S.shielded.progress.isStrictlyComplete())v.push("shielded");if(o!=="no-dust"&&cf(S))v.push("dust");if(!S.unshielded.progress.isStrictlyComplete())v.push("unshielded")}catch{}if(v.length>0){n?.(v.join(", "));let A=v.join(",");if(m===1||A!==h||m%100===0)F("sync",`Waiting on: ${v.join(", ")} (emission #${m})`),h=A}if(Ks(S,o)){p=!0,clearTimeout(y),F("sync",`Sync complete after ${m} emissions`),l(S);return}if(d){let A=Date.now()-u;if(A>=df&&Ks(S,"no-dust"))p=!0,clearTimeout(y),F("sync",`Sync resolved via cached-restore grace (${A}ms, ${m} emissions)`),l(S)}},error:(S)=>{if(!p)F("sync",`Sync error: ${S.message}`),clearTimeout(y),f(S)}})})}function lf(e){let{appliedId:t,highestTransactionId:r}=e.unshielded.progress;if(r>0n&&t>r)return`unshielded cache applied=${t} but chain highest=${r}.`;return}async function ma(e){let t=(r)=>{let n=r.unshielded.progress.isStrictlyComplete(),s=r.dust.progress.isStrictlyComplete();return n&&s};try{return await Pe.firstValueFrom(e.facade.state().pipe(Pe.filter(t),Pe.timeout(15000)))}catch{return await Pe.firstValueFrom(e.facade.state())}}function $t(e){return e.dust.availableCoins.length>0||e.dust.balance(new Date)>0n}async function Nn(e,t=60000){try{return await Pe.firstValueFrom(e.facade.state().pipe(Pe.filter($t),Pe.timeout(t)))}catch{return await Pe.firstValueFrom(e.facade.state())}}async function Js(e,t="full"){return Pe.firstValueFrom(e.facade.state().pipe(Pe.filter((r)=>Ks(r,t)),Pe.timeout(yi)))}async function Ue(e){e.keepAlive?.unsubscribe(),await Promise.race([e.facade.stop(),new Promise((t)=>setTimeout(t,5000))])}function Re(e){let t=(n)=>{let s=n?._tag;if(typeof s==="string"&&s.startsWith("Wallet.")){let o=n?.message??"transient error";e?.(s,o);return}r("Unhandled rejection:",n),process.exit(1)},r=console.error;return console.error=(...n)=>{let s=n[0];if(typeof s==="object"&&s?._tag?.startsWith("Wallet.")){e?.(s._tag,s?.message??"transient error");return}if(typeof s==="string"&&s.startsWith("Wallet.")){e?.("Wallet.Sync","transient error");return}r(...n)},process.on("unhandledRejection",t),()=>{process.removeListener("unhandledRejection",t),console.error=r}}var df=1e4,Tn;var Ke=T(()=>{me();mt();Tt();It();ht();Tn=class Tn extends Error{code="STALE_CACHE";constructor(e){super(`Cached wallet state is stale (from a previous chain). ${e}
|
|
86
86
|
Run: midnight cache clear --wallet <name> --network <name>
|
|
87
|
-
Or: midnight cache clear (wipe all caches)`);this.name="StaleCacheError"}}});function
|
|
88
|
-
Use midnight-wallet-cli 0.5.x for ledger-8 networks.`);this.name="UnsupportedLedgerError"}};
|
|
87
|
+
Or: midnight cache clear (wipe all caches)`);this.name="StaleCacheError"}}});function uf(e){let t=e;while(t){let r=String(t?.message??"").toLowerCase();if(r.includes("submission error"))return!0;if(r.includes("transaction")&&r.includes("invalid"))return!0;if(r.includes("138"))return!0;let n=t?._tag;if(n==="TransactionInvalidError"||n==="SubmissionError")return!0;t=t.cause}return!1}function qs(e){let t=new Set,r=[e];while(r.length>0){let n=r.pop();if(!n||typeof n!=="object"||t.has(n))continue;t.add(n);let s=n;if(s._tag==="Wallet.InsufficientFunds"&&s.tokenType==="dust")return!0;if(typeof s.message==="string"&&/no dust tokens|dust.*unavailable/i.test(s.message))return!0;r.push(s.cause,s[pf],s.error,s.defect,s.left,s.right)}return!1}function Rn(e){let t=e?.message?.toLowerCase()??"";return t.includes("not enough dust")||t.includes("dust generated")||t.includes("insufficient generated dust")||t.includes("insufficient funds")||t.includes("no dust tokens")||uf(e)}function ga(e){let t=e?.message?.toLowerCase()??"";if(e?._tag==="Wallet.InsufficientFunds")return!0;return t==="insufficient funds"||t.startsWith("insufficient funds")}function Dn(e){return ga(e)&&!qs(e)}var pf;var Br=T(()=>{pf=Symbol.for("effect/Runtime/FiberFailure/Cause")});import{existsSync as Hr,mkdirSync as ff,writeFileSync as mf,readFileSync as ha,unlinkSync as jr,readdirSync as In,renameSync as gf}from"node:fs";import{join as Qe,dirname as hf}from"node:path";import{homedir as zs}from"node:os";import{randomBytes as wf}from"node:crypto";function Ys(e,t,r){let n=r??Qe(zs(),ie,Me),s=e.slice(0,20);return Qe(n,t,`${s}.json`)}function yt(e,t,r){let n=Ys(e,t,r);if(!Hr(n))return null;try{let s=ha(n,"utf-8"),o=JSON.parse(s);if(o.version!==Cs)return null;if(o.network!==t)return null;if(o.address!==e)return null;if(!o.wallets||typeof o.wallets.shielded!=="string"||typeof o.wallets.unshielded!=="string"||typeof o.wallets.dust!=="string")return null;return o.wallets}catch{return null}}async function it(e,t,r,n,s){let[o,i,a]=await Promise.all([r.shielded.serializeState(),r.unshielded.serializeState(),r.dust.serializeState()]),c={version:Cs,network:t,address:e,timestamp:new Date().toISOString(),wallets:{shielded:o,unshielded:i,dust:a},...s?{chainId:s}:{}},d=Ys(e,t,n),u=hf(d);if(!Hr(u))ff(u,{recursive:!0,mode:Te});let l=d+`.tmp.${wf(4).toString("hex")}`;try{mf(l,JSON.stringify(c),{mode:Ne}),gf(l,d)}catch(f){try{jr(l)}catch{}throw f}}function wa(e,t,r){if(!t)return[];let n=r??Qe(zs(),ie,Me),s=Qe(n,e);if(!Hr(s))return[];let o=[],i;try{i=In(s)}catch{return[]}for(let a of i){if(!a.endsWith(".json"))continue;let c=Qe(s,a);try{let d=JSON.parse(ha(c,"utf-8"));if(!d.chainId)continue;if(d.chainId!==t)jr(c),o.push(c)}catch{}}return o}function Ve(e,t,r){let n=r??Qe(zs(),ie,Me);if(e&&t){let s=Ys(e,t,r);try{jr(s)}catch{}return}if(t){let s=Qe(n,t);if(!Hr(s))return;try{for(let o of In(s))if(o.endsWith(".json"))jr(Qe(s,o))}catch{}return}if(!Hr(n))return;try{for(let s of In(n)){let o=Qe(n,s);try{for(let i of In(o))if(i.endsWith(".json"))jr(Qe(o,i))}catch{}}}catch{}}var Pt=()=>{};import yf from"ws";async function Zt(e,t,r=[]){let n=e.timeoutMs??Sf;return new Promise((s,o)=>{let i=new yf(e.url),a=!1,c=(u)=>{if(!a)a=!0,u()},d=setTimeout(()=>{c(()=>{try{i.close()}catch{}o(Error(`RPC ${t} timed out after ${n}ms`))})},n);i.on("open",()=>{try{i.send(JSON.stringify({jsonrpc:"2.0",id:1,method:t,params:r}))}catch(u){clearTimeout(d),c(()=>o(u instanceof Error?u:Error(String(u))))}}),i.on("message",(u)=>{clearTimeout(d),c(()=>{try{let l=JSON.parse(u.toString());try{i.close()}catch{}if(l.error)o(Error(`RPC ${t}: ${l.error.message}`));else s(l.result)}catch(l){o(l instanceof Error?l:Error(String(l)))}})}),i.on("error",(u)=>{clearTimeout(d),c(()=>o(u instanceof Error?u:Error(String(u))))})})}var Sf=5000;var $n=()=>{};async function Qt(e){let t=ya.get(e);if(t&&Date.now()-t.fetchedAt<bf)return t.hash;try{let r=await Zt({url:e,timeoutMs:5000},"chain_getBlockHash",[0]);if(typeof r!=="string"||!r.startsWith("0x"))return null;return ya.set(e,{hash:r,fetchedAt:Date.now()}),r}catch{return null}}var ya,bf=60000;var Pn=T(()=>{$n();ya=new Map});async function St(e,t,r,n){let s;try{s=await fetch(e,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(r?{query:t,variables:r}:{query:t}),signal:AbortSignal.timeout(n)})}catch(i){throw new _t(i.message)}if(!s.ok)throw new _t(`HTTP ${s.status} ${s.statusText}`.trim());let o;try{o=await s.json()}catch(i){throw new _t(`the answer is not JSON: ${i.message}`)}if(o.errors?.length)throw new _t(o.errors.map((i)=>i.message).join("; "));if(o.data==null)throw new _t("the answer has no data");return o.data}var _t;var Gr=T(()=>{_t=class _t extends Error{constructor(e){super(e);this.name="IndexerQueryError",Object.setPrototypeOf(this,_t.prototype)}}});function ba(e,t){if(t!==null&&t<st.v9)throw new Sa(e,t)}async function _n(e){try{let r=(await St(e,"{ block { protocolVersion } }",void 0,vf)).block?.protocolVersion;return typeof r==="number"?BigInt(r):null}catch{return null}}async function Be(e,t,r=_n){ba(e,await r(t.indexer))}async function va(e,t,r={}){let n=await(r.fetchVersion??_n)(t.indexer);if(n===null)throw new Xs("indexer",t.indexer);if(ba(e,n),await(r.fetchGenesis??Qt)(t.node)===null)throw new Xs("node",t.node)}function ka(e){return["shielded","unshielded","dust"].filter((t)=>e[t]<st.v9)}var Sa,vf=5000,Xs;var Ot=T(()=>{me();Pn();Gr();Sa=class Sa extends Error{code="UNSUPPORTED_LEDGER";constructor(e,t){super(`${e} is on ledger 8 (protocol version ${t}), and this build of mn supports ledger 9 only.
|
|
88
|
+
Use midnight-wallet-cli 0.5.x for ledger-8 networks.`);this.name="UnsupportedLedgerError"}};Xs=class Xs extends Error{code="LOCAL_STACK_UNREACHABLE";constructor(e,t){super(`No ledger-9 stack is reachable: the ${e} at ${t} did not answer.
|
|
89
89
|
This build of mn can't start a localnet (no published indexer image runs ledger 9 yet).
|
|
90
90
|
Start a ledger-9 stack (node 2.1.0-rc.2, proof-server 9.0.0-rc.8, a 4.4 indexer) and point mn at it:
|
|
91
|
-
midnight config set network undeployed, then midnight config set node / indexer-ws / proof-server <url>`);this.name="LocalStackUnreachableError"}}});function
|
|
91
|
+
midnight config set network undeployed, then midnight config set node / indexer-ws / proof-server <url>`);this.name="LocalStackUnreachableError"}}});function kf(e,t){if(t<=0n)return[];let r=[...new Set(e)].filter((o)=>o>=0n&&o<t).sort((o,i)=>o<i?-1:o>i?1:0),n=[],s=-1n;for(let o of r){if(o>s+1n)n.push([s+1n,o-1n]);s=o}if(t-1n>s)n.push([s+1n,t-1n]);return n}function On(e,t,r){let n=kf(t,r);if(n.length===0)return{state:e,collapsed:!1,rangesCollapsed:0,reason:"nothing-foreign"};let s=e.syncTime instanceof Date?e.syncTime:new Date(String(e.syncTime)),o,i;try{o=e.walletBalance(s),i=e.generatingTreeRoot()}catch(c){return{state:e,collapsed:!1,rangesCollapsed:0,reason:`no-reference: ${c.message}`}}let a=e;try{for(let[c,d]of n)a=a.collapseGenerationTree(c,d)}catch(c){return{state:e,collapsed:!1,rangesCollapsed:0,reason:`collapse-threw: ${c.message}`}}try{if(a.walletBalance(s)!==o||a.generatingTreeRoot()!==i)return{state:e,collapsed:!1,rangesCollapsed:0,reason:"guard-mismatch"};for(let c of a.utxos)if(a.generationInfo(c)===void 0)return{state:e,collapsed:!1,rangesCollapsed:0,reason:"guard-utxo-generation-missing"}}catch(c){return{state:e,collapsed:!1,rangesCollapsed:0,reason:`guard-threw: ${c.message}`}}return{state:a,collapsed:!0,rangesCollapsed:n.length}}import xf from"ws";function er(e,t){let{query:r,variables:n,onNext:s,buildResult:o,timeoutMs:i,idleMs:a,idleBeforeFirstEvent:c,initialSilenceMs:d,signal:u}=t;return new Promise((l,f)=>{let p=new xf(e,["graphql-transport-ws"]),m=!1,h=!1,w,y,S,v=()=>{if(clearTimeout(w),y)clearTimeout(y);if(S)clearTimeout(S);try{p.close()}catch{}u?.removeEventListener("abort",L)},A=(q,V)=>{if(h)return;h=!0,v();try{l(o(V))}catch(O){f(O instanceof Error?O:Error(String(O)))}},N=(q)=>{if(h)return;h=!0,v(),f(q)},L=()=>N(Error("Operation cancelled"));u?.addEventListener("abort",L,{once:!0});let X=()=>{if(y)clearTimeout(y);y=setTimeout(()=>{if(!h&&(m||c))A("idle",!1)},a)};p.on("open",()=>{p.send(JSON.stringify({type:"connection_init"}))}),p.on("message",(q)=>{let V;try{V=JSON.parse(q.toString())}catch{return}if(V.type==="connection_ack"){if(p.send(JSON.stringify({id:"1",type:"subscribe",payload:{query:r,variables:n}})),c)X();if(d&&d>0)S=setTimeout(()=>{if(!m&&!h)A("initial-silence",!1)},d);return}if(V.type==="error"){N(Error(`GraphQL subscription error: ${JSON.stringify(V.payload)?.slice(0,300)}`));return}if(V.type!=="next")return;if(V.payload?.errors){N(Error(`GraphQL error: ${V.payload.errors[0]?.message||"unknown"}`));return}if(m=!0,S)clearTimeout(S),S=void 0;let O;try{O=s(V.payload?.data)}catch(_){N(_ instanceof Error?_:Error(String(_)));return}if(X(),O)A("caught-up",!1)}),p.on("error",(q)=>N(Error(`WebSocket error: ${q.message}`))),p.on("close",()=>{if(h)return;A(m?"closed-early":"graceful-close",m)}),w=setTimeout(()=>A("timeout",!0),i)})}var Mn=()=>{};import*as tr from"@midnightntwrk/ledger-v9";function Ef(){let e=new tr.DustParameters(mi,gi,hi);return new tr.DustLocalState(e)}function xa(e,t,r={}){let{onProgress:n,onCheckpoint:s,timeoutMs:o=600000,idleMs:i=5000,initialSilenceMs:a=3000,signal:c,initialState:d,startFromId:u=0,initialRetention:l,collapse:f}=r,p=f!==!1&&process.env[Zs]!=="1",m=500,h=d??Ef(),w=[],y=e.publicKey,S=new Set((l?.ownedGenerationIndices??[]).map(BigInt)),v=BigInt(l?.generationFrontier??0),A=(O)=>{let _=O.content;if(_?.tag!=="dustInitialUtxo"||_.generationIndex===void 0)return;let ne=_.generationIndex;if(ne+1n>v)v=ne+1n;if(_.generation?.owner===y)S.add(ne)},N=()=>({ownedGenerationIndices:[...S].map(Number),generationFrontier:Number(v)}),L=0,X=u-1,q=-1,V=()=>{if(w.length===0)return;if(h=h.replayEvents(e,w),L+=w.length,w.length=0,p)h=On(h,S,v).state;if(s&&X>=0)try{s(h,X,N())}catch{}};return er(t,{query:Cf,variables:{id:u},idleMs:i,timeoutMs:o,initialSilenceMs:d?a:0,signal:c,onNext:(O)=>{let _=O?.dustLedgerEvents;if(!_)return!1;let ne;try{ne=tr.Event.deserialize(Buffer.from(_.raw,"hex"))}catch(pe){throw Error(`Failed to deserialize dust event ${_.id}: ${pe.message}`)}if(A(ne),w.push(ne),X=_.id,_.maxId>q)q=_.maxId;if(w.length>=500)try{V()}catch(pe){throw Error(`Failed applying dust events: ${pe.message}`)}return n?.(L+w.length,q),X>=q},buildResult:(O)=>{try{V();let _=new Date;return h=h.processTtls(_),{balance:h.walletBalance(_),availableCoins:h.utxos.length,eventCount:L,ownedUtxoCount:h.utxos.length,syncTime:h.syncTime,state:h,retention:N(),lastAppliedEventId:X,partial:O}}catch(_){throw Error(`Failed to build dust state: ${_.message}`)}}})}var Zs="MN_DISABLE_DUST_COLLAPSE",Cf=`
|
|
92
92
|
subscription DustLedgerEvents($id: Int) {
|
|
93
93
|
dustLedgerEvents(id: $id) {
|
|
94
94
|
type: __typename
|
|
@@ -97,9 +97,9 @@ Start a ledger-9 stack (node 2.1.0-rc.2, proof-server 9.0.0-rc.8, a 4.4 indexer)
|
|
|
97
97
|
maxId
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
|
-
`;var
|
|
100
|
+
`;var Qs=T(()=>{Mn()});import{spawn as Af}from"node:child_process";import{existsSync as Mt,mkdirSync as Tf,readFileSync as Ta,readdirSync as Ca,unlinkSync as Ea,writeFileSync as Nf}from"node:fs";import{homedir as Na}from"node:os";import{dirname as Aa,join as at}from"node:path";import{fileURLToPath as Rf}from"node:url";import*as Ra from"@midnightntwrk/ledger-v9";function Da(){let e=process.env.MN_DUST_SYNC_BIN;if(e&&Mt(e))return e;let t=process.platform==="win32"?"dust-sync.exe":"dust-sync",r=Aa(Rf(import.meta.url));for(let n of[["..",".."],[".."]]){let s=at(r,...n,"sidecar","dust-sync","target","release",t);if(Mt(s))return s}try{let n=`@nel349/dust-sync-${process.platform}-${process.arch}`,s=Df(import.meta.url),o=at(Aa(s.resolve(`${n}/package.json`)),t);if(Mt(o))return o}catch{}return null}function Df(e){return globalThis.require??ii("node:module").createRequire(e)}function Ia(){if(If!==$f)return!1;if(process.env.MN_DISABLE_NATIVE_DUST==="1")return!1;return Da()!==null}function Pf(e,t,r){if(e+1>=t)return"existing";if(r)return"seed";return"fresh"}function _f(e){if(!Mt(e))return-2;try{let t=JSON.parse(Ta(e,"utf-8"));return typeof t.last_applied_event_id==="number"?t.last_applied_event_id:-2}catch{return-2}}function Of(e,t){let r=at(Na(),ie,Me,e);if(!Mt(r))Tf(r,{recursive:!0,mode:Te});return at(r,`dust-native-${t.slice(0,20)}.json`)}function Fn(e,t){let r=at(Na(),ie,Me);if(e&&t){try{Ea(at(r,e,`dust-native-${t.slice(0,20)}.json`))}catch{}return}let n=(s)=>{if(!Mt(s))return;try{for(let o of Ca(s))if(o.startsWith("dust-native-")&&o.endsWith(".json"))try{Ea(at(s,o))}catch{}}catch{}};if(e){n(at(r,e));return}if(!Mt(r))return;try{for(let s of Ca(r))n(at(r,s))}catch{}}function $a(e,t,r){return new Promise((n,s)=>{let o=Da();if(!o){s(Error("dust-sync sidecar not found"));return}let i=t.networkId.toLowerCase(),a=Xe(e),c=Of(i,a),d=["--indexer-ws",t.indexerWS,"--out",c],u=Pf(_f(c),r.startFromId,!!r.initialState);if(u==="seed"){let w={dust_state:Buffer.from(r.initialState.serialize()).toString("hex"),last_applied_event_id:r.startFromId-1,owned_generation_indices:r.initialRetention?.ownedGenerationIndices??[],generation_frontier:r.initialRetention?.generationFrontier??0,balance:"0",available_coins:0,events_applied:0,partial:!0};Nf(c,JSON.stringify(w),{mode:Ne})}if(u!=="fresh")d.push("--resume",c);let l=Af(o,d,{stdio:["pipe","pipe","pipe"]}),f=()=>{try{l.kill("SIGINT")}catch{}};r.signal?.addEventListener("abort",f,{once:!0}),l.stdin.on("error",()=>{});let p=Buffer.from(ft(e)).toString("hex");l.stdin.write(p+`
|
|
101
101
|
`),l.stdin.end();let m="",h="";l.stdout.on("data",(w)=>{m+=w.toString()}),l.stderr.on("data",(w)=>{let y=w.toString();h=(h+y).slice(-2000);for(let S of y.matchAll(/applied (\d+) \/ (\d+)/g))r.onProgress?.(Number(S[1]),Number(S[2]))}),l.on("error",(w)=>{r.signal?.removeEventListener("abort",f),s(w)}),l.on("close",(w)=>{if(r.signal?.removeEventListener("abort",f),w!==0){s(Error(`dust-sync exited ${w}: ${h.trim().slice(-300)}`));return}try{let y=m.trim().split(`
|
|
102
|
-
`).filter(Boolean).pop(),S=y?JSON.parse(y):JSON.parse(
|
|
102
|
+
`).filter(Boolean).pop(),S=y?JSON.parse(y):JSON.parse(Ta(c,"utf-8"));n(Mf(S))}catch(y){s(Error(`dust-sync output parse failed: ${y.message}`))}})})}function Mf(e){let t=new Date,r=Ra.DustLocalState.deserialize(new Uint8Array(Buffer.from(e.dust_state,"hex")));if(process.env[Zs]!=="1"){let s=new Set(e.owned_generation_indices.map((o)=>BigInt(o)));r=On(r,s,BigInt(e.generation_frontier)).state}r=r.processTtls(t);let n=r.utxos.length;return{balance:r.walletBalance(t),availableCoins:n,eventCount:e.events_applied,ownedUtxoCount:n,syncTime:r.syncTime instanceof Date?r.syncTime:new Date(String(r.syncTime)),state:r,retention:{ownedGenerationIndices:e.owned_generation_indices,generationFrontier:e.generation_frontier},lastAppliedEventId:e.last_applied_event_id,partial:e.partial}}var If=8,$f=9;var eo=T(()=>{Tt();Qs();It()});async function Ln(e,t){let r=Ff[t],n=null;try{return await er(e,{query:`subscription { ${r}(id: 0) { id maxId } }`,variables:{},onNext:(s)=>{let o=s[r]?.maxId;if(typeof o==="number")n=o;return n!==null},buildResult:()=>n,timeoutMs:1e4,idleMs:3000,idleBeforeFirstEvent:!0})}catch{return null}}function Un(e,t){return t!==null&&e>t}var Ff;var to=T(()=>{Mn();Ff={dust:"dustLedgerEvents",zswap:"zswapLedgerEvents"}});import*as _a from"@midnightntwrk/ledger-v9";class Oa{now;fetchTip;fetchUnshielded;fetchDust;fetchChainId;fetchEventTip;fetchProtocolVersion;cacheDir;dustMemo=new Map;unshieldedMemo=new Map;tipMemo=new Map;constructor(e={}){this.now=e.now??Date.now,this.fetchTip=e.fetchTip??Hf,this.fetchUnshielded=e.fetchUnshielded??Gf,this.fetchDust=e.fetchDust??Vf,this.fetchChainId=e.fetchChainId??Qt,this.fetchEventTip=e.fetchEventTip??Ln,this.fetchProtocolVersion=e.fetchProtocolVersion??_n,this.cacheDir=e.cacheDir}async dust(e,t,r={}){let n=Wn(t);await Be(n,t,this.fetchProtocolVersion);let s=Xe(e),o=`${n}:${s}`;if(!r.forceFresh){let m=await this.tryMemo(o,t,this.dustMemo,r.signal);if(m)return{...m,fromCache:!0,eventsApplied:0}}let i=await this.fetchChainId(t.node).catch(()=>null);ia(n,i,this.cacheDir);let a=i??void 0,c=r.forceFresh?null:Wr(n,s,this.cacheDir);if(c&&Un(c.lastAppliedEventId,await this.fetchEventTip(t.indexerWS,"dust")))ot(n,s,this.cacheDir),c=null;let d=c!==null,u=0,l=c?.lastAppliedEventId??-1,f=null;for(let m=0;m<Uf;m++){if(r.signal?.aborted)throw Error("Operation cancelled");let h=c?c.lastAppliedEventId+1:0;if(r.onStatus?.(m>0?`Resuming dust from event ${h} (continuation ${m+1})…`:c?`Resuming dust from event ${h}…`:"Reading dust events…"),f=await this.fetchDust(e,t,{startFromId:h,initialState:c?.state,initialRetention:c?.retention,signal:r.signal,onProgress:(w,y)=>{let S=Math.max(1,y+1-h);r.onStatus?.(`Reading dust events… ${w}/${S}`),r.onProgress?.(w,y)},onCheckpoint:(w,y,S)=>{try{Gs(n,s,w,y,this.cacheDir,a,S)}catch{}}}),l=f.lastAppliedEventId>=0?f.lastAppliedEventId:c?.lastAppliedEventId??-1,f.lastAppliedEventId>=0||!c)try{Gs(n,s,f.state,l,this.cacheDir,a,f.retention)}catch{}if(u+=f.eventCount,!f.partial)break;c=Wr(n,s,this.cacheDir)}if(!f)throw Error("Dust sync exhausted retries without producing a result");let p={state:f.state,balance:f.balance,availableCoins:f.availableCoins,ownedUtxoCount:f.ownedUtxoCount,syncTime:f.syncTime,fromCache:d,eventsApplied:u,lastAppliedEventId:l,partial:f.partial,fetchedAt:this.now()};return await this.memoize(this.dustMemo,o,p,t,r.signal),p}async unshielded(e,t,r={}){let n=Wn(t),s=typeof e==="string"?e:ve(e,n),o=`${n}:${s}`;if(!r.forceFresh){let c=await this.tryMemo(o,t,this.unshieldedMemo,r.signal);if(c)return{...c,fromCache:!0}}let a={...await this.fetchUnshielded(s,t,r.onProgress),fromCache:!1,fetchedAt:this.now()};return await this.memoize(this.unshieldedMemo,o,a,t,r.signal),a}async withFacade(e,t,r,n={}){let s=n.syncMode??"full",o=n.requireStrictSync??!0,i=o&&!n.readOnly,a=Wn(t),c=ve(e,a),d=t.networkId!=="Undeployed",u=n.syncTimeoutMs??(d?Bf:Wf);await Be(a,t,this.fetchProtocolVersion);let l=await this.fetchChainId(t.node).catch(()=>null);wa(a,l,this.cacheDir);let f=l??void 0;if(i&&!n.noPrime&&!n.forceFresh)try{await this.dust(e,t,{signal:n.signal,onStatus:n.onStatus})}catch(y){n.onSyncWarning?.("PrePrime",y.message)}let p,m,h=!1,w=async()=>{if(h||!p)return;h=!0;try{await Ue(p)}catch{}};try{for(let v=1;v<=Kr;v++){if(n.signal?.aborted)throw Error("Operation cancelled");let A=n.forceFresh?null:yt(c,a,this.cacheDir);p=await Ze(e,t,A);try{m=await wt(p,{onProgress:n.onSyncProgress,onSyncDetail:n.onSyncDetail,timeoutMs:u,syncMode:s,requireStrictSync:o});break}catch(N){if(n.signal?.aborted)throw Error("Operation cancelled");if(N instanceof Tn&&v<Kr&&i){n.onStatus?.(`Cache is stale, clearing and rebuilding (attempt ${v+1}/${Kr})...`),await Ue(p).catch(()=>{}),p=void 0,Ve(c,a,this.cacheDir),ot(a,Xe(e),this.cacheDir);try{await this.dust(e,t,{signal:n.signal,onStatus:n.onStatus})}catch{}continue}if(v<Kr&&String(N?.message??"").includes("timed out")){try{await it(c,a,p.facade,this.cacheDir,f)}catch{}n.onStatus?.(`Sync timed out, retrying (attempt ${v+1}/${Kr})...`),await Ue(p).catch(()=>{}),p=void 0;continue}throw N}}if(!p||!m)throw Error("Sync failed: no facade state after retries");let y,S=0;while(!0){if(S++,n.signal?.aborted)throw Error("Operation cancelled");try{y=await r({bundle:p,state:m});break}catch(v){if(!(i&&S<Pa&&Dn(v)))throw v;if(n.onStatus?.(`Refreshing wallet state (attempt ${S+1}/${Pa})...`),await Ue(p).catch(()=>{}),p=void 0,await new Promise((L)=>setTimeout(L,jf)),n.signal?.aborted)throw Error("Operation cancelled");let N=yt(c,a,this.cacheDir);p=await Ze(e,t,N),m=await wt(p,{onProgress:n.onSyncProgress,onSyncDetail:n.onSyncDetail,timeoutMs:u,syncMode:s,requireStrictSync:o})}}if(!n.skipAutoSave)try{await it(c,a,p.facade,this.cacheDir,f)}catch{}if(!n.readOnly)this.invalidate({network:t,seed:e});return y}finally{await w()}}invalidate(e){let t=Wn(e.network),r=e.kinds??["dust","unshielded","facade"];if(r.includes("dust"))if(e.seed){let n=Xe(e.seed);this.dustMemo.delete(`${t}:${n}`)}else this.deleteByPrefix(this.dustMemo,`${t}:`);if(r.includes("unshielded")){let n=e.address??(e.seed?ve(e.seed,t):null);if(n)this.unshieldedMemo.delete(`${t}:${n}`);else this.deleteByPrefix(this.unshieldedMemo,`${t}:`)}if(r.includes("facade")&&e.seed){let n=ve(e.seed,t);try{Ve(n,t,this.cacheDir)}catch{}}}resetTipMemo(){this.tipMemo.clear()}async tryMemo(e,t,r,n){let s=r.get(e);if(!s)return null;let o;try{o=await this.getTip(t,n)}catch{return s.value}if(o===s.tipAtFetch)return s.value;return r.delete(e),null}async memoize(e,t,r,n,s){try{let o=await this.getTip(n,s);e.set(t,{value:r,fetchedAt:this.now(),tipAtFetch:o})}catch{F("repo",`tip unavailable; skipping memo for ${t}`)}}async getTip(e,t){let r=this.tipMemo.get(e.networkId);if(r&&this.now()-r.fetchedAt<Lf)return r.tip;let n=await this.fetchTip(e,t);return this.tipMemo.set(e.networkId,{tip:n,fetchedAt:this.now()}),n}deleteByPrefix(e,t){for(let r of e.keys())if(r.startsWith(t))e.delete(r)}}function Hf(e){return Zt({url:e.node,timeoutMs:3000},"chain_getBlockHash",[])}function Gf(e,t,r){return Xt(e,t.indexerWS,r)}function Kf(e,t,r){let n=ft(e),s=_a.DustSecretKey.fromSeed(n);return xa(s,t.indexerWS,r)}async function Vf(e,t,r){if(Ia())try{return await $a(e,t,r)}catch(n){F("dust",`native sidecar failed, using WASM: ${n.message}`)}return Kf(e,t,r)}function Wn(e){let t=e.networkId.toLowerCase();if(be(t))return t;throw Error(`Unsupported network: ${e.networkId}`)}function Ce(){if(!ro)ro=new Oa;return ro}var Lf=5000,Uf=6,Wf=30000,Bf=120000,Kr=3,Pa=5,jf=5000,ro=null;var bt=T(()=>{me();Ke();Br();It();Pt();Pn();Ot();Lr();Qs();eo();ht();$n();Tt();He();to()});import*as rr from"@midnightntwrk/ledger-v9";function qf(e){let t=rr.unshieldedToken().raw,r=0n,n=0;for(let s of e.coins)if(s.type===t)r+=s.value,n++;return{balance:r,count:n}}function Ma(e,t,r={}){let{onProgress:n,onCheckpoint:s,timeoutMs:o=600000,idleMs:i=5000,initialSilenceMs:a=3000,signal:c,initialState:d,startFromId:u=0}=r,l=500,f=d??new rr.ZswapLocalState,p=[],m=0,h=u-1,w=-1,y=()=>{if(p.length===0)return;if(f=f.replayEventsWithChanges(e,p).state,m+=p.length,p.length=0,s&&h>=0)try{s(f,h)}catch{}};return er(t,{query:Jf,variables:{id:u},idleMs:i,timeoutMs:o,initialSilenceMs:d?a:0,signal:c,onNext:(S)=>{let v=S?.zswapLedgerEvents;if(!v)return!1;let A;try{A=rr.Event.deserialize(new Uint8Array(Buffer.from(v.raw,"hex")))}catch(N){throw Error(`Failed to deserialize zswap event ${v.id}: ${N.message}`)}if(p.push(A),h=v.id,v.maxId>w)w=v.maxId;if(p.length>=500)try{y()}catch(N){throw Error(`Failed applying zswap events: ${N.message}`)}return n?.(m+p.length,w),h>=w},buildResult:(S)=>{try{y();let{balance:v,count:A}=qf(f);return{balance:v,availableCoins:A,eventCount:m,state:f,lastAppliedEventId:h,partial:S}}catch(v){throw Error(`Failed to build shielded state: ${v.message}`)}}})}var Jf=`
|
|
103
103
|
subscription ZswapLedgerEvents($id: Int) {
|
|
104
104
|
zswapLedgerEvents(id: $id) {
|
|
105
105
|
id
|
|
@@ -107,110 +107,106 @@ Start a ledger-9 stack (node 2.1.0-rc.2, proof-server 9.0.0-rc.8, a 4.4 indexer)
|
|
|
107
107
|
maxId
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
|
-
`;var
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
Dust
|
|
114
|
-
|
|
115
|
-
Available: ${Mn(N)} DUST, need ≥${Mn(yr)} DUST.
|
|
116
|
-
Dust regenerates over time from registered NIGHT UTXOs.
|
|
117
|
-
Check status: midnight dust status`);if(o?.aborted)throw Error("Operation cancelled");if(F("transfer","Ensuring dust availability..."),await et(y,c,S),F("transfer","Dust available"),o?.aborted)throw Error("Operation cancelled");return F("transfer","Building and submitting transaction..."),{txHash:await Ff(y,m,p,d,u,c,l),amountMicroNight:p}},{syncMode:"lite",requireStrictSync:!0,signal:o,onStatus:c,onSyncProgress:i,onSyncDetail:a,onSyncWarning:f})}finally{w(),h()}}var Qs=6;var Pt=T(()=>{pt();He();yt();mt();Ur();Ur();Ys();$a();de()});function Ma(e){return e.replace(/\x1b\[[0-9;]*m/g,"")}function G(e){let t=!1;if(!Ir()){let a=e;process.stderr.write(`⠋ ${a}`);let c={update(d){a=d,process.stderr.write(`\r⠋ ${a}\x1B[K`)},stop(d){if(t)return;t=!0,nr=null,process.stderr.write(`\r✓ ${d??a}\x1B[K
|
|
118
|
-
`)},fail(d){if(t)return;t=!0,nr=null,process.stderr.write(`\r✗ ${d??a}\x1B[K
|
|
110
|
+
`;var Fa=T(()=>{Mn()});import{existsSync as Bn,mkdirSync as zf,writeFileSync as Yf,readFileSync as Xf,unlinkSync as so,readdirSync as La,renameSync as Zf}from"node:fs";import{join as nr,dirname as Qf}from"node:path";import{homedir as Ua}from"node:os";import{randomBytes as em}from"node:crypto";import*as Vr from"@midnightntwrk/ledger-v9";function Ba(e){return Vr.ZswapSecretKeys.fromSeed(At(e)).coinPublicKey}function ja(e,t){let r=t??nr(Ua(),ie,Me);return nr(r,e)}function oo(e,t,r){let n=t.slice(0,20);return nr(ja(e,r),`shielded-${n}.json`)}function tm(e,t,r,n){let s=oo(e,t,r);if(!Bn(s))return null;try{let o=JSON.parse(Xf(s,"utf-8"));if(o.version!==Wa)return null;if(o.network!==e)return null;if(o.coinPublicKeyHex!==t)return null;if(typeof o.lastAppliedEventId!=="number")return null;if(typeof o.zswapState!=="string")return null;if(n&&o.chainId&&o.chainId!==n)return null;return{state:Vr.ZswapLocalState.deserialize(new Uint8Array(Buffer.from(o.zswapState,"hex"))),lastAppliedEventId:o.lastAppliedEventId}}catch{return null}}function no(e,t,r,n,s,o){let i={version:Wa,network:e,coinPublicKeyHex:t,lastAppliedEventId:n,timestamp:new Date().toISOString(),zswapState:Buffer.from(r.serialize()).toString("hex"),...o?{chainId:o}:{}},a=oo(e,t,s),c=Qf(a);if(!Bn(c))zf(c,{recursive:!0,mode:Te});let d=a+`.tmp.${em(4).toString("hex")}`;try{Yf(d,JSON.stringify(i),{mode:Ne}),Zf(d,a)}catch(u){try{so(d)}catch{}throw u}}function Jr(e,t,r){let n=r??nr(Ua(),ie,Me);if(e&&t){let o=oo(e,t,r);try{so(o)}catch{}return}let s=(o)=>{if(!Bn(o))return;try{for(let i of La(o))if(i.startsWith("shielded-")&&i.endsWith(".json"))try{so(nr(o,i))}catch{}}catch{}};if(e){s(ja(e,r));return}if(!Bn(n))return;try{for(let o of La(n))s(nr(n,o))}catch{}}async function Ha(e,t,r,n={}){let s=Vr.ZswapSecretKeys.fromSeed(At(e)),o=s.coinPublicKey,i=n.forceFresh?null:tm(t,o,void 0,n.chainId);if(i&&Un(i.lastAppliedEventId,await Ln(r,"zswap")))Jr(t,o),i=null;let a=i?i.lastAppliedEventId+1:0,c=await Ma(s,r,{initialState:i?.state,startFromId:a,onProgress:n.onProgress,signal:n.signal,timeoutMs:n.timeoutMs,onCheckpoint:(d,u)=>{try{no(t,o,d,u,void 0,n.chainId)}catch{}}});if(c.lastAppliedEventId>=0)no(t,o,c.state,c.lastAppliedEventId,void 0,n.chainId);else if(!i)no(t,o,c.state,-1,void 0,n.chainId);return{balance:c.balance,availableCoins:c.availableCoins,eventCount:c.eventCount,lastAppliedEventId:c.lastAppliedEventId>=0?c.lastAppliedEventId:i?.lastAppliedEventId??-1,fromCache:i!==null,partial:c.partial}}var Wa=2;var io=T(()=>{Tt();Fa();to()});function Ga(e={}){let t=Math.min(Math.max(e.windowMs??15000,1000),60000),r=[],n=null,s=(i)=>{let a=i-t;while(r.length>0&&r[0].t<a)r.shift()},o=()=>{let i=r[r.length-1],a=r[0],c=i.highest>0?Math.min(100,Math.round(i.applied/i.highest*100)):null,d=null,u=null;if(r.length>=2){let l=i.applied-a.applied,f=i.t-a.t;if(f>=1000&&l>0){d=l/(f/1000);let p=Math.max(0,i.highest-i.applied);u=p>0?p/d:0}}return{applied:i.applied,highest:i.highest,percent:c,ratePerSec:d,etaSec:u}};return{sample(i){return r.push(i),s(i.t),n=o(),n},snapshot(){return n},reset(){r.length=0,n=null}}}function Ka(e,t="Syncing"){let r=[t];if(e.percent!==null)r.push(`${e.percent}%`);else if(e.highest===0)r.push(`${e.applied} events`);if(e.etaSec!==null&&e.etaSec>0)r.push(`ETA ${rm(e.etaSec)}`);if(e.ratePerSec!==null&&e.ratePerSec>0)r.push(`${Math.round(e.ratePerSec)} evt/s`);return r.join(" · ")}function rm(e){if(!Number.isFinite(e)||e<0)return"?";if(e<60)return`${Math.ceil(e)}s`;let t=Math.floor(e/60),r=Math.round(e-t*60);if(t<60)return r>0?`${t}m ${r}s`:`${t}m`;let n=Math.floor(t/60),s=t-n*60;return s>0?`${n}h ${s}m`:`${n}h`}function Va(e,t){let r=(a)=>t.reduce((c,d)=>c+a(d),0n),n=r((a)=>a.dust.generatedNow),s=r((a)=>a.dust.rate),o=r((a)=>a.dust.maxCap),i;if(n>=e)i=0;else if(o<e||s<=0n)i=null;else i=Number(((e-n)*1000n+s-1n)/s);return{fee:e,generated:n,ratePerSecond:s,cap:o,waitMs:i}}function ct(e){if(e<60000){let r=Math.max(1,Math.ceil(e/1000));return`about ${r} second${r===1?"":"s"}`}let t=Math.ceil(e/60000);if(t<2)return"about a minute";if(t<120)return`about ${t} minutes`;return`about ${Math.round(t/60)} hours`}var jn;var Hn=T(()=>{ue();jn=class jn extends Error{code="DUST_GENERATING";constructor(e,t){let r=`Registering for Dust costs a ${de(e.fee)} DUST fee, paid from the Dust this wallet's NIGHT generates`,n=`It has generated ${de(e.generated)} DUST so far`;super(e.waitMs===null?`${r}, but it can never generate that much: its NIGHT holds at most ${de(e.cap)} DUST. ${n}. Add more NIGHT (on undeployed: midnight airdrop 1000), then run: midnight dust register`:`${r}. ${n}, so the fee is covered in ${ct(e.waitMs)} (around ${new Date(t.getTime()+e.waitMs).toISOString()}). Run midnight dust register again then, or add more NIGHT to register sooner (on undeployed: midnight airdrop 1000).`);this.name="DustFeeNotGeneratedError",Object.setPrototypeOf(this,jn.prototype)}}});async function Ja(e){try{let r=(await St(e,"{ block { timestamp } }",void 0,5000)).block?.timestamp;return typeof r==="number"?new Date(r):null}catch{return null}}function qa(e,t){if(t.getTime()-e.getTime()>nm)throw new ao(e,t)}var nm=120000,ao;var za=T(()=>{Gr();Hn();ao=class ao extends Error{code="CHAIN_CLOCK_BEHIND";constructor(e,t){super(`This chain's clock is ${ct(t.getTime()-e.getTime())} behind this computer's (its latest block is stamped ${e.toISOString()}). Dust is generated in chain time, so a registration now would be refused for an unpaid fee. A local chain falls behind like this after the machine sleeps and catches up as it produces blocks: run midnight dust register again once it has, or restart the local chain.`);this.name="ChainClockBehindError",Object.setPrototypeOf(this,ao.prototype)}}});function im(e,t,r,n){let s=(a)=>e.balance(new Date(r.getTime()+a*1000));if(s(0)>=t)return 0;let o=Math.ceil(n/1000);if(s(o)<t)return null;let i=0;while(o-i>1){let a=Math.floor((i+o)/2);if(s(a)>=t)o=a;else i=a}return o*1000}function am(e,t,r){let n=r===null?"This wallet's registered NIGHT won't generate that within a day: register more NIGHT (midnight dust register).":`This wallet's NIGHT generates that in ${ct(r)}; retry then.`;return Error(`Insufficient dust for transaction fees.
|
|
111
|
+
Available: ${de(e)} DUST, need ≥${de(t)} DUST.
|
|
112
|
+
${n}`)}async function Gn(e,t,r,n){let s=new Date,o=e.balance(s);if(o===0n||o>=t)return;let i=im(e,t,s,om);if(i===null||i>sm)throw am(o,t,i);r?.(`Waiting ${ct(i)} for Dust to cover the fee (${de(o)} of ${de(t)} DUST)...`),await co(i,n)}function co(e,t){if(t?.aborted)return Promise.reject(Error("Operation cancelled"));return new Promise((r,n)=>{let s=()=>{clearTimeout(o),n(Error("Operation cancelled"))},o=setTimeout(()=>{t?.removeEventListener("abort",s),r()},e);t?.addEventListener("abort",s,{once:!0})})}var sm=120000,om=86400000;var Ya=T(()=>{Hn();ue()});import*as po from"@midnightntwrk/ledger-v9";import{MidnightBech32m as cm,UnshieldedAddress as dm}from"@midnightntwrk/wallet-sdk/address-format";function sr(e){if(e<=0)throw Error("Amount must be greater than 0");if(!Number.isFinite(e))throw Error("Amount must be a finite number");let t=e.toFixed(6),[r,n]=t.split("."),s=r+(n??"").padEnd(6,"0"),o=BigInt(s);if(o<=0n)throw Error("Amount too small — minimum is 0.000001 NIGHT");return o}function qr(e){let t=e.trim(),r=/^(\d*)(?:\.(\d*))?$/.exec(t);if(!r||r[1]===""&&!r[2])throw Error(`Invalid amount: "${e}" — must be a positive number, e.g. 1.5`);let n=r[2]??"";if(n.length>lo)throw Error(`Invalid amount: "${e}" — NIGHT has ${lo} decimals, this has ${n.length}`);let s=Number(t);if(s<=0)throw Error(`Invalid amount: "${e}" — must be greater than 0`);let o=BigInt((r[1]||"0")+n.padEnd(lo,"0"));if(sr(s)!==o)throw Error(`Invalid amount: "${e}" — too many digits to handle exactly`);return s}function lm(e,t){let r=Fe(t.networkId);try{return cm.parse(e).decode(dm,r)}catch(n){throw Error(`Invalid recipient address: ${n.message}
|
|
113
|
+
Expected a bech32m address for network "${t.networkId}"`)}}function uo(e){let t=Math.round(e/1000);if(t<60)return`${t}s`;let r=Math.floor(t/60),n=t%60;return`${r}m ${n}s`}function De(){let{warn:e,error:t}=console,r=(n)=>n.some((s)=>String(s).includes("RPC-CORE"));return console.warn=(...n)=>{if(!r(n))e(...n)},console.error=(...n)=>{if(!r(n))t(...n)},()=>{console.warn=e,console.error=t}}async function um(e,t,r,n){await Promise.race([e.facade.dust.waitForSyncedState(),new Promise((a,c)=>setTimeout(()=>c(Error("Insufficient funds: dust wallet sync timed out")),ln))]);let{fee:s}=await e.facade.estimateRegistration(t);await e.facade.waitForGeneratedDust(t,s,{timeoutMs:n});let o=await e.facade.registerNightUtxosForDustGeneration(t,e.keystore.getPublicKey(),e.keystore.signDataAsync,r),i;try{i=await e.facade.finalizeRecipe(o)}catch(a){try{await e.facade.revert(o)}catch{}throw a}return await e.facade.submitTransaction(i)}async function pm(e,t,r,n){let s=Date.now(),o=s+xi,i,a=!1,c=e.indexerHttpUrl?await Ja(e.indexerHttpUrl):null;if(c)qa(c,new Date);let{fee:d,dustGenerationEstimations:u}=await e.facade.estimateRegistration(t),l=Va(d,u);if(l.waitMs===null||l.waitMs>o-Date.now())throw new jn(l,new Date);let f=l.waitMs>0?`, fee covered in ${ct(l.waitMs)}`:"";if(l.waitMs>0)n?.(`Waiting for the NIGHT to generate the ${de(l.fee)} DUST registration fee (${ct(l.waitMs)})...`);let p=setInterval(()=>{if(a&&n){let m=uo(Date.now()-s);n(`Waiting for dust generation capacity (${m} elapsed${f})...`)}},1000);try{while(Date.now()<o)try{return await um(e,t,r,o-Date.now())}catch(m){if(i=m,Rn(m)&&Date.now()+ks<o){a=!0;let h=uo(Date.now()-s);n?.(`Waiting for dust generation capacity (${h} elapsed${f})...`),await new Promise((w)=>setTimeout(w,ks));continue}throw m}throw i??Error("Dust registration timed out")}finally{clearInterval(p)}}async function et(e,t,r){let n=r??await e.facade.waitForSyncedState();if($t(n))return t?.("Dust available"),{alreadyAvailable:!0};if(n.unshielded.availableCoins.length===0&&(n.unshielded.pendingCoins?.length??0)===0)throw Error("This wallet has no NIGHT, so it generates no Dust to pay fees. Fund it first (on undeployed: midnight airdrop <amount>), then run: midnight dust register");let s=n.unshielded.availableCoins.filter((a)=>!a.meta.registeredForDustGeneration),o;if(s.length>0)t?.(`Registering ${s.length} UTXO(s) for dust generation...`),o=await pm(e,s,n.dust.address,t);else t?.("UTXOs already registered, waiting for dust generation...");t?.("Waiting for dust tokens...");let i=Date.now();while(Date.now()-i<bs){try{if((await Promise.race([e.facade.waitForSyncedState(),new Promise((c,d)=>setTimeout(()=>d(Error("Poll sync timed out")),ln))])).dust.balance(new Date)>0n)return t?.("Dust available"),{alreadyAvailable:!1,txHash:o}}catch{}await new Promise((a)=>setTimeout(a,5000))}throw Error("Timed out waiting for dust tokens. Try running: midnight dust register")}async function fm(e,t,r,n,s,o,i,a){let c=Date.now(),d=c+bs,u,l=0;while(!0)try{if(u)await Js(e,"lite");let f=new Date(Date.now()+pn*60*1000);F("transfer","Building transfer transaction...");let p=await e.facade.transferTransaction([{type:"unshielded",outputs:[{amount:r,receiverAddress:t,type:po.unshieldedToken().raw}]}],{ttl:f,payFees:!0});F("transfer","Signing recipe...");let m=await e.facade.signRecipe(p,e.keystore.signDataAsync);F("transfer","Generating ZK proof..."),n?.();let h=await Promise.race([e.facade.finalizeRecipe(m),new Promise((v,A)=>{setTimeout(()=>A(Error("ZK proof generation timed out")),un)})]);F("transfer","Submitting transaction to node..."),s?.();let w=Date.now(),y=i?setInterval(()=>i(Date.now()-w),1000):void 0,S;try{S=await e.facade.submitTransaction(h)}finally{if(y)clearInterval(y)}return F("transfer",`Transaction submitted: ${S}`),S}catch(f){if(u=f,(f?.code===Ci||f?.message?.includes("115")||f?.message?.toLowerCase().includes("stale"))&&++l<ki)continue;if(Dn(f))throw f;if(Rn(f)&&Date.now()<d){let m=uo(Date.now()-c);o?.(`Dust insufficient, re-ensuring (${m} elapsed)...`);try{let h=await Js(e,"lite");if(await Gn(h.dust,kr,o,a),h.dust.balance(new Date)>=kr)o?.(`Dust is short of this transaction's fee; waiting ${Xa/1000} s for more...`),await co(Xa,a);await et(e,o,h)}catch(h){if(String(h?.message).startsWith("Insufficient dust"))throw h;await new Promise((w)=>setTimeout(w,5000))}continue}throw f}}async function or(e){let{seedBuffer:t,networkConfig:r,recipientAddress:n,amountNight:s,signal:o,onSync:i,onSyncDetail:a,onDust:c,onProving:d,onSubmitting:u,onSubmittingTick:l,onSyncWarning:f}=e,p=sr(s),m=lm(n,r),h=Re(f),w=De();try{return await Ce().withFacade(t,r,async({bundle:y,state:S})=>{if(o?.aborted)throw Error("Operation cancelled");F("transfer","Sync complete, checking balance...");let v=S.unshielded.balances[po.unshieldedToken().raw]??0n,A=S.unshielded.availableCoins?.length??0;if(F("transfer",`Balance: ${Number(v)/Ss} NIGHT, coins: ${A}`),v<p){let X=Number(v)/Ss;throw Error(`Insufficient balance: ${X.toFixed(6)} NIGHT available, ${s} NIGHT requested`)}if(await Gn(S.dust,kr,c,o),o?.aborted)throw Error("Operation cancelled");if(F("transfer","Ensuring dust availability..."),!(await et(y,c,S)).alreadyAvailable){let X,q=await Promise.race([y.facade.waitForSyncedState(),new Promise((V)=>{X=setTimeout(()=>V(null),ln)})]).finally(()=>clearTimeout(X));if(q)await Gn(q.dust,kr,c,o)}if(F("transfer","Dust available"),o?.aborted)throw Error("Operation cancelled");return F("transfer","Building and submitting transaction..."),{txHash:await fm(y,m,p,d,u,c,l,o),amountMicroNight:p}},{syncMode:"lite",requireStrictSync:!0,signal:o,onStatus:c,onSyncProgress:i,onSyncDetail:a,onSyncWarning:f})}finally{w(),h()}}var lo=6,Xa=1e4;var Ft=T(()=>{mt();Ke();bt();ht();Br();Br();Hn();za();Ya();ue()});function Qa(e){return e.replace(/\x1b\[[0-9;]*m/g,"")}function K(e){let t=!1;if(!Pr()){let a=e;process.stderr.write(`⠋ ${a}`);let c={update(d){a=d,process.stderr.write(`\r⠋ ${a}\x1B[K`)},stop(d){if(t)return;t=!0,ir=null,process.stderr.write(`\r✓ ${d??a}\x1B[K
|
|
114
|
+
`)},fail(d){if(t)return;t=!0,ir=null,process.stderr.write(`\r✗ ${d??a}\x1B[K
|
|
119
115
|
`)},log(d){process.stderr.write(`\r\x1B[K${d}
|
|
120
|
-
`),process.stderr.write(`⠋ ${a}`)}};return
|
|
121
|
-
`)},fail(a){if(t)return;t=!0,clearInterval(o),
|
|
116
|
+
`),process.stderr.write(`⠋ ${a}`)}};return ir=c,c}let r=0,n=e,s=()=>{let a=G(Za[r]),d=(process.stderr.columns||80)-4,u=n;if(Qa(u).length>d)u=Qa(u).slice(0,d);process.stderr.write(`\r${a} ${u}\x1B[K`),r=(r+1)%Za.length};s();let o=setInterval(s,mm),i={update(a){n=a},stop(a){if(t)return;t=!0,clearInterval(o),ir=null;let c=a??n;process.stderr.write(`\r\x1B[32m✓\x1B[0m ${c}\x1B[K
|
|
117
|
+
`)},fail(a){if(t)return;t=!0,clearInterval(o),ir=null;let c=a??n;process.stderr.write(`\r\x1B[31m✗\x1B[0m ${c}\x1B[K
|
|
122
118
|
`)},log(a){process.stderr.write(`\r\x1B[K${a}
|
|
123
|
-
`),s()}};return
|
|
124
|
-
Drop --network (we'll infer from the address) or pass an address for ${n}.`);if(!n&&r)e={...e,flags:{...e.flags,network:r}};let{name:s,config:o}=le({args:e});if(R(e,"shielded")){let a=
|
|
119
|
+
`),s()}};return ir=i,i}async function Kn(e,t,r){let n=Date.now(),s=(a)=>{let c=Math.floor(a/1000),d=Math.floor(c/60).toString().padStart(2,"0"),u=(c%60).toString().padStart(2,"0");return`${d}:${u}`},o=()=>e.update(`${t} ${s(Date.now()-n)}`);o();let i=setInterval(o,1000);try{return await r}finally{clearInterval(i)}}var Za,mm=80,ir=null;var dt=T(()=>{Za=["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"]});var nc={};he(nc,{default:()=>tc});import*as ec from"@midnightntwrk/ledger-v9";import{MidnightBech32m as gm}from"@midnightntwrk/wallet-sdk/address-format";async function tc(e){if(e.subcommand)return wm(e);return rc(e)}function hm(e){let t=e.match(/^mn_addr_([a-z]+)1/);if(!t)return null;let r=t[1];return be(r)?r:null}async function wm(e){if(je(e))Ge();let t=e.subcommand;F("balance",`address=${t}`);let r=hm(t),n=x(e,"network");if(n&&r&&n!==r)throw Error(`Address belongs to ${r} but --network is ${n}.
|
|
120
|
+
Drop --network (we'll infer from the address) or pass an address for ${n}.`);if(!n&&r)e={...e,flags:{...e.flags,network:r}};let{name:s,config:o}=le({args:e});if(R(e,"shielded")){let a=ji(t);if(a){F("balance",`shielded positional → wallet ${a.wallet.name} on ${a.network}`);let c={...e,flags:{...e.flags,wallet:a.wallet.file,network:a.network}};return rc(c)}throw Error("Shielded balances are private — they can only be read with the wallet's secret key, "+`not from an address alone.
|
|
125
121
|
This address isn't one of your wallets. Check its shielded balance from the wallet that owns it:
|
|
126
|
-
midnight balance --wallet <name> --shielded --network ${s}`)}
|
|
127
|
-
`);else for(let[c,d]of a.balances)process.stdout.write(`${
|
|
122
|
+
midnight balance --wallet <name> --shielded --network ${s}`)}$e(o,{proofServer:x(e,"proof-server"),node:x(e,"node"),indexerWS:x(e,"indexer-ws")},s);let i=K(`Checking balance on ${s}...`);try{let a=await Ce().unshielded(t,o,{forceFresh:R(e,"no-cache"),onProgress:(c,d)=>{if(d>0){let u=Math.round(c/d*100);i.update(`Syncing transactions... ${u}%`)}}});if(i.stop(`Synced ${a.txCount} transactions`),R(e,"json")){let c={};for(let[u,l]of a.balances){let f=Fr(u)?"NIGHT":u;c[f]=Fr(u)?Rt(l):l.toString()}let d=c.NIGHT!==void 0?{NIGHT:c.NIGHT}:{};if(pt(e)){D({network:s,balances:c,...d,utxoCount:a.utxoCount});return}D({address:t,network:s,balances:c,...d,utxoCount:a.utxoCount,txCount:a.txCount});return}if(a.balances.size===0)process.stdout.write(`0
|
|
123
|
+
`);else for(let[c,d]of a.balances)process.stdout.write(`${Fr(c)?"NIGHT":c}=${d}
|
|
128
124
|
`);if(process.stderr.write(`
|
|
129
|
-
`+
|
|
125
|
+
`+B("Balance")+`
|
|
130
126
|
|
|
131
|
-
`),process.stderr.write(
|
|
132
|
-
`),process.stderr.write(
|
|
133
|
-
`),process.stderr.write(
|
|
134
|
-
`),process.stderr.write(
|
|
127
|
+
`),process.stderr.write(C("Address",ee(t))+`
|
|
128
|
+
`),process.stderr.write(C("Network",s)+`
|
|
129
|
+
`),process.stderr.write(C("UTXOs",a.utxoCount.toString())+`
|
|
130
|
+
`),process.stderr.write(C("Transactions",a.txCount.toString())+`
|
|
135
131
|
`),process.stderr.write(`
|
|
136
132
|
`),a.balances.size===0)process.stderr.write(` ${g("No balance found")}
|
|
137
|
-
`);else for(let[c,d]of a.balances)if(
|
|
138
|
-
`);else{let u=c.slice(0,8)+"…"+c.slice(-8);process.stderr.write(
|
|
133
|
+
`);else for(let[c,d]of a.balances)if(Fr(c))process.stderr.write(C("NIGHT",P(vn(d)))+`
|
|
134
|
+
`);else{let u=c.slice(0,8)+"…"+c.slice(-8);process.stderr.write(C(`Token ${u}`,P(d.toString()))+`
|
|
139
135
|
`)}process.stderr.write(`
|
|
140
|
-
`+
|
|
136
|
+
`+J()+`
|
|
141
137
|
|
|
142
|
-
`)}catch(a){throw i.fail("Failed"),a}}async function
|
|
143
|
-
`+
|
|
138
|
+
`)}catch(a){throw i.fail("Failed"),a}}async function rc(e){if(je(e))Ge();let{name:t,config:r}=le({args:e});F("balance",`network=${t} indexerWS=${r.indexerWS}`);let{seed:n,walletPath:s,config:o}=Ls(e);F("balance",`wallet path=${s??"(from --seed/MN_SEED)"}`);let i=o?.addresses[t]??ve(n,t),a=o?.shieldedAddresses?.[t]??"";$e(r,{proofServer:x(e,"proof-server"),node:x(e,"node"),indexerWS:x(e,"indexer-ws")},t);let c=Re(),d=De(),u=R(e,"no-cache"),l=R(e,"json"),f=ec.unshieldedToken().raw,p=null;try{if(!l){if(process.stderr.write(`
|
|
139
|
+
`+B("Balance")+`
|
|
144
140
|
|
|
145
|
-
`),process.stderr.write(
|
|
146
|
-
`),a)process.stderr.write(
|
|
147
|
-
`);process.stderr.write(
|
|
141
|
+
`),process.stderr.write(C("Address",ee(i))+`
|
|
142
|
+
`),a)process.stderr.write(C("Shielded",ee(a))+`
|
|
143
|
+
`);process.stderr.write(C("Network",t)+`
|
|
148
144
|
`),process.stderr.write(`
|
|
149
|
-
`+
|
|
150
|
-
`)}if(!l)p=
|
|
151
|
-
`),process.stderr.write(
|
|
145
|
+
`+P("Unshielded")+`
|
|
146
|
+
`)}if(!l)p=K("Checking unshielded...");F("balance",`phase=unshielded forceFresh=${u}`);let m=await Ce().unshielded(i,r,{forceFresh:u}),h=m.balances.get(f)??0n,w=m.utxoCount;if(F("balance",`unshielded fromCache=${m.fromCache} utxos=${w} txs=${m.txCount}`),p)if(p.stop("Unshielded ready"),p=null,h>0n)process.stderr.write(C(" NIGHT",P(vn(h)))+`
|
|
147
|
+
`),process.stderr.write(C(" UTXOs",w.toString())+`
|
|
152
148
|
`);else process.stderr.write(` ${g("No unshielded balance")}
|
|
153
149
|
`);if(!l)process.stdout.write(`NIGHT=${h}
|
|
154
150
|
`),process.stderr.write(`
|
|
155
|
-
`+
|
|
156
|
-
`);let y=
|
|
157
|
-
`),process.stderr.write(
|
|
151
|
+
`+P("Shielded")+`
|
|
152
|
+
`);let y=xn(t,R(e,"force-shielded")),S=a,v=0n,A=0,N=0;if(y){if(!l)p=K("Syncing shielded...");let L=Ga(),X=Fe(r.networkId);if(S=gm.encode(X,Dr(n)).asString(),s)Jt(s,t,S);await Be(t,r);let q=await Qt(r.node).catch(()=>null)??void 0,V=await Ha(n,t,r.indexerWS,{forceFresh:u,chainId:q,onProgress:(O,_)=>{if(!p)return;let ne=L.sample({applied:O,highest:_,t:Date.now()});p.update(Ka(ne,"Syncing shielded"))}});if(v=V.balance,A=V.availableCoins,N=0,p)if(p.stop("Shielded ready"),p=null,v>0n)process.stderr.write(C(" NIGHT",P(vn(v)))+`
|
|
153
|
+
`),process.stderr.write(C(" Coins",`${A} available, ${N} pending`)+`
|
|
158
154
|
`);else process.stderr.write(` ${g("No shielded balance")}
|
|
159
|
-
`)}else if(!l)process.stderr.write(` ${g("Skipped — "+
|
|
160
|
-
`);if(l){if(
|
|
155
|
+
`)}else if(!l)process.stderr.write(` ${g("Skipped — "+Cn(t))}
|
|
156
|
+
`);if(l){if(pt(e)){D({network:t,unshielded:{NIGHT:Rt(h),utxoCount:w},shielded:{NIGHT:Rt(v),availableCoins:A,pendingCoins:N},shieldedSynced:y});return}D({address:i,shieldedAddress:S,network:t,unshielded:{NIGHT:Rt(h),utxoCount:w},shielded:{NIGHT:Rt(v),availableCoins:A,pendingCoins:N},shieldedSynced:y});return}process.stdout.write(`SHIELDED_NIGHT=${y?v:"skipped"}
|
|
161
157
|
`),process.stderr.write(`
|
|
162
|
-
`+
|
|
158
|
+
`+J()+`
|
|
163
159
|
|
|
164
|
-
`)}catch(m){throw p?.fail("Failed"),m}finally{d(),c()}}var
|
|
160
|
+
`)}catch(m){throw p?.fail("Failed"),m}finally{d(),c()}}var sc=T(()=>{ht();me();Le();zt();ke();me();Us();mt();Lr();bt();io();Ot();He();Pn();Ke();Ft();ue();dt()});var ic={};he(ic,{default:()=>oc});async function oc(e){let t=bn(e,{requireExplicit:!0,label:"address"}),r=x(e,"index"),n=r!==void 0?parseInt(r,10):0;if(isNaN(n)||n<0||!Number.isInteger(Number(r??"0")))throw Error("Key index must be a non-negative integer");let s=we({args:e}),o=ve(t,s,n),i=`m/44'/2400'/0'/NightExternal/${n}`;if(R(e,"json")){D({address:o,network:s,index:n,path:i});return}process.stdout.write(o+`
|
|
165
161
|
`),process.stderr.write(`
|
|
166
|
-
`),process.stderr.write(
|
|
167
|
-
`),process.stderr.write(
|
|
168
|
-
`),process.stderr.write(
|
|
169
|
-
`),process.stderr.write(
|
|
170
|
-
`),process.stderr.write(
|
|
162
|
+
`),process.stderr.write(C("Network",s)+`
|
|
163
|
+
`),process.stderr.write(C("Index",n.toString())+`
|
|
164
|
+
`),process.stderr.write(C("Address",ee(o))+`
|
|
165
|
+
`),process.stderr.write(C("Path",g(i))+`
|
|
166
|
+
`),process.stderr.write(J()+`
|
|
171
167
|
|
|
172
|
-
`)}var
|
|
168
|
+
`)}var ac=T(()=>{zt();He();ke();ue()});var dc={};he(dc,{default:()=>cc});async function cc(e){let t=we({args:e}),r=Buffer.from(rt,"hex"),n=ve(r,t);if(R(e,"json")){D({address:n,network:t});return}process.stdout.write(n+`
|
|
173
169
|
`),process.stderr.write(`
|
|
174
|
-
`),process.stderr.write(
|
|
175
|
-
`),process.stderr.write(
|
|
176
|
-
`),process.stderr.write(
|
|
177
|
-
`),process.stderr.write(
|
|
170
|
+
`),process.stderr.write(C("Network",t)+`
|
|
171
|
+
`),process.stderr.write(C("Address",ee(n))+`
|
|
172
|
+
`),process.stderr.write(C("Seed",g("0x01 (genesis)"))+`
|
|
173
|
+
`),process.stderr.write(J()+`
|
|
178
174
|
|
|
179
|
-
`)}var
|
|
175
|
+
`)}var lc=T(()=>{He();ke();ue()});import*as uc from"@midnightntwrk/ledger-v9";async function pc(e){let t=await St(e,"{ block { height ledgerParameters } }",void 0,1e4),r=t.block?.ledgerParameters;if(typeof r!=="string"||typeof t.block?.height!=="number")throw Error("The indexer returned no ledger parameters for its latest block");return{height:t.block.height,params:uc.LedgerParameters.deserialize(Buffer.from(r,"hex"))}}var fc=T(()=>{Gr()});var gc={};he(gc,{default:()=>mc});function zr(e,t,r){let n={readTime:0n,computeTime:0n,blockUsage:0n,bytesWritten:0n,bytesChurned:0n};n[t]=r;let o=e.normalizeFullness(n)[t];return Math.round(Number(r)/o)}function ym(e){return{readTime:zr(e,"readTime",1000000000n),computeTime:zr(e,"computeTime",1000000000n),blockUsage:zr(e,"blockUsage",10000n),bytesWritten:zr(e,"bytesWritten",10000n),bytesChurned:zr(e,"bytesChurned",1000000n)}}async function mc(e){let{name:t,config:r}=le({args:e});await Be(t,r);let{height:n,params:s}=await pc(r.indexer),o=ym(s);if(R(e,"json")){D({...o,network:t,height:n});return}for(let[i,a]of Object.entries(o))process.stdout.write(`${i}=${a}
|
|
180
176
|
`);process.stderr.write(`
|
|
181
|
-
`+
|
|
177
|
+
`+B("Block Limits")+`
|
|
182
178
|
|
|
183
|
-
`),process.stderr.write(g(
|
|
179
|
+
`),process.stderr.write(g(` From the ledger parameters of block ${n} on ${t}`)+`
|
|
184
180
|
|
|
185
|
-
`);for(let[
|
|
181
|
+
`);for(let[i,a]of Object.entries(o)){let c=Sm[i]??"";process.stderr.write(C(i,`${P(a.toLocaleString())} ${g(c)}`)+`
|
|
186
182
|
`)}process.stderr.write(`
|
|
187
|
-
`+
|
|
183
|
+
`+J()+`
|
|
188
184
|
`),process.stderr.write(g(" bytesWritten is typically the tightest constraint")+`
|
|
189
185
|
`),process.stderr.write(g(" for large contract deployments.")+`
|
|
190
186
|
|
|
191
|
-
`)}var
|
|
187
|
+
`)}var Sm;var hc=T(()=>{ue();ke();fc();Ot();Sm={readTime:"picoseconds",computeTime:"picoseconds",blockUsage:"bytes",bytesWritten:"bytes",bytesChurned:"bytes"}});var bc={};he(bc,{default:()=>Sc});import*as wc from"@midnightntwrk/ledger-v9";import{MidnightBech32m as yc,ShieldedAddress as bm}from"@midnightntwrk/wallet-sdk/address-format";async function Sc(e,t){jt(e);let r=e.subcommand;if(!r)throw Error(`Missing amount.
|
|
192
188
|
Usage: midnight airdrop <amount> [--wallet <name|file|address>]
|
|
193
189
|
Example: midnight airdrop 1000
|
|
194
190
|
Example: midnight airdrop 1000 --wallet alice
|
|
195
|
-
Example: midnight airdrop 1000 --wallet mn_addr_undeployed1...`);let n=
|
|
191
|
+
Example: midnight airdrop 1000 --wallet mn_addr_undeployed1...`);let n=qr(r),{name:s,config:o}=le({args:e});if($e(o,{proofServer:x(e,"proof-server"),node:x(e,"node"),indexerWS:x(e,"indexer-ws")},s),s!=="undeployed")throw Error(`Airdrop is only available on the "undeployed" network (local devnet).
|
|
196
192
|
Current network: "${s}"
|
|
197
|
-
On preprod/preview, use a faucet or transfer from another wallet.`);let i=
|
|
193
|
+
On preprod/preview, use a faucet or transfer from another wallet.`);let i=x(e,"wallet"),a=R(e,"shielded")||i!==void 0&&i.startsWith("mn_shield-addr_"),c=km(e,s,o,a);if(a)return Em(e,c,n,s,o,t);return Cm(e,c,n,s,o,t)}function vm(e){return e.startsWith("mn_addr_")||e.startsWith("mn_shield-addr_")}function km(e,t,r,n){let s=x(e,"wallet");if(s!==void 0&&vm(s))return xm(s,t,r,n);let o=re(s),i=ae(o);if(n){let a=Fe(r.networkId),c=Buffer.from(i.seed,"hex"),d=Dr(c),u=yc.encode(a,d).asString();return{kind:"wallet",raw:d,bech32m:u,walletPath:o}}return{kind:"address",address:i.addresses[t]}}function xm(e,t,r,n){let s=e.startsWith("mn_shield-addr_");if(n&&!s)throw Error(`--shielded was passed but --wallet is an unshielded address.
|
|
198
194
|
Pass a shielded address (mn_shield-addr_...) or drop --shielded.
|
|
199
195
|
Got: ${e}`);let o=n?`mn_shield-addr_${t}1`:`mn_addr_${t}1`;if(!e.startsWith(o))throw Error(`Address does not match network "${t}".
|
|
200
196
|
Expected prefix: ${o}
|
|
201
|
-
Got: ${e}`);if(n){let i=
|
|
202
|
-
`+
|
|
197
|
+
Got: ${e}`);if(n){let i=Fe(r.networkId),a;try{a=yc.parse(e).decode(bm,i)}catch(c){throw Error(`Invalid shielded address: ${c.message}`)}return{kind:"address",raw:a,bech32m:e}}return{kind:"address",address:e}}async function Cm(e,t,r,n,s,o){if(je(e))Ge();let i=t.address,a=Buffer.from(rt,"hex");process.stderr.write(`
|
|
198
|
+
`+B("Airdrop")+`
|
|
203
199
|
|
|
204
|
-
`),process.stderr.write(
|
|
205
|
-
`),process.stderr.write(
|
|
206
|
-
`),process.stderr.write(
|
|
207
|
-
`),process.stderr.write(
|
|
200
|
+
`),process.stderr.write(C("Network",n)+`
|
|
201
|
+
`),process.stderr.write(C("From",g("genesis (seed 0x01)"))+`
|
|
202
|
+
`),process.stderr.write(C("To",ee(i,!0))+`
|
|
203
|
+
`),process.stderr.write(C("Amount",P(r+" NIGHT"))+`
|
|
208
204
|
`),process.stderr.write(`
|
|
209
|
-
`);let c=
|
|
205
|
+
`);let c=K("Starting genesis wallet...");try{let d=await or({seedBuffer:a,networkConfig:s,recipientAddress:i,amountNight:r,signal:o,onSync(u,l){if(l>0){let f=Math.round(u/l*100);c.update(`Syncing genesis wallet... ${f}%`)}},onDust(u){c.update(`Dust: ${u}`)},onProving(){c.update("Generating ZK proof (this may take a few minutes)...")},onSubmitting(){c.update("Submitting and waiting for finalization (typically 12 to 30s)...")},onSubmittingTick(u){let l=Math.floor(u/1000),f=Math.floor(l/60).toString().padStart(2,"0"),p=(l%60).toString().padStart(2,"0");c.update(`Submitting and waiting for finalization... ${f}:${p} elapsed (typically 12 to 30s)`)},onSyncWarning(u,l){c.update(`Syncing genesis wallet... (${l}, retrying)`)}});if(c.stop("Transaction submitted"),R(e,"json")){D({txHash:d.txHash,amount:r,recipient:i,network:n});return}process.stdout.write(d.txHash+`
|
|
210
206
|
`),process.stderr.write(`
|
|
211
|
-
`+
|
|
207
|
+
`+gt(`Airdropped ${r} NIGHT to your wallet`,d.txHash)+`
|
|
212
208
|
`),process.stderr.write(`
|
|
213
|
-
`+
|
|
209
|
+
`+J()+`
|
|
214
210
|
`),process.stderr.write(g(" Verify: midnight balance")+`
|
|
215
211
|
`),process.stderr.write(g(" Register dust: midnight dust register")+`
|
|
216
212
|
`),process.stderr.write(g(" Note: registering pays its fee from Dust this NIGHT generates, so it waits longer the less NIGHT")+`
|
|
@@ -219,128 +215,130 @@ Got: ${e}`);if(n){let i=Me(r.networkId),a;try{a=Qa.parse(e).decode(Gf,i)}catch(c
|
|
|
219
215
|
`)}catch(d){if(c.fail("Failed"),d instanceof Error&&d.message.toLowerCase().includes("dust"))throw Error(`${d.message}
|
|
220
216
|
|
|
221
217
|
On a fresh localnet, the minimum airdrop is ~1 NIGHT.
|
|
222
|
-
Try: midnight airdrop 1`);throw d}}async function
|
|
223
|
-
`+
|
|
218
|
+
Try: midnight airdrop 1`);throw d}}async function Em(e,t,r,n,s,o){let i=sr(r);if(je(e))Ge();let a=Buffer.from(rt,"hex"),c=wc.unshieldedToken().raw,{raw:d,bech32m:u}=t;if(t.kind==="wallet")Jt(t.walletPath,n,u);process.stderr.write(`
|
|
219
|
+
`+B("Shielded Airdrop")+`
|
|
224
220
|
|
|
225
|
-
`),process.stderr.write(
|
|
226
|
-
`),process.stderr.write(
|
|
227
|
-
`),process.stderr.write(
|
|
228
|
-
`),process.stderr.write(
|
|
221
|
+
`),process.stderr.write(C("Network",n)+`
|
|
222
|
+
`),process.stderr.write(C("From",g("genesis shielded (seed 0x01)"))+`
|
|
223
|
+
`),process.stderr.write(C("To",ee(u,!0))+`
|
|
224
|
+
`),process.stderr.write(C("Amount",P(r+" NIGHT (shielded)"))+`
|
|
229
225
|
`),process.stderr.write(`
|
|
230
|
-
`);let l=
|
|
226
|
+
`);let l=Re(),f=De(),p=K("Syncing genesis wallet...");try{let m=await Ce().withFacade(a,s,async({bundle:h,state:w})=>{let y=w.shielded.balances[c]??0n;if(y<i){let L=Number(y)/1e6;throw Error(`Genesis wallet has insufficient shielded balance: ${L.toFixed(6)} NIGHT available, ${r} NIGHT requested`)}if(p.update("Checking dust..."),await et(h,(L)=>p.update(L)),o?.aborted)throw Error("Operation cancelled");p.update("Building shielded transaction...");let S=await h.facade.transferTransaction([{type:"shielded",outputs:[{type:c,amount:i,receiverAddress:d}]}],{ttl:new Date(Date.now()+3600000)});p.update("Signing...");let v=await h.facade.signRecipe(S,h.keystore.signDataAsync);p.update("Generating ZK proof (this may take a few minutes)...");let A=await h.facade.finalizeRecipe(v),N=await Kn(p,"Submitting and waiting for finalization (typically 12 to 30s)...",h.facade.submitTransaction(A));return String(N)},{syncMode:"full",requireStrictSync:!0,signal:o,onStatus:(h)=>p.update(h),onSyncProgress:(h,w)=>{if(w>0){let y=Math.min(Math.round(h/w*100),100);p.update(y>=100?"Syncing genesis wallet...":`Syncing genesis wallet... ${y}%`)}},onSyncDetail:(h)=>p.update(`Syncing genesis wallet... (waiting on: ${h})`)});if(p.stop("Transaction submitted"),R(e,"json")){D({txHash:m,amount:r,shieldedAddress:u,network:n,type:"shielded"});return}process.stdout.write(m+`
|
|
231
227
|
`),process.stderr.write(`
|
|
232
|
-
`+
|
|
228
|
+
`+gt(`Airdropped ${r} shielded NIGHT to your wallet`,m)+`
|
|
233
229
|
`),process.stderr.write(`
|
|
234
|
-
`+
|
|
230
|
+
`+J()+`
|
|
235
231
|
`),process.stderr.write(g(" Verify: midnight balance --shielded")+`
|
|
236
232
|
|
|
237
|
-
`)}catch(m){throw p.fail("Failed"),m}finally{f(),l()}}var
|
|
233
|
+
`)}catch(m){throw p.fail("Failed"),m}finally{f(),l()}}var vc=T(()=>{ht();Le();ke();me();mt();He();Ft();Ke();bt();ue();dt()});var Ec={};he(Ec,{default:()=>Cc});import*as xc from"@midnightntwrk/ledger-v9";import{MidnightBech32m as kc,ShieldedAddress as Am}from"@midnightntwrk/wallet-sdk/address-format";async function Cc(e,t){jt(e);let r=e.subcommand,n=e.positionals[0];if(!r)throw Error(`Missing recipient address.
|
|
238
234
|
Usage: midnight transfer <to> <amount>
|
|
239
235
|
Example: midnight transfer mn_addr_undeployed1... 100
|
|
240
236
|
Example: midnight transfer alice 100`);if(!n)throw Error(`Missing amount.
|
|
241
237
|
Usage: midnight transfer <to> <amount>
|
|
242
|
-
Example: midnight transfer mn_addr_undeployed1... 100`);let s=R(e,"shielded"),o=
|
|
243
|
-
Regenerate the wallet or run "midnight balance --shielded" first.`);return i}return s.addresses[o]}async function
|
|
244
|
-
`+
|
|
245
|
-
|
|
246
|
-
`),process.stderr.write(
|
|
247
|
-
`),process.stderr.write(
|
|
248
|
-
`),process.stderr.write(
|
|
249
|
-
`),process.stderr.write(
|
|
238
|
+
Example: midnight transfer mn_addr_undeployed1... 100`);let s=R(e,"shielded"),o=Tm(r,e,s);if(s)return Rm(e,o,n,t);return Nm(e,o,n,t)}function Tm(e,t,r){if(e.startsWith("mn_addr_")||e.startsWith("mn_shield-addr_"))return e;let n=re(e),s=ae(n),o=we({args:t});if(r){let i=s.shieldedAddresses?.[o];if(!i)throw Error(`Wallet "${e}" has no shielded address for network "${o}".
|
|
239
|
+
Regenerate the wallet or run "midnight balance --shielded" first.`);return i}return s.addresses[o]}async function Nm(e,t,r,n){let s=qr(r),o=re(x(e,"wallet")),i=ae(o),a=Buffer.from(i.seed,"hex"),{name:c,config:d}=le({args:e}),u=i.addresses[c];if($e(d,{proofServer:x(e,"proof-server"),node:x(e,"node"),indexerWS:x(e,"indexer-ws")},c),process.stderr.write(`
|
|
240
|
+
`+B("Transfer")+`
|
|
241
|
+
|
|
242
|
+
`),process.stderr.write(C("Network",c)+`
|
|
243
|
+
`),process.stderr.write(C("From",ee(u,!0))+`
|
|
244
|
+
`),process.stderr.write(C("To",ee(t,!0))+`
|
|
245
|
+
`),process.stderr.write(C("Amount",P(s+" NIGHT"))+`
|
|
250
246
|
`),process.stderr.write(`
|
|
251
|
-
`),
|
|
247
|
+
`),je(e))Ge();let l=K("Starting wallet...");try{let f=await or({seedBuffer:a,networkConfig:d,recipientAddress:t,amountNight:s,signal:n,onSync(p,m){if(m>0){let h=Math.min(Math.round(p/m*100),100);l.update(h>=100?"Syncing wallet...":`Syncing wallet... ${h}%`)}},onSyncDetail(p){l.update(`Syncing wallet... (waiting on: ${p})`)},onDust(p){l.update(`Dust: ${p}`)},onProving(){l.update("Generating ZK proof (this may take a few minutes)...")},onSubmitting(){l.update("Submitting and waiting for finalization (typically 12 to 30s)...")},onSubmittingTick(p){let m=Math.floor(p/1000),h=Math.floor(m/60).toString().padStart(2,"0"),w=(m%60).toString().padStart(2,"0");l.update(`Submitting and waiting for finalization... ${h}:${w} elapsed (typically 12 to 30s)`)},onSyncWarning(p,m){l.update(`Syncing wallet... (${m}, retrying)`)}});if(l.stop("Transaction submitted"),R(e,"json")){D({txHash:f.txHash,amount:s,recipient:t,network:c});return}process.stdout.write(f.txHash+`
|
|
252
248
|
`),process.stderr.write(`
|
|
253
|
-
`+
|
|
249
|
+
`+gt(`Transferred ${s} NIGHT`,f.txHash)+`
|
|
254
250
|
`),process.stderr.write(`
|
|
255
|
-
`+
|
|
251
|
+
`+J()+`
|
|
256
252
|
`),process.stderr.write(g(" Verify: midnight balance")+`
|
|
257
253
|
|
|
258
|
-
`)}catch(f){throw l.fail("Failed"),f}}async function
|
|
254
|
+
`)}catch(f){throw l.fail("Failed"),f}}async function Rm(e,t,r,n){let s=qr(r),o=sr(s),i=re(x(e,"wallet")),a=ae(i),c=Buffer.from(a.seed,"hex"),{name:d,config:u}=le({args:e});if(!xn(d,R(e,"force-shielded")))throw Error(Cn(d));let l=a.addresses[d],f=Fe(u.networkId),p=xc.unshieldedToken().raw;$e(u,{proofServer:x(e,"proof-server"),node:x(e,"node"),indexerWS:x(e,"indexer-ws")},d);let m;try{m=kc.parse(t).decode(Am,f)}catch(S){throw Error(`Invalid shielded address: ${S.message}
|
|
259
255
|
Expected a shielded address (mn_shield-addr_...) for network "${u.networkId}"`)}if(process.stderr.write(`
|
|
260
|
-
`+
|
|
256
|
+
`+B("Shielded Transfer")+`
|
|
261
257
|
|
|
262
|
-
`),process.stderr.write(
|
|
263
|
-
`),process.stderr.write(
|
|
264
|
-
`),process.stderr.write(
|
|
258
|
+
`),process.stderr.write(C("Network",d)+`
|
|
259
|
+
`),process.stderr.write(C("To",ee(t,!0))+`
|
|
260
|
+
`),process.stderr.write(C("Amount",P(s+" NIGHT (shielded)"))+`
|
|
265
261
|
`),process.stderr.write(`
|
|
266
|
-
`),
|
|
267
|
-
Fund shielded balance: midnight airdrop ${s} --shielded`)}if(y.update("Checking dust..."),await et(v,(
|
|
262
|
+
`),je(e))Ge();let h=Re(),w=De(),y=K("Syncing wallet...");try{let S=await Ce().withFacade(c,u,async({bundle:v,state:A})=>{let N=kc.encode(f,A.shielded.address).asString();Jt(i,d,N);let L=A.shielded.balances[p]??0n;if(L<o){let _=Number(L)/1e6;throw Error(`Insufficient shielded balance: ${_.toFixed(6)} NIGHT available, ${s} NIGHT requested.
|
|
263
|
+
Fund shielded balance: midnight airdrop ${s} --shielded`)}if(y.update("Checking dust..."),await et(v,(_)=>y.update(_)),n?.aborted)throw Error("Operation cancelled");y.update("Building shielded transaction...");let X=await v.facade.transferTransaction([{type:"shielded",outputs:[{type:p,amount:o,receiverAddress:m}]}],{ttl:new Date(Date.now()+3600000)});y.update("Signing...");let q=await v.facade.signRecipe(X,v.keystore.signDataAsync);y.update("Generating ZK proof (this may take a few minutes)...");let V=await v.facade.finalizeRecipe(q),O=await Kn(y,"Submitting and waiting for finalization (typically 12 to 30s)...",v.facade.submitTransaction(V));return String(O)},{syncMode:"full",requireStrictSync:!0,signal:n,onStatus:(v)=>y.update(v),onSyncProgress:(v,A)=>{if(A>0){let N=Math.min(Math.round(v/A*100),100);y.update(N>=100?"Syncing wallet...":`Syncing wallet... ${N}%`)}},onSyncDetail:(v)=>y.update(`Syncing wallet... (waiting on: ${v})`)});if(y.stop("Transaction submitted"),R(e,"json")){D({txHash:S,amount:s,recipient:t,network:d,type:"shielded"});return}process.stdout.write(S+`
|
|
268
264
|
`),process.stderr.write(`
|
|
269
|
-
`+
|
|
265
|
+
`+gt(`Transferred ${s} shielded NIGHT`,S)+`
|
|
270
266
|
`),process.stderr.write(`
|
|
271
|
-
`+
|
|
267
|
+
`+J()+`
|
|
272
268
|
`),process.stderr.write(g(" Verify: midnight balance --shielded")+`
|
|
273
269
|
|
|
274
|
-
`)}catch(S){throw y.fail("Failed"),S}finally{w(),h()}}var
|
|
270
|
+
`)}catch(S){throw y.fail("Failed"),S}finally{w(),h()}}var Ac=T(()=>{ht();Le();ke();me();Us();mt();Ft();Ke();bt();ue();dt()});async function Dm(e,t){let r=await Ze(e,t,null);try{return await r.facade.dust.serializeState()}finally{await Ue(r)}}async function Tc(e,t,r,n={}){let s=Xe(e),i=await(n.repository??Ce()).dust(e,r,{signal:n.signal,onProgress:n.onProgress}),a=await(n.buildBaseDust??Dm)(e,r),c=i.lastAppliedEventId>=0?Vs(a,{state:i.state,lastAppliedEventId:i.lastAppliedEventId}):a;return{network:t,dustPublicKey:s,offset:i.lastAppliedEventId,balance:i.balance,eventCount:i.eventsApplied,fromCache:i.fromCache,partial:i.partial,snapshot:c}}var Nc=T(()=>{It();Ke();bt()});var Dc={};he(Dc,{default:()=>Rc});async function Rc(e,t){let r=e.subcommand;if(!r||r!=="register"&&r!=="status"&&r!=="export")throw new U(`Missing or invalid subcommand.
|
|
275
271
|
Usage:
|
|
276
272
|
midnight dust register Register NIGHT UTXOs for dust generation
|
|
277
273
|
midnight dust status Check dust registration status
|
|
278
|
-
midnight dust export Export a restorable dust snapshot (dustSerializedState)`);let{name:n,config:s}=le({args:e});if(
|
|
274
|
+
midnight dust export Export a restorable dust snapshot (dustSerializedState)`);let{name:n,config:s}=le({args:e});if($e(s,{proofServer:x(e,"proof-server"),node:x(e,"node"),indexerWS:x(e,"indexer-ws")},n),je(e))Ge();let o=R(e,"json"),i=pt(e);if(r==="export"){let p=De();try{await Im(bn(e),n,s,o,i,t)}finally{p()}return}let a=ae(re(x(e,"wallet"))),c=Buffer.from(a.seed,"hex"),d=a.addresses[n];if(r==="status"){let p=await $m(d,n,s.indexerWS,t);if(!p.isRegistered){Pm(n,p,o,i);return}let m=!R(e,"no-cache");await Om(c,s,p,o,i,m,t);return}jt(e);let u={},l=Re((p,m)=>u.current?.(p,m)),f=De();try{await _m(c,s,o,t,u)}finally{f(),l()}}async function Im(e,t,r,n,s,o){let i=K(`Reading dust events from ${t}...`);try{let a=await Tc(e,t,r,{signal:o,onProgress:(c,d)=>i.update(d>0?`Reading dust events... ${c}/${d+1}`:`Reading dust events... ${c}`)});if(i.stop(a.partial?"Dust snapshot ready (incomplete)":a.fromCache&&a.eventCount===0?"Cache up to date":"Dust snapshot ready"),n){D({subcommand:"export",network:a.network,dustPublicKey:a.dustPublicKey,offset:a.offset,dustBalance:de(a.balance),eventCount:a.eventCount,fromCache:a.fromCache,partial:a.partial,snapshot:a.snapshot});return}if(process.stdout.write(a.snapshot+`
|
|
279
275
|
`),s)return;if(process.stderr.write(`
|
|
280
|
-
`+
|
|
281
|
-
`),process.stderr.write(
|
|
282
|
-
`),process.stderr.write(
|
|
276
|
+
`+C("Network",a.network)+`
|
|
277
|
+
`),process.stderr.write(C("Dust balance",Mr(a.balance))+`
|
|
278
|
+
`),process.stderr.write(C("Snapshot offset",String(a.offset))+`
|
|
283
279
|
`),a.partial)process.stderr.write(`
|
|
284
|
-
`+
|
|
280
|
+
`+Z(P("⚠ Snapshot is INCOMPLETE — the sync did not reach the chain tip."))+`
|
|
285
281
|
`+g(" Restoring it still beats a cold start, but the wallet has events left to catch up on.")+`
|
|
286
282
|
`+g(" Re-run `mn dust export` to resume from this checkpoint and finish.")+`
|
|
287
283
|
`);process.stderr.write(`
|
|
288
284
|
`+g("Restore with the wallet SDK dustSerializedState to skip the cold dust sync.")+`
|
|
289
|
-
`)}catch(a){throw i.fail("Failed"),a}}async function
|
|
290
|
-
`+
|
|
285
|
+
`)}catch(a){throw i.fail("Failed"),a}}async function $m(e,t,r,n){process.stderr.write(`
|
|
286
|
+
`+B("Dust Status")+`
|
|
291
287
|
|
|
292
|
-
`),process.stderr.write(
|
|
288
|
+
`),process.stderr.write(C("Network",t)+`
|
|
293
289
|
|
|
294
|
-
`);let s=
|
|
290
|
+
`);let s=K(`Checking registration on ${t}...`);try{let o=await Xt(e,r,(c,d)=>{if(d>0){let u=Math.min(Math.round(c/d*100),100);s.update(u>=100?"Checking registration...":`Checking registration... ${u}%`)}});if(n?.aborted)throw Error("Operation cancelled");let{registeredUtxos:i,unregisteredUtxos:a}=o;return s.stop("Registration checked"),{isRegistered:i>0,registeredUtxos:i,unregisteredUtxos:a}}catch(o){throw s.fail("Failed"),o}}function Pm(e,t,r,n){let{registeredUtxos:s,unregisteredUtxos:o}=t,i=s+o;if(r){if(n){D({network:e,registered:!1,registeredUtxos:s,unregisteredUtxos:o});return}D({subcommand:"status",registered:!1,registeredUtxos:s,unregisteredUtxos:o,network:e});return}if(process.stdout.write(`registered=no
|
|
295
291
|
`),process.stdout.write(`registered_utxos=${s}
|
|
296
292
|
`),process.stdout.write(`unregistered_utxos=${o}
|
|
297
|
-
`),process.stderr.write(
|
|
298
|
-
`),process.stderr.write(
|
|
293
|
+
`),process.stderr.write(C("Registered",P("no"))+`
|
|
294
|
+
`),process.stderr.write(C("UTXOs",`${s} registered, ${o} unregistered`)+`
|
|
299
295
|
`),i===0)process.stderr.write(`
|
|
300
296
|
`+g("No NIGHT UTXOs at this address. Fund the wallet first.")+`
|
|
301
297
|
`);else process.stderr.write(`
|
|
302
298
|
`+g("Not generating dust. Run: midnight dust register")+`
|
|
303
299
|
`);process.stderr.write(`
|
|
304
|
-
`+
|
|
300
|
+
`+J()+`
|
|
305
301
|
|
|
306
|
-
`)}async function
|
|
307
|
-
`+
|
|
302
|
+
`)}async function _m(e,t,r,n,s){let o=t.networkId.toLowerCase();process.stderr.write(`
|
|
303
|
+
`+B("Dust Register")+`
|
|
308
304
|
|
|
309
|
-
`),process.stderr.write(
|
|
305
|
+
`),process.stderr.write(C("Network",o)+`
|
|
310
306
|
|
|
311
|
-
`);let i=
|
|
307
|
+
`);let i=K("Syncing wallet...");if(s)s.current=(a,c)=>i.update(`Syncing wallet... (${c}, retrying)`);try{let{result:a,dustBal:c}=await Ce().withFacade(e,t,async({bundle:d,state:u})=>{if(n?.aborted)throw Error("Operation cancelled");i.update("Checking dust status...");let l=await et(d,(p)=>i.update(p),u);if(n?.aborted)throw Error("Operation cancelled");let f=await ma(d);return{result:l,dustBal:f.dust.balance(new Date)}},{syncMode:"lite",requireStrictSync:!0,signal:n,onStatus:(d)=>i.update(d),onSyncProgress:(d,u)=>{if(u>0){let l=Math.min(Math.round(d/u*100),100);i.update(l>=100?"Syncing wallet...":`Syncing wallet... ${l}%`)}},onSyncDetail:(d)=>i.update(`Syncing wallet... (waiting on: ${d})`)});if(i.stop(a.alreadyAvailable?"Dust already available":"Dust registration complete"),r){let d={subcommand:"register",dustBalance:de(c)};if(a.txHash)d.txHash=a.txHash;D(d);return}process.stdout.write(c.toString()+`
|
|
312
308
|
`),process.stderr.write(`
|
|
313
|
-
`+
|
|
309
|
+
`+gt(a.alreadyAvailable?`Dust tokens already available: ${Mr(c)}`:`Dust tokens available: ${Mr(c)}`)+`
|
|
314
310
|
|
|
315
|
-
`)}catch(a){throw i.fail("Failed"),a}}async function
|
|
311
|
+
`)}catch(a){throw i.fail("Failed"),a}}async function Om(e,t,r,n,s,o,i){let a=t.networkId.toLowerCase(),c=K(`Reading dust events from ${a}...`);try{let d=await Ce().dust(e,t,{forceFresh:!o,signal:i,onStatus:(f)=>c.update(f)});c.stop(d.fromCache&&d.eventsApplied===0?"Cache up to date":"Dust events applied");let{registeredUtxos:u,unregisteredUtxos:l}=r;if(n){if(s){D({network:a,registered:!0,registeredUtxos:u,unregisteredUtxos:l,dustBalance:de(d.balance),dustAvailable:d.availableCoins>0});return}D({subcommand:"status",registered:!0,registeredUtxos:u,unregisteredUtxos:l,dustBalance:de(d.balance),dustAvailable:d.availableCoins>0,eventsApplied:d.eventsApplied,ownedUtxos:d.ownedUtxoCount,cached:d.fromCache,network:a});return}if(process.stdout.write(`registered=yes
|
|
316
312
|
`),process.stdout.write(`dust=${d.balance}
|
|
317
313
|
`),process.stdout.write(`registered_utxos=${u}
|
|
318
314
|
`),process.stdout.write(`unregistered_utxos=${l}
|
|
319
|
-
`),process.stderr.write(
|
|
320
|
-
`),process.stderr.write(
|
|
321
|
-
`),process.stderr.write(
|
|
322
|
-
`),process.stderr.write(
|
|
323
|
-
`),process.stderr.write(
|
|
315
|
+
`),process.stderr.write(C("Registered",P("yes"))+`
|
|
316
|
+
`),process.stderr.write(C("UTXOs",`${u} registered, ${l} unregistered`)+`
|
|
317
|
+
`),process.stderr.write(C("Dust Balance",P(Mr(d.balance)))+`
|
|
318
|
+
`),process.stderr.write(C("Dust Available",d.availableCoins>0?"yes":"no")+`
|
|
319
|
+
`),process.stderr.write(C("Events applied",d.eventsApplied.toString()+(d.fromCache?" (delta)":""))+`
|
|
324
320
|
`),l>0)process.stderr.write(`
|
|
325
321
|
`+g(`${l} UTXO(s) not yet registered. Run: midnight dust register`)+`
|
|
326
322
|
`);process.stderr.write(`
|
|
327
|
-
`+
|
|
328
|
-
|
|
329
|
-
`)}catch(d){throw c.fail("Failed"),d}}var
|
|
330
|
-
`)}else if(n){if(
|
|
331
|
-
`)}else{if(
|
|
332
|
-
`)}}var
|
|
333
|
-
Valid keys: ${
|
|
334
|
-
Valid keys: ${
|
|
335
|
-
`)
|
|
336
|
-
`)}else
|
|
337
|
-
|
|
338
|
-
|
|
323
|
+
`+J()+`
|
|
324
|
+
|
|
325
|
+
`)}catch(d){throw c.fail("Failed"),d}}var Ic=T(()=>{Oe();ht();Le();zt();ke();me();Ke();Ft();Lr();Nc();bt();ue();dt()});var Pc={};he(Pc,{default:()=>$c});async function $c(e){if(e.subcommand!=="clear")throw new U("Usage: midnight cache clear [--network <name>] [--wallet <name|file>]");let r=x(e,"wallet"),n=x(e,"network"),s=R(e,"json");if(r){let o=re(r),i=ae(o),a=we({args:e}),c=i.addresses[a];Ve(c,a);let d=Xe(Buffer.from(i.seed,"hex"));ot(a,d),Fn(a,d);let u=Ba(Buffer.from(i.seed,"hex"));if(Jr(a,u),s){D({action:"clear",scope:"wallet",wallet:r,network:a});return}process.stderr.write(W("✓")+` Cache cleared for wallet "${r}" on ${a}
|
|
326
|
+
`)}else if(n){if(Ve(void 0,n),ot(n),Fn(n),Jr(n),s){D({action:"clear",scope:"network",network:n});return}process.stderr.write(W("✓")+` Cache cleared for network "${n}"
|
|
327
|
+
`)}else{if(Ve(),ot(),Fn(),Jr(),s){D({action:"clear",scope:"all"});return}process.stderr.write(W("✓")+` Cache cleared
|
|
328
|
+
`)}}var _c=T(()=>{Oe();Pt();It();io();eo();Le();ke()});var Mc={};he(Mc,{default:()=>Oc});async function Oc(e){let t=e.subcommand;if(!t||!["get","set","unset"].includes(t))throw new U(`Usage: midnight config <get|set|unset> <key> [value]
|
|
329
|
+
Valid keys: ${Is().join(", ")}`);let r=e.positionals[0];if(!r)throw new U(`Missing config key.
|
|
330
|
+
Valid keys: ${Is().join(", ")}`);let n=x(e,"network");if(n!==void 0&&!be(n))throw new U(`Invalid network: "${n}"
|
|
331
|
+
Valid networks: preprod, preview, undeployed`);let s=n;if(t==="get"){let o=Ii(r,void 0,s);if(R(e,"json")){D({action:"get",key:r,value:o});return}process.stdout.write(o+`
|
|
332
|
+
`)}else if(t==="unset"){Pi(r,void 0,s);let o=r==="network"?"(default)":"(removed)";if(R(e,"json")){D({action:"unset",key:r,value:o});return}process.stderr.write(W("✓")+` ${r} ${o}
|
|
333
|
+
`)}else{let o=e.positionals[1];if(o===void 0)throw new U(`Missing value for config set.
|
|
334
|
+
Usage: midnight config set ${r} <value>`);if($i(r,o,void 0,s),R(e,"json")){D({action:"set",key:r,value:o});return}process.stderr.write(W("✓")+` ${r} = ${o}
|
|
335
|
+
`)}}var Fc=T(()=>{me();Oe();Kt()});import{execSync as ar}from"child_process";import{existsSync as Lc,mkdirSync as Mm,readFileSync as Fm,writeFileSync as Uc}from"fs";import{homedir as Lm}from"os";import{join as mo}from"path";function jc(){try{return ar("docker compose version",{...Yr,timeout:1e4}).trim()}catch{try{throw ar("docker --version",{...Yr,timeout:5000}),Error(`Docker Compose v2 is required.
|
|
339
336
|
Install it from https://docs.docker.com/compose/install/`)}catch(e){if(e instanceof Error&&e.message.includes("Docker Compose v2"))throw e;throw Error(`Docker is required but was not found.
|
|
340
|
-
Install Docker from https://docs.docker.com/get-docker/`)}}}function
|
|
341
|
-
`),r=[];for(let n of t){if(!n.trim())continue;try{let s=JSON.parse(n),o=s.Service??"unknown";r.push({name:o,state:s.State??"unknown",health:s.Health??"",port:
|
|
337
|
+
Install Docker from https://docs.docker.com/get-docker/`)}}}function ho(){if(!Hm)throw new Hc}function Gc(){if(ho(),Lc(fo)&&Lc(Vn)&&Fm(fo,"utf-8").trim()===Wc)return!1;return Mm(go,{recursive:!0,mode:Te}),Uc(Vn,jm,"utf-8"),Uc(fo,Wc,"utf-8"),!0}function cr(e){return ar(`docker compose -f "${Vn}" ${e}`,Yr)}function Jn(){try{let e=cr("ps --format json");if(!e.trim())return[];let t=e.trim().split(`
|
|
338
|
+
`),r=[];for(let n of t){if(!n.trim())continue;try{let s=JSON.parse(n),o=s.Service??"unknown";r.push({name:o,state:s.State??"unknown",health:s.Health??"",port:Gm[o]??"",image:s.Image??""})}catch{}}return r}catch{return[]}}function Kc(e=120000,t=3000){let r=Date.now()+e;while(Date.now()<r){let n=Jn();if(n.length===3&&n.every((o)=>o.state==="running")){if(n.every((i)=>i.health==="healthy"||i.health===""))return!0}ar(`sleep ${t/1000}`,{timeout:t+1000})}return!1}function wo(){return Vn}function Vm(e){return{remove:e.filter((t)=>t.project===Bc).map((t)=>t.name),keep:e.filter((t)=>t.project!==Bc)}}function Vc(){let e=[];for(let s of Km){let o;try{o=ar(`docker ps -a --filter "name=^/${s}$" --format '{{.Names}}|{{.Label "com.docker.compose.project"}}'`,{...Yr,timeout:1e4}).toString()}catch{e.push({name:s,project:"(unknown: docker ps failed)"});continue}let i=o.split(`
|
|
339
|
+
`).find((a)=>a.startsWith(`${s}|`));if(i)e.push({name:s,project:i.slice(s.length+1).trim()})}let{remove:t,keep:r}=Vm(e),n=[];for(let s of t)try{ar(`docker rm -f "${s}"`,{...Yr,timeout:1e4}),n.push(s)}catch{}return{removed:n,kept:r}}var Wc="3.0.6",Um="midnightntwrk/midnight-node:1.0.0",Wm="midnightntwrk/indexer-standalone:4.3.3",Bm="midnightntwrk/proof-server:8.1.0",go,Vn,fo,jm,Yr,Hm=!1,Hc,Gm,Km,Bc;var Jc=T(()=>{go=mo(Lm(),ie,xs),Vn=mo(go,"compose.yml"),fo=mo(go,".version"),jm=`services:
|
|
342
340
|
proof-server:
|
|
343
|
-
image: '${
|
|
341
|
+
image: '${Bm}'
|
|
344
342
|
container_name: "proof-server"
|
|
345
343
|
# Self-heal across Docker Desktop restarts and transient stops. Without this,
|
|
346
344
|
# a stopped node/proof-server never comes back while the indexer (below) does,
|
|
@@ -351,7 +349,7 @@ Install Docker from https://docs.docker.com/get-docker/`)}}}function Ec(){if(!fm
|
|
|
351
349
|
- "6300:6300"
|
|
352
350
|
|
|
353
351
|
indexer:
|
|
354
|
-
image: '${
|
|
352
|
+
image: '${Wm}'
|
|
355
353
|
container_name: "indexer"
|
|
356
354
|
# unless-stopped covers two cases: (1) indexer >=4.3.x runs an SPO sub-indexer
|
|
357
355
|
# that queries block #1 at startup and exits the whole process if it isn't there
|
|
@@ -387,7 +385,7 @@ Install Docker from https://docs.docker.com/get-docker/`)}}}function Ec(){if(!fm
|
|
|
387
385
|
condition: service_started
|
|
388
386
|
|
|
389
387
|
node:
|
|
390
|
-
image: '${
|
|
388
|
+
image: '${Um}'
|
|
391
389
|
container_name: "node"
|
|
392
390
|
# Self-heal across Docker Desktop restarts / transient stops (see proof-server).
|
|
393
391
|
restart: unless-stopped
|
|
@@ -401,41 +399,42 @@ Install Docker from https://docs.docker.com/get-docker/`)}}}function Ec(){if(!fm
|
|
|
401
399
|
start_period: 5s
|
|
402
400
|
environment:
|
|
403
401
|
CFG_PRESET: "dev"
|
|
404
|
-
`,
|
|
402
|
+
`,Yr={encoding:"utf-8",timeout:30000};Hc=class Hc extends Error{code="LOCALNET_UNAVAILABLE";constructor(){super(`mn localnet can't start a ledger-9 network yet: no published indexer image runs ledger 9.
|
|
405
403
|
Run a ledger-9 stack yourself (node 2.1.0-rc.2, proof-server 9.0.0-rc.8, a 4.4 indexer) and point mn at it:
|
|
406
404
|
per command: --node ws://localhost:9944 --indexer-ws ws://localhost:8088/api/v4/graphql/ws --proof-server http://localhost:6300
|
|
407
|
-
or once: midnight config set node <url>; midnight config set indexer-ws <url>; midnight config set proof-server <url>`);this.name="LocalnetUnavailableError"}};
|
|
408
|
-
`)}async function
|
|
409
|
-
`);let r=
|
|
410
|
-
`+g(" Tip: run ")+
|
|
411
|
-
`);else{r.update("Waiting for chain to produce first block...");try{await Promise.resolve().then(() =>
|
|
412
|
-
`+g(" Tip: give it a few more seconds then retry. Run ")+
|
|
413
|
-
`)}}}catch(s){if(r.fail("Failed to start local network"),s instanceof Error){if(s.message.includes("is already in use by container"))throw Error(`Container name conflict — containers with the same names already exist
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
`+"Check ports 9944, 8088, and 6300, then try again.")}throw s}let n=
|
|
418
|
-
`+
|
|
405
|
+
or once: midnight config set node <url>; midnight config set indexer-ws <url>; midnight config set proof-server <url>`);this.name="LocalnetUnavailableError"}};Gm={node:"9944",indexer:"8088","proof-server":"6300"};Km=["node","indexer","proof-server"],Bc=xs});async function qc(e,t={}){let r=t.timeoutMs??30000,n=t.pollIntervalMs??1000,s=Date.now()+r;while(Date.now()<s){try{let o=await Zt({url:e,timeoutMs:3000},"chain_getHeader"),i=typeof o?.number==="string"?o.number:"0x0",a=Number.parseInt(i,16);if(Number.isFinite(a)&&a>=1)return}catch{}await new Promise((o)=>setTimeout(o,n))}throw Error(`Node did not produce a block within ${r/1000}s`)}var zc=T(()=>{$n()});async function Yc(e,t,r={}){let n=r.timeoutMs??30000,s=r.pollIntervalMs??1000,o=Date.now()+n;while(Date.now()<o){try{if((await Xt(t,e)).utxoCount>0)return}catch{}await new Promise((i)=>setTimeout(i,s))}throw Error(`Indexer did not report funds for ${t.slice(0,20)}… within ${n/1000}s`)}var Xc=T(()=>{Lr()});async function Zc(e,t={}){let r=t.timeoutMs??30000,n=t.pollIntervalMs??1000,s=t.requestTimeoutMs??2000,o=Date.now()+r,i=e.endsWith("/")?e:e+"/";while(Date.now()<o){try{let a=new AbortController,c=setTimeout(()=>a.abort(),s);try{if((await fetch(i,{method:"GET",signal:a.signal})).ok)return}finally{clearTimeout(c)}}catch{}await new Promise((a)=>setTimeout(a,n))}throw Error(`Proof server at ${i} did not respond within ${r/1000}s`)}var nd={};he(nd,{default:()=>rd});import{spawn as Qc}from"child_process";import{existsSync as Jm,rmSync as qm}from"node:fs";import{resolve as zm}from"node:path";function Ym(e){return ed.includes(e)}function td(e){let t=[];for(let r of e){let n=r.state==="running"?W:ce,s=r.health?` (${r.health})`:"",o=r.port?`:${r.port}`:"",i=r.image?` ${g(r.image)}`:"";if(t.push(` ${r.name.padEnd(16)}${n(r.state)}${g(s)}${g(o)}`),i)t.push(i)}return t.join(`
|
|
406
|
+
`)}async function Xm(e){if(Gc())process.stderr.write(g(` Wrote compose.yml to ${wo()}`)+`
|
|
407
|
+
`);let r=K("Starting local network...");try{if(cr("up -d"),r.update("Waiting for services to be healthy..."),!Kc(120000))r.stop(Z("Services started but not all healthy yet")),process.stderr.write(`
|
|
408
|
+
`+g(" Tip: run ")+P("midnight localnet logs")+g(" to check for errors")+`
|
|
409
|
+
`);else{r.update("Waiting for chain to produce first block...");try{await Promise.resolve().then(() => zc());await Promise.resolve().then(() => Xc());await Promise.resolve();await Promise.resolve().then(() => me());await Promise.resolve().then(() => He());await Promise.resolve();let l=Tr("undeployed");await qc(l.node,{timeoutMs:30000}),r.update("Waiting for indexer to ingest genesis state...");let f=ve(Buffer.from(rt,"hex"),"undeployed");await Yc(l.indexerWS,f,{timeoutMs:30000}),r.update("Waiting for proof server..."),await Zc(l.proofServer,{timeoutMs:30000}),r.stop("Local network is running")}catch(o){r.stop(Z("Services running but chain/indexer/proof-server not fully ready yet")),process.stderr.write(`
|
|
410
|
+
`+g(" Tip: give it a few more seconds then retry. Run ")+P("midnight localnet logs")+g(" if this persists.")+`
|
|
411
|
+
`)}}}catch(s){if(r.fail("Failed to start local network"),s instanceof Error){if(s.message.includes("is already in use by container"))throw Error(`Container name conflict — containers with the same names already exist.
|
|
412
|
+
|
|
413
|
+
`+`If an earlier mn localnet created them, "midnight localnet clean" removes them;
|
|
414
|
+
it leaves containers from anything else alone and lists them.`);if(s.message.includes("address already in use"))throw Error(`Port conflict detected — another process is using a required port.
|
|
415
|
+
`+"Check ports 9944, 8088, and 6300, then try again.")}throw s}let n=Jn();if(e){D({subcommand:"up",services:n.map((s)=>({name:s.name,state:s.state,port:s.port,health:s.health,image:s.image}))});return}if(n.length>0)process.stderr.write(`
|
|
416
|
+
`+td(n)+`
|
|
419
417
|
`);for(let s of n)process.stdout.write(`${s.name}=${s.state}:${s.port}
|
|
420
418
|
`);process.stderr.write(`
|
|
421
|
-
`+g(" Next: ")+
|
|
422
|
-
`)}async function
|
|
423
|
-
`)}catch(r){throw t.fail("Failed to tear down local network"),r}}function
|
|
424
|
-
`+
|
|
419
|
+
`+g(" Next: ")+P("midnight wallet generate dev --network undeployed")+`
|
|
420
|
+
`)}async function Zm(e){let t=K("Stopping local network...");try{if(cr("stop"),t.stop("Local network stopped (containers preserved)"),e){D({subcommand:"stop",status:"stopped"});return}}catch(r){throw t.fail("Failed to stop local network"),r}}async function Qm(e){let t=K("Tearing down local network...");try{cr("down --volumes");await Promise.resolve().then(() => Pt());await Promise.resolve().then(() => It());Ve(void 0,"undeployed"),ot("undeployed");let s=eg();if(t.stop("Local network removed (containers, networks, volumes, caches)"),e){D({subcommand:"down",status:"removed",cachesCleared:!0,dappLevelDbWiped:s});return}if(s)process.stderr.write(g(" Also cleared dapp leveldb at ./midnight-level-db (private state from old chain)")+`
|
|
421
|
+
`)}catch(r){throw t.fail("Failed to tear down local network"),r}}function eg(){let e=zm(process.cwd(),"midnight-level-db");if(!Jm(e))return!1;try{return qm(e,{recursive:!0,force:!0}),!0}catch{return!1}}async function tg(e){let t=Jn();if(e){D({subcommand:"status",services:t.map((r)=>({name:r.name,state:r.state,port:r.port,health:r.health,image:r.image}))});return}if(t.length===0){process.stderr.write(`
|
|
422
|
+
`+B("Localnet Status")+`
|
|
425
423
|
|
|
426
424
|
`),process.stderr.write(g(" No services running.")+`
|
|
427
|
-
`),process.stderr.write(g(" ")+
|
|
425
|
+
`),process.stderr.write(g(" ")+P("midnight localnet up")+g(" is refused on this ledger-9 build; see ")+P("midnight help localnet")+g(".")+`
|
|
428
426
|
|
|
429
427
|
`);return}process.stderr.write(`
|
|
430
|
-
`+
|
|
428
|
+
`+B("Localnet Status")+`
|
|
431
429
|
|
|
432
|
-
`),process.stderr.write(
|
|
430
|
+
`),process.stderr.write(td(t)+`
|
|
433
431
|
`),process.stderr.write(`
|
|
434
|
-
`+
|
|
432
|
+
`+J()+`
|
|
435
433
|
|
|
436
434
|
`);for(let r of t)process.stdout.write(`${r.name}=${r.state}:${r.port}
|
|
437
|
-
`)}async function
|
|
438
|
-
`).
|
|
435
|
+
`)}async function rg(e){let t=K("Removing conflicting containers...");try{try{cr("down")}catch{}let{removed:r,kept:n}=Vc();if(r.length>0)t.stop(`Removed ${r.length} container${r.length>1?"s":""}: ${r.join(", ")}`);else t.stop("No conflicting containers found");if(e){D({subcommand:"clean",status:"cleaned",removed:r,kept:n});return}for(let s of n)process.stderr.write(g(` Left "${s.name}" alone: it belongs to ${s.project?`compose project "${s.project}"`:"no compose project"}, not mn's localnet. Remove it yourself if it is in the way.`)+`
|
|
436
|
+
`)}catch(r){throw t.fail("Failed to clean up"),r}}async function ng(e){let t=wo(),r=x(e,"tail"),n=R(e,"json");if(r!==void 0||n){let o=r??"200",i=Qc("docker",["compose","-f",t,"logs","--tail",o,"--no-color"],{stdio:["ignore","pipe","pipe"]}),a="",c="";return i.stdout.on("data",(d)=>{a+=d.toString()}),i.stderr.on("data",(d)=>{c+=d.toString()}),new Promise((d,u)=>{i.on("close",(l)=>{if(l!==0&&l!==null){u(Error(`docker compose logs exited with code ${l}: ${c.trim()}`));return}if(n)D({tail:Number(o),lines:a.split(`
|
|
437
|
+
`).filter(Boolean)});else process.stdout.write(a);d()}),i.on("error",u)})}let s=Qc("docker",["compose","-f",t,"logs","-f"],{stdio:"inherit"});return new Promise((o,i)=>{s.on("close",(a)=>{if(a===0||a===130||a===null)o();else i(Error(`docker compose logs exited with code ${a}`))}),s.on("error",i)})}async function rd(e){let t=e.subcommand;if(!t||!Ym(t))throw new U(`Usage: midnight localnet <${ed.join("|")}>
|
|
439
438
|
|
|
440
439
|
Subcommands:
|
|
441
440
|
up Start the local network (refused on this ledger-9 build)
|
|
@@ -445,139 +444,139 @@ Subcommands:
|
|
|
445
444
|
logs Stream service logs
|
|
446
445
|
clean Remove conflicting containers
|
|
447
446
|
|
|
448
|
-
Example: midnight localnet status`);
|
|
449
|
-
`+
|
|
447
|
+
Example: midnight localnet status`);if(t==="up")ho();jc();let r=R(e,"json");switch(process.stderr.write(`
|
|
448
|
+
`+B("Localnet")+`
|
|
450
449
|
|
|
451
|
-
`),t){case"up":return
|
|
450
|
+
`),t){case"up":return Xm(r);case"stop":return Zm(r);case"down":return Qm(r);case"status":return tg(r);case"logs":return ng(e);case"clean":return rg(r)}}var ed;var sd=T(()=>{Oe();Jc();ue();dt();ed=["up","stop","down","status","logs","clean"]});var cd={};he(cd,{default:()=>ad});import*as id from"fs";import*as yo from"path";import{homedir as sg}from"os";import{generateMnemonic as og,mnemonicToSeedSync as od,mnemonicToEntropy as ig,validateMnemonic as ag}from"@scure/bip39";import{wordlist as So}from"@scure/bip39/wordlists/english.js";async function ad(e){let t=e.subcommand;switch(t){case"generate":return cg(e);case"list":case"ls":return dg(e);case"use":return lg(e);case"info":return ug(e);case"remove":case"rm":return pg(e);case"seed":return fg(e);default:throw new U(`Unknown wallet subcommand: "${t??"(none)"}"
|
|
452
451
|
Available: generate, list, use, info, remove, seed
|
|
453
|
-
Run "midnight help wallet" for usage.`)}}async function
|
|
454
|
-
Usage: midnight wallet generate <name> [--network <name>]`);if(!
|
|
455
|
-
Wallet name must be a simple name (no path separators, .json suffix, or special characters).`);let r=we({args:e}),n=
|
|
456
|
-
Use --force to overwrite.`);let a,c;if(n!==void 0)a
|
|
452
|
+
Run "midnight help wallet" for usage.`)}}async function cg(e){let t=e.positionals[0];if(!t)throw Error(`Missing wallet name.
|
|
453
|
+
Usage: midnight wallet generate <name> [--network <name>]`);if(!Ct(t))throw Error(`Invalid wallet name: "${t}"
|
|
454
|
+
Wallet name must be a simple name (no path separators, .json suffix, or special characters).`);let r=we({args:e}),n=x(e,"seed"),s=x(e,"mnemonic");if(n!==void 0&&s!==void 0)throw Error("Cannot specify both --seed and --mnemonic. Use one or the other.");let o=yo.join(sg(),ie,mn),i=yo.join(o,`${t}.json`);if(id.existsSync(i)&&!R(e,"force"))throw Error(`Wallet "${t}" already exists: ${i}
|
|
455
|
+
Use --force to overwrite.`);let a,c;if(n!==void 0)a=$r(n,"--seed");else if(s!==void 0){if(!ag(s,So))throw Error("Invalid BIP-39 mnemonic. Expected 12 or 24 words from the English wordlist.");c=s,a=Buffer.from(od(c))}else c=og(So,256),a=Buffer.from(od(c));let d=Nt(a),u=Rr(a),l=d[r],f={seed:a.toString("hex"),addresses:d,shieldedAddresses:u,createdAt:new Date().toISOString()};if(c)f.mnemonic=c;let p=Sn(f,i);if(Ms(t),R(e,"json")){let h={name:t,addresses:d,shieldedAddresses:u,activeAddress:l,activeNetwork:r,seed:a.toString("hex"),file:p,createdAt:f.createdAt,active:!0};if(c)h.mnemonic=c;D(h);return}process.stdout.write(l+`
|
|
457
456
|
`),process.stderr.write(`
|
|
458
|
-
`+
|
|
459
|
-
|
|
460
|
-
`),process.stderr.write(
|
|
461
|
-
`),process.stderr.write(
|
|
462
|
-
`),process.stderr.write(
|
|
463
|
-
`);let m=u[r];if(m)process.stderr.write(
|
|
464
|
-
`);if(process.stderr.write(
|
|
465
|
-
`),process.stderr.write(
|
|
457
|
+
`+B("Wallet Generated")+`
|
|
458
|
+
|
|
459
|
+
`),process.stderr.write(C("Name",t)+`
|
|
460
|
+
`),process.stderr.write(C("Network",r)+`
|
|
461
|
+
`),process.stderr.write(C("Address",ee(l))+`
|
|
462
|
+
`);let m=u[r];if(m)process.stderr.write(C("Shielded",ee(m))+`
|
|
463
|
+
`);if(process.stderr.write(C("File",p)+`
|
|
464
|
+
`),process.stderr.write(C("Active","yes")+`
|
|
466
465
|
`),process.stderr.write(`
|
|
467
|
-
`),c)process.stderr.write(
|
|
466
|
+
`),c)process.stderr.write(Z(P(" MNEMONIC (save securely!):"))+`
|
|
468
467
|
`),process.stderr.write(` ${c}
|
|
469
468
|
|
|
470
|
-
`);process.stderr.write(
|
|
469
|
+
`);process.stderr.write(Z(P(" SEED (hex):"))+`
|
|
471
470
|
`),process.stderr.write(` ${a.toString("hex")}
|
|
472
471
|
|
|
473
|
-
`),process.stderr.write(
|
|
472
|
+
`),process.stderr.write(J()+`
|
|
474
473
|
`),process.stderr.write(g(" Next: midnight wallet list | midnight balance")+`
|
|
475
474
|
|
|
476
|
-
`),process.stderr.write(
|
|
477
|
-
`)}async function
|
|
475
|
+
`),process.stderr.write(W("✓")+` Wallet saved
|
|
476
|
+
`)}async function dg(e){let t=Fs(),r=we({args:e});if(R(e,"json")){if(pt(e)){D({activeNetwork:r,wallets:t.map((a)=>({name:a.name,active:a.isActive,network:r,address:a.addresses[r]??null,shieldedAddress:a.shieldedAddresses?.[r]??null}))});return}D({activeNetwork:r,wallets:t.map((a)=>({name:a.name,active:a.isActive,addresses:a.addresses,shieldedAddresses:a.shieldedAddresses,createdAt:a.createdAt,file:a.file}))});return}if(t.length===0){process.stderr.write(`
|
|
478
477
|
No wallets found.
|
|
479
478
|
`),process.stderr.write(g(" Create one: midnight wallet generate <name> --network <name>")+`
|
|
480
479
|
|
|
481
480
|
`);return}process.stderr.write(`
|
|
482
|
-
`+
|
|
481
|
+
`+B("Wallets")+`
|
|
483
482
|
|
|
484
483
|
`);let n=Math.max(...t.map((a)=>a.name.length)),s=19,o=19,i=" ".repeat(n-4);process.stderr.write(` ${g("name")}${i} ${g("unshielded".padEnd(s))} ${g("shielded")}
|
|
485
|
-
`);for(let a of t){let c=a.isActive?
|
|
484
|
+
`);for(let a of t){let c=a.isActive?W("●"):" ",d=a.isActive?P(G(a.name)):G(a.name),u=" ".repeat(n-a.name.length),l=a.addresses[r]??"(unknown)",f=a.shieldedAddresses?.[r],p=f?ee(f,!0):g("—".padEnd(o));process.stderr.write(` ${c} ${d}${u} ${ee(l,!0)} ${p}
|
|
486
485
|
`)}process.stderr.write(`
|
|
487
|
-
`+
|
|
486
|
+
`+J()+`
|
|
488
487
|
`),process.stderr.write(g(` ● = active wallet · network: ${r} · details: midnight wallet info <name>`)+`
|
|
489
488
|
|
|
490
|
-
`)}async function
|
|
491
|
-
Usage: midnight wallet use <name>`);if(
|
|
492
|
-
`)}async function
|
|
489
|
+
`)}async function lg(e){let t=e.positionals[0];if(!t)throw Error(`Missing wallet name.
|
|
490
|
+
Usage: midnight wallet use <name>`);if(Ms(t),R(e,"json")){D({wallet:t,active:!0});return}process.stderr.write(W("✓")+` Active wallet set to "${t}"
|
|
491
|
+
`)}async function ug(e){let t=x(e,"wallet")??e.positionals[0]??qt(),r=re(t),n=ae(r),s=t===qt(),o=we({args:e}),i=n.addresses[o];if(R(e,"json")){if(pt(e)){D({name:t,active:s,network:o,address:i,shieldedAddress:n.shieldedAddresses?.[o]??null});return}let c={name:t,addresses:n.addresses,activeAddress:i,activeNetwork:o,createdAt:n.createdAt,file:r,active:s};if(n.shieldedAddresses)c.shieldedAddresses=n.shieldedAddresses;D(c);return}process.stdout.write(i+`
|
|
493
492
|
`),process.stderr.write(`
|
|
494
|
-
`+
|
|
493
|
+
`+B(`Wallet: ${t}`)+`
|
|
495
494
|
|
|
496
|
-
`);let a=Object.keys(n.addresses);for(let c=0;c<a.length;c++){let d=a[c],u=d===o,l=n.addresses[d],f=n.shieldedAddresses?.[d],p=u?
|
|
497
|
-
`),process.stderr.write(` ${g("unshielded")} ${
|
|
498
|
-
`),f)process.stderr.write(` ${g("shielded ")} ${
|
|
495
|
+
`);let a=Object.keys(n.addresses);for(let c=0;c<a.length;c++){let d=a[c],u=d===o,l=n.addresses[d],f=n.shieldedAddresses?.[d],p=u?P(G(d))+g(" (active)"):d;if(process.stderr.write(` ${p}
|
|
496
|
+
`),process.stderr.write(` ${g("unshielded")} ${ee(l)}
|
|
497
|
+
`),f)process.stderr.write(` ${g("shielded ")} ${ee(f)}
|
|
499
498
|
`);else process.stderr.write(` ${g("shielded ")} ${g("(unavailable)")}
|
|
500
499
|
`);if(c<a.length-1)process.stderr.write(`
|
|
501
500
|
`)}process.stderr.write(`
|
|
502
|
-
`+
|
|
501
|
+
`+J()+`
|
|
503
502
|
|
|
504
503
|
`),process.stderr.write(` ${g("created")} ${n.createdAt}
|
|
505
504
|
`),process.stderr.write(` ${g("file ")} ${r}
|
|
506
|
-
`),process.stderr.write(` ${g("active ")} ${s?
|
|
507
|
-
|
|
508
|
-
`)}async function
|
|
509
|
-
Usage: midnight wallet remove <name>`);if(
|
|
510
|
-
`)}async function
|
|
511
|
-
`+"The 32-byte entropy can only be computed from the original 24-word mnemonic.");i=Buffer.from(
|
|
512
|
-
`),process.stderr.write(
|
|
513
|
-
`),process.stderr.write(
|
|
514
|
-
`),process.stderr.write(
|
|
505
|
+
`),process.stderr.write(` ${g("active ")} ${s?W("yes"):"no"}
|
|
506
|
+
|
|
507
|
+
`)}async function pg(e){let t=e.positionals[0];if(!t)throw Error(`Missing wallet name.
|
|
508
|
+
Usage: midnight wallet remove <name>`);if(Hi(t),R(e,"json")){D({wallet:t,removed:!0});return}process.stderr.write(W("✓")+` Wallet "${t}" removed
|
|
509
|
+
`)}async function fg(e){let t=x(e,"wallet")??e.positionals[0]??qt(),r=re(t),n=await import("fs"),s=JSON.parse(n.readFileSync(r,"utf-8"));if(!s.seed)throw Error(`Wallet "${t}" has no seed in ${r}`);let o=R(e,"entropy"),i;if(o){if(!s.mnemonic)throw Error(`Wallet "${t}" has no mnemonic on file — cannot derive BIP-39 entropy.
|
|
510
|
+
`+"The 32-byte entropy can only be computed from the original 24-word mnemonic.");i=Buffer.from(ig(s.mnemonic,So)).toString("hex")}if(R(e,"json")){let c={name:t,seed:s.seed};if(s.mnemonic)c.mnemonic=s.mnemonic;if(i)c.entropy=i;D(c);return}if(process.stderr.write(`
|
|
511
|
+
`),process.stderr.write(Z(P(" ⚠ WARNING: This will display your wallet seed and mnemonic."))+`
|
|
512
|
+
`),process.stderr.write(Z(" Anyone with this seed can access your funds.")+`
|
|
513
|
+
`),process.stderr.write(Z(" Never share it. Never paste it into a website.")+`
|
|
515
514
|
`),process.stderr.write(`
|
|
516
|
-
`),!await
|
|
515
|
+
`),!await mg(" Show seed? (y/N) ")){process.stderr.write(g(" Cancelled.")+`
|
|
517
516
|
|
|
518
517
|
`);return}if(process.stdout.write(s.seed+`
|
|
519
518
|
`),process.stderr.write(`
|
|
520
|
-
`),process.stderr.write(
|
|
521
|
-
`),process.stderr.write(
|
|
522
|
-
`),i)process.stderr.write(
|
|
523
|
-
`);if(s.mnemonic)process.stderr.write(
|
|
524
|
-
`);if(process.stderr.write(
|
|
519
|
+
`),process.stderr.write(C("Name",t)+`
|
|
520
|
+
`),process.stderr.write(C("Seed (64-byte PBKDF2)",s.seed)+`
|
|
521
|
+
`),i)process.stderr.write(C("Entropy (32-byte BIP-39)",i)+`
|
|
522
|
+
`);if(s.mnemonic)process.stderr.write(C("Mnemonic",s.mnemonic)+`
|
|
523
|
+
`);if(process.stderr.write(C("File",r)+`
|
|
525
524
|
`),i)process.stderr.write(`
|
|
526
525
|
`),process.stderr.write(g(" Note: seed and entropy derive DIFFERENT Midnight wallets from the")+`
|
|
527
526
|
`),process.stderr.write(g(" same mnemonic. Use the value your target project accepts.")+`
|
|
528
527
|
`);process.stderr.write(`
|
|
529
|
-
`)}function
|
|
530
|
-
`+
|
|
528
|
+
`)}function mg(e){return new Promise((t)=>{let r=ii("readline"),n=r.createInterface({input:process.stdin,output:process.stderr});n.question(e,(s)=>{n.close(),t(s.trim().toLowerCase()==="y")})})}var dd=T(()=>{Oe();He();ke();zt();Le();ue()});var md={};he(md,{default:()=>fd});function vo(e){let t=Date.now()-new Date(e).getTime();if(t<60000)return"just now";if(t<3600000)return`${Math.floor(t/60000)}m ago`;if(t<86400000)return`${Math.floor(t/3600000)}h ago`;return`${Math.floor(t/86400000)}d ago`}function bo(e){let t=!1,r=!1;for(let n of Object.values(e)){if(n.status==="down")t=!0;if(n.status==="degraded")r=!0}if(t)return"down";if(r)return"degraded";return"up"}async function qn(e){let t=`${gn}${e}`,r=await fetch(t,{signal:AbortSignal.timeout(1e4)});if(!r.ok)throw Error(`Dashboard returned HTTP ${r.status} for ${e}`);return r.json()}async function yg(e){let t=x(e,"network");if(t)return t;try{await Promise.resolve().then(() => Kt());let n=Ie();if(n.network&&be(n.network))return n.network}catch{}return}async function Yn(e,t={}){let r=new AbortController,n=setTimeout(()=>r.abort(),wg),s=Date.now();try{return{response:await fetch(e,{...t,signal:r.signal}),latencyMs:Date.now()-s}}finally{clearTimeout(n)}}async function Sg(e){let t=new Date().toISOString();try{let{response:r,latencyMs:n}=await Yn(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({query:"{ block { height } }"})});if(!r.ok){if(r.status===403)return{status:"degraded",latencyMs:n,lastChecked:t,notes:"HTTP 403 — likely WAF blocking"};return{status:"down",latencyMs:n,lastChecked:t,notes:`HTTP ${r.status}`}}let s=await r.json();if(!s?.data)return{status:"down",latencyMs:n,lastChecked:t,notes:"No data field"};let o=s.data?.block?.height;return{status:n>zn?"degraded":"up",latencyMs:n,lastChecked:t,...o!==void 0?{blockHeight:o}:{},...n>zn?{notes:`Slow (${n}ms)`}:{}}}catch(r){return{status:"down",latencyMs:0,lastChecked:t,notes:r.message}}}async function bg(e){let t=new Date().toISOString(),r=e.replace(/^wss:/,"https:").replace(/^ws:/,"http:");try{let{response:n,latencyMs:s}=await Yn(r,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:1,method:"system_health",params:[]})});if(!n.ok){if(n.status===403)return{status:"degraded",latencyMs:s,lastChecked:t,notes:"HTTP 403 — likely WAF blocking"};return{status:"down",latencyMs:s,lastChecked:t,notes:`HTTP ${n.status}`}}let i=(await n.json())?.result;if(!i)return{status:"down",latencyMs:s,lastChecked:t,notes:"No result in response"};let a=i.peers??0,c=i.isSyncing??!1,d="up",u;if(c)d="degraded",u="Node is syncing";else if(a===0)d="degraded",u="No peers";return{status:d,latencyMs:s,lastChecked:t,peers:a,isSyncing:c,...u?{notes:u}:{}}}catch(n){return{status:"down",latencyMs:0,lastChecked:t,notes:n.message}}}async function vg(e){let t=new Date().toISOString();if(!e)return{status:"unknown",latencyMs:0,lastChecked:t,notes:"No faucet URL"};try{let{response:r,latencyMs:n}=await Yn(e);if(!r.ok)return{status:"down",latencyMs:n,lastChecked:t,notes:`HTTP ${r.status}`};return{status:n>ud?"degraded":"up",latencyMs:n,lastChecked:t,...n>ud?{notes:`Slow (${n}ms)`}:{}}}catch(r){return{status:"down",latencyMs:0,lastChecked:t,notes:r.message}}}async function kg(e){let t=new Date().toISOString();if(!e)return{status:"unknown",latencyMs:0,lastChecked:t,notes:"URL not configured"};try{let{response:r,latencyMs:n}=await Yn(e);if(!r.ok)return{status:"down",latencyMs:n,lastChecked:t,notes:`HTTP ${r.status}`};let s=await r.text();if(!s||s.length===0)return{status:"down",latencyMs:n,lastChecked:t,notes:"Empty response"};return{status:n>zn?"degraded":"up",latencyMs:n,lastChecked:t,...n>zn?{notes:`Slow (${n}ms)`}:{}}}catch(r){return{status:"down",latencyMs:0,lastChecked:t,notes:r.message}}}async function pd(e){if(!be(e))return{};let t=Tr(e),r=gg[e];if(!r)return{};let[n,s,o,i]=await Promise.all([Sg(t.indexer),bg(t.node),vg(r.faucet),kg(r.explorer)]);return{indexer:n,rpc:s,faucet:o,explorer:i}}function xg(e,t,r){process.stderr.write(`
|
|
529
|
+
`+P(e)+`
|
|
531
530
|
`),process.stderr.write(g(" "+"─".repeat(62))+`
|
|
532
|
-
`);let n=new Set([...Object.keys(r),...t?Object.keys(t):[]]);for(let s of n){let o=r[s],i=t?.[s],a=(
|
|
533
|
-
`)}else if(i){let c=
|
|
534
|
-
`)}}}function
|
|
535
|
-
`+
|
|
531
|
+
`);let n=new Set([...Object.keys(r),...t?Object.keys(t):[]]);for(let s of n){let o=r[s],i=t?.[s],a=(hg[s]??s).padEnd(18);if(o){let c=ld[o.status]??g("—"),d=o.latencyMs>0?g(` ${o.latencyMs}ms`):"",u=o.notes?g(` — ${o.notes}`):"",l="";if(i&&i.status!==o.status&&i.status!=="unknown")l=g(` (canary: ${i.status}${i.lastChecked?" "+vo(i.lastChecked):""})`);process.stderr.write(` ${Or(a)}${c}${d}${u}${l}
|
|
532
|
+
`)}else if(i){let c=ld[i.status]??g("—"),d=i.latencyMs>0?g(` ${i.latencyMs}ms`):"",u=i.lastChecked?g(` (${vo(i.lastChecked)})`):"",l=i.notes?g(` — ${i.notes}`):"";process.stderr.write(` ${Or(a)}${c}${d}${u}${l}
|
|
533
|
+
`)}}}function Cg(e,t){let r=t?e.filter((n)=>n.affects.toLowerCase().includes(t.toLowerCase())):e;if(r.length===0)return;process.stderr.write(`
|
|
534
|
+
`+B("Known Issues")+`
|
|
536
535
|
|
|
537
|
-
`);for(let n of r)process.stderr.write(` ${
|
|
536
|
+
`);for(let n of r)process.stderr.write(` ${ce(n.id.padEnd(28))}${n.summary}
|
|
538
537
|
`),process.stderr.write(` ${" ".repeat(28)}${g(n.status)}
|
|
539
|
-
`)}async function
|
|
540
|
-
`+
|
|
541
|
-
`),i?.lastUpdated)process.stderr.write(g(` Canary: ${
|
|
538
|
+
`)}async function fd(e){let t=R(e,"json"),r=R(e,"all"),n=R(e,"watch"),s=await yg(e)??"preprod",o=K("Checking network status..."),i=null,a=null,c,d;if(r)d=["preprod","preview"];else d=[s];let[u,...l]=await Promise.all([Promise.all([qn("/api/status"),qn("/api/issues")]).catch((h)=>(c=h.message,null)),...d.map((h)=>pd(h))]);if(u)[i,a]=u;o.stop("Done");let f={};for(let h=0;h<d.length;h++)f[d[h]]=l[h];if(t){let h={lastUpdated:i?.lastUpdated??null,dashboard:gn,canaryAvailable:i!==null,networks:{}};for(let y of d){let S=f[y]??{},v=i?.networks[y],A={...v,...S};h.networks[y]={overall:bo(A),live:S,canary:v??null}}if(a){let y=r?void 0:d[0];h.issues=y?a.issues.filter((S)=>S.affects.toLowerCase().includes(y.toLowerCase())):a.issues}if(c)h.canaryError=c;D(h);let w=d.reduce((y,S)=>{let v={...i?.networks[S]??{},...f[S]??{}},A=bo(v);if(A==="down")return"down";if(A==="degraded"&&y!=="down")return"degraded";return y},"up");if(w==="down")process.exitCode=2;else if(w==="degraded")process.exitCode=1;return}let p=()=>{if(process.stderr.write(`
|
|
539
|
+
`+B("Midnight Network Status")+`
|
|
540
|
+
`),i?.lastUpdated)process.stderr.write(g(` Canary: ${vo(i.lastUpdated)}`)+" ");if(process.stderr.write(g("Live: just now")+`
|
|
542
541
|
`),c)process.stderr.write(g(` (Dashboard unreachable: ${c})`)+`
|
|
543
542
|
`);if(d.length===0){process.stderr.write(`
|
|
544
543
|
`+g("No network data available.")+`
|
|
545
544
|
|
|
546
|
-
`);return}for(let h of d)
|
|
547
|
-
`+
|
|
548
|
-
`),process.stderr.write(g(" Dashboard: ")+
|
|
545
|
+
`);return}for(let h of d)xg(h,i?.networks[h],f[h]??{});if(a){let h=r?void 0:d[0];Cg(a.issues,h)}process.stderr.write(`
|
|
546
|
+
`+J()+`
|
|
547
|
+
`),process.stderr.write(g(" Dashboard: ")+G(gn)+`
|
|
549
548
|
|
|
550
|
-
`)};if(p(),n){let h=setInterval(async()=>{try{let[w,...y]=await Promise.all([Promise.all([
|
|
551
|
-
`)}},30000);await new Promise(()=>{process.on("SIGINT",()=>{clearInterval(h),process.exit(0)})})}let m=d.reduce((h,w)=>{let y={...i?.networks[w]??{},...f[w]??{}},S=
|
|
552
|
-
Available: ${i.join(", ")}`);a=t}else a=i[0];let c=i.filter((u)=>u!==a),d=
|
|
553
|
-
Expected: managed/<name>/compiler/${
|
|
554
|
-
Searched: ${
|
|
555
|
-
Run "compact compile" first, or use --managed <path> to specify the managed directory.`)}function
|
|
549
|
+
`)};if(p(),n){let h=setInterval(async()=>{try{let[w,...y]=await Promise.all([Promise.all([qn("/api/status"),qn("/api/issues")]).catch(()=>null),...d.map((S)=>pd(S))]);if(w)[i,a]=w;for(let S=0;S<d.length;S++)f[d[S]]=y[S];process.stderr.write("\x1B[2J\x1B[H"),p()}catch{process.stderr.write(g(" Refresh failed — retrying in 30s")+`
|
|
550
|
+
`)}},30000);await new Promise(()=>{process.on("SIGINT",()=>{clearInterval(h),process.exit(0)})})}let m=d.reduce((h,w)=>{let y={...i?.networks[w]??{},...f[w]??{}},S=bo(y);if(S==="down")return"down";if(S==="degraded"&&h!=="down")return"degraded";return h},"up");if(m==="down")process.exitCode=2;else if(m==="degraded")process.exitCode=1}var gg,hg,ld,wg=15000,zn=5000,ud=1e4;var gd=T(()=>{me();ue();dt();gg={preprod:{faucet:"https://faucet.preprod.midnight.network/",explorer:"https://preprod.midnightexplorer.com/"},preview:{faucet:"https://faucet.preview.midnight.network/",explorer:null},undeployed:{faucet:"",explorer:""}},hg={indexer:"Indexer",rpc:"RPC Node",faucet:"Faucet",explorer:"Explorer",chain:"Chain",dust:"Dust Generation",wallet:"Wallet Ops",dapp:"DApp Flow"},ld={up:W("UP"),down:ce("DOWN"),degraded:P("\x1B[33mDEGRADED\x1B[0m"),unknown:g("—")}});function ko(e){if(!/^[0-9a-fA-F]{64}$/.test(e))throw new U(`A contract address is 64 hex characters (32 bytes); got "${e}" (${e.length} characters).`)}function hd(e,t,r){let n=e.circuits.filter((i)=>i.proof),s=n.find((i)=>i.name===t);if(!s){if(e.circuits.some((a)=>a.name===t))throw new U(`${t} is a pure circuit of ${e.name}: it runs locally and makes no transaction, so it can't be called.`);let i=n.map((a)=>a.name);throw new U(`${e.name} has no circuit "${t}". `+(i.length>0?`Its callable circuits: ${i.join(", ")}.`:"It has no circuits to call."))}let o=s.arguments.length;if(r.length!==o){let i=s.arguments.map((a)=>a.name).join(", ");throw new U(`${t} takes ${o} argument${o===1?"":"s"}${o>0?` (${i})`:""}; --args gave ${r.length}.`)}}var wd=T(()=>{Oe()});import{existsSync as xo,readFileSync as Eg,readdirSync as Ag}from"node:fs";import{join as dr,basename as Tg}from"node:path";function lt(e,t){let r=dr(e,"compiler",Xn);if(xo(r))return Sd(r,e,[]);for(let n of yd){let s=n?dr(e,n,"managed"):dr(e,"managed");if(!xo(s))continue;let o;try{o=Ag(s).sort()}catch{continue}let i=o.filter((u)=>xo(dr(s,u,"compiler",Xn)));if(i.length===0)continue;let a;if(t){if(!i.includes(t))throw Error(`Contract "${t}" not found in ${s}
|
|
551
|
+
Available: ${i.join(", ")}`);a=t}else a=i[0];let c=i.filter((u)=>u!==a),d=dr(s,a,"compiler",Xn);return Sd(d,dr(s,a),c)}throw Error(`No compiled contract found in ${e}
|
|
552
|
+
Expected: managed/<name>/compiler/${Xn}
|
|
553
|
+
Searched: ${yd.map((n)=>n?`${n}/managed/`:"managed/").join(", ")}
|
|
554
|
+
Run "compact compile" first, or use --managed <path> to specify the managed directory.`)}function Sd(e,t,r){let n;try{n=JSON.parse(Eg(e,"utf-8"))}catch(o){throw Error(`Failed to parse ${e}: ${o.message}`)}return{info:Ng(n,e,t,r),infoPath:e}}function Ng(e,t,r,n){if(typeof e!=="object"||e===null||Array.isArray(e))throw Error(`${t}: must be a JSON object`);let s=e,o=typeof s["compiler-version"]==="string"?s["compiler-version"]:"unknown",i=typeof s["language-version"]==="string"?s["language-version"]:"unknown",a=typeof s["runtime-version"]==="string"?s["runtime-version"]:"unknown",c=Array.isArray(s.circuits)?s.circuits:[],d=Array.isArray(s.witnesses)?s.witnesses:[];return{name:Tg(r),managedDir:r,compilerVersion:o,languageVersion:i,runtimeVersion:a,circuits:c,witnesses:d,siblings:n}}function We(e){switch(e["type-name"]){case"Uint":return"bigint";case"Bytes":return"Uint8Array";case"Opaque":return e.tsType??"unknown";case"Tuple":if(!e.types||e.types.length===0)return"void";return`[${e.types.map(We).join(", ")}]`;case"Boolean":return"boolean";case"String":return"string";case"Vector":return e.types?.[0]?`${We(e.types[0])}[]`:"unknown[]";case"Map":if(e.types&&e.types.length>=2)return`Map<${We(e.types[0])}, ${We(e.types[1])}>`;return"Map<unknown, unknown>";case"Set":return e.types?.[0]?`Set<${We(e.types[0])}>`:"Set<unknown>";case"Option":return e.types?.[0]?`${We(e.types[0])} | null`:"unknown | null";default:return e["type-name"]??"unknown"}}function bd(e){let t=e.arguments.map((r)=>`${r.name}: ${We(r.type)}`).join(", ");return`${e.name}(${t})`}function vd(e){if(e.pure)return"pure";let t=["impure"];if(e.proof)t.push("proof");return t.join(", ")}function kd(e){let t=e.arguments.map((s)=>`${s.name}: ${We(s.type)}`).join(", "),r=We(e["result type"]),n=r!=="void"?` → ${r}`:"";return`${e.name}(${t})${n}`}function xd(e){return{name:e.name,compilerVersion:e.compilerVersion,languageVersion:e.languageVersion,runtimeVersion:e.runtimeVersion,managedDir:e.managedDir,siblings:e.siblings,circuits:e.circuits.map((t)=>({name:t.name,pure:t.pure,proof:t.proof,arguments:t.arguments.map((r)=>({name:r.name,type:We(r.type)})),returnType:We(t["result-type"])})),witnesses:e.witnesses.map((t)=>({name:t.name,arguments:t.arguments.map((r)=>({name:r.name,type:We(r.type)})),returnType:We(t["result type"])}))}}var Xn="contract-info.json",yd;var Zn=T(()=>{yd=["","contract/src","contract","contracts/src","contracts","src"]});import*as Cd from"node:readline";function Ig(e){return Rg.has(e)}function $g(e){return Dg.has(e)}function Pg(e){let t=[],r=e.dappName?`Request from "${e.dappName}"`:"DApp Request";if(t.push(P(r)),t.push(""),t.push(` ${g("Action:")} ${G(e.method)}`),t.push(` ${g("Network:")} ${e.network}`),e.details.length>0){t.push("");for(let n of e.details)t.push(` ${g(n.label+":")} ${n.value}`)}return t.push(""),t.push(` ${W("[A]pprove")} ${ce("[R]eject")}`),Vi(t,"heavy")}function _g(e,t){if(t.approveFees)return`--approve-fees approves only paying the Dust fee for an agent's own balanced transaction (and its submit); ${e.method} needs a terminal to approve`;return`${$g(e.method)?"Balancing prompts like any other write":`${e.method} needs a terminal to approve`}: use --approve-all for non-interactive environments, or --approve-fees for a fee wallet that only pays an agent's Dust fee`}async function Ed(e,t={}){if(t.approveAll)return process.stderr.write(g(` Auto-approved: ${e.method}`)+`
|
|
556
555
|
`),"approve";if(t.approveFees&&e.feeOnly)return process.stderr.write(g(` Auto-approved (fee-only): ${e.method}`)+`
|
|
557
|
-
`),"approve";if(t.autoApproveReads&&
|
|
558
|
-
`),"approve";if(!process.stdin.isTTY)return process.stderr.write(
|
|
559
|
-
`),process.stderr.write(g(` ${
|
|
560
|
-
`),"reject";if(
|
|
556
|
+
`),"approve";if(t.autoApproveReads&&Ig(e.method))return process.stderr.write(g(` Auto-approved (read-only): ${e.method}`)+`
|
|
557
|
+
`),"approve";if(!process.stdin.isTTY)return process.stderr.write(ce(" Cannot prompt for approval: stdin is not a TTY")+`
|
|
558
|
+
`),process.stderr.write(g(` ${_g(e,t)}`)+`
|
|
559
|
+
`),"reject";if(Xr)return process.stderr.write(ce(" Rejected: another approval prompt is active")+`
|
|
561
560
|
`),"reject";process.stderr.write(`
|
|
562
|
-
`+
|
|
561
|
+
`+Pg(e)+`
|
|
563
562
|
|
|
564
|
-
`),
|
|
565
|
-
`),"reject"}return new Promise((n)=>{let s=(o)=>{
|
|
566
|
-
`)}),c.on("connection",(l)=>{let f=`conn_${++
|
|
563
|
+
`),Xr=!0;let r;try{r=Cd.createInterface({input:process.stdin,output:process.stderr})}catch{return Xr=!1,process.stderr.write(ce(" Cannot create readline interface")+`
|
|
564
|
+
`),"reject"}return new Promise((n)=>{let s=(o)=>{Xr=!1,r.close(),n(o)};r.on("close",()=>{if(Xr)s("reject")}),r.question(Z(" Approve? [A/r] "),(o)=>{let i=o.trim().toLowerCase();if(i==="r"||i==="reject")s("reject");else s("approve")})})}var Rg,Dg,Xr=!1;var Ad=T(()=>{ue();Rg=new Set(["getShieldedBalances","getUnshieldedBalances","getDustBalance","getShieldedAddresses","getUnshieldedAddress","getDustAddress","getTxHistory","getConfiguration","getConnectionStatus"]),Dg=new Set(["balanceUnsealedTransaction","balanceSealedTransaction"])});import{WebSocketServer as Og}from"ws";function Fg(e){if(Co(e))return Mg[e.code]??-32603;return-32603}function Co(e){return typeof e==="object"&&e!==null&&"type"in e&&e.type==="DAppConnectorAPIError"}function Lg(e){if(!(e instanceof Error)&&!(typeof e==="object"&&e!==null&&("_tag"in e)))return;let t=[],r=e.cause,n=new Set;while(r&&!n.has(r)){n.add(r);let s=r;if(r instanceof Error||typeof r==="object"&&s._tag){let o=s._tag,i=s.message??"";t.push(o?`[${o}] ${i}`:i),r=s.cause}else if(typeof r==="string"){t.push(r);break}else{try{t.push(JSON.stringify(r))}catch{t.push(String(r))}break}}if(t.length===0)return;return{causes:t}}function Qn(e,t){if(typeof t==="bigint")return t.toString();return t}function Ug(e,t){return t}function Wg(e){let t;try{t=JSON.parse(e,Ug)}catch{throw Object.assign(Error("Parse error"),{rpcCode:-32700})}if(typeof t!=="object"||t===null||t.jsonrpc!=="2.0"||typeof t.method!=="string")throw Object.assign(Error("Invalid Request"),{rpcCode:-32600});let r=t;if(r.id===void 0||r.id===null)throw Object.assign(Error("Missing request id"),{rpcCode:-32600});return r}function Td(e){let{port:t,handlers:r,onConnect:n,onDisconnect:s,onRequest:o,onResponse:i}=e,a=new Map,c=new Og({port:t,host:"127.0.0.1"}),d=new Promise((l,f)=>{c.once("listening",()=>l()),c.once("error",f)});d.catch(()=>{}),c.on("error",(l)=>{process.stderr.write(`WebSocket server error: ${l.message}
|
|
565
|
+
`)}),c.on("connection",(l)=>{let f=`conn_${++Bg}`,p={ws:l,id:f,connectedAt:new Date,authenticated:!1,requestCount:0,notify(w,y){if(l.readyState!==l.OPEN)return;let S={jsonrpc:"2.0",method:w,...y&&{params:y}};l.send(JSON.stringify(S,Qn))}};a.set(f,p),n?.(p);let m=!1,h=()=>{if(m)return;m=!0,a.delete(f),s?.(p)};l.on("message",async(w)=>{let y=null,S,v,A=Date.now();try{S=Wg(w.toString("utf-8")),y=S.id,p.requestCount++,o?.(p,S);let N=Object.hasOwn(r,S.method)?r[S.method]:void 0;if(!N){let V={jsonrpc:"2.0",id:S.id,error:{code:-32601,message:`Method not found: ${S.method}`}};l.send(JSON.stringify(V,Qn));return}v={notify:p.notify.bind(p),connectionId:f,requestId:S.id,metadata:{}};let L=await N(S.params??{},v),X=Date.now()-A;if(S.method==="connect"&&L&&typeof L==="object")p.authenticated=!0,p.networkId=L.networkId;let q={jsonrpc:"2.0",id:S.id,result:L};l.send(JSON.stringify(q,Qn)),i?.(p,S,X,L,void 0,v.metadata)}catch(N){let L=Date.now()-A,X=N?.rpcCode??Fg(N),q=N instanceof Error?N.message:"Internal error",V=Co(N)?{type:N.type,code:N.code}:Lg(N),O={jsonrpc:"2.0",id:y,error:{code:X,message:q,data:V}};if(l.send(JSON.stringify(O,Qn)),S){let _={message:q,code:Co(N)?N.code:void 0};i?.(p,S,L,void 0,_,v?.metadata)}}}),l.on("close",h),l.on("error",()=>{h();try{l.close()}catch{}})});async function u(){for(let l of a.values())l.ws.close(1001,"Server shutting down");return a.clear(),new Promise((l,f)=>{c.close((p)=>{if(p)f(p);else l()})})}return{wss:c,connections:a,ready:d,close:u}}function te(e,t){let r=Error(t);return r.type="DAppConnectorAPIError",r.code=e,r.reason=t,r}var Mg,Bg=0;var Eo=T(()=>{Mg={Rejected:-32000,PermissionRejected:-32001,Disconnected:-32002,InvalidRequest:-32602,InternalError:-32603}});function Nd(e){let t=[],r,n;function s(){if(r!==void 0&&n!==void 0){let a=Date.now()-n;t.push({phase:r,durationMs:a}),e?.onComplete?.(r,a),r=void 0,n=void 0}}function o(a){s(),r=a,n=Date.now(),e?.onStart?.(a)}function i(){return[...t]}return{start:o,complete:s,getTimings:i}}function Rd(e){return Buffer.from(e).toString("hex")}function lr(e){if(!/^[0-9a-fA-F]*$/.test(e))throw Error("Invalid hex string: contains non-hex characters");if(e.length%2!==0)throw Error("Invalid hex string: odd length");return new Uint8Array(Buffer.from(e,"hex"))}function Id(e,t){if(e<=t.maxFeeSpecks)return;return`the estimated fee ${de(e)} DUST is over --max-fee ${de(t.maxFeeSpecks)} DUST`}function $d(e,t){if(e<t.maxPending)return;return`${e} balanced transactions are still waiting to be submitted (--max-pending ${t.maxPending})`}var jg,Dd;var Pd=T(()=>{Oe();ue();jg=10n**15n,Dd={maxFeeSpecks:10n*jg,maxPending:2}});import{Transaction as Hg}from"@midnightntwrk/ledger-v9";function Ao(e,t){let r=[];r.push({label:"Tx size",value:Jg(e.length/2)});let n=Gg(e,t);if(n){let s=Kg(n);if(s.action)r.push({label:"Type",value:s.action});if(s.circuits.length>0)r.push({label:"Circuits",value:s.circuits.join(", ")});if(s.ttl)r.push({label:"TTL",value:s.ttl})}return r}function Gg(e,t){let r=Vg(e),n=t==="sealed"?[["signature","proof","binding"],["signature","proof","pre-binding"]]:[["signature","proof","pre-binding"],["signature","pre-proof","pre-binding"]];for(let[s,o,i]of n)try{return Hg.deserialize(s,o,i,r).toString(!0)}catch{}return null}function Kg(e){let t={networkId:null,action:null,circuits:[],ttl:null},r=e.match(/network_id:\s*"([^"]+)"/);if(r)t.networkId=r[1];if(e.includes("Deploy ContractState"))t.action="Deploy contract";else if(e.match(/Call\s/))t.action="Call contract";let n=/(\w+):\s*<verifier key>/g,s;while((s=n.exec(e))!==null)t.circuits.push(s[1]);if(t.circuits.length===0){let i=e.match(/Call\s+\S+\s+(\w+)/);if(i)t.circuits.push(i[1])}let o=e.match(/ttl:\s*Timestamp\((\d+)\)/);if(o){let i=parseInt(o[1],10),a=new Date(i*1000);t.ttl=a.toISOString().replace("T"," ").slice(0,19)}return t}function Vg(e){return new Uint8Array(Buffer.from(e,"hex"))}function Jg(e){if(e<1024)return`${e} B`;let t=e/1024;if(t<1024)return`${t.toFixed(1)} KB`;return`${(t/1024).toFixed(1)} MB`}var _d=()=>{};import{Transaction as Od,addressFromKey as Md}from"@midnightntwrk/ledger-v9";function ur(e,t){return t==="unsealed"?Od.deserialize("signature","proof","pre-binding",e):Od.deserialize("signature","proof","binding",e)}function To(e){return new Set([qg,...e.intents?.keys()??[],...e.fallibleOffer?.keys()??[]])}function Fd(e,t){return[...e.intents??new Map].filter(([,r])=>r.ttl.getTime()<=t.getTime()).map(([r,n])=>({segment:r,ttl:n.ttl}))}function No(e){let t=[];for(let[r,n]of e.intents??new Map){let s=[["guaranteed",n.guaranteedUnshieldedOffer],["fallible",n.fallibleUnshieldedOffer]];for(let[o,i]of s)i?.inputs.forEach((a,c)=>t.push({where:`intent ${r} ${o} unshielded input ${c}`,owner:a.owner,signed:i.signatures[c]!==void 0}))}return t}function Ld(e,t){if(e.rewards!==void 0)return["it is a rewards claim, not a standard transaction"];let r=[],n=Md(t);for(let{where:s,owner:o,signed:i}of No(e)){if(Md(o)===n)r.push(`${s} spends this wallet's own funds`);if(!i)r.push(`${s} is unsigned, so this wallet would sign it`)}for(let s of To(e)){let o;try{o=e.imbalances(s)}catch(i){r.push(`segment ${s}'s balance could not be computed: ${i.message??i}`);continue}for(let[i,a]of o){if(i.tag==="dust"||a>=0n)continue;r.push(`segment ${s} is short ${-a} of ${i.tag} token ${i.raw}, which a Dust-only balance can't fund`)}}return r}var qg=0;var Ro=()=>{};function Ud(e){let t=No(e),r=t.filter((n)=>n.signed).length;if(r===0)return"none";return r===t.length?"all":"some"}function zg(e){return[...To(e)].filter((t)=>[...e.imbalances(t)].some(([r,n])=>r.tag==="unshielded"&&n!==0n))}function Wd(e,t){let r=Ud(e);if(r==="some")throw new pr;if(r==="all"&&t){let n=zg(e);if(n.length>0)throw new Do(n)}}async function Bd(e,t,r){if(t.type!=="UNBOUND_TRANSACTION")return e.signRecipe(t,r);let n=ur(t.baseTransaction.serialize(),"unsealed"),s=Ud(n);if(s==="none")return e.signRecipe(t,r);if(s==="some")throw new pr;if(!t.balancingTransaction)return t;let o=await e.signRecipe({type:"UNPROVEN_TRANSACTION",protocolVersion:t.protocolVersion,transaction:t.balancingTransaction},r);if(o.type!=="UNPROVEN_TRANSACTION")throw Error(`The wallet SDK signed an unproven transaction into a ${o.type} recipe`);return{...t,balancingTransaction:o.transaction}}var pr,Do;var jd=T(()=>{Ro();pr=class pr extends Error{constructor(){super("The transaction has both signed and unsigned unshielded inputs. This wallet can't add its signatures to it without duplicating the existing ones (a wallet SDK limitation): send it with every unshielded input signed, or with none signed.");this.name="PartlySignedTransactionError",Object.setPrototypeOf(this,pr.prototype)}};Do=class Do extends Error{constructor(e){super(`The transaction's unshielded inputs are already signed, but segment ${e.join(", ")} is not balanced in unshielded value. This wallet balances it by adding inputs and outputs to the same intent, which invalidates those signatures. Leave the unshielded inputs unsigned so they are signed after balancing, or balance the sealed transaction with balanceSealedTransaction, which adds a separate intent.`);this.name="SignedTransactionNeedsUnshieldedError",Object.setPrototypeOf(this,Do.prototype)}}});async function Hd(e,t){let r;try{r=await St(e,Xg,{hash:t},Yg)}catch(o){throw new Zr(t,o.message)}let n=r.transactions?.find((o)=>o.__typename==="RegularTransaction");if(!n)throw new Zr(t,"the indexer has no such transaction");let s=n.transactionResult?.status;if(s!=="PARTIAL_SUCCESS")throw new Zr(t,`the indexer reports it as ${s??"having no result"}, not a partial success`);return n.transactionResult?.segments??[]}var Yg=1e4,Xg=`query ($hash: HexEncoded!) {
|
|
567
566
|
transactions(offset: { hash: $hash }) {
|
|
568
567
|
__typename
|
|
569
568
|
... on RegularTransaction { transactionResult { status segments { id success } } }
|
|
570
569
|
}
|
|
571
|
-
}`,
|
|
572
|
-
`)},
|
|
573
|
-
`)}function S(){return new Date(Date.now()+
|
|
574
|
-
`);let
|
|
575
|
-
`),!await
|
|
576
|
-
`)}};function Se(){l.unsubscribe();for(let[,k]of m)for(let[,b]of k)clearTimeout(b.timer);m.clear()}function tt(){for(let[,k]of m)if(k.size>0)return!0;return!1}return{handlers:
|
|
577
|
-
`)}var
|
|
578
|
-
${r}`)}}async function
|
|
579
|
-
${n}`)}}async function
|
|
580
|
-
${r}`)}}function
|
|
570
|
+
}`,Zr;var Gd=T(()=>{Gr();Zr=class Zr extends Error{constructor(e,t){super(`Could not read the segment results of transaction ${e} from the indexer: ${t}`);this.name="SegmentResultsUnavailableError",Object.setPrototypeOf(this,Zr.prototype)}}});import*as fr from"rxjs";import{MidnightBech32m as Io,UnshieldedAddress as Zg,ShieldedAddress as Qg}from"@midnightntwrk/wallet-sdk/address-format";function Lt(e){let t=[],r=e,n=new Set;while(r&&!n.has(r)){n.add(r);let o=r;if(r instanceof Error||typeof r==="object"&&o._tag){let i=o._tag,a=o.message??"";if(i&&a)t.push(`[${i}] ${a}`);else if(a)t.push(a);else if(i)t.push(`[${i}]`);if(o.data&&typeof o.data==="object")try{t.push(`data=${JSON.stringify(o.data)}`)}catch{}r=o.cause}else if(typeof r==="string"){t.push(r);break}else{try{let i=JSON.stringify(r);if(i&&i!=="{}")t.push(i);else t.push(String(r))}catch{t.push(String(r))}break}}let s=[];for(let o of t)if(s.length===0||s[s.length-1]!==o)s.push(o);return s.join(" → ")||"Unknown error"}function Vd(e,t){switch(e.lifecycle.status){case"finalized":return{txHash:e.hash,txStatus:{status:"finalized",executionStatus:eh(e,t)}};case"rejected":return{txHash:e.hash,txStatus:{status:"discarded"}};case"pending":return{txHash:e.hash,txStatus:{status:"pending"}}}}function eh(e,t){switch(e.status){case"SUCCESS":return{0:"Success"};case"FAILURE":return{0:"Failure"};case"PARTIAL_SUCCESS":if(!t||t.length===0)throw Error(`Transaction ${e.hash} partly succeeded, but its segment results are missing`);return Object.fromEntries(t.map((r)=>[r.id,r.success?"Success":"Failure"]));case void 0:return{}}}function th(e){if(e!=="schnorr")throw Error(`Unexpected signature scheme "${e}": mn signs with BIP-340 Schnorr only`);return"schnorr_bip340"}function Jd(e){let{bundle:t,networkConfig:r,approvalOptions:n,callbacks:s}=e,o=e.feeLimits??Dd,{facade:i,keystore:a}=t,c=Fe(r.networkId),d,u,l=i.state().subscribe((k)=>{if(u=k.protocolVersion,k.isSynced)d=k});function f(){if(!d)throw te("Disconnected","Wallet not synced yet");return d}function p(){if(!u)throw te("Disconnected","Wallet not synced yet");let k=ka(u);if(k.length>0){let b=k.map((E)=>`${E} at ${u[E]}`).join(", ");throw te("Disconnected",`This wallet can't take transactions until all three of its wallets are on ledger 9 (fork at ${st.v9}); still behind: ${b}. Wait for them to sync past the fork and retry.`)}}let m=new Map;function h(k,b,E,I=!1){let M=m.get(k);if(!M)M=new Map,m.set(k,M);let j=setTimeout(async()=>{if(M.delete(b),M.size===0)m.delete(k);try{await i.revert(E)}catch{}process.stderr.write(g(` abandoned tx reverted (${k})`)+`
|
|
571
|
+
`)},Ai);M.set(b,{finalized:E,timer:j,feeOnly:I})}function w(k,b){let E=m.get(k);if(!E)return;let I=E.get(b);if(I)clearTimeout(I.timer),E.delete(b);if(E.size===0)m.delete(k)}async function y(k){let b=m.get(k);if(!b||b.size===0)return;m.delete(k);for(let[,E]of b){clearTimeout(E.timer);try{await i.revert(E.finalized)}catch{}}process.stderr.write(g(` reverted ${b.size} pending tx(s) on disconnect`)+`
|
|
572
|
+
`)}function S(){return new Date(Date.now()+pn*60*1000)}async function v(k,b){b?.start("signing");let E;try{E=await Bd(i,k,a.signDataAsync)}catch(H){try{await i.revert(k)}catch{}if(H instanceof pr)throw te("InvalidRequest",H.message);throw H}b?.start("proving");let I,M,j=i.finalizeRecipe(E);try{M=await Promise.race([j,new Promise((H,Ae)=>{I=setTimeout(()=>Ae(Error("ZK proof generation timed out")),un)})])}catch(H){try{await i.revert(k)}catch{}throw j.then((Ae)=>i.revert(Ae)).catch(()=>{}),H}finally{clearTimeout(I)}return b?.complete(),{hex:Rd(M.serialize()),finalized:M}}function A(k,b){try{return i.adoptTransaction(lr(k),b)}catch(E){throw te("InvalidRequest",`The transaction could not be read at stage ${b} as this wallet's ledger version: ${Lt(E)}`)}}async function N(k,b=[],E,I=!1){E?.notify("approval:pending",{method:k});let M=await Ed({method:k,network:r.networkId,details:b,dappName:E?.connectionId,feeOnly:I},n),j=M==="reject"?"rejected":"approved";if(E?.notify("approval:resolved",{method:k,result:j}),M==="reject")throw te("Rejected",n.approveFees?`${Kd}: this fee wallet (--approve-fees) approves without the operator only paying the Dust fee for an agent's own transaction and submitting a transaction it balanced that way on the same connection`:Kd)}function L(k,b,E){if(E===!1)throw te("InvalidRequest","This wallet is a fee wallet (--approve-fees): it only pays the Dust fee, so payFees: false leaves it nothing to do");let I;try{I=ur(lr(k),b)}catch(j){throw te("InvalidRequest",`The transaction could not be read as a proven ledger-9 ${b} transaction: ${Lt(j)}`)}let M=Ld(I,a.getPublicKey());if(M.length>0)throw te("Rejected",`This wallet is a fee wallet (--approve-fees) and pays only the Dust fee; it refuses this transaction because ${M.join("; ")}`)}function X(k,b){let E;try{E=Fd(ur(lr(k),b),new Date)}catch(I){throw te("InvalidRequest",Lt(I))}if(E.length>0){let I=E.map(({segment:M,ttl:j})=>`intent ${M}'s TTL (${j.toISOString()})`).join(", ");throw te("InvalidRequest",`The transaction has expired: ${I} has passed. Build it again with a later TTL.`)}}function q(k,b){try{Wd(ur(lr(k),"unsealed"),b)}catch(E){throw te("InvalidRequest",Lt(E))}}function V(){let k=0;for(let[,b]of m)k+=b.size;return k}function O(k){return te("Rejected",`This wallet is a fee wallet (--approve-fees) and refuses this transaction: ${k}`)}let _=0;function ne(){let k=$d(V()+_,o);if(k)throw O(k);_++;let b=!1;return()=>{if(!b)b=!0,_--}}async function pe(k,b){let E=await Wt(()=>i.estimateTransactionFee(k,{ttl:b}));process.stderr.write(g(` fee-only: estimated fee ${de(E)} DUST (limit ${de(o.maxFeeSpecks)})`)+`
|
|
573
|
+
`);let I=Id(E,o);if(I)throw O(I)}async function sn(k,b,E,I){let M=String(E.tx??"");if(!M)throw te("InvalidRequest","tx is required");p();let j=E.options?.payFees,H=n.approveFees===!0;if(H)L(M,b,j);let Ae=H?["dust"]:j===!1?["shielded","unshielded"]:"all",_e=S(),qe=b==="unsealed"?A(M,"Unbound"):A(M,"Finalized");if(X(M,b),b==="unsealed")q(M,Ae==="all"||Ae.includes("unshielded"));let ze=H?ne():void 0;try{if(H)await pe(qe,_e);let Ye=vt(k,I);Ye.start("approve"),await N(k,Ao(M,b),I,H),Ye.start("building");let Bt={ttl:_e,tokenKindsToBalance:Ae},ps;if(b==="unsealed"){let fs=qe;ps=await Wt(()=>i.balanceUnboundTransaction(fs,Bt))}else{let fs=qe;ps=await Wt(()=>i.balanceFinalizedTransaction(fs,Bt))}let{hex:oi,finalized:Ju}=await v(ps,Ye);return h(I.connectionId,oi,Ju,H),I.metadata.phases=Ye.getTimings(),{tx:oi}}finally{ze?.()}}function ut(k){return Io.encode(c,k).asString()}function fe(k){let b={};for(let E of k){let I=E.kind;if(I!=="shielded"&&I!=="unshielded")throw te("InvalidRequest",`Invalid output kind: "${I}" — must be "shielded" or "unshielded"`);if(!b[I])b[I]=[];let M=BigInt(E.value),j;if(I==="unshielded")j=Io.parse(E.recipient).decode(Zg,c);else j=Io.parse(E.recipient).decode(Qg,c);b[I].push({type:E.type,receiverAddress:j,amount:M})}return Object.entries(b).map(([E,I])=>({type:E,outputs:I}))}function vt(k,b){return Nd({onStart:(E)=>{let I=b?.connectionId??"unknown";s?.onPhaseStart?.(I,k,E),b?.notify("progress",{method:k,phase:E,status:"started"})},onComplete:(E,I)=>{let M=b?.connectionId??"unknown";s?.onPhaseComplete?.(M,k,E,I),b?.notify("progress",{method:k,phase:E,status:"completed",durationMs:I})}})}function kt(){return d!==void 0&&$t(d)}async function Ee(k){return new Promise((b)=>{if(kt()){b(!0);return}let E=i.state().pipe(fr.filter(()=>kt()),fr.take(1),fr.timeout(k)).subscribe({next:()=>{E.unsubscribe(),b(!0)},error:()=>{E.unsubscribe(),b(!1)}})})}function xt(k){return te("InternalError",`No Dust is free to pay the fee (${Lt(k)}). Each balanced transaction reserves a whole Dust coin until it is submitted and on chain, or released when its connection closes or it expires; ${V()} balanced transaction(s) are waiting to be submitted on this server. Retry once they settle. To pay for more transactions at once, the wallet needs more Dust coins: one per NIGHT UTXO registered for Dust generation.`)}async function Wt(k){for(let b=1;b<=xr;b++)try{return await k()}catch(E){let I=String(E?.message??E??"");if(!qs(E))throw E;if(b===xr)throw xt(E);if(process.stderr.write(g(` dust unavailable, waiting for recovery (${b}/${xr})... [${I.slice(0,60)}]`)+`
|
|
574
|
+
`),!await Ee(As)&&b<xr)await new Promise((j)=>setTimeout(j,As))}throw Error("unreachable")}let ge={connect:async(k)=>{let b=String(k.networkId??"");if(b.toLowerCase()!==r.networkId.toLowerCase())throw te("InvalidRequest",`Network mismatch: wallet is on ${r.networkId}, requested ${b}`);return{networkId:r.networkId}},getUnshieldedBalances:async()=>f().unshielded.balances,getShieldedBalances:async()=>f().shielded.balances,getDustBalance:async()=>{let b=f().dust.balance(new Date);return{cap:b,balance:b}},getUnshieldedAddress:async()=>{let k=f();return{unshieldedAddress:ut(k.unshielded.address)}},getShieldedAddresses:async()=>{let b=f().shielded.address;return{shieldedAddress:ut(b),shieldedCoinPublicKey:b.coinPublicKeyString(),shieldedEncryptionPublicKey:b.encryptionPublicKeyString()}},getDustAddress:async()=>{let k=f();return{dustAddress:ut(k.dust.address)}},getTxHistory:async(k)=>{f();let b=Number(k.pageNumber??0),E=Number(k.pageSize??20),I=b*E,M=await i.getAllFromTxHistory(),j=[];for(let H of M.slice(I,I+E)){if(H.lifecycle.status!=="finalized"||H.status!=="PARTIAL_SUCCESS"){j.push(Vd(H));continue}try{j.push(Vd(H,await Hd(r.indexer,H.hash)))}catch(Ae){throw te("InternalError",Lt(Ae))}}return j},getConfiguration:async()=>({indexerUri:r.indexer,indexerWsUri:r.indexerWS,proverServerUri:r.proofServer,substrateNodeUri:r.node,networkId:r.networkId}),getConnectionStatus:async()=>({status:"connected",networkId:c}),makeTransfer:async(k,b)=>{let E=k.desiredOutputs;if(!Array.isArray(E)||E.length===0)throw te("InvalidRequest","desiredOutputs must be a non-empty array");p();let I=vt("makeTransfer",b),M=E.map((ze,Ye)=>({label:`Output ${Ye+1}`,value:`${ze.value} → ${String(ze.recipient).slice(0,20)}... (${ze.kind})`}));I.start("approve"),await N("makeTransfer",M,b),I.start("building");let j=fe(E),H=k.options?.payFees??!0,Ae=await Wt(()=>i.transferTransaction(j,{ttl:S(),payFees:H})),{hex:_e,finalized:qe}=await v(Ae,I);return h(b.connectionId,_e,qe),b.metadata.phases=I.getTimings(),{tx:_e}},submitTransaction:async(k,b)=>{let E=String(k.tx??"");if(!E)throw te("InvalidRequest","tx is required");p();let I=vt("submitTransaction",b),M=n.approveFees===!0&&m.get(b.connectionId)?.get(E)?.feeOnly===!0;I.start("approve");try{await N("submitTransaction",Ao(E,"sealed"),b,M)}catch(H){let _e=m.get(b.connectionId)?.get(E);if(_e)try{await i.revert(_e.finalized)}catch{}throw w(b.connectionId,E),H}let j=A(E,"Finalized");I.start("submitting");try{let H=await i.submitTransaction(j);return I.complete(),w(b.connectionId,E),b.metadata.phases=I.getTimings(),{txHash:H}}catch(H){I.complete();let _e=m.get(b.connectionId)?.get(E);if(_e)try{await i.revert(_e.finalized)}catch{}w(b.connectionId,E);let qe=Lt(H),ze=Error(`Transaction submission failed: ${qe}`);throw ze.cause=H,ze}},balanceUnsealedTransaction:(k,b)=>sn("balanceUnsealedTransaction","unsealed",k,b),balanceSealedTransaction:(k,b)=>sn("balanceSealedTransaction","sealed",k,b),makeIntent:async(k,b)=>{let{desiredInputs:E,desiredOutputs:I,options:M}=k;if(!M)throw te("InvalidRequest","options is required for makeIntent");p();let j=vt("makeIntent",b);j.start("approve"),await N("makeIntent",[],b),j.start("building");let H={};if(Array.isArray(E))for(let Ye of E){let Bt=Ye.kind;if(!H[Bt])H[Bt]={};H[Bt][Ye.type]=BigInt(Ye.value)}let Ae=fe(I??[]),_e=await Wt(()=>i.initSwap(H,Ae,{ttl:S(),payFees:M.payFees??!0})),{hex:qe,finalized:ze}=await v(_e,j);return h(b.connectionId,qe,ze),b.metadata.phases=j.getTimings(),{tx:qe}},signData:async(k,b)=>{let E=String(k.data??""),I=k.options;if(!E||!I?.encoding)throw te("InvalidRequest","data and options.encoding are required");if(I.keyType&&I.keyType!=="unshielded")throw te("InvalidRequest",`Unsupported keyType: "${I.keyType}" — only "unshielded" is supported`);await N("signData",[{label:"Encoding",value:I.encoding},{label:"Data",value:E.length>64?E.slice(0,64)+"...":E}],b);let M;switch(I.encoding){case"hex":M=lr(E);break;case"base64":M=new Uint8Array(Buffer.from(E,"base64"));break;case"text":M=new Uint8Array(Buffer.from(E,"utf-8"));break;default:throw te("InvalidRequest",`Unknown encoding: ${I.encoding}`)}let j=await a.signDataAsync(M),H=a.getPublicKey();return{data:E,signature:j.value,verifyingKey:H.value,scheme:th(j.tag)}},getProvingProvider:async()=>({provingProvider:"ready",proverServerUri:r.proofServer}),hintUsage:async(k)=>{let b=k.methodNames??[];process.stderr.write(g(` DApp hints usage: ${b.join(", ")}`)+`
|
|
575
|
+
`)}};function Se(){l.unsubscribe();for(let[,k]of m)for(let[,b]of k)clearTimeout(b.timer);m.clear()}function tt(){for(let[,k]of m)if(k.size>0)return!0;return!1}return{handlers:ge,revertPendingTxs:y,hasPendingTxs:tt,dispose:Se}}var Kd="User rejected the request";var qd=T(()=>{Ke();me();Ad();Eo();mt();Br();Pd();_d();Ro();jd();Gd();Ot();ue()});import{Socket as rh}from"node:net";function zd(e){let{name:t,config:r}=le({args:{command:"serve",subcommand:void 0,positionals:[],flags:{...e.network?{network:e.network}:{},...yn(e.endpoints??{})}}});return $e(r,e.endpoints??{},t),{networkName:t,networkConfig:r}}function nh(e,t){let r=(s,o)=>s!==void 0&&s.replace(/\/+$/,"")===o.replace(/\/+$/,""),n=[];if(!r(e.substrateNodeUri,t.node))n.push(`node ${e.substrateNodeUri} (need ${t.node})`);if(!r(e.indexerWsUri,t.indexerWS))n.push(`indexer ${e.indexerWsUri} (need ${t.indexerWS})`);return n.length>0?n.join(", "):void 0}function sh(e){return new Promise((t)=>{let r=new rh;r.setTimeout(1000),r.once("connect",()=>{r.destroy(),t(!0)}),r.once("timeout",()=>{r.destroy(),t(!1)}),r.once("error",()=>t(!1)),r.connect(e,"127.0.0.1")})}async function oh(e){let r=(await Yd(e,"getConnectionStatus"))?.networkId;return typeof r==="string"?r:null}async function ih(e){let t=await Yd(e,"getConfiguration");return t&&typeof t==="object"?t:null}async function Yd(e,t){let r=(await import("ws")).default;return new Promise((n)=>{let s=new r(`ws://127.0.0.1:${e}`),o=setTimeout(()=>{try{s.close()}catch{}n(null)},2000);s.on("open",()=>{s.send(JSON.stringify({jsonrpc:"2.0",id:1,method:t,params:{}}))}),s.on("message",(i)=>{clearTimeout(o);try{let a=JSON.parse(i.toString());s.close(),n(a?.result??null)}catch{s.close(),n(null)}}),s.on("error",()=>{clearTimeout(o),n(null)})})}async function es(e){let t=e.port??Cr,r=(e.network??"undeployed").toLowerCase(),n=e.onMessage??(()=>{});if(await sh(t)){let s=await oh(t);if(!s)throw Error(`Port ${t} is in use by a process that does not look like mn serve. Free the port (e.g. \`lsof -nP -iTCP:${t} -sTCP:LISTEN\` then \`kill <pid>\`) and retry.`);let o=s.toLowerCase();if(o!==r)throw Error(`mn serve is already running on port ${t} for network ${o}, but this run needs ${r}. Stop the wrong-network serve first (\`pkill -f 'mn serve'\`) and retry.`);let i=await ih(t),a=i?nh(i,zd(e).networkConfig):"its endpoints could not be read";if(a)throw Error(`mn serve on port ${t} is on a different ${o} chain: ${a}. Stop it first (\`pkill -f 'mn serve'\`) and retry.`);return n(`Reusing existing mn serve on port ${t}`),{port:t,async stop(){}}}return ah(e)}async function ah(e){let t=e.port??Cr,r=e.onMessage??(()=>{}),n=ae(re(e.wallet)),s=Buffer.from(n.seed,"hex"),{networkName:o,networkConfig:i}=zd(e);await Be(o,i);let a=n.addresses[o],c=Re((m,h)=>{r(`SDK: ${h}`)}),d=De();r("Building wallet facade...");let u=yt(a,o),l=await Ze(s,i,u);r("Syncing wallet..."),await wt(l,{onProgress:(m,h)=>{if(h>0){let w=Math.min(Math.round(m/h*100),100);r(`Syncing wallet... ${w}%`)}}}),r("Wallet synced"),r("Waiting for dust..."),await Nn(l),r("Dust ready");try{await it(a,o,l.facade)}catch{}let f=Jd({bundle:l,networkConfig:i,approvalOptions:{approveAll:!0,autoApproveReads:!0},callbacks:{onPhaseStart:(m,h,w)=>{r(`${w}...`)},onPhaseComplete:(m,h,w,y)=>{r(`${w} ${Math.round(y)}ms`)}}}),p=Td({port:t,handlers:f.handlers,onConnect:(m)=>{r(`connected ${m.id}`)},onDisconnect:(m)=>{r(`disconnected ${m.id}`),f.revertPendingTxs(m.id).catch(()=>{})},onRequest:(m,h)=>{r(`${m.id} → ${h.method}`)},onResponse:(m,h,w,y,S)=>{if(S)r(`${m.id} ← ${h.method} FAILED: ${S.message}`);else r(`${m.id} ← ${h.method} (${Math.round(w)}ms)`)}});try{await p.ready}catch(m){throw f.dispose(),await p.close(),await Ue(l),c(),d(),Error(`Could not start mn serve on port ${t}: ${m.message}`)}return r(`Server ready on ws://localhost:${t}`),{port:t,async stop(){p.close(),f.dispose(),d(),c();try{await Ue(l)}catch{}}}}var $o=T(()=>{Le();ke();Ot();me();Ke();Pt();Ft();qd();Eo()});import{existsSync as Xd}from"node:fs";import{join as Zd}from"node:path";function Qd(e){for(let t of ts){let r=Zd(e,t);if(Xd(r))return r}return null}function dh(e){for(let t of ch){let r=Zd(e,t);if(Xd(r))return r}return null}function el(e){let{projectRoot:t,witnessNames:r}=e,n=dh(t),s=[`Contract declares ${r.length} witness(es): ${r.join(", ")}`,"but no compiled witnesses module was found.","",`Searched (relative to ${t}):`,...ts.map((o)=>` - ${o}`),""];if(n)s.push(`Found ${n} — looks like it isn't compiled yet.`,'Build it (e.g. "npm run build") so a .js exists, then retry.');else s.push('Add a witnesses module exporting a "witnesses" object that maps each',"declared name to its implementation. Example: src/witnesses.ts → tsc → dist/witnesses.js.");return s.join(`
|
|
576
|
+
`)}var ts,ch;var Po=T(()=>{ts=["dist/witnesses.js","src/witnesses.js","contract/dist/witnesses.js","contract/src/witnesses.js"],ch=["src/witnesses.ts","contract/src/witnesses.ts"]});function rs(e){if(typeof e==="number")return Number.isInteger(e)?BigInt(e):e;if(typeof e==="string"){if(/^-?\d+n$/.test(e))return BigInt(e.slice(0,-1));return e}if(Array.isArray(e)){if(e.length>0&&e.every((t)=>typeof t==="number"&&Number.isInteger(t)&&t>=0&&t<=255))return Uint8Array.from(e);return e.map(rs)}if(e&&typeof e==="object"&&Object.getPrototypeOf(e)===Object.prototype){let t={};for(let r in e)if(Object.prototype.hasOwnProperty.call(e,r))t[r]=rs(e[r]);return t}return e}function tl(e,t){let r=new Uint8Array(32);if(e&&e.length===64){for(let s=0;s<32;s++)r[s]=parseInt(e.substr(s*2,2),16);return r}let n=t??"";if(n.length>=64){for(let s=0;s<32;s++)r[s]=parseInt(n.substr(s*2,2),16);return r}return globalThis.crypto.getRandomValues(r),r}import{spawn as lh}from"node:child_process";import{writeFileSync as uh,unlinkSync as rl,existsSync as ns,symlinkSync as nl}from"node:fs";import{join as Qr,dirname as sl}from"node:path";import{fileURLToPath as ph}from"node:url";function fh(){let e=sl(ph(import.meta.url));for(let t=0;t<8;t++){let r=Qr(e,"node_modules");if(ns(r))return r;let n=sl(e);if(n===e)break;e=n}return null}async function mr(e){let t=yh(e),r=await Fo(e.dappDir,t,e.onMessage);try{return JSON.parse(r)}catch{throw Error(`State script returned unexpected output:
|
|
577
|
+
${r}`)}}async function ss(e){let t=hh(e),r=e.privateStateSecretKey?{MN_PRIVATE_STATE_SECRET:e.privateStateSecretKey}:void 0,n=await Fo(e.dappDir,t,e.onMessage,r);try{return JSON.parse(n)}catch{throw Error(`Deploy script returned unexpected output:
|
|
578
|
+
${n}`)}}async function os(e){let t=wh(e),r=await Fo(e.dappDir,t,e.onMessage);try{return JSON.parse(r)}catch{throw Error(`Call script returned unexpected output:
|
|
579
|
+
${r}`)}}function ol(e){return`
|
|
581
580
|
import WebSocket from 'ws';
|
|
582
581
|
|
|
583
582
|
const RPC_URL = 'ws://127.0.0.1:${e}';
|
|
@@ -618,7 +617,7 @@ function rpcCall(method, params = {}) {
|
|
|
618
617
|
function rpcClose() {
|
|
619
618
|
if (rpcWs) rpcWs.close();
|
|
620
619
|
}
|
|
621
|
-
`}function
|
|
620
|
+
`}function al(){return`
|
|
622
621
|
const walletState = await rpcCall('getShieldedAddresses', {});
|
|
623
622
|
|
|
624
623
|
const walletProvider = createWalletProvider({
|
|
@@ -635,7 +634,7 @@ const midnightProvider = createMidnightProvider(async (tx) => {
|
|
|
635
634
|
await rpcCall('submitTransaction', { tx: toHex(tx.serialize()) });
|
|
636
635
|
return tx.identifiers()[0];
|
|
637
636
|
});
|
|
638
|
-
`}function
|
|
637
|
+
`}function cl(e,t){return`
|
|
639
638
|
import { pathToFileURL } from 'node:url';
|
|
640
639
|
import { resolve } from 'node:path';
|
|
641
640
|
import { CompiledContract } from '@midnight-ntwrk/compact-js';
|
|
@@ -649,7 +648,7 @@ const contractMod = await import(pathToFileURL(resolve(MANAGED_DIR, 'contract',
|
|
|
649
648
|
// Both relative-to-cwd locations and contract/<...> locations are checked
|
|
650
649
|
// so mn dev (which chdirs into the contract sub-package) and mn contract
|
|
651
650
|
// deploy run from a workspace root both work.
|
|
652
|
-
const WITNESS_CANDIDATES = ${JSON.stringify(
|
|
651
|
+
const WITNESS_CANDIDATES = ${JSON.stringify(ts)};
|
|
653
652
|
let witnesses;
|
|
654
653
|
let createPrivateState;
|
|
655
654
|
for (const p of WITNESS_CANDIDATES) {
|
|
@@ -680,7 +679,7 @@ if (!witnesses) {
|
|
|
680
679
|
// Uses a deterministic seed derived from the wallet so post/takeDown use the same key.
|
|
681
680
|
// The private state provider (leveldb) persists between calls, but initialPrivateState
|
|
682
681
|
// is the fallback when no stored state exists yet.
|
|
683
|
-
${
|
|
682
|
+
${mh}
|
|
684
683
|
function makeInitialPrivateState() {
|
|
685
684
|
if (createPrivateState) {
|
|
686
685
|
// Secret precedence (see resolvePrivateStateSecretKey, injected above via
|
|
@@ -706,7 +705,7 @@ const compiled = witnesses
|
|
|
706
705
|
CompiledContract.withVacantWitnesses,
|
|
707
706
|
(c) => CompiledContract.withCompiledFileAssets(c, MANAGED_DIR),
|
|
708
707
|
);
|
|
709
|
-
`}function
|
|
708
|
+
`}function dl(e,t){return`
|
|
710
709
|
const zkConfigProvider = new NodeZkConfigProvider(MANAGED_DIR);
|
|
711
710
|
|
|
712
711
|
const providers = {
|
|
@@ -724,24 +723,24 @@ const providers = {
|
|
|
724
723
|
walletProvider,
|
|
725
724
|
midnightProvider,
|
|
726
725
|
};
|
|
727
|
-
`}function
|
|
726
|
+
`}function gh(e,t){let r=new RegExp(`^${Oo} (.*)$`,"m").exec(e);if(r)try{return JSON.parse(r[1])}catch{return r[1]}return e.trim()||`Script exited with code ${t}`}function hh(e){let t=e.privateStateKey??`${e.contractName}PrivateState`,r=JSON.stringify(e.args??[]);return`${Mo}
|
|
728
727
|
import { setNetworkId } from '@midnight-ntwrk/midnight-js-network-id';
|
|
729
728
|
setNetworkId(${JSON.stringify(e.networkConfig.networkId.toLowerCase())});
|
|
730
729
|
|
|
731
|
-
${
|
|
732
|
-
${
|
|
730
|
+
${ol(e.servePort)}
|
|
731
|
+
${cl(e.contractName,e.managedDir)}
|
|
733
732
|
|
|
734
733
|
process.stderr.write('Connecting to mn serve...\\n');
|
|
735
734
|
await rpcConnect();
|
|
736
735
|
process.stderr.write('Connected\\n');
|
|
737
736
|
|
|
738
|
-
${
|
|
739
|
-
${
|
|
740
|
-
${
|
|
737
|
+
${il}
|
|
738
|
+
${al()}
|
|
739
|
+
${dl(e.networkConfig,t)}
|
|
741
740
|
|
|
742
741
|
import { deployContract } from '@midnight-ntwrk/midnight-js-contracts';
|
|
743
742
|
|
|
744
|
-
${
|
|
743
|
+
${ll}
|
|
745
744
|
const constructorArgs = (${r}).map(coerceArg);
|
|
746
745
|
process.stderr.write('Deploying contract' + (constructorArgs.length ? ' with ' + constructorArgs.length + ' constructor arg(s)...' : '...') + '\\n');
|
|
747
746
|
const deployed = await deployContract(providers, {
|
|
@@ -757,20 +756,20 @@ process.stderr.write('Deploy complete: ' + address + '\\n');
|
|
|
757
756
|
console.log(JSON.stringify({ contractAddress: address }));
|
|
758
757
|
rpcClose();
|
|
759
758
|
process.exit(0);
|
|
760
|
-
`}function
|
|
759
|
+
`}function wh(e){let t=e.privateStateKey??`${e.contractName}PrivateState`;return`${Mo}
|
|
761
760
|
import { setNetworkId } from '@midnight-ntwrk/midnight-js-network-id';
|
|
762
761
|
setNetworkId(${JSON.stringify(e.networkConfig.networkId.toLowerCase())});
|
|
763
762
|
|
|
764
|
-
${
|
|
765
|
-
${
|
|
763
|
+
${ol(e.servePort)}
|
|
764
|
+
${cl(e.contractName,e.managedDir)}
|
|
766
765
|
|
|
767
766
|
process.stderr.write('Connecting to mn serve...\\n');
|
|
768
767
|
await rpcConnect();
|
|
769
768
|
process.stderr.write('Connected\\n');
|
|
770
769
|
|
|
771
|
-
${
|
|
772
|
-
${
|
|
773
|
-
${
|
|
770
|
+
${il}
|
|
771
|
+
${al()}
|
|
772
|
+
${dl(e.networkConfig,t)}
|
|
774
773
|
|
|
775
774
|
import { findDeployedContract } from '@midnight-ntwrk/midnight-js-contracts';
|
|
776
775
|
|
|
@@ -783,14 +782,14 @@ const deployed = await findDeployedContract(providers, {
|
|
|
783
782
|
});
|
|
784
783
|
|
|
785
784
|
process.stderr.write('Calling ${e.circuit}...\\n');
|
|
786
|
-
${
|
|
785
|
+
${ll}
|
|
787
786
|
const args = (${JSON.stringify(e.args??[])}).map(coerceArg);
|
|
788
787
|
await deployed.callTx.${e.circuit}(...args);
|
|
789
788
|
|
|
790
789
|
console.log(JSON.stringify({ status: 'success', circuit: ${JSON.stringify(e.circuit)} }));
|
|
791
790
|
rpcClose();
|
|
792
791
|
process.exit(0);
|
|
793
|
-
`}function
|
|
792
|
+
`}function yh(e){return`${Mo}
|
|
794
793
|
import { setNetworkId } from '@midnight-ntwrk/midnight-js-network-id';
|
|
795
794
|
setNetworkId(${JSON.stringify(e.networkConfig.networkId.toLowerCase())});
|
|
796
795
|
|
|
@@ -804,8 +803,7 @@ const MANAGED_DIR = ${JSON.stringify(e.managedDir)};
|
|
|
804
803
|
const contractMod = await import(pathToFileURL(resolve(MANAGED_DIR, 'contract', 'index.js')).href);
|
|
805
804
|
|
|
806
805
|
if (typeof contractMod.ledger !== 'function') {
|
|
807
|
-
|
|
808
|
-
process.exit(1);
|
|
806
|
+
fail(new Error('Contract module does not export a ledger() function'));
|
|
809
807
|
}
|
|
810
808
|
|
|
811
809
|
process.stderr.write('Querying contract state...\\n');
|
|
@@ -816,8 +814,7 @@ const provider = indexerPublicDataProvider({
|
|
|
816
814
|
|
|
817
815
|
const contractState = await provider.queryContractState(${JSON.stringify(e.contractAddress)});
|
|
818
816
|
if (!contractState) {
|
|
819
|
-
|
|
820
|
-
process.exit(1);
|
|
817
|
+
fail(new Error('No contract found at address ${e.contractAddress}'));
|
|
821
818
|
}
|
|
822
819
|
|
|
823
820
|
process.stderr.write('Parsing ledger state...\\n');
|
|
@@ -853,46 +850,52 @@ for (const key of Object.keys(state)) {
|
|
|
853
850
|
|
|
854
851
|
console.log(JSON.stringify({ fields, maps }));
|
|
855
852
|
process.exit(0);
|
|
856
|
-
`}function
|
|
857
|
-
`,r?.(m)}),u.on("close",(p)=>{if(a(),p!==0){d(Error(f.trim()||`Script exited with code ${p}`));return}c(l.trim())}),u.on("error",(p)=>{a(),d(p)})})}var ko,Ld=`
|
|
853
|
+
`}function bh(e){if(!_o)return[];let t=[];if(!ns(e)){try{nl(_o,e),t.push(e)}catch{}return t}for(let r of Sh){let n=Qr(_o,r),s=Qr(e,r);if(!ns(n)||ns(s))continue;try{nl(n,s),t.push(s)}catch{}}return t}async function Fo(e,t,r,n){let s=Qr(e,"node_modules"),o=bh(s),i=Qr(e,`.mn-contract-${Date.now()}.mjs`);uh(i,t);let a=()=>{try{rl(i)}catch{}for(let c of o.slice().reverse())try{rl(c)}catch{}};return new Promise((c,d)=>{let u=lh("node",[i],{cwd:e,stdio:["ignore","pipe","pipe"],env:{...process.env,NODE_NO_WARNINGS:"1",...n}}),l="",f="";u.stdout?.on("data",(p)=>{l+=p.toString()}),u.stderr?.on("data",(p)=>{f+=p.toString();let m=p.toString().trim();if(m&&!m.includes(Oo))r?.(m)}),u.on("close",(p)=>{if(a(),p!==0){d(Error(gh(f,p)));return}c(l.trim())}),u.on("error",(p)=>{a(),d(p)})})}var _o,il=`
|
|
858
854
|
import { createWalletProvider, createMidnightProvider, Transaction } from '@midnight-ntwrk/midnight-js-types';
|
|
859
855
|
import { toHex, fromHex } from '@midnight-ntwrk/midnight-js-utils';
|
|
860
856
|
import { NodeZkConfigProvider } from '@midnight-ntwrk/midnight-js-node-zk-config-provider';
|
|
861
857
|
import { httpClientProofProvider } from '@midnight-ntwrk/midnight-js-http-client-proof-provider';
|
|
862
858
|
import { indexerPublicDataProvider } from '@midnight-ntwrk/midnight-js-indexer-public-data-provider';
|
|
863
859
|
import { levelPrivateStateProvider } from '@midnight-ntwrk/midnight-js-level-private-state-provider';
|
|
864
|
-
`,
|
|
865
|
-
const resolvePrivateStateSecretKey = (${
|
|
866
|
-
`;
|
|
867
|
-
const coerceArg = (${
|
|
868
|
-
|
|
860
|
+
`,mh,ll,Oo="__MN_ERROR__",Mo,Sh;var en=T(()=>{Po();_o=fh();mh=`
|
|
861
|
+
const resolvePrivateStateSecretKey = (${tl.toString()});
|
|
862
|
+
`;ll=`
|
|
863
|
+
const coerceArg = (${rs.toString()});
|
|
864
|
+
`,Mo=`
|
|
865
|
+
const fail = (e) => {
|
|
866
|
+
process.stderr.write('\\n${Oo} ' + JSON.stringify(String(e?.message ?? e)) + '\\n');
|
|
867
|
+
process.exit(1);
|
|
868
|
+
};
|
|
869
|
+
process.on('uncaughtException', fail);
|
|
870
|
+
process.on('unhandledRejection', fail);
|
|
871
|
+
`;Sh=["@midnight-ntwrk","ws"]});import{indexerPublicDataProvider as vh}from"@midnight-ntwrk/midnight-js-indexer-public-data-provider";function ul(e){return vh({queryURL:e.indexer,subscriptionURL:e.indexerWS??e.indexer.replace("http","ws")})}var pl=()=>{};var wl={};he(wl,{default:()=>ml});import{resolve as is}from"node:path";function tn(){return{update(){},stop(){},fail(){},log(){}}}function kh(e){return fl.includes(e)}async function ml(e,t){let r=e.subcommand;if(!r||!kh(r))throw new U(`Usage: midnight contract <${fl.join("|")}>
|
|
869
872
|
|
|
870
873
|
inspect Show circuits, witnesses, and types for a compiled contract
|
|
871
874
|
deploy Deploy a contract to the network
|
|
872
875
|
call Call a circuit on a deployed contract
|
|
873
876
|
state Read the ledger state of a deployed contract
|
|
874
877
|
|
|
875
|
-
Run "midnight help contract" for more info.`);switch(r){case"inspect":return
|
|
876
|
-
`+
|
|
878
|
+
Run "midnight help contract" for more info.`);switch(r){case"inspect":return xh(e);case"deploy":return Ch(e);case"call":return Ah(e);case"state":return Th(e)}}function as(e){let t=x(e,"managed"),r=x(e,"path");return is(t??r??process.cwd())}async function xh(e){let t=R(e,"json"),r=as(e),n=x(e,"name"),{info:s}=lt(r,n);if(t){D(xd(s));return}if(process.stderr.write(`
|
|
879
|
+
`+B(`Contract: ${s.name}`)+`
|
|
877
880
|
|
|
878
|
-
`),process.stderr.write(
|
|
879
|
-
`),process.stderr.write(
|
|
880
|
-
`),process.stderr.write(
|
|
881
|
+
`),process.stderr.write(C("Compiler",s.compilerVersion)+`
|
|
882
|
+
`),process.stderr.write(C("Language",s.languageVersion)+`
|
|
883
|
+
`),process.stderr.write(C("Runtime",s.runtimeVersion)+`
|
|
881
884
|
`),process.stderr.write(`
|
|
882
|
-
`+
|
|
885
|
+
`+P(" Circuits")+`
|
|
883
886
|
`),s.circuits.length===0)process.stderr.write(g(" (none)")+`
|
|
884
|
-
`);else for(let o of s.circuits){let i=
|
|
887
|
+
`);else for(let o of s.circuits){let i=bd(o),a=vd(o),c=o.pure?G(a):Z(a);process.stderr.write(` ${i} ${g("—")} ${c}
|
|
885
888
|
`)}if(process.stderr.write(`
|
|
886
|
-
`+
|
|
889
|
+
`+P(" Witnesses")+`
|
|
887
890
|
`),s.witnesses.length===0)process.stderr.write(g(" (none)")+`
|
|
888
|
-
`);else for(let o of s.witnesses)process.stderr.write(` ${
|
|
891
|
+
`);else for(let o of s.witnesses)process.stderr.write(` ${kd(o)}
|
|
889
892
|
`);if(s.siblings.length>0){process.stderr.write(`
|
|
890
|
-
`+
|
|
891
|
-
`);for(let o of s.siblings)process.stderr.write(` ${
|
|
893
|
+
`+P(" Other contracts in this project")+`
|
|
894
|
+
`);for(let o of s.siblings)process.stderr.write(` ${G(o)}
|
|
892
895
|
`);process.stderr.write(`
|
|
893
896
|
`+g(" Inspect a sibling: mn contract inspect --name <name>")+`
|
|
894
897
|
`)}process.stderr.write(`
|
|
895
|
-
`)}async function
|
|
898
|
+
`)}async function Lo(e,t){await Promise.resolve().then(() => ke());let n=x(e,"network")??"undeployed",s={node:x(e,"node"),indexerWS:x(e,"indexer-ws"),proofServer:x(e,"proof-server")},{name:o,config:i}=le({args:{command:"contract",subcommand:t,positionals:[],flags:{network:n,...yn(s)}}});return $e(i,s,o),{network:n,networkConfig:i,endpoints:s}}async function gl({network:e,networkConfig:t},r,n){await Promise.resolve().then(() => Le());await Promise.resolve().then(() => bt());await Promise.resolve();let c=ae(re(n)),d=Buffer.from(c.seed,"hex"),u=c.addresses[e],l=r?tn():K("Checking wallet..."),f=Ce();try{let m=(await f.unshielded(u,t)).balances.get(br)??0n;if(m===0n)throw l.fail("No NIGHT balance"),Error(`Wallet has 0 NIGHT on ${e}.
|
|
896
899
|
|
|
897
900
|
Fund your wallet before deploying:
|
|
898
901
|
Address: ${u}
|
|
@@ -903,63 +906,63 @@ Run "midnight help contract" for more info.`);switch(r){case"inspect":return Kg(
|
|
|
903
906
|
Register for dust generation:
|
|
904
907
|
Run: midnight dust register --network ${e}
|
|
905
908
|
Then wait: midnight dust status --network ${e}
|
|
906
|
-
`);l.stop(`Wallet OK (${m} NIGHT, dust available)`)}catch(p){throw l.fail("Wallet check failed"),p}}async function
|
|
907
|
-
`+
|
|
909
|
+
`);l.stop(`Wallet OK (${m} NIGHT, dust available)`)}catch(p){throw l.fail("Wallet check failed"),p}}async function hl({network:e,endpoints:t},r,n){await Promise.resolve().then(() => $o());let o=r?tn():K("Starting mn serve..."),i=await es({network:e,endpoints:t,wallet:n,onMessage:(a)=>o.update(a)});return o.stop("mn serve ready (port "+i.port+")"),{port:i.port,stop:()=>i.stop()}}async function Ch(e){let t=R(e,"json"),r=is(x(e,"path")??process.cwd()),n=as(e),s=x(e,"name");await Promise.resolve().then(() => en());if(!t)process.stderr.write(`
|
|
910
|
+
`+B("Contract Deploy")+`
|
|
908
911
|
|
|
909
|
-
`);let{info:i}=
|
|
910
|
-
`),process.stderr.write(
|
|
911
|
-
`),f.length>0)process.stderr.write(
|
|
912
|
+
`);let{info:i}=lt(n,s),a=i.witnesses.map((w)=>w.name);if(a.length>0){await Promise.resolve().then(() => Po());if(!Qd(r))throw Error(el({projectRoot:r,witnessNames:a}))}let c=await Lo(e,"deploy"),{network:d,networkConfig:u}=c,l=x(e,"args"),f=[];if(l)try{let w=JSON.parse(l);f=Array.isArray(w)?w:Object.values(w)}catch(w){throw new U(`Invalid --args JSON: ${w.message}`)}let p=x(e,"secret-key");if(p!==void 0&&!/^[0-9a-fA-F]{64}$/.test(p))throw new U("--secret-key must be 32 bytes of hex (64 chars)");if(!t){if(process.stderr.write(C("Contract",i.name)+`
|
|
913
|
+
`),process.stderr.write(C("Network",d)+`
|
|
914
|
+
`),f.length>0)process.stderr.write(C("Constructor args",String(f.length))+`
|
|
912
915
|
`);process.stderr.write(`
|
|
913
|
-
`)}await
|
|
914
|
-
`),process.stderr.write(
|
|
916
|
+
`)}await gl(c,t,x(e,"wallet"));let m=await hl(c,t,x(e,"wallet")),h=t?tn():K("Deploying contract...");try{let w=await ss({dappDir:r,networkConfig:u,managedDir:i.managedDir,contractName:i.name,servePort:m.port,args:f,privateStateSecretKey:p,onMessage:(y)=>h.update(y)});if(h.stop(W("✓")+" Contract deployed"),t)D({subcommand:"deploy",contractName:i.name,address:w.contractAddress,network:d});else process.stderr.write(`
|
|
917
|
+
`),process.stderr.write(C("Address",w.contractAddress)+`
|
|
915
918
|
`),process.stderr.write(`
|
|
916
|
-
`+
|
|
917
|
-
`),
|
|
918
|
-
`)}catch(w){throw h.fail("Deploy failed"),w}finally{await m.stop()}}function
|
|
919
|
+
`+W(" ✓ Deploy successful")+`
|
|
920
|
+
`),Eh(w.contractAddress,i.circuits,d),process.stdout.write(w.contractAddress+`
|
|
921
|
+
`)}catch(w){throw h.fail("Deploy failed"),w}finally{await m.stop()}}function Eh(e,t,r){let n=r==="undeployed"?"":` --network ${r}`;process.stderr.write(`
|
|
919
922
|
`+g(" Next:")+`
|
|
920
|
-
`),process.stderr.write(g(" mn contract state --address ")+
|
|
921
|
-
`);let s=t.find((o)=>o.arguments.length===0);if(s)process.stderr.write(g(" mn contract call --address ")+
|
|
923
|
+
`),process.stderr.write(g(" mn contract state --address ")+G(e)+g(n)+`
|
|
924
|
+
`);let s=t.find((o)=>o.arguments.length===0);if(s)process.stderr.write(g(" mn contract call --address ")+G(e)+g(" --circuit ")+G(s.name)+g(n)+`
|
|
922
925
|
`);process.stderr.write(`
|
|
923
|
-
`)}async function
|
|
924
|
-
`+
|
|
926
|
+
`)}async function Ah(e){let t=R(e,"json"),r=is(x(e,"path")??process.cwd()),n=as(e),s=x(e,"name"),o=an(e,"address","contract address"),i=an(e,"circuit","circuit name"),a=x(e,"args");await Promise.resolve().then(() => en());if(!t)process.stderr.write(`
|
|
927
|
+
`+B("Contract Call")+`
|
|
925
928
|
|
|
926
|
-
`);let{info:d}=
|
|
927
|
-
`),process.stderr.write(
|
|
928
|
-
`),process.stderr.write(
|
|
929
|
+
`);let{info:d}=lt(n,s),u=[];if(a)try{let w=JSON.parse(a);u=Array.isArray(w)?w:Object.values(w)}catch(w){throw new U(`Invalid --args JSON: ${w.message}`)}ko(o),hd(d,i,u);let l=await Lo(e,"call"),{network:f,networkConfig:p}=l;if(!t)process.stderr.write(C("Contract",d.name)+`
|
|
930
|
+
`),process.stderr.write(C("Circuit",i)+`
|
|
931
|
+
`),process.stderr.write(C("Address",o.slice(0,20)+"...")+`
|
|
929
932
|
|
|
930
|
-
`);await
|
|
931
|
-
`+
|
|
933
|
+
`);await gl(l,t,x(e,"wallet"));let m=await hl(l,t,x(e,"wallet")),h=t?tn():K(`Calling ${i}...`);try{let w=await os({dappDir:r,networkConfig:p,managedDir:d.managedDir,contractName:d.name,contractAddress:o,circuit:i,args:u,servePort:m.port,onMessage:(y)=>h.update(y)});if(h.stop(W("✓")+` ${i} called`),t)D({subcommand:"call",contractName:d.name,circuit:i,address:o,network:f,status:w.status});else process.stderr.write(`
|
|
934
|
+
`+W(" ✓ Circuit call successful")+`
|
|
932
935
|
|
|
933
|
-
`)}catch(w){throw h.fail("Call failed"),w}finally{await m.stop()}}async function
|
|
934
|
-
`+
|
|
936
|
+
`)}catch(w){throw h.fail("Call failed"),w}finally{await m.stop()}}async function Th(e){let t=R(e,"json"),r=is(x(e,"path")??process.cwd()),n=as(e),s=x(e,"name"),o=an(e,"address","contract address");ko(o);await Promise.resolve().then(() => en());let{network:a,networkConfig:c}=await Lo(e,"state");if(!t)process.stderr.write(`
|
|
937
|
+
`+B("Contract State")+`
|
|
935
938
|
|
|
936
|
-
`),process.stderr.write(
|
|
937
|
-
`),process.stderr.write(
|
|
939
|
+
`),process.stderr.write(C("Address",o.slice(0,20)+"...")+`
|
|
940
|
+
`),process.stderr.write(C("Network",a)+`
|
|
938
941
|
|
|
939
|
-
`);let d=t?
|
|
940
|
-
`);for(let[m,h]of Object.entries(l.fields))process.stderr.write(` ${m}: ${
|
|
942
|
+
`);let d=t?tn():K("Querying contract state...");try{let{info:u}=lt(n,s),l=await mr({dappDir:r,networkConfig:c,managedDir:u.managedDir,contractName:u.name,contractAddress:o,onMessage:(f)=>d.update(f)});if(d.stop(W("✓")+" State retrieved"),t)D({subcommand:"state",address:o,network:a,...l});else{let f=Object.keys(l.fields).length>0,p=Object.keys(l.maps).length>0;if(f||p){process.stderr.write(P(" Ledger State")+`
|
|
943
|
+
`);for(let[m,h]of Object.entries(l.fields))process.stderr.write(` ${m}: ${G(h)}
|
|
941
944
|
`);for(let[m,h]of Object.entries(l.maps))process.stderr.write(` ${m}: ${g(`Map (${h.size} entries)`)}
|
|
942
945
|
`)}else process.stderr.write(g(" (no ledger fields found)")+`
|
|
943
946
|
`);process.stderr.write(`
|
|
944
|
-
`)}}catch(u){d.stop(
|
|
947
|
+
`)}}catch(u){d.stop(Z("⚠")+" Parsed state unavailable, showing raw");await Promise.resolve().then(() => pl());let p=await ul(c).queryContractState(o);if(!p)throw Error(`No contract found at address ${o} on ${a}`);let m=p.data??p;if(t)D({subcommand:"state",address:o,network:a,raw:m});else process.stderr.write(P(" Raw State")+`
|
|
945
948
|
`),process.stderr.write(g(" (run from dApp root for parsed ledger fields)")+`
|
|
946
949
|
`),process.stderr.write(` ${JSON.stringify(m).slice(0,200)}
|
|
947
950
|
|
|
948
|
-
`)}}var
|
|
949
|
-
Run this command from the root of a dApp project, or create a ${
|
|
950
|
-
Check the build log: ${i}`);if(await
|
|
951
|
-
Check the build log: ${i}`)}function
|
|
951
|
+
`)}}var fl;var yl=T(()=>{me();Oe();ue();dt();wd();Zn();fl=["inspect","deploy","call","state"]});import{existsSync as gr,readFileSync as rn,readdirSync as Nh}from"node:fs";import{join as Ut,resolve as Rh}from"node:path";function cs(e){let t=Rh(e??process.cwd()),r=Ut(t,Uo);if(!gr(r))throw Error(`No ${Uo} found in ${t}
|
|
952
|
+
Run this command from the root of a dApp project, or create a ${Uo} file.`);let n;try{n=JSON.parse(rn(r,"utf-8"))}catch(o){throw Error(`Failed to parse ${r}: ${o.message}`)}return{config:$h(n,r),configPath:r,dappDir:t}}function Wo(e){let t=Ut(e,Dh);if(!gr(t))return[];let r=Nh(t,{withFileTypes:!0}),n=[];for(let s of r){if(!s.isDirectory())continue;let o=Ut(t,s.name),i=Ut(o,"suite.json");if(!gr(i))continue;let a;try{a=JSON.parse(rn(i,"utf-8"))}catch(c){throw Error(`Failed to parse ${i}: ${c.message}`)}n.push({suite:Ph(a,i),suiteDir:o})}return n}function xl(e){let t=Ut(e,"assertions.json");if(!gr(t))return null;let r;try{r=JSON.parse(rn(t,"utf-8"))}catch(n){throw Error(`Failed to parse ${t}: ${n.message}`)}return _h(r,t)}function Cl(e){let t=Ut(e,"actions.json");if(!gr(t))return null;let r;try{r=JSON.parse(rn(t,"utf-8"))}catch(n){throw Error(`Failed to parse ${t}: ${n.message}`)}return Oh(r,t)}function El(e){let t=Ut(e,"prompt.md");if(!gr(t))return null;return rn(t,"utf-8")}function $h(e,t){if(typeof e!=="object"||e===null||Array.isArray(e))throw Error(`${t}: must be a JSON object`);let r=e;if(typeof r.name!=="string"||r.name.length===0)throw Error(`${t}: "name" is required and must be a non-empty string`);if(r.network!==void 0&&!Sl.includes(r.network))throw Error(`${t}: "network" must be one of: ${Sl.join(", ")}`);if(r.port!==void 0&&(typeof r.port!=="number"||r.port<1||r.port>65535))throw Error(`${t}: "port" must be a number between 1 and 65535`);if(r.buildCmd!==void 0&&typeof r.buildCmd!=="string")throw Error(`${t}: "buildCmd" must be a string`);if(r.buildDir!==void 0&&typeof r.buildDir!=="string")throw Error(`${t}: "buildDir" must be a string`);if(r.url!==void 0&&typeof r.url!=="string")throw Error(`${t}: "url" must be a string`);if(!Array.isArray(r.prep))throw Error(`${t}: "prep" is required and must be an array of prep step IDs`);for(let n of r.prep)if(typeof n!=="string"||!Ih.test(n))throw Error(`${t}: invalid prep step "${n}". Valid steps: cache-clear, localnet-up, balance:<amount>, dust-register, dust-wait, mn-serve, build-and-serve`);return{name:r.name,network:r.network??"undeployed",port:r.port,buildCmd:r.buildCmd,buildDir:r.buildDir,url:r.url,contractEntry:r.contractEntry,prep:r.prep}}function Ph(e,t){if(typeof e!=="object"||e===null||Array.isArray(e))throw Error(`${t}: must be a JSON object`);let r=e;if(typeof r.name!=="string"||r.name.length===0)throw Error(`${t}: "name" is required and must be a non-empty string`);if(typeof r.description!=="string")throw Error(`${t}: "description" is required and must be a string`);if(!bl.includes(r.strategy))throw Error(`${t}: "strategy" must be one of: ${bl.join(", ")}`);if(r.timeout!==void 0&&(typeof r.timeout!=="number"||r.timeout<=0))throw Error(`${t}: "timeout" must be a positive number (seconds)`);if(r.browserMode!==void 0&&!vl.includes(r.browserMode))throw Error(`${t}: "browserMode" must be one of: ${vl.join(", ")}`);return{name:r.name,description:r.description,strategy:r.strategy,browserMode:r.browserMode,model:r.model,effort:r.effort,timeout:r.timeout,depends:Array.isArray(r.depends)?r.depends:void 0}}function _h(e,t){if(typeof e!=="object"||e===null||Array.isArray(e))throw Error(`${t}: must be a JSON object`);let r=e;if(!Array.isArray(r.post))throw Error(`${t}: "post" is required and must be an array of assertion checks`);for(let n of r.post){if(typeof n!=="object"||n===null)throw Error(`${t}: each assertion check must be an object`);let s=n;if(typeof s.id!=="string")throw Error(`${t}: each assertion check must have a string "id"`);if(typeof s.type!=="string")throw Error(`${t}: assertion "${s.id}" must have a string "type"`);if(typeof s.expect!=="string"||s.expect!=="pass"&&s.expect!=="fail")throw Error(`${t}: assertion "${s.id}" must have "expect" set to "pass" or "fail"`)}return{pre:Array.isArray(r.pre)?r.pre:void 0,post:r.post}}function Oh(e,t){if(typeof e!=="object"||e===null||Array.isArray(e))throw Error(`${t}: must be a JSON object`);let r=e;if(!Array.isArray(r.actions))throw Error(`${t}: "actions" is required and must be an array`);for(let n of r.actions){if(typeof n!=="object"||n===null)throw Error(`${t}: each action must be an object`);let s=n;if(typeof s.id!=="string")throw Error(`${t}: each action must have a string "id"`);if(typeof s.type!=="string"||!kl.includes(s.type))throw Error(`${t}: action "${s.id}" has invalid type "${s.type}". Valid: ${kl.join(", ")}`);if(s.type==="contract-call"&&typeof s.circuit!=="string")throw Error(`${t}: action "${s.id}" (contract-call) requires a "circuit" field`)}return{actions:r.actions}}var Uo="dapp.test.json",Dh="tests/suites",Sl,bl,vl,Ih,kl;var Al=T(()=>{Sl=["undeployed","preprod","preview"],bl=["browser","cli","hybrid"],vl=["dom","script","vision","auto"],Ih=/^(cache-clear|localnet-up|balance:\d+|dust|dust-register|dust-wait|mn-serve|build-and-serve)$/;kl=["contract-deploy","contract-call","contract-state","wallet-cmd"]});function Tl(){let e=[];return{cleanups:e,addCleanup(t){e.push(t)}}}import{spawn as Mh}from"node:child_process";import{createWriteStream as Fh}from"node:fs";import{join as Lh}from"node:path";import Uh from"node:http";import Wh from"node:net";async function Rl(e){let{dappDir:t,buildCmd:r,buildDir:n=".",port:s,url:o,logFile:i,timeoutMs:a=240000,onMessage:c=()=>{}}=e;if(await Bh(s)){if(await Nl(o))return c(`Reusing existing dev server on port ${s} (URL responds 200)`),{port:s,child:{kill:()=>!0},stop(){}};c(`Port ${s} in use by an unresponsive process — killing it`),await jh(s),await new Promise((h)=>setTimeout(h,2000))}let d=Lh(t,n),u=Fh(i,{flags:"a"}),l=Mh("bash",["-lc",r],{cwd:d,stdio:["ignore","pipe","pipe"],detached:!1});l.stdout?.pipe(u),l.stderr?.pipe(u);let f=!1,p=null;l.on("exit",(h)=>{f=!0,p=h}),c(`Building (${r})...`);let m=Date.now()+a;while(Date.now()<m){if(f)throw Error(`Build process exited with code ${p} before the UI was ready.
|
|
953
|
+
Check the build log: ${i}`);if(await Nl(o))return c("UI ready"),{port:s,child:l,stop(){if(!f)l.kill("SIGTERM"),setTimeout(()=>{if(!f)l.kill("SIGKILL")},5000).unref();u.end()}};await new Promise((h)=>setTimeout(h,2000))}throw l.kill("SIGTERM"),u.end(),Error(`UI did not start within ${Math.round(a/1000)}s at ${o}
|
|
954
|
+
Check the build log: ${i}`)}function Bh(e){return new Promise((t)=>{let r=new Wh.Socket;r.setTimeout(1000),r.on("connect",()=>{r.destroy(),t(!0)}),r.on("timeout",()=>{r.destroy(),t(!1)}),r.on("error",()=>{t(!1)}),r.connect(e,"127.0.0.1")})}async function jh(e){let{execSync:t}=await import("node:child_process");try{let r=t(`lsof -ti:${e}`,{encoding:"utf-8"}).trim();if(r)t(`kill ${r}`,{stdio:"pipe"})}catch{}}function Nl(e){return new Promise((t)=>{let r=Uh.get(e,{timeout:3000},(n)=>{t(n.statusCode===200),n.resume()});r.on("error",()=>t(!1)),r.on("timeout",()=>{r.destroy(),t(!1)})})}var Dl=()=>{};import*as $l from"@midnightntwrk/ledger-v9";import{join as Hh}from"node:path";async function Pl(e,t,r,n){let s=[];for(let o of e.prep){let i=Date.now();n.onStepStart(o);try{await Gh(o,e,t,r,n);let a=Date.now()-i;s.push({step:o,status:"pass",duration:a}),n.onStepComplete(o,"pass",a)}catch(a){let c=Date.now()-i,d=a.message;throw s.push({step:o,status:"fail",duration:c,error:d}),n.onStepComplete(o,"fail",c,d),Error(`Prep step "${o}" failed: ${d}`)}}return s}async function Gh(e,t,r,n,s){if(e==="cache-clear")return Kh(t);if(e==="localnet-up")return Vh(t,s);if(e.startsWith("balance:")){let o=parseInt(e.split(":")[1],10);return Jh(o,t,s)}if(e==="dust"||e==="dust-register"||e==="dust-wait")return qh(t,s);if(e==="mn-serve")return zh(t,n,s);if(e==="build-and-serve")return Yh(t,r,n,s);throw Error(`Unknown prep step: ${e}`)}async function Kh(e){let t=e.network??"undeployed";Ve(void 0,t)}async function Vh(e,t){let r=e.network??"undeployed",{config:n}=le({args:{command:"test",subcommand:void 0,positionals:[],flags:{network:r}}});await va(r,n),t.onMessage(`Using the ledger-9 stack at ${n.node} (indexer ${n.indexer})`)}async function Jh(e,t,r){let n=t.network??"undeployed",{config:s}=le({args:{command:"test",subcommand:void 0,positionals:[],flags:{network:n}}});await Be(n,s);let o=ae(re()),i=Buffer.from(o.seed,"hex"),a=o.addresses[n];r.onMessage("Checking balance...");let c=Re((m,h)=>{r.onMessage(`SDK: ${h}`)}),d=De(),u=yt(a,n),l=await Ze(i,s,u);try{let m=await wt(l,{syncMode:"lite",onProgress:(y,S)=>{if(S>0){let v=Math.min(Math.round(y/S*100),100);r.onMessage(`Syncing wallet... ${v}%`)}},onSyncDetail:(y)=>{r.onMessage(`Syncing wallet... (${y})`)}}),h=$l.unshieldedToken().raw,w=m.unshielded.balances[h]??0n;if(w>0n){r.onMessage(`Balance OK: ${w}`);try{await it(a,n,l.facade)}catch{}return}}finally{d(),c();try{await Ue(l)}catch{}}if(n!=="undeployed")throw Error(`Wallet has 0 NIGHT on ${n}. Fund your wallet before running tests:
|
|
952
955
|
mn airdrop ${e} (if faucet available)
|
|
953
|
-
Or transfer NIGHT from another wallet.`);r.onMessage(`Balance is 0. Airdropping ${e} NIGHT from genesis...`);let f=Buffer.from(rt,"hex"),p=
|
|
956
|
+
Or transfer NIGHT from another wallet.`);r.onMessage(`Balance is 0. Airdropping ${e} NIGHT from genesis...`);let f=Buffer.from(rt,"hex"),p=ve(f,n);await or({seedBuffer:f,networkConfig:s,recipientAddress:a,amountNight:e,onSync(m,h){},onDust(m){r.onMessage(`Dust: ${m}`)},onProving(){r.onMessage("Generating ZK proof...")},onSubmitting(){r.onMessage("Submitting airdrop transaction...")},onSyncWarning(m,h){r.onMessage(`Syncing genesis... (${h})`)}}),r.onMessage(`Airdropped ${e} NIGHT`)}async function qh(e,t){let r=e.network??"undeployed",{config:n}=le({args:{command:"test",subcommand:void 0,positionals:[],flags:{network:r}}});await Be(r,n);let s=ae(re()),o=Buffer.from(s.seed,"hex"),i=s.addresses[r],a=Re(),c=De(),d=yt(i,r),u=await Ze(o,n,d);try{if(t.onMessage("Syncing wallet..."),await wt(u,{syncMode:"lite"}),t.onMessage("Ensuring dust..."),(await et(u,(m)=>t.onMessage(`Dust: ${m}`))).alreadyAvailable){t.onMessage("Dust already available");try{await it(i,r,u.facade)}catch{}return}t.onMessage("Dust registered. Waiting for coins to become available...");let f=await Nn(u,Il);if(!$t(f)){if(r!=="undeployed")throw Error(`Dust not available on ${r}. Register dust and wait for it to generate:
|
|
954
957
|
mn dust register
|
|
955
|
-
mn dust status (check until dustAvailable: true)`);throw Error(`Dust not available after ${
|
|
956
|
-
`).filter(Boolean);e(`Found ${r.length} orphan chrome-devtools-mcp Chrome process(es), killing`);for(let n of r)try{
|
|
958
|
+
mn dust status (check until dustAvailable: true)`);throw Error(`Dust not available after ${Il/1000}s. The chain may be slow — try again.`)}t.onMessage("Dust is available");try{await it(i,r,u.facade)}catch{}}finally{c(),a();try{await Ue(u)}catch{}}}async function zh(e,t,r){r.onMessage("Starting mn serve...");let n=await es({port:void 0,network:e.network,onMessage:(s)=>r.onMessage(`[serve] ${s}`)});t.serveHandle=n,t.addCleanup(async()=>n.stop()),r.onMessage(`mn serve ready on port ${n.port}`)}async function Yh(e,t,r,n){if(!e.buildCmd){n.onMessage("No buildCmd in config, skipping build");return}let s=e.port??4173,o=e.url??`http://localhost:${s}/`,i=Hh(t,"tests","results",`build_${Date.now()}.log`),a=await Rl({dappDir:t,buildCmd:e.buildCmd,buildDir:e.buildDir,port:s,url:o,logFile:i,onMessage:(c)=>n.onMessage(`[build] ${c}`)});r.buildHandle=a,r.addCleanup(async()=>a.stop())}var Il=90000;var _l=T(()=>{Pt();Le();ke();Ot();Ke();Pt();Ft();He();$o();Dl()});import{execSync as Ol,spawn as Xh}from"node:child_process";import{createWriteStream as Zh,existsSync as Qh,mkdirSync as ew,readFileSync as tw}from"node:fs";import{dirname as rw,join as nw}from"node:path";import{homedir as sw}from"node:os";function ow(){let e=nw(sw(),".claude.json");if(!Qh(e))return!1;try{let t=JSON.parse(tw(e,"utf-8"));return Boolean(t.mcpServers?.["chrome-devtools"])}catch{return!1}}function aw(e){let t;try{t=Ol(`ps -ax -o pid,command | grep "${iw}" | grep -v grep | awk '{print $1}'`,{encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim()}catch{return}if(!t)return;let r=t.split(`
|
|
959
|
+
`).filter(Boolean);e(`Found ${r.length} orphan chrome-devtools-mcp Chrome process(es), killing`);for(let n of r)try{Ol(`kill ${n}`,{stdio:"pipe"})}catch{}}function Bo(e){let t=e.browserMode??"vision";if(t==="auto")return"vision";return t}async function Ml(e){let{suite:t,prompt:r,dappDir:n,logFile:s,onMessage:o=()=>{}}=e,i=(t.timeout??600)*1000,a=Bo(t);if(a==="dom"||a==="script"){if(!ow())throw Error(`Browser mode "${a}" requires the chrome-devtools MCP server, which is not registered in ~/.claude.json.
|
|
957
960
|
|
|
958
961
|
Install it:
|
|
959
962
|
claude mcp add chrome-devtools --scope user npx chrome-devtools-mcp@latest
|
|
960
963
|
|
|
961
|
-
Then re-run the suite. Alternatively, switch the suite to "browserMode": "vision" `+"(no MCP needed, but slower — uses screenshots).");
|
|
962
|
-
`),s}function
|
|
964
|
+
Then re-run the suite. Alternatively, switch the suite to "browserMode": "vision" `+"(no MCP needed, but slower — uses screenshots).");aw(o)}ew(rw(s),{recursive:!0});let c=Zh(s),d=[];if(a==="vision")d.push("--chrome");if(d.push("--dangerously-skip-permissions"),t.model)d.push("--model",t.model);if(t.effort)d.push("--effort",t.effort);let u=r;if(a==="dom")u=cw+r;else if(a==="script")u=dw+r;return d.push("-p",u),o(`Launching Claude (mode: ${a}, model: ${t.model??"default"}, timeout: ${t.timeout??600}s)`),new Promise((l)=>{let f=Xh("claude",d,{cwd:n,stdio:["inherit","pipe","inherit"]}),p=!1;f.stdout?.on("data",(h)=>{process.stdout.write(h),c.write(h)});let m=setTimeout(()=>{p=!0,o(`Timeout: test exceeded ${t.timeout??600}s`),f.kill("SIGTERM"),setTimeout(()=>{if(!f.killed)f.kill("SIGKILL")},1e4).unref()},i);f.on("close",(h)=>{clearTimeout(m),c.end(),l({exitCode:h??1,logFile:s,timedOut:p})}),f.on("error",(h)=>{clearTimeout(m),c.end(),o(`Claude process error: ${h.message}`),l({exitCode:1,logFile:s,timedOut:!1})})})}var iw="chrome-devtools-mcp/chrome-profile",cw="## Browser Automation Mode: DOM (Accessibility Tree)\n\nYou have chrome-devtools MCP tools available. You MUST follow these rules:\n\n1. Use `navigate_page` to open URLs in Chrome.\n2. Use `take_snapshot` to read the page — it returns a structured accessibility tree with element UIDs. This is your primary tool for understanding page state.\n3. Use `click`, `fill`, and `type_text` with element UIDs from the snapshot to interact with the page.\n4. Use `press_key` for keyboard input (Enter, Escape, Tab, etc.).\n5. Only use `take_screenshot` for final visual verification or when the accessibility tree is insufficient.\n6. Do NOT rely on screenshots for navigation — the accessibility tree is faster and more reliable.\n7. After each interaction, take a new `take_snapshot` to verify the result.\n\n---\n\n",dw="## Browser Automation Mode: Script (Canvas App)\n\nYou have chrome-devtools MCP tools available. This is a canvas-based app — the accessibility tree will be empty. You MUST follow these rules:\n\n1. Use `navigate_page` to open the URL in Chrome.\n2. Use `evaluate_script` to dispatch keyboard input via `window.dispatchEvent(new KeyboardEvent(...))`.\n3. Use `evaluate_script` to read DOM state (e.g., toast notifications via `document.querySelector`).\n4. Use `list_console_messages` to monitor app output (contract addresses, errors, status changes).\n5. Use `take_screenshot` at key checkpoints to verify visual state — but minimize usage (a few, not every step).\n6. Do NOT use `take_snapshot` — the accessibility tree is empty for canvas content.\n7. Between actions, use `take_screenshot` or `list_console_messages` to verify transitions — not rapid polling.\n\n---\n\n";var Fl=()=>{};import{existsSync as lw,readFileSync as uw}from"node:fs";import pw from"node:net";async function Ll(e,t){let r=[];for(let n of e)try{let s=await fw(n,t),o=n.expect==="pass"?s:!s;r.push({id:n.id,status:o?"pass":"fail",message:o?void 0:`Expected ${n.expect}, got ${s?"pass":"fail"}`})}catch(s){r.push({id:n.id,status:"fail",message:s.message})}return r}async function fw(e,t){switch(e.type){case"balance-changed":return mw(e,t);case"process-exit-code":return gw(e,t);case"port-listening":return hw(e);case"agent-report-no-failure":return yw(e,t);default:throw Error(`Unsupported assertion type: "${e.type}" (available in v2)`)}}function mw(e,t){if(t.preBalance===void 0||t.postBalance===void 0)throw Error("Balance data not available — balance:N prep step may not have run");let r=BigInt(t.preBalance),n=BigInt(t.postBalance),s=e.params.direction;if(s==="decreased")return n<r;if(s==="increased")return n>r;if(s==="unchanged")return n===r;return n!==r}function gw(e,t){if(t.processExitCode===void 0)throw Error("Process exit code not available");let r=e.params.code;return t.processExitCode===r}function hw(e){let t=e.params.port;return new Promise((r)=>{let n=new pw.Socket;n.setTimeout(2000),n.on("connect",()=>{n.destroy(),r(!0)}),n.on("timeout",()=>{n.destroy(),r(!1)}),n.on("error",()=>{r(!1)}),n.connect(t,"127.0.0.1")})}function yw(e,t){let r=e.params??{},n=r.logPath??t.agentLogPath;if(!n||!lw(n))return!0;let s;try{s=uw(n,"utf-8")}catch{return!0}let o=bw(s),i=r.markers??ww;for(let a of i)if(Sw(o,a))return!1;return!0}function Sw(e,t){if(/\s/.test(t)||/[^ -~]/.test(t))return e.toLowerCase().includes(t.toLowerCase());let r=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return new RegExp(`\\b${r}\\b`,"i").test(e)}function bw(e){return e.replace(/```[\s\S]*?```/g,"").replace(/`[^`]*`/g,"")}var ww;var Ul=T(()=>{ww=["FAILED","❌","did not pass","test failed","overall: fail","result: fail"]});import{existsSync as vw,mkdirSync as kw,writeFileSync as xw,readFileSync as Cw,readdirSync as Ew}from"node:fs";import{join as ds}from"node:path";function Bl(e,t){let r=ds(t,Wl);kw(r,{recursive:!0});let n=`${e.suite}_${e.timestamp.replace(/[:.]/g,"-")}.json`,s=ds(r,n);return xw(s,JSON.stringify(e,null,2)+`
|
|
965
|
+
`),s}function jl(e,t){let r=jo(e,t);return r.length>0?r[0]:null}function jo(e,t){let r=ds(e,Wl);if(!vw(r))return[];let n=Ew(r).filter((o)=>o.endsWith(".json")).filter((o)=>!t||o.startsWith(t+"_")),s=[];for(let o of n)try{let i=Cw(ds(r,o),"utf-8");s.push(JSON.parse(i))}catch{}return s.sort((o,i)=>i.timestamp.localeCompare(o.timestamp)),s}var Wl="tests/results";var Hl=()=>{};import{execSync as Aw}from"node:child_process";async function Ho(e,t){if(e.buildHandle)try{e.buildHandle.stop(),t?.("Stopped build process")}catch{t?.("Failed to stop build process (may have already exited)")}if(e.serveHandle)try{await e.serveHandle.stop(),t?.("Stopped mn serve")}catch{t?.("Failed to stop mn serve")}for(let r of e.cleanups.reverse())try{await r()}catch{}if(e.buildHandle?.port)Tw(e.buildHandle.port,t)}function Tw(e,t){try{Aw(`osascript -e 'tell application "Google Chrome"
|
|
963
966
|
repeat with theWindow in every window
|
|
964
967
|
repeat with theTab in every tab of theWindow
|
|
965
968
|
if URL of theTab contains "localhost:${e}" then
|
|
@@ -967,7 +970,7 @@ Then re-run the suite. Alternatively, switch the suite to "browserMode": "vision
|
|
|
967
970
|
end if
|
|
968
971
|
end repeat
|
|
969
972
|
end repeat
|
|
970
|
-
end tell'`,{timeout:5000,stdio:"pipe"}),t?.(`Closed Chrome tabs for localhost:${e}`)}catch{}}var
|
|
973
|
+
end tell'`,{timeout:5000,stdio:"pipe"}),t?.(`Closed Chrome tabs for localhost:${e}`)}catch{}}var Gl=()=>{};function Kl(e){switch(e["type-name"]){case"Uint":return 0;case"Bytes":{let t=e.length??32;return Array.from({length:t},()=>0)}case"Boolean":return!1;case"String":return"test";case"Opaque":return e.tsType==="string"?"test":null;case"Vector":return[];case"Map":return{};case"Set":return[];case"Option":return null;case"Tuple":return(e.types??[]).map(Kl);default:return null}}function Go(e){let t={};for(let r of e.arguments)t[r.name]=Kl(r.type);return t}function Ko(e,t){if((t.strategy??"cli")==="browser"){if(!t.browser)throw Error("Browser strategy requires browser options (port, buildCmd, buildDir?, url?)");return _w(t,t.browser)}return Pw(e,t)}function Pw(e,t){let r=t.suiteName??Nw,n=t.network??Vl,s=t.servePort??Jl;return{dappConfig:{name:t.contractName,network:n,prep:ql},suite:{name:r,description:`Auto-generated CLI test suite for ${t.contractName}. Edit args and add ledger-field assertions to taste.`,strategy:"cli",timeout:t.timeoutSeconds??Dw},actions:{actions:Mw(e)},assertions:{post:[zl(s)]},prompt:null,suiteName:r}}function _w(e,t){let r=e.suiteName??Rw,n=e.network??Vl,s=e.servePort??Jl,o=t.url??`http://localhost:${t.port}/`,i={name:e.contractName,network:n,port:t.port,buildCmd:t.buildCmd,url:o,prep:$w};if(t.buildDir)i.buildDir=t.buildDir;return{dappConfig:i,suite:{name:r,description:`Auto-generated browser test suite for ${e.contractName}. Edit prompt.md to describe the dApp-specific user flow.`,strategy:"browser",timeout:e.timeoutSeconds??Iw,...t.browserMode?{browserMode:t.browserMode}:{}},actions:null,assertions:{post:[{id:"claude-exit-ok",type:"process-exit-code",params:{code:0},expect:"pass"},zl(s),{id:"agent-no-failure",type:"agent-report-no-failure",params:{},expect:"pass"}]},prompt:Ow(e.contractName,o),suiteName:r}}function zl(e){return{id:"serve-port-listening",type:"port-listening",params:{port:e},expect:"pass"}}function Ow(e,t){return`You are running an automated E2E test of ${e}.
|
|
971
974
|
|
|
972
975
|
The UI is at ${t} — open it in Chrome.
|
|
973
976
|
mn serve is running with --approve-all so contract calls will auto-approve.
|
|
@@ -997,44 +1000,44 @@ Follow these steps:
|
|
|
997
1000
|
|
|
998
1001
|
If any step fails, report exactly what you see on screen and stop.
|
|
999
1002
|
Take screenshots at each major step to document the test.
|
|
1000
|
-
`}function
|
|
1003
|
+
`}function Mw(e){let t=[{id:"deploy",type:"contract-deploy"},{id:"check-initial",type:"contract-state"}],r=e.filter((n)=>!n.pure);for(let n of r){let s={id:`call-${n.name}`,type:"contract-call",circuit:n.name};if(n.arguments.length>0)s.args=Go(n);t.push(s)}return t.push({id:"check-final",type:"contract-state"}),t}var Vl="undeployed",Nw="cli-default",Rw="ui-default",Dw=300,Iw=600,Jl=9932,ql,$w;var Vo=T(()=>{ql=["cache-clear","localnet-up","balance:1000","dust","mn-serve"],$w=[...ql,"build-and-serve"]});import{existsSync as Xl,mkdirSync as Fw,readFileSync as Lw,writeFileSync as Yl}from"node:fs";import{join as hr}from"node:path";function Zl(e,t){let{dappDir:r,force:n=!1}=t,s=hr(r,"tests","suites",e.suiteName),o=hr(r,"dapp.test.json"),i=[{path:hr(s,"suite.json"),kind:"json",body:e.suite},{path:hr(s,"assertions.json"),kind:"json",body:e.assertions}];if(e.actions)i.push({path:hr(s,"actions.json"),kind:"json",body:e.actions});if(e.prompt)i.push({path:hr(s,"prompt.md"),kind:"text",body:e.prompt});if(!n){let u=i.filter((l)=>Xl(l.path)).map((l)=>l.path);if(u.length>0)throw Error(`Suite "${e.suiteName}" already exists at ${s}.
|
|
1001
1004
|
Pick a different suite name (--suite <name>) or pass --force to overwrite.
|
|
1002
1005
|
Existing files:
|
|
1003
1006
|
`+u.map((l)=>` - ${l}`).join(`
|
|
1004
|
-
`))}let a=
|
|
1007
|
+
`))}let a=Uw(o,e,n);Fw(s,{recursive:!0});let c=[],d=[];if(a.action==="write")Yl(o,JSON.stringify(e.dappConfig,null,2)+`
|
|
1005
1008
|
`),c.push(o);else d.push(o);for(let u of i){let l=u.kind==="json"?JSON.stringify(u.body,null,2)+`
|
|
1006
|
-
`:u.body;
|
|
1007
|
-
Fix or remove it (or pass --force to overwrite).`)}if(n.name!==t.dappConfig.name)throw Error(`${e} exists with name "${String(n.name)}" but this scaffold targets "${t.dappConfig.name}". Use --force to overwrite, or run from the right project directory.`);return{action:"preserve"}}var
|
|
1008
|
-
`+
|
|
1009
|
-
`);for(;;){let e=(await
|
|
1010
|
-
`))}}async function
|
|
1009
|
+
`:u.body;Yl(u.path,l),c.push(u.path)}return{written:c,preserved:d}}function Uw(e,t,r){if(r||!Xl(e))return{action:"write"};let n;try{n=JSON.parse(Lw(e,"utf-8"))}catch(s){let o=s instanceof Error?s.message:String(s);throw Error(`${e} exists but is not valid JSON: ${o}
|
|
1010
|
+
Fix or remove it (or pass --force to overwrite).`)}if(n.name!==t.dappConfig.name)throw Error(`${e} exists with name "${String(n.name)}" but this scaffold targets "${t.dappConfig.name}". Use --force to overwrite, or run from the right project directory.`);return{action:"preserve"}}var Ql=()=>{};import{existsSync as tu,readdirSync as Ww,readFileSync as Bw,statSync as jw}from"node:fs";import{basename as Hw,extname as Gw,join as ru,relative as Kw}from"node:path";function nu(e){let t=new Map;for(let r of Vw){let n=ru(e,r);if(!tu(n))continue;Jo(n,e,t)}return[...t.values()].sort((r,n)=>r.name.localeCompare(n.name))}function su(e,t=e){if(!tu(e))return[];let r=new Map;return Jo(e,t,r),[...r.values()].sort((n,s)=>n.name.localeCompare(s.name))}function Jo(e,t,r){let n;try{n=Ww(e)}catch{return}for(let s of n){let o=ru(e,s),i;try{i=jw(o)}catch{continue}if(i.isDirectory()){if(Jw.has(s.toLowerCase()))continue;Jo(o,t,r);continue}if(Gw(s)!==eu)continue;if(s.endsWith(".test.tsx")||s.endsWith(".spec.tsx"))continue;let a=Hw(s,eu);if(!qw(a,o))continue;let c=Yw(a);if(r.has(c))continue;r.set(c,{name:c,component:a,path:o,relativePath:Kw(t,o)})}}function qw(e,t){if(!/^[A-Z][A-Za-z0-9]*$/.test(e))return!1;let r;try{r=Bw(t,"utf-8")}catch{return!1}return zw.test(r)}function Yw(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1-$2").toLowerCase()}var Vw,eu=".tsx",Jw,zw;var qo=T(()=>{Vw=["src/components","src/pages","src/screens","src/views"];Jw=new Set(["layout","layouts","shared","common","ui","icons","styles"]);zw=/\bexport\s+(default\b|const\s+[A-Z]|function\s+[A-Z])/});import{existsSync as Xw,statSync as Zw}from"node:fs";import*as ou from"node:readline";function iu(){return process.stdin.isTTY===!0}function Je(e,t){let r=ou.createInterface({input:process.stdin,output:process.stderr}),n=t!==void 0?g(` [${t}]`):"";return new Promise((s)=>{r.question(` ${e}${n}: `,(o)=>{r.close();let i=o.trim();s(i===""&&t!==void 0?t:i)})})}async function au(){process.stderr.write(`
|
|
1011
|
+
`+G("Test scaffold setup")+`
|
|
1012
|
+
`);for(;;){let e=(await Je("Strategy? cli or ui","cli")).toLowerCase();if(e==="cli")return"cli";if(e==="ui"||e==="browser")return"browser";process.stderr.write(g(` Unknown strategy "${e}". Pick "cli" or "ui".
|
|
1013
|
+
`))}}async function cu(e={}){process.stderr.write(`
|
|
1011
1014
|
`+g("Browser test scaffold needs your dApp UI details:")+`
|
|
1012
|
-
`);let t=e.port!==void 0?String(e.port):await
|
|
1013
|
-
`+
|
|
1015
|
+
`);let t=e.port!==void 0?String(e.port):await Je("Dev server port","4173"),r=parseInt(t,10);if(!Number.isFinite(r)||r<=0||r>65535)throw Error(`Invalid port "${t}" — must be a number between 1 and 65535.`);let n=e.buildCmd??await Je("Build command","npm run dev");if(!n)throw Error("Build command is required for browser strategy.");let s=e.buildDir!==void 0?e.buildDir:await Je("Build dir (blank for project root)",""),o=s===""?void 0:s,i=e.url??await Je("URL",`http://localhost:${r}/`),a=e.browserMode??await Qw();return{port:r,buildCmd:n,buildDir:o,url:i,browserMode:a}}async function Qw(){process.stderr.write(`
|
|
1016
|
+
`+G("Browser mode — how should Claude perceive the page?")+`
|
|
1014
1017
|
`),process.stderr.write(` ${g("1.")} dom ${g("— accessibility tree (text). Fast. HTML / React / Vue UIs.")}
|
|
1015
1018
|
`),process.stderr.write(` ${g("2.")} vision ${g("— screenshots. Slow. Canvas games (no DOM).")}
|
|
1016
1019
|
`),process.stderr.write(` ${g("3.")} script ${g("— direct JS. Fastest. Needs dApp-side hooks (advanced).")}
|
|
1017
1020
|
`),process.stderr.write(g(` dom and script need chrome-devtools-mcp installed.
|
|
1018
|
-
`));for(;;){let e=(await
|
|
1019
|
-
`))}}async function
|
|
1021
|
+
`));for(;;){let e=(await Je("Mode","dom")).toLowerCase().trim();if(e==="1"||e==="dom")return"dom";if(e==="2"||e==="vision")return"vision";if(e==="3"||e==="script")return"script";process.stderr.write(Z(` Pick 1 (dom), 2 (vision), or 3 (script).
|
|
1022
|
+
`))}}async function du(e){let t=e.filter((r)=>!r.pure);if(t.length===0){process.stderr.write(g(` No impure circuits in this contract — nothing to test as a write path.
|
|
1020
1023
|
`));return}process.stderr.write(`
|
|
1021
|
-
`+
|
|
1024
|
+
`+G("Pick the circuit this suite will exercise:")+`
|
|
1022
1025
|
`);for(let r=0;r<t.length;r++)process.stderr.write(` ${g(`${r+1}.`)} ${t[r].name}
|
|
1023
1026
|
`);process.stderr.write(g(` (or type "skip" to scaffold all circuits without AI)
|
|
1024
|
-
`));for(;;){let r=(await
|
|
1025
|
-
`))}}async function
|
|
1026
|
-
`+
|
|
1027
|
+
`));for(;;){let r=(await Je("Circuit","1")).trim();if(r.toLowerCase()==="skip")return;let n=parseInt(r,10);if(Number.isFinite(n)&&n>=1&&n<=t.length)return t[n-1];let s=t.find((o)=>o.name===r);if(s)return s;process.stderr.write(g(` Pick a number 1–${t.length}, the circuit name, or "skip".
|
|
1028
|
+
`))}}async function zo(e){if(e.length===0)return ey();process.stderr.write(`
|
|
1029
|
+
`+G("Pick the screen this suite will test:")+`
|
|
1027
1030
|
`);for(let t=0;t<e.length;t++)process.stderr.write(` ${g(`${t+1}.`)} ${e[t].name} ${g(`(${e[t].relativePath})`)}
|
|
1028
1031
|
`);process.stderr.write(g(` (or type "skip" to scaffold a generic prompt.md without AI)
|
|
1029
|
-
`));for(;;){let t=(await
|
|
1030
|
-
`))}}async function
|
|
1032
|
+
`));for(;;){let t=(await Je("Screen","1")).trim();if(t.toLowerCase()==="skip")return;let r=parseInt(t,10);if(Number.isFinite(r)&&r>=1&&r<=e.length)return e[r-1];let n=e.find((s)=>s.name===t||s.component===t);if(n)return n;process.stderr.write(g(` Pick a number 1–${e.length}, the screen name, or "skip".
|
|
1033
|
+
`))}}async function ey(){process.stderr.write(g(`
|
|
1031
1034
|
Could not auto-discover screens (no src/components, src/pages, or src/screens under the build dir).
|
|
1032
|
-
`));for(;;){let e=(await
|
|
1033
|
-
`));continue}let t;try{t=
|
|
1034
|
-
`));continue}if(t.isDirectory()){let r=
|
|
1035
|
-
`));continue}return
|
|
1036
|
-
`));continue}return
|
|
1037
|
-
`))}}function
|
|
1035
|
+
`));for(;;){let e=(await Je('Path to a .tsx file or a UI directory (or "skip")')).trim();if(e.toLowerCase()==="skip"||e==="")return;if(!Xw(e)){process.stderr.write(g(` No such path: ${e}
|
|
1036
|
+
`));continue}let t;try{t=Zw(e)}catch{process.stderr.write(g(` Cannot stat: ${e}
|
|
1037
|
+
`));continue}if(t.isDirectory()){let r=su(e);if(r.length===0){process.stderr.write(g(` No PascalCase .tsx components in ${e}
|
|
1038
|
+
`));continue}return zo(r)}if(!e.endsWith(".tsx")){process.stderr.write(g(` Not a .tsx file: ${e}
|
|
1039
|
+
`));continue}return ry(e)}}async function lu(){let e=(await Je("What does success look like? (one line, optional)")).trim();return e===""?void 0:e}async function Yo(e){for(;;){let t=(await Je("Suite name",e)).trim();if(ty(t))return t;process.stderr.write(Z(` Suite names must be kebab-case (a–z, 0–9, dashes, underscores). Try again.
|
|
1040
|
+
`))}}function ty(e){return/^[a-z0-9][a-z0-9_-]{0,63}$/.test(e)}function ry(e){let r=(e.split("/").pop()??e).replace(/\.tsx$/,"");return{name:r.replace(/([a-z0-9])([A-Z])/g,"$1-$2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1-$2").toLowerCase(),component:r,path:e,relativePath:e}}var uu=T(()=>{qo()});function mu(e){let{contractName:t,contractSummary:r,contractSource:n,targetCircuit:s,goal:o,witnessDependentCircuits:i}=e,a=i&&i.size>0?`
|
|
1038
1041
|
## Circuits NOT testable from a CLI suite
|
|
1039
1042
|
|
|
1040
1043
|
These circuits call witnesses that read from private state. In a
|
|
@@ -1139,9 +1142,9 @@ Args coercion the runner applies (so JSON arg values can be):
|
|
|
1139
1142
|
- [0..255] int array → Uint8Array for Bytes<N>
|
|
1140
1143
|
- object → recurses into Struct fields
|
|
1141
1144
|
|
|
1142
|
-
${
|
|
1145
|
+
${fu}
|
|
1143
1146
|
|
|
1144
|
-
Now produce the JSON.`}function
|
|
1147
|
+
Now produce the JSON.`}function gu(e){let{contractName:t,contractSummary:r,screenComponent:n,screenSource:s,relatedSources:o,url:i,goal:a}=e,c=(o??[]).map((l)=>`
|
|
1145
1148
|
--- ${l.path} ---
|
|
1146
1149
|
${l.source}
|
|
1147
1150
|
--- end ${l.path} ---`).join(`
|
|
@@ -1218,104 +1221,104 @@ A JSON object with three keys:
|
|
|
1218
1221
|
chain (e.g. ledger-field on a contract-state read).
|
|
1219
1222
|
- description: one short sentence summarising what this suite verifies.
|
|
1220
1223
|
|
|
1221
|
-
${
|
|
1224
|
+
${fu}
|
|
1222
1225
|
|
|
1223
|
-
Now produce the JSON.`}function
|
|
1224
|
-
`)}var
|
|
1226
|
+
Now produce the JSON.`}function Xo(e){let{name:t,circuits:r,witnesses:n}=e,s=[`Contract: ${t}`];if(r.length>0){s.push("","Circuits:");for(let o of r){let i=o.arguments.length===0?"()":"("+o.arguments.map((a)=>`${a.name}: ${a.type["type-name"]}`).join(", ")+")";s.push(` ${o.pure?"pure ":"impure"} ${o.name}${i}`)}}if(n.length>0){s.push("","Witnesses:");for(let o of n){let i=o.arguments.length===0?"()":"("+o.arguments.map((a)=>`${a.name}: ${a.type["type-name"]}`).join(", ")+")";s.push(` ${o.name}${i}`)}}return s.join(`
|
|
1227
|
+
`)}var pu="```json",fu;var hu=T(()=>{fu=`Output rules:
|
|
1225
1228
|
- Reply with EXACTLY one ${"```json"} ... \`\`\` fenced code block.
|
|
1226
1229
|
- Inside the fence: valid JSON, nothing else (no comments, no trailing text).
|
|
1227
1230
|
- Fields you don't know about: omit them. Don't invent fields.
|
|
1228
1231
|
- Use only the circuit / ledger field names that appear in the inputs below.
|
|
1229
|
-
- Be concise — fewer, well-named actions beat many vague ones.`});function fr(e,t){if(t.length===0)return{byCircuit:new Map};let r=Tw(e),n=Nw(r);if(n.size===0)return{byCircuit:new Map};let s=new Set(t),o=new Map,i=new Map;for(let[d,u]of n){o.set(d,new Set),i.set(d,new Set);for(let l of Iw(u.body,u.argNames))if(s.has(l))o.get(d).add(l);else if(n.has(l))i.get(d).add(l)}let a=!0;while(a){a=!1;for(let[d,u]of i){let l=o.get(d);for(let f of u)for(let p of o.get(f)??[])if(!l.has(p))l.add(p),a=!0}}let c=new Map;for(let[d,u]of n){if(!u.isCircuit)continue;let l=o.get(d);if(l&&l.size>0)c.set(d,[...l].sort())}return{byCircuit:c}}function Tw(e){return e.replace(Aw,"").replace(xw,"")}function Nw(e){let t=new Map,r=/\b(circuit|function)\s+([A-Za-z_][A-Za-z0-9_]*)\s*\(([^)]*)\)/gms,n;while((n=r.exec(e))!==null){let s=n[1],o=n[2],i=n[3],a=n.index+n[0].length,c=e.indexOf("{",a);if(c<0)continue;let d=1,u=c+1;for(;u<e.length&&d>0;u++){let p=e[u];if(p==="{")d++;else if(p==="}")d--}if(d!==0)continue;let l=e.slice(c+1,u-1),f=Rw(i);t.set(o,{body:l,argNames:f,isCircuit:s==="circuit"})}return t}function Rw(e){let t=new Set;for(let r of e.split(",")){let n=r.trim();if(!n)continue;let s=n.indexOf(":"),o=s>-1?n.slice(0,s).trim():n;if(/^[A-Za-z_][A-Za-z0-9_]*$/.test(o))t.add(o)}return t}function Iw(e,t){let r=new Set,n=/\b([A-Za-z_][A-Za-z0-9_]*)\s*\(/g,s;while((s=n.exec(e))!==null){let o=s[1];if(Dw.has(o)||t.has(o))continue;r.add(o)}return r}var xw,Aw,Dw;var ns=T(()=>{xw=/\/\/[^\n]*/g,Aw=/\/\*[\s\S]*?\*\//g;Dw=new Set(["if","for","while","switch","return","new","assert","disclose","transientHash","persistentHash","ownPublicKey","publicKey","Map","Set","Vector","Tuple","Option","Bytes","Field","Uint","Boolean"])});var su={};ge(su,{claudeSubprocessRunner:()=>Uo,findContractSourcePath:()=>Wo,generateCliScaffoldWithAI:()=>Hw,generateUiScaffoldWithAI:()=>Gw,isClaudeAvailable:()=>Lw});import{execFileSync as _w,spawn as Pw}from"node:child_process";import{existsSync as Lo,readdirSync as $w,readFileSync as Yl}from"node:fs";import{dirname as mr,join as ss}from"node:path";function Lw(){try{return _w("claude",["--version"],{stdio:"ignore",timeout:5000}),!0}catch{return!1}}function tu(e){let r=new RegExp("```json\\s*\\n([\\s\\S]*?)\\n```").exec(e);if(!r)throw Error(`Claude response did not contain a ${Gl} ... \`\`\` fenced block. First 200 chars: ${e.slice(0,200)}`);try{return JSON.parse(r[1])}catch(n){let s=n instanceof Error?n.message:String(n);throw Error(`JSON inside the fence failed to parse: ${s}`)}}function Uw(e,t){if(!e||typeof e!=="object")throw Error("AI response must be an object");if(typeof e.description!=="string"||!e.description)throw Error("AI response missing string `description`");if(!e.assertions||!Array.isArray(e.assertions.post))throw Error("AI response missing `assertions.post` array");let r=Bw(e);if(!r)throw Error("AI response missing actions — expected either `actions: [...]` (top-level array) "+"or `actions: { actions: [...] }` (wrapped). Got: "+JSON.stringify(e.actions??null).slice(0,200));let n=new Map(t.circuits.map((s)=>[s.name,s]));for(let s of r){if(s.type!=="contract-call"||!s.circuit)continue;let o=n.get(s.circuit);if(!o)throw Error(`AI response references unknown circuit "${s.circuit}". Valid circuits: ${[...n.keys()].join(", ")||"(none)"}`);Ww(s,o)}return{actions:r}}function Ww(e,t){if(t.arguments.length===0)return;let r=e.args??{};for(let n of t.arguments){let s=r[n.name];if(s===void 0)throw Error(`Action "${e.id}" (circuit ${t.name}) is missing required arg "${n.name}" of type ${n.type["type-name"]}. Declared args: ${t.arguments.map((i)=>`${i.name}: ${i.type["type-name"]}`).join(", ")}`);let o=n.type["type-name"];if((o==="Struct"||o==="Alias")&&(s===null||typeof s!=="object"||Array.isArray(s)))throw Error(`Action "${e.id}" (circuit ${t.name}) arg "${n.name}" must be an object for ${o} type; got ${s===null?"null":typeof s}. Read the contract source to find the inner field names.`)}}function Bw(e){if(Array.isArray(e.actions))return e.actions;let t=e.actions;if(t&&Array.isArray(t.actions))return t.actions;return null}function jw(e){if(!e||typeof e!=="object")throw Error("AI response must be an object");if(typeof e.description!=="string"||!e.description)throw Error("AI response missing string `description`");if(typeof e.prompt!=="string"||!e.prompt.trim())throw Error("AI response missing non-empty `prompt`");if(!e.assertions||!Array.isArray(e.assertions.post))throw Error("AI response missing `assertions.post` array")}async function Hw(e,t=Uo){let r=e.contractSourcePath&&Lo(e.contractSourcePath)?Yl(e.contractSourcePath,"utf-8"):void 0,n=e.contract.witnesses.map((y)=>y.name),s=r?fr(r,n).byCircuit:new Map,o=e.targetCircuit?Io(e.targetCircuit):void 0,i=Vl({contractName:e.contract.name,contractSummary:Fo({name:e.contract.name,circuits:e.contract.circuits,witnesses:e.contract.witnesses}),contractSource:r,targetCircuit:e.targetCircuit,startingArgs:o,witnessDependentCircuits:s,goal:e.goal}),a=await t(i),c=tu(a),d=Uw(c,e.contract),u=e.suiteName??(e.targetCircuit?`cli-${e.targetCircuit.name.toLowerCase().replace(/_/g,"-")}`:`cli-${nu(e.goal)??"ai"}`),l=e.network??Zl,f=e.servePort??Ql,p={name:e.contract.name,network:l,prep:eu},m={name:u,description:c.description,strategy:"cli",timeout:Ow},h=Kw(c.assertions,f),w=[...s.entries()].filter(([y])=>y!==e.targetCircuit?.name).map(([y,S])=>({name:y,reason:`uses witness ${S.join(", ")} (private state — UI-only)`}));return{dappConfig:p,suite:m,actions:d,assertions:h,prompt:null,suiteName:u,excludedCircuits:w.length>0?w:void 0}}async function Gw(e,t=Uo){let r=e.screen?Yl(e.screen.path,"utf-8"):void 0,n=Jl({contractName:e.contract.name,contractSummary:Fo({name:e.contract.name,circuits:e.contract.circuits,witnesses:e.contract.witnesses}),screenComponent:e.screen?.component,screenSource:r,relatedSources:e.relatedSources,url:e.url,goal:e.goal}),s=await t(n),o=tu(s);jw(o);let i=e.suiteName??(e.screen?`ui-${e.screen.name}`:`ui-${nu(e.goal)??"ai"}`),a=e.network??Zl,c=e.servePort??Ql,d=e.url,u={name:e.contract.name,network:a,port:e.port,buildCmd:e.buildCmd,url:d,prep:Fw};if(e.buildDir)u.buildDir=e.buildDir;let l={name:i,description:o.description,strategy:"browser",timeout:Mw,...e.browserMode?{browserMode:e.browserMode}:{}},f=Vw(o.assertions,c);return{dappConfig:u,suite:l,actions:null,assertions:f,prompt:o.prompt,suiteName:i}}function ru(e){let t=e.params;return typeof t?.port==="number"?t.port:void 0}function Kw(e,t){if(e.post.some((n)=>n.type==="port-listening"&&ru(n)===t))return e;return{...e,post:[...e.post,{id:"serve-port-listening",type:"port-listening",params:{port:t},expect:"pass"}]}}function Vw(e,t){let r=e.post;if(!r.some((i)=>i.type==="process-exit-code"))r=[...r,{id:"claude-exit-ok",type:"process-exit-code",params:{code:0},expect:"pass"}];if(!r.some((i)=>i.type==="port-listening"&&ru(i)===t))r=[...r,{id:"serve-port-listening",type:"port-listening",params:{port:t},expect:"pass"}];if(!r.some((i)=>i.type==="agent-report-no-failure"))r=[...r,{id:"agent-no-failure",type:"agent-report-no-failure",params:{},expect:"pass"}];return{...e,post:r}}function nu(e){if(!e)return;let t=e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,32);return t.length>=2?t:void 0}function Wo(e){let t=e.split("/").pop(),r=[mr(e),ss(mr(e),"src"),mr(mr(e)),ss(mr(mr(e)),"src")];for(let n of r){if(!Lo(n))continue;if(t){let i=ss(n,`${t}.compact`);if(Lo(i))return i}let s;try{s=$w(n)}catch{continue}let o=s.find((i)=>i.endsWith(".compact"));if(o)return ss(n,o)}return}var Zl="undeployed",Ql=9932,Ow=300,Mw=600,eu,Fw,zl=300000,Xl=4194304,Uo=(e)=>new Promise((t,r)=>{let n=Pw("claude",["--print"],{stdio:["pipe","pipe","pipe"]}),s="",o="",i=0,a=!1,c=setTimeout(()=>{n.kill("SIGTERM"),r(Error(`claude --print timed out after ${zl/1000}s`))},zl);n.stdout?.on("data",(d)=>{if(i+=d.length,i>Xl){a=!0,n.kill("SIGTERM");return}s+=d.toString()}),n.stderr?.on("data",(d)=>{o+=d.toString()}),n.on("error",(d)=>{if(clearTimeout(c),d.code==="ENOENT"){r(Error("claude CLI not found on PATH. Install Claude Code (npm install -g @anthropic-ai/claude-code) or run mn test create without --goal / --screen for the deterministic scaffolder."));return}r(d)}),n.on("exit",(d,u)=>{if(clearTimeout(c),a){r(Error(`claude --print response exceeded ${Xl/1024/1024}MB; aborted.`));return}if(u==="SIGTERM")return;if(d!==0){let l=o.trim().slice(0,300)||`(no stderr; exit ${d})`;r(Error(`claude --print exited with code ${d}: ${l}`));return}t(s)}),n.stdin?.write(e),n.stdin?.end()});var Bo=T(()=>{ql();_o();ns();eu=["cache-clear","localnet-up","balance:1000","dust","mn-serve"],Fw=[...eu,"build-and-serve"]});import{existsSync as ou,readFileSync as iu,writeFileSync as Jw,mkdirSync as qw}from"node:fs";import{join as au}from"node:path";async function cu(e){let{actions:t,config:r,dappDir:n,suiteName:s,networkConfig:o,servePort:i,redeploy:a,onActionStart:c,onActionComplete:d,onMessage:u}=e,l=[],f=r.network??"undeployed",p;if(!a)p=ty(n,s,f);let{info:m}=ct(n),h=ey(m),w;for(let y of t){c?.(y);let S=Date.now();if(w&&(y.type==="contract-call"||y.type==="contract-state")){let v={id:y.id,type:y.type,status:"skip",duration:0,message:`cascaded skip — depends on ${w}`};l.push(v),d?.(y,v);continue}try{let v=await zw(y,{dappDir:n,networkConfig:o,managedDir:m.managedDir,contractName:m.name,servePort:i,contractAddress:p,witnessDeps:h,onMessage:u});if(v.contractAddress){if(p=v.contractAddress,ry(n,s,f,p),y.type==="contract-deploy")w=void 0}let A=Date.now()-S,N={...v,duration:A};if(l.push(N),d?.(y,N),v.status==="skip"&&y.type==="contract-call")w=`skipped action "${y.id}"`}catch(v){let A=Date.now()-S,N={id:y.id,type:y.type,status:"fail",duration:A,message:v.message};l.push(N),d?.(y,N);break}}return l}async function zw(e,t){switch(e.type){case"contract-deploy":return Xw(e,t);case"contract-call":return Yw(e,t);case"contract-state":return Zw(e,t);case"wallet-cmd":return Qw(e,t);default:throw Error(`Unknown action type: ${e.type}`)}}async function Xw(e,t){if(t.contractAddress)return{id:e.id,type:e.type,status:"pass",duration:0,contractAddress:t.contractAddress,message:`Reusing cached contract ${t.contractAddress.slice(0,16)}...`};let r=await Yn({dappDir:t.dappDir,networkConfig:t.networkConfig,managedDir:t.managedDir,contractName:t.contractName,servePort:t.servePort,onMessage:t.onMessage});return{id:e.id,type:e.type,status:"pass",duration:0,contractAddress:r.contractAddress,message:`Deployed at ${r.contractAddress.slice(0,16)}...`}}async function Yw(e,t){if(!t.contractAddress)throw Error(`Action "${e.id}": no contract address. Add a contract-deploy action first.`);if(!e.circuit)throw Error(`Action "${e.id}": missing circuit name.`);let r=t.witnessDeps.get(e.circuit);if(r&&r.length>0)return{id:e.id,type:e.type,status:"skip",duration:0,message:"not CLI-testable — circuit reads private state via witness "+`${r.join(", ")}. Cover with mn test create --strategy ui.`};let n;try{n=await lr({dappDir:t.dappDir,networkConfig:t.networkConfig,managedDir:t.managedDir,contractName:t.contractName,contractAddress:t.contractAddress,onMessage:()=>{}})}catch{}let s=e.args?Object.values(e.args):[];await Zn({dappDir:t.dappDir,networkConfig:t.networkConfig,managedDir:t.managedDir,contractName:t.contractName,contractAddress:t.contractAddress,circuit:e.circuit,args:s,servePort:t.servePort,onMessage:t.onMessage});let o;try{o=await lr({dappDir:t.dappDir,networkConfig:t.networkConfig,managedDir:t.managedDir,contractName:t.contractName,contractAddress:t.contractAddress,onMessage:()=>{}})}catch{}return{id:e.id,type:e.type,status:"pass",duration:0,message:`${e.circuit} called`,stateBefore:n,stateAfter:o}}async function Zw(e,t){if(!t.contractAddress)throw Error(`Action "${e.id}": no contract address. Add a contract-deploy action first.`);let r=await lr({dappDir:t.dappDir,networkConfig:t.networkConfig,managedDir:t.managedDir,contractName:t.contractName,contractAddress:t.contractAddress,onMessage:t.onMessage});if(e.assert){let n=[];for(let[s,o]of Object.entries(e.assert)){let i=r.fields[s];if(i===void 0){let a=r.maps[s];if(a)jo(s,BigInt(a.size),o,n);else n.push(`Field "${s}" not found in ledger state`);continue}try{let a=BigInt(i);jo(s,a,o,n)}catch{jo(s,i,o,n)}}if(n.length>0)throw Error(`State assertion failed:
|
|
1232
|
+
- Be concise — fewer, well-named actions beat many vague ones.`});function wr(e,t){if(t.length===0)return{byCircuit:new Map};let r=oy(e),n=iy(r);if(n.size===0)return{byCircuit:new Map};let s=new Set(t),o=new Map,i=new Map;for(let[d,u]of n){o.set(d,new Set),i.set(d,new Set);for(let l of cy(u.body,u.argNames))if(s.has(l))o.get(d).add(l);else if(n.has(l))i.get(d).add(l)}let a=!0;while(a){a=!1;for(let[d,u]of i){let l=o.get(d);for(let f of u)for(let p of o.get(f)??[])if(!l.has(p))l.add(p),a=!0}}let c=new Map;for(let[d,u]of n){if(!u.isCircuit)continue;let l=o.get(d);if(l&&l.size>0)c.set(d,[...l].sort())}return{byCircuit:c}}function oy(e){return e.replace(sy,"").replace(ny,"")}function iy(e){let t=new Map,r=/\b(circuit|function)\s+([A-Za-z_][A-Za-z0-9_]*)\s*\(([^)]*)\)/gms,n;while((n=r.exec(e))!==null){let s=n[1],o=n[2],i=n[3],a=n.index+n[0].length,c=e.indexOf("{",a);if(c<0)continue;let d=1,u=c+1;for(;u<e.length&&d>0;u++){let p=e[u];if(p==="{")d++;else if(p==="}")d--}if(d!==0)continue;let l=e.slice(c+1,u-1),f=ay(i);t.set(o,{body:l,argNames:f,isCircuit:s==="circuit"})}return t}function ay(e){let t=new Set;for(let r of e.split(",")){let n=r.trim();if(!n)continue;let s=n.indexOf(":"),o=s>-1?n.slice(0,s).trim():n;if(/^[A-Za-z_][A-Za-z0-9_]*$/.test(o))t.add(o)}return t}function cy(e,t){let r=new Set,n=/\b([A-Za-z_][A-Za-z0-9_]*)\s*\(/g,s;while((s=n.exec(e))!==null){let o=s[1];if(dy.has(o)||t.has(o))continue;r.add(o)}return r}var ny,sy,dy;var ls=T(()=>{ny=/\/\/[^\n]*/g,sy=/\/\*[\s\S]*?\*\//g;dy=new Set(["if","for","while","switch","return","new","assert","disclose","transientHash","persistentHash","ownPublicKey","publicKey","Map","Set","Vector","Tuple","Option","Bytes","Field","Uint","Boolean"])});var Au={};he(Au,{claudeSubprocessRunner:()=>Qo,findContractSourcePath:()=>ei,generateCliScaffoldWithAI:()=>vy,generateUiScaffoldWithAI:()=>ky,isClaudeAvailable:()=>hy});import{execFileSync as ly,spawn as uy}from"node:child_process";import{existsSync as Zo,readdirSync as py,readFileSync as Su}from"node:fs";import{dirname as yr,join as us}from"node:path";function hy(){try{return ly("claude",["--version"],{stdio:"ignore",timeout:5000}),!0}catch{return!1}}function xu(e){let r=new RegExp("```json\\s*\\n([\\s\\S]*?)\\n```").exec(e);if(!r)throw Error(`Claude response did not contain a ${pu} ... \`\`\` fenced block. First 200 chars: ${e.slice(0,200)}`);try{return JSON.parse(r[1])}catch(n){let s=n instanceof Error?n.message:String(n);throw Error(`JSON inside the fence failed to parse: ${s}`)}}function wy(e,t){if(!e||typeof e!=="object")throw Error("AI response must be an object");if(typeof e.description!=="string"||!e.description)throw Error("AI response missing string `description`");if(!e.assertions||!Array.isArray(e.assertions.post))throw Error("AI response missing `assertions.post` array");let r=Sy(e);if(!r)throw Error("AI response missing actions — expected either `actions: [...]` (top-level array) "+"or `actions: { actions: [...] }` (wrapped). Got: "+JSON.stringify(e.actions??null).slice(0,200));let n=new Map(t.circuits.map((s)=>[s.name,s]));for(let s of r){if(s.type!=="contract-call"||!s.circuit)continue;let o=n.get(s.circuit);if(!o)throw Error(`AI response references unknown circuit "${s.circuit}". Valid circuits: ${[...n.keys()].join(", ")||"(none)"}`);yy(s,o)}return{actions:r}}function yy(e,t){if(t.arguments.length===0)return;let r=e.args??{};for(let n of t.arguments){let s=r[n.name];if(s===void 0)throw Error(`Action "${e.id}" (circuit ${t.name}) is missing required arg "${n.name}" of type ${n.type["type-name"]}. Declared args: ${t.arguments.map((i)=>`${i.name}: ${i.type["type-name"]}`).join(", ")}`);let o=n.type["type-name"];if((o==="Struct"||o==="Alias")&&(s===null||typeof s!=="object"||Array.isArray(s)))throw Error(`Action "${e.id}" (circuit ${t.name}) arg "${n.name}" must be an object for ${o} type; got ${s===null?"null":typeof s}. Read the contract source to find the inner field names.`)}}function Sy(e){if(Array.isArray(e.actions))return e.actions;let t=e.actions;if(t&&Array.isArray(t.actions))return t.actions;return null}function by(e){if(!e||typeof e!=="object")throw Error("AI response must be an object");if(typeof e.description!=="string"||!e.description)throw Error("AI response missing string `description`");if(typeof e.prompt!=="string"||!e.prompt.trim())throw Error("AI response missing non-empty `prompt`");if(!e.assertions||!Array.isArray(e.assertions.post))throw Error("AI response missing `assertions.post` array")}async function vy(e,t=Qo){let r=e.contractSourcePath&&Zo(e.contractSourcePath)?Su(e.contractSourcePath,"utf-8"):void 0,n=e.contract.witnesses.map((y)=>y.name),s=r?wr(r,n).byCircuit:new Map,o=e.targetCircuit?Go(e.targetCircuit):void 0,i=mu({contractName:e.contract.name,contractSummary:Xo({name:e.contract.name,circuits:e.contract.circuits,witnesses:e.contract.witnesses}),contractSource:r,targetCircuit:e.targetCircuit,startingArgs:o,witnessDependentCircuits:s,goal:e.goal}),a=await t(i),c=xu(a),d=wy(c,e.contract),u=e.suiteName??(e.targetCircuit?`cli-${e.targetCircuit.name.toLowerCase().replace(/_/g,"-")}`:`cli-${Eu(e.goal)??"ai"}`),l=e.network??bu,f=e.servePort??vu,p={name:e.contract.name,network:l,prep:ku},m={name:u,description:c.description,strategy:"cli",timeout:fy},h=xy(c.assertions,f),w=[...s.entries()].filter(([y])=>y!==e.targetCircuit?.name).map(([y,S])=>({name:y,reason:`uses witness ${S.join(", ")} (private state — UI-only)`}));return{dappConfig:p,suite:m,actions:d,assertions:h,prompt:null,suiteName:u,excludedCircuits:w.length>0?w:void 0}}async function ky(e,t=Qo){let r=e.screen?Su(e.screen.path,"utf-8"):void 0,n=gu({contractName:e.contract.name,contractSummary:Xo({name:e.contract.name,circuits:e.contract.circuits,witnesses:e.contract.witnesses}),screenComponent:e.screen?.component,screenSource:r,relatedSources:e.relatedSources,url:e.url,goal:e.goal}),s=await t(n),o=xu(s);by(o);let i=e.suiteName??(e.screen?`ui-${e.screen.name}`:`ui-${Eu(e.goal)??"ai"}`),a=e.network??bu,c=e.servePort??vu,d=e.url,u={name:e.contract.name,network:a,port:e.port,buildCmd:e.buildCmd,url:d,prep:gy};if(e.buildDir)u.buildDir=e.buildDir;let l={name:i,description:o.description,strategy:"browser",timeout:my,...e.browserMode?{browserMode:e.browserMode}:{}},f=Cy(o.assertions,c);return{dappConfig:u,suite:l,actions:null,assertions:f,prompt:o.prompt,suiteName:i}}function Cu(e){let t=e.params;return typeof t?.port==="number"?t.port:void 0}function xy(e,t){if(e.post.some((n)=>n.type==="port-listening"&&Cu(n)===t))return e;return{...e,post:[...e.post,{id:"serve-port-listening",type:"port-listening",params:{port:t},expect:"pass"}]}}function Cy(e,t){let r=e.post;if(!r.some((i)=>i.type==="process-exit-code"))r=[...r,{id:"claude-exit-ok",type:"process-exit-code",params:{code:0},expect:"pass"}];if(!r.some((i)=>i.type==="port-listening"&&Cu(i)===t))r=[...r,{id:"serve-port-listening",type:"port-listening",params:{port:t},expect:"pass"}];if(!r.some((i)=>i.type==="agent-report-no-failure"))r=[...r,{id:"agent-no-failure",type:"agent-report-no-failure",params:{},expect:"pass"}];return{...e,post:r}}function Eu(e){if(!e)return;let t=e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,32);return t.length>=2?t:void 0}function ei(e){let t=e.split("/").pop(),r=[yr(e),us(yr(e),"src"),yr(yr(e)),us(yr(yr(e)),"src")];for(let n of r){if(!Zo(n))continue;if(t){let i=us(n,`${t}.compact`);if(Zo(i))return i}let s;try{s=py(n)}catch{continue}let o=s.find((i)=>i.endsWith(".compact"));if(o)return us(n,o)}return}var bu="undeployed",vu=9932,fy=300,my=600,ku,gy,wu=300000,yu=4194304,Qo=(e)=>new Promise((t,r)=>{let n=uy("claude",["--print"],{stdio:["pipe","pipe","pipe"]}),s="",o="",i=0,a=!1,c=setTimeout(()=>{n.kill("SIGTERM"),r(Error(`claude --print timed out after ${wu/1000}s`))},wu);n.stdout?.on("data",(d)=>{if(i+=d.length,i>yu){a=!0,n.kill("SIGTERM");return}s+=d.toString()}),n.stderr?.on("data",(d)=>{o+=d.toString()}),n.on("error",(d)=>{if(clearTimeout(c),d.code==="ENOENT"){r(Error("claude CLI not found on PATH. Install Claude Code (npm install -g @anthropic-ai/claude-code) or run mn test create without --goal / --screen for the deterministic scaffolder."));return}r(d)}),n.on("exit",(d,u)=>{if(clearTimeout(c),a){r(Error(`claude --print response exceeded ${yu/1024/1024}MB; aborted.`));return}if(u==="SIGTERM")return;if(d!==0){let l=o.trim().slice(0,300)||`(no stderr; exit ${d})`;r(Error(`claude --print exited with code ${d}: ${l}`));return}t(s)}),n.stdin?.write(e),n.stdin?.end()});var ti=T(()=>{hu();Vo();ls();ku=["cache-clear","localnet-up","balance:1000","dust","mn-serve"],gy=[...ku,"build-and-serve"]});import{existsSync as Tu,readFileSync as Nu,writeFileSync as Ey,mkdirSync as Ay}from"node:fs";import{join as Ru}from"node:path";async function Du(e){let{actions:t,config:r,dappDir:n,suiteName:s,networkConfig:o,servePort:i,redeploy:a,onActionStart:c,onActionComplete:d,onMessage:u}=e,l=[],f=r.network??"undeployed",p;if(!a)p=Py(n,s,f);let{info:m}=lt(n),h=$y(m),w;for(let y of t){c?.(y);let S=Date.now();if(w&&(y.type==="contract-call"||y.type==="contract-state")){let v={id:y.id,type:y.type,status:"skip",duration:0,message:`cascaded skip — depends on ${w}`};l.push(v),d?.(y,v);continue}try{let v=await Ty(y,{dappDir:n,networkConfig:o,managedDir:m.managedDir,contractName:m.name,servePort:i,contractAddress:p,witnessDeps:h,onMessage:u});if(v.contractAddress){if(p=v.contractAddress,_y(n,s,f,p),y.type==="contract-deploy")w=void 0}let A=Date.now()-S,N={...v,duration:A};if(l.push(N),d?.(y,N),v.status==="skip"&&y.type==="contract-call")w=`skipped action "${y.id}"`}catch(v){let A=Date.now()-S,N={id:y.id,type:y.type,status:"fail",duration:A,message:v.message};l.push(N),d?.(y,N);break}}return l}async function Ty(e,t){switch(e.type){case"contract-deploy":return Ny(e,t);case"contract-call":return Ry(e,t);case"contract-state":return Dy(e,t);case"wallet-cmd":return Iy(e,t);default:throw Error(`Unknown action type: ${e.type}`)}}async function Ny(e,t){if(t.contractAddress)return{id:e.id,type:e.type,status:"pass",duration:0,contractAddress:t.contractAddress,message:`Reusing cached contract ${t.contractAddress.slice(0,16)}...`};let r=await ss({dappDir:t.dappDir,networkConfig:t.networkConfig,managedDir:t.managedDir,contractName:t.contractName,servePort:t.servePort,onMessage:t.onMessage});return{id:e.id,type:e.type,status:"pass",duration:0,contractAddress:r.contractAddress,message:`Deployed at ${r.contractAddress.slice(0,16)}...`}}async function Ry(e,t){if(!t.contractAddress)throw Error(`Action "${e.id}": no contract address. Add a contract-deploy action first.`);if(!e.circuit)throw Error(`Action "${e.id}": missing circuit name.`);let r=t.witnessDeps.get(e.circuit);if(r&&r.length>0)return{id:e.id,type:e.type,status:"skip",duration:0,message:"not CLI-testable — circuit reads private state via witness "+`${r.join(", ")}. Cover with mn test create --strategy ui.`};let n;try{n=await mr({dappDir:t.dappDir,networkConfig:t.networkConfig,managedDir:t.managedDir,contractName:t.contractName,contractAddress:t.contractAddress,onMessage:()=>{}})}catch{}let s=e.args?Object.values(e.args):[];await os({dappDir:t.dappDir,networkConfig:t.networkConfig,managedDir:t.managedDir,contractName:t.contractName,contractAddress:t.contractAddress,circuit:e.circuit,args:s,servePort:t.servePort,onMessage:t.onMessage});let o;try{o=await mr({dappDir:t.dappDir,networkConfig:t.networkConfig,managedDir:t.managedDir,contractName:t.contractName,contractAddress:t.contractAddress,onMessage:()=>{}})}catch{}return{id:e.id,type:e.type,status:"pass",duration:0,message:`${e.circuit} called`,stateBefore:n,stateAfter:o}}async function Dy(e,t){if(!t.contractAddress)throw Error(`Action "${e.id}": no contract address. Add a contract-deploy action first.`);let r=await mr({dappDir:t.dappDir,networkConfig:t.networkConfig,managedDir:t.managedDir,contractName:t.contractName,contractAddress:t.contractAddress,onMessage:t.onMessage});if(e.assert){let n=[];for(let[s,o]of Object.entries(e.assert)){let i=r.fields[s];if(i===void 0){let a=r.maps[s];if(a)ri(s,BigInt(a.size),o,n);else n.push(`Field "${s}" not found in ledger state`);continue}try{let a=BigInt(i);ri(s,a,o,n)}catch{ri(s,i,o,n)}}if(n.length>0)throw Error(`State assertion failed:
|
|
1230
1233
|
${n.join(`
|
|
1231
|
-
`)}`)}return{id:e.id,type:e.type,status:"pass",duration:0,message:`State checked (${Object.keys(r.fields).length} fields, ${Object.keys(r.maps).length} maps)`,stateAfter:r}}function
|
|
1232
|
-
`)}var
|
|
1234
|
+
`)}`)}return{id:e.id,type:e.type,status:"pass",duration:0,message:`State checked (${Object.keys(r.fields).length} fields, ${Object.keys(r.maps).length} maps)`,stateAfter:r}}function ri(e,t,r,n){for(let[s,o]of Object.entries(r)){let i=typeof o==="number"?BigInt(o):o;if(typeof t==="bigint"&&(typeof i==="bigint"||typeof i==="number")){let a=BigInt(i);switch(s){case">":if(!(t>a))n.push(`${e}: expected > ${a}, got ${t}`);break;case">=":if(!(t>=a))n.push(`${e}: expected >= ${a}, got ${t}`);break;case"<":if(!(t<a))n.push(`${e}: expected < ${a}, got ${t}`);break;case"<=":if(!(t<=a))n.push(`${e}: expected <= ${a}, got ${t}`);break;case"==":if(t!==a)n.push(`${e}: expected == ${a}, got ${t}`);break;case"!=":if(t===a)n.push(`${e}: expected != ${a}, got ${t}`);break;default:n.push(`${e}: unknown operator "${s}"`)}}else{let a=String(i);switch(s){case"==":if(t!==a)n.push(`${e}: expected == "${a}", got "${t}"`);break;case"!=":if(t===a)n.push(`${e}: expected != "${a}", got "${t}"`);break;default:n.push(`${e}: operator "${s}" not supported for string values`)}}}}async function Iy(e,t){return{id:e.id,type:e.type,status:"pass",duration:0,message:`wallet-cmd: ${e.cmd??"no command"} (not yet implemented)`}}function $y(e){if(e.witnesses.length===0)return new Map;let t=ei(e.managedDir);if(!t||!Tu(t))return new Map;let r=Nu(t,"utf-8"),n=e.witnesses.map((s)=>s.name);return wr(r,n).byCircuit}function Iu(e,t){if(!e||!t)return[];let r=[],n=new Set([...Object.keys(e.fields),...Object.keys(t.fields)]);for(let o of n){let i=e.fields[o]??"(absent)",a=t.fields[o]??"(absent)";if(i!==a)r.push({field:o,before:i,after:a})}let s=new Set([...Object.keys(e.maps),...Object.keys(t.maps)]);for(let o of s){let i=e.maps[o]?.size??"0",a=t.maps[o]?.size??"0";if(i!==a)r.push({field:`${o} (entries)`,before:i,after:a})}return r}function $u(e,t){return Ru(e,"tests","results",`.contract-cache-${t}.json`)}function Py(e,t,r){let n=$u(e,t);if(!Tu(n))return;try{let s=JSON.parse(Nu(n,"utf-8"));if(s.network!==r)return;return s.address}catch{return}}function _y(e,t,r,n){let s=$u(e,t);Ay(Ru(e,"tests","results"),{recursive:!0});let o={address:n,network:r,timestamp:new Date().toISOString()};Ey(s,JSON.stringify(o,null,2)+`
|
|
1235
|
+
`)}var Pu=T(()=>{en();Zn();ls();ti()});var Lu={};he(Lu,{default:()=>Mu});import{join as _u}from"node:path";import{mkdirSync as Oy}from"node:fs";function My(e){return Ou.includes(e)}async function Mu(e,t){let r=e.subcommand;if(!r||!My(r))throw new U(`Usage: midnight test <${Ou.join("|")}>
|
|
1233
1236
|
|
|
1234
1237
|
create Generate dapp.test.json + a CLI test suite from the contract
|
|
1235
1238
|
run Run test suites for the current dApp
|
|
1236
1239
|
list List available test suites
|
|
1237
1240
|
results Show latest test results
|
|
1238
1241
|
|
|
1239
|
-
Run from the root of a dApp project containing dapp.test.json.`);let n=R(e,"json");switch(r){case"create":return
|
|
1240
|
-
`+
|
|
1242
|
+
Run from the root of a dApp project containing dapp.test.json.`);let n=R(e,"json");switch(r){case"create":return By(e,n);case"run":return Ky(e,n,t);case"list":return Vy(n);case"results":return Jy(e,n)}}function Fy(e){let t=(e??"").toLowerCase();if(t==="")return;if(t==="cli"||t==="browser")return t;if(t==="ui")return"browser";throw new U(`Unknown strategy "${e}". Use "cli" or "ui".`)}function Ly(e){return e==="preprod"||e==="preview"||e==="undeployed"?e:void 0}function Uy(e){let t={},r=x(e,"port");if(r!==void 0){let a=parseInt(r,10);if(!Number.isFinite(a)||a<=0||a>65535)throw new U(`Invalid --port "${r}" — must be 1–65535.`);t.port=a}let n=x(e,"build-cmd");if(n!==void 0)t.buildCmd=n;let s=x(e,"build-dir");if(s!==void 0)t.buildDir=s;let o=x(e,"url");if(o!==void 0)t.url=o;let i=x(e,"browser-mode");if(i!==void 0){if(i!=="dom"&&i!=="vision"&&i!=="script"&&i!=="auto")throw new U(`Invalid --browser-mode "${i}" — must be dom, vision, or script.`);t.browserMode=i}return t}function Wy(e){if(e.port===void 0||e.buildCmd===void 0)throw new U("Browser strategy needs --port and --build-cmd (and optionally --build-dir, --url) when running non-interactively.");return{port:e.port,buildCmd:e.buildCmd,buildDir:e.buildDir,url:e.url}}async function By(e,t){let{resolve:r}=await import("node:path");await Promise.resolve().then(() => Zn());await Promise.resolve().then(() => Vo());await Promise.resolve().then(() => Ql());let i=await Promise.resolve().then(() => (uu(),{}));await Promise.resolve();let h=await Promise.resolve().then(() => (ti(),Au));await Promise.resolve().then(() => qo());let y=r(x(e,"path")??process.cwd()),S=x(e,"name"),v=x(e,"suite"),A=Ly(x(e,"network")),N=R(e,"force"),L=!t&&iu(),X=x(e,"goal"),q=x(e,"screen"),V=R(e,"no-ai"),_=Fy(x(e,"strategy"))??(L?await au():"cli"),ne;if(_==="browser"){let Ee=Uy(e);ne=L?await cu(Ee):Wy(Ee)}let{info:pe}=lt(y,S),sn=!V&&h.isClaudeAvailable(),ut=!V&&(X!==void 0||q!==void 0||L&&sn),fe=ut?await jy({strategy:_,info:pe,dappDir:y,browser:ne,network:A,suiteName:v,goalFlag:X,screenFlag:q,interactive:L,jsonMode:t,ai:h,promptCircuit:du,promptScreen:zo,promptGoal:lu,promptSuiteName:Yo,discoverScreens:nu})??Ko(pe.circuits,{contractName:pe.name,suiteName:v,strategy:_,browser:ne,network:A}):Ko(pe.circuits,{contractName:pe.name,suiteName:v,strategy:_,browser:ne,network:A});if(L&&!v){let Ee=await Yo(fe.suiteName);if(Ee!==fe.suiteName)fe.suiteName=Ee,fe.suite.name=Ee}let vt=Zl(fe,{dappDir:y,force:N});if(t){D({subcommand:"create",contractName:pe.name,suiteName:fe.suiteName,strategy:_,aiAssisted:ut&&fe.suiteName!=="cli-default"&&fe.suiteName!=="ui-default",written:vt.written,excludedCircuits:fe.excludedCircuits});return}process.stderr.write(`
|
|
1243
|
+
`+B(`Test scaffold: ${pe.name}`)+`
|
|
1241
1244
|
|
|
1242
|
-
`);for(let
|
|
1243
|
-
`);let
|
|
1245
|
+
`);for(let Ee of vt.written)process.stderr.write(` ${W("✓")} ${Ee}
|
|
1246
|
+
`);let kt=_==="browser"?{file:"prompt.md",hint:"verify the UI steps match your dApp — exact button labels, expected screens, success criteria. Claude follows these literally."}:{file:"actions.json",hint:'review args — placeholder values like 0 may violate contract assertions (e.g. "amount > 0").'};if(fe.excludedCircuits&&fe.excludedCircuits.length>0){process.stderr.write(`
|
|
1244
1247
|
`+g(" Skipped (not CLI-testable):")+`
|
|
1245
|
-
`);for(let
|
|
1248
|
+
`);for(let Ee of fe.excludedCircuits)process.stderr.write(` ${Z("!")} ${Ee.name} ${g("— "+Ee.reason)}
|
|
1246
1249
|
`);process.stderr.write(g(` These need the dApp UI to populate private state first.
|
|
1247
1250
|
`)),process.stderr.write(g(` Cover them with a browser-strategy suite (mn test create --strategy ui).
|
|
1248
1251
|
`))}process.stderr.write(`
|
|
1249
1252
|
`+g(" Next:")+`
|
|
1250
|
-
`),process.stderr.write(g(" Edit ")+
|
|
1251
|
-
`),process.stderr.write(g(" ")+g(
|
|
1252
|
-
`),process.stderr.write(g(" Run ")+
|
|
1253
|
-
`),process.stderr.write(g(" List ")+
|
|
1253
|
+
`),process.stderr.write(g(" Edit ")+G(`tests/suites/${fe.suiteName}/${kt.file}`)+`
|
|
1254
|
+
`),process.stderr.write(g(" ")+g(kt.hint)+`
|
|
1255
|
+
`),process.stderr.write(g(" Run ")+G(`mn test run --suite ${fe.suiteName}`)+`
|
|
1256
|
+
`),process.stderr.write(g(" List ")+G("mn test list")+g(" (see every suite in this project)")+`
|
|
1254
1257
|
|
|
1255
|
-
`)}async function
|
|
1258
|
+
`)}async function jy(e){try{if(!e.ai.isClaudeAvailable())return null;let t=e.goalFlag??(e.interactive?await e.promptGoal():void 0);if(e.strategy==="cli")return await Hy(e,t);return await Gy(e,t)}catch(t){return process.stderr.write(`
|
|
1256
1259
|
${g("AI scaffold failed, falling back to deterministic:")} ${t.message}
|
|
1257
|
-
`),null}}async function
|
|
1258
|
-
`+
|
|
1260
|
+
`),null}}async function Fu(e,t,r){if(!r)return t();let n=K(e);try{let s=await t();return n.stop(),s}catch(s){throw n.fail("AI scaffold failed"),s}}async function Hy(e,t){let r=e.interactive?await e.promptCircuit(e.info.circuits):e.info.circuits.find((s)=>!s.pure);if(!r&&!t)return null;let n=e.ai.findContractSourcePath(e.info.managedDir);if(r&&n&&e.interactive){let{readFileSync:s}=await import("node:fs");await Promise.resolve().then(() => ls());let i=s(n,"utf-8"),a=e.info.witnesses.map((u)=>u.name),d=wr(i,a).byCircuit.get(r.name);if(d&&d.length>0)process.stderr.write(`
|
|
1261
|
+
`+Z("!")+` ${r.name} calls ${d.join(", ")} — a witness that reads private state.
|
|
1259
1262
|
`),process.stderr.write(g(` The CLI suite will deploy + run, but expect a "Cannot read properties of undefined" failure
|
|
1260
1263
|
`)+g(` unless the dApp UI populates that state first. Consider --strategy ui instead.
|
|
1261
|
-
`))}return
|
|
1262
|
-
`+
|
|
1263
|
-
|
|
1264
|
-
`),process.stderr.write(
|
|
1265
|
-
`),n.port)process.stderr.write(
|
|
1266
|
-
`);if(a){if(process.stderr.write(
|
|
1267
|
-
`),process.stderr.write(
|
|
1268
|
-
`),a.suite.strategy==="browser"){let p=
|
|
1264
|
+
`))}return Fu("Asking Claude to scaffold the test suite (30–60s)...",()=>e.ai.generateCliScaffoldWithAI({contract:e.info,contractSourcePath:n,targetCircuit:r,goal:t,network:e.network,suiteName:e.suiteName}),e.interactive&&!e.jsonMode)}async function Gy(e,t){if(!e.browser)return null;let{join:r}=await import("node:path"),n=e.browser.buildDir?r(e.dappDir,e.browser.buildDir):e.dappDir,s=e.discoverScreens(n),o=e.screenFlag?s.find((i)=>i.name===e.screenFlag||i.component===e.screenFlag):e.interactive?await e.promptScreen(s):s[0];if(!o&&!t)return null;return Fu("Asking Claude to scaffold the test suite (30–60s)...",()=>e.ai.generateUiScaffoldWithAI({contract:e.info,screen:o,url:e.browser.url??`http://localhost:${e.browser.port}/`,port:e.browser.port,buildCmd:e.browser.buildCmd,buildDir:e.browser.buildDir,browserMode:e.browser.browserMode,goal:t,network:e.network,suiteName:e.suiteName}),e.interactive&&!e.jsonMode)}async function Ky(e,t,r){let{config:n,dappDir:s}=cs(),o=Wo(s),i=x(e,"suite"),a;if(i){if(a=o.find((p)=>p.suite.name===i),!a){let p=o.map((m)=>m.suite.name).join(", ")||"none found";throw new U(`Suite "${i}" not found. Available: ${p}`)}}else if(o.length>0)a=o[0];Oy(_u(s,"tests","results"),{recursive:!0});let c=Date.now(),d=new Date().toISOString();if(!t){if(process.stderr.write(`
|
|
1265
|
+
`+B(`E2E Test: ${n.name}`)+`
|
|
1266
|
+
|
|
1267
|
+
`),process.stderr.write(C("Network",n.network??"undeployed")+`
|
|
1268
|
+
`),n.port)process.stderr.write(C("Port",String(n.port))+`
|
|
1269
|
+
`);if(a){if(process.stderr.write(C("Suite",a.suite.name)+`
|
|
1270
|
+
`),process.stderr.write(C("Strategy",a.suite.strategy)+`
|
|
1271
|
+
`),a.suite.strategy==="browser"){let p=Bo(a.suite);process.stderr.write(C("Browser Mode",p)+`
|
|
1269
1272
|
`)}}process.stderr.write(`
|
|
1270
|
-
`)}let u=
|
|
1271
|
-
`)};r?.addEventListener("abort",()=>
|
|
1272
|
-
`));let p=
|
|
1273
|
-
`);let h=0,w="";if(a){let O=a.suite;if(O.strategy==="browser"){let
|
|
1273
|
+
`)}let u=Tl(),l=[],f=(p)=>{if(!t)process.stderr.write(g(` [teardown] ${p}`)+`
|
|
1274
|
+
`)};r?.addEventListener("abort",()=>Ho(u,f),{once:!0});try{if(!t)process.stderr.write(P(` Prep
|
|
1275
|
+
`));let p=K("Starting prep..."),m=await Pl(n,s,u,{onStepStart(O){p.update(`[prep] ${O}...`)},onStepComplete(O,_,ne,pe){if(_==="pass")p.stop(`${W("✓")} ${O} (${qy(ne)})`);else p.stop(`${ce("✗")} ${O}: ${pe??"failed"}`);p=K("")},onMessage(O){p.update(O)}});if(p.stop(""),l.push(...m),!t)process.stderr.write(`
|
|
1276
|
+
`);let h=0,w="";if(a){let O=a.suite;if(O.strategy==="browser"){let _=El(a.suiteDir);if(!_)throw Error(`No prompt.md found in ${a.suiteDir} — required for browser strategy`);if(w=_u(s,"tests","results",`${O.name}_${d.replace(/[:.]/g,"-")}_claude.log`),!t)process.stderr.write(P(` Browser Test
|
|
1274
1277
|
`)),process.stderr.write(g(` Claude will take over the terminal. Output is also logged.
|
|
1275
1278
|
|
|
1276
|
-
`));let ne=await
|
|
1279
|
+
`));let ne=await Ml({suite:O,prompt:_,dappDir:s,logFile:w,onMessage:(pe)=>{if(!t)process.stderr.write(g(` ${pe}`)+`
|
|
1277
1280
|
`)}});if(h=ne.exitCode,!t)if(process.stderr.write(`
|
|
1278
|
-
`),ne.timedOut)process.stderr.write(` ${
|
|
1279
|
-
`);else process.stderr.write(` ${h===0?
|
|
1280
|
-
`)}else if(O.strategy==="cli"){let
|
|
1281
|
-
`)),process.stderr.write(g(` Executing ${
|
|
1282
|
-
|
|
1283
|
-
`));await Promise.resolve().then(() =>
|
|
1284
|
-
`)}}},onMessage:(
|
|
1285
|
-
`);let
|
|
1286
|
-
`)}u._actionResults=
|
|
1287
|
-
`));let y={processExitCode:h,agentLogPath:w},S=[];if(a){let O=
|
|
1288
|
-
`+
|
|
1289
|
-
`));if(S=await
|
|
1290
|
-
`)}}}let v=Math.round((Date.now()-c)/1000),A=l.every((O)=>O.status==="pass"),N=S.every((O)=>O.status==="pass"),L=A&&N&&h===0?"pass":"fail",
|
|
1291
|
-
`+
|
|
1292
|
-
`),process.stderr.write(` ${L==="pass"?
|
|
1281
|
+
`),ne.timedOut)process.stderr.write(` ${ce("✗")} Browser test timed out
|
|
1282
|
+
`);else process.stderr.write(` ${h===0?W("✓"):ce("✗")} Claude exited with code ${h}
|
|
1283
|
+
`)}else if(O.strategy==="cli"){let _=Cl(a.suiteDir);if(!_)throw Error(`No actions.json found in ${a.suiteDir} — required for CLI strategy`);if(!t)process.stderr.write(P(` CLI Test
|
|
1284
|
+
`)),process.stderr.write(g(` Executing ${_.actions.length} action(s)
|
|
1285
|
+
|
|
1286
|
+
`));await Promise.resolve().then(() => Pu());await Promise.resolve().then(() => ke());let ut=n.network??"undeployed",{config:fe}=le({args:{command:"test",subcommand:"run",positionals:[],flags:{network:ut}}});await Promise.resolve();let kt=u.serveHandle?.port??Cr,Ee=R(e,"redeploy"),xt=await Du({actions:_.actions,config:n,dappDir:s,suiteName:O.name,networkConfig:fe,servePort:kt,redeploy:Ee,onActionStart:(ge)=>{if(!t){let Se=K(`[${ge.id}] ${ge.type}${ge.circuit?` ${ge.circuit}`:""}...`);ge._spinner=Se}},onActionComplete:(ge,Se)=>{if(!t){let tt=ge._spinner;if(tt)if(Se.status==="pass")tt.stop(`${W("✓")} ${ge.id}: ${Se.message??"pass"}`);else if(Se.status==="skip")tt.stop(`${Z("⊘")} ${ge.id}: ${Se.message??"skipped"}`);else tt.stop(`${ce("✗")} ${ge.id}: ${Se.message??"fail"}`);if(Se.stateBefore&&Se.stateAfter){let k=Iu(Se.stateBefore,Se.stateAfter);if(k.length>0)for(let b of k)process.stderr.write(g(` ${b.field}: ${b.before} → `)+G(b.after)+`
|
|
1287
|
+
`)}}},onMessage:(ge)=>{}});if(h=xt.some((ge)=>ge.status==="fail")?1:0,!t){process.stderr.write(`
|
|
1288
|
+
`);let ge=xt.filter((b)=>b.status==="pass").length,Se=xt.filter((b)=>b.status==="skip").length,tt=xt.filter((b)=>b.status==="fail").length,k=W(String(ge)+" passed");if(Se>0)k+=`, ${Z(String(Se)+" skipped")}`;if(tt>0)k+=`, ${ce(String(tt)+" failed")}`;process.stderr.write(` Actions: ${k}
|
|
1289
|
+
`)}u._actionResults=xt}}else if(!t)process.stderr.write(g(` No test suites found — only prep was run
|
|
1290
|
+
`));let y={processExitCode:h,agentLogPath:w},S=[];if(a){let O=xl(a.suiteDir);if(O&&O.post.length>0){if(!t)process.stderr.write(`
|
|
1291
|
+
`+P(` Assertions
|
|
1292
|
+
`));if(S=await Ll(O.post,y),!t)for(let _ of S){let ne=_.status==="pass"?W("✓"):ce("✗"),pe=_.message?g(` — ${_.message}`):"";process.stderr.write(` ${ne} ${_.id}${pe}
|
|
1293
|
+
`)}}}let v=Math.round((Date.now()-c)/1000),A=l.every((O)=>O.status==="pass"),N=S.every((O)=>O.status==="pass"),L=A&&N&&h===0?"pass":"fail",X=u._actionResults,q={id:`${n.name}_${d}`,dapp:n.name,suite:a?.suite.name??"prep-only",timestamp:d,duration:v,network:n.network??"undeployed",strategy:a?.suite.strategy??"none",model:a?.suite.model,status:L,prep:l,actions:X?.map((O)=>({id:O.id,type:O.type,status:O.status,duration:O.duration,message:O.message,contractAddress:O.contractAddress})),assertions:S,testOutput:w?{exitCode:h,logFile:w}:void 0},V=Bl(q,s);if(t)D(q);else process.stderr.write(`
|
|
1294
|
+
`+J()+`
|
|
1295
|
+
`),process.stderr.write(` ${L==="pass"?W(P("PASS")):ce(P("FAIL"))} — ${n.name} (${v}s)
|
|
1293
1296
|
`),process.stderr.write(g(` Results: ${V}`)+`
|
|
1294
1297
|
|
|
1295
|
-
`);if(L==="fail")process.exitCode=1}finally{await
|
|
1296
|
-
`+
|
|
1298
|
+
`);if(L==="fail")process.exitCode=1}finally{await Ho(u,f)}}function Vy(e){let{config:t,dappDir:r}=cs(),n=Wo(r);if(e){D({dapp:t.name,suites:n.map((s)=>({name:s.suite.name,description:s.suite.description,strategy:s.suite.strategy,timeout:s.suite.timeout}))});return}if(process.stderr.write(`
|
|
1299
|
+
`+B(`Tests: ${t.name}`)+`
|
|
1297
1300
|
|
|
1298
1301
|
`),n.length===0)process.stderr.write(g(` No test suites found.
|
|
1299
1302
|
`)),process.stderr.write(g(` Create tests/suites/<name>/suite.json to add one.
|
|
1300
|
-
`));else for(let{suite:s}of n)process.stderr.write(` ${
|
|
1303
|
+
`));else for(let{suite:s}of n)process.stderr.write(` ${P(G(s.name))}
|
|
1301
1304
|
`),process.stderr.write(` ${g(s.description)}
|
|
1302
1305
|
`),process.stderr.write(g(` strategy: ${s.strategy}`)+(s.timeout?g(`, timeout: ${s.timeout}s`):"")+`
|
|
1303
1306
|
|
|
1304
1307
|
`);process.stderr.write(`
|
|
1305
|
-
`)}function
|
|
1306
|
-
`+
|
|
1308
|
+
`)}function Jy(e,t){let{config:r,dappDir:n}=cs(),s=R(e,"all"),o=x(e,"suite"),i=s?jo(n,o):(()=>{let a=jl(n,o);return a?[a]:[]})();if(t){D(s?{dapp:r.name,results:i}:i[0]??{});return}if(process.stderr.write(`
|
|
1309
|
+
`+B(`Results: ${r.name}`)+`
|
|
1307
1310
|
|
|
1308
1311
|
`),i.length===0)process.stderr.write(g(` No test results found.
|
|
1309
1312
|
`)),process.stderr.write(g(` Run "midnight test run" to generate results.
|
|
1310
|
-
`));else for(let a of i){let c=a.status==="pass"?
|
|
1313
|
+
`));else for(let a of i){let c=a.status==="pass"?W("✓"):ce("✗"),d=a.status==="pass"?W(P("PASS")):ce(P("FAIL"));process.stderr.write(` ${c} ${P(a.suite)} — ${d} (${a.duration}s)
|
|
1311
1314
|
`),process.stderr.write(g(` ${a.timestamp} | ${a.network} | ${a.strategy}`)+`
|
|
1312
|
-
`);let u=a.prep.filter((f)=>f.status==="fail");if(u.length>0)process.stderr.write(
|
|
1313
|
-
`);let l=a.assertions.filter((f)=>f.status==="fail");if(l.length>0)process.stderr.write(
|
|
1315
|
+
`);let u=a.prep.filter((f)=>f.status==="fail");if(u.length>0)process.stderr.write(ce(` prep: ${u.length} failed`)+`
|
|
1316
|
+
`);let l=a.assertions.filter((f)=>f.status==="fail");if(l.length>0)process.stderr.write(ce(` assertions: ${l.length} failed`)+`
|
|
1314
1317
|
`);process.stderr.write(`
|
|
1315
1318
|
`)}process.stderr.write(`
|
|
1316
|
-
`)}function
|
|
1319
|
+
`)}function qy(e){if(e<1000)return`${e}ms`;return`${(e/1000).toFixed(1)}s`}var Ou;var Uu=T(()=>{Oe();ue();dt();Al();_l();Fl();Ul();Hl();Gl();Ou=["run","list","results","create"]});import{readFileSync as Wu}from"node:fs";import{fileURLToPath as Hu}from"node:url";import{Server as zy}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as Yy}from"@modelcontextprotocol/sdk/server/stdio.js";import{ListToolsRequestSchema as Xy,CallToolRequestSchema as Zy,ListResourcesRequestSchema as Qy,ReadResourceRequestSchema as eS}from"@modelcontextprotocol/sdk/types.js";async function z(e,t,r){let n=[];gs((s)=>n.push(s));try{if(t.flags.json=!0,!(on in t.flags))t.flags[on]=!0;await e(t,r);let s=n.join("").trim();if(!s)return{};return JSON.parse(s)}finally{gs(null)}}Oe();var Zu=1,ci=2,Qu=3,cn=4,hs=5,Ht=6,ep=7,oe={INVALID_ARGS:"INVALID_ARGS",WALLET_NOT_FOUND:"WALLET_NOT_FOUND",NETWORK_ERROR:"NETWORK_ERROR",INSUFFICIENT_BALANCE:"INSUFFICIENT_BALANCE",TX_REJECTED:"TX_REJECTED",STALE_UTXO:"STALE_UTXO",STALE_CACHE:"STALE_CACHE",PROOF_TIMEOUT:"PROOF_TIMEOUT",PROOF_FAILURE:"PROOF_FAILURE",INVALID_DUST_PROOF:"INVALID_DUST_PROOF",DUST_REQUIRED:"DUST_REQUIRED",DUST_GENERATING:"DUST_GENERATING",CHAIN_CLOCK_BEHIND:"CHAIN_CLOCK_BEHIND",SYNC_TIMEOUT:"SYNC_TIMEOUT",CANCELLED:"CANCELLED",UNSUPPORTED_LEDGER:"UNSUPPORTED_LEDGER",LOCALNET_UNAVAILABLE:"LOCALNET_UNAVAILABLE",LOCAL_STACK_UNREACHABLE:"LOCAL_STACK_UNREACHABLE",AMBIGUOUS_LOCAL_STACKS:"AMBIGUOUS_LOCAL_STACKS",UNKNOWN:"UNKNOWN"},tp=new Set([oe.UNSUPPORTED_LEDGER,oe.LOCALNET_UNAVAILABLE,oe.LOCAL_STACK_UNREACHABLE,oe.AMBIGUOUS_LOCAL_STACKS]);function di(e){if(ai(e))return{exitCode:ci,errorCode:oe.INVALID_ARGS};let t=e.code;if(typeof t==="string"&&tp.has(t))return{exitCode:cn,errorCode:t};if(t===oe.DUST_GENERATING)return{exitCode:hs,errorCode:oe.DUST_GENERATING};if(t===oe.CHAIN_CLOCK_BEHIND)return{exitCode:cn,errorCode:oe.CHAIN_CLOCK_BEHIND};let r=(e.message??"").toLowerCase();if(r.includes("operation cancelled")||r.includes("operation aborted")||r==="cancelled"||r==="aborted")return{exitCode:ep,errorCode:oe.CANCELLED};if(r.includes("wallet file not found")||r.includes("wallet")&&r.includes("not found"))return{exitCode:Qu,errorCode:oe.WALLET_NOT_FOUND};if(r.includes("missing required flag")||r.includes("missing amount")||r.includes("missing recipient")||r.includes("missing config key")||r.includes("missing or invalid subcommand")||r.includes("unknown command")||r.includes("cannot specify both")||r.includes("invalid bip-39")||r.includes("seed must be")||r.includes("key index must be")||r.includes("shielded balances are private")||r.includes("shielded is unavailable")||r.includes("belongs to")&&r.includes("--network is")||r.includes("usage:"))return{exitCode:ci,errorCode:oe.INVALID_ARGS};if(r.includes("proof")&&r.includes("timeout"))return{exitCode:Ht,errorCode:oe.PROOF_TIMEOUT};if(r.includes("stale utxo")||r.includes("error code 115")||r.includes("errorcode: 115"))return{exitCode:Ht,errorCode:oe.STALE_UTXO};if(r.includes("error 170")||r.includes("errorcode: 170")||r.includes("invaliddustspendproof"))return{exitCode:Ht,errorCode:oe.INVALID_DUST_PROOF};if(r.includes("stale cache")||r.includes("chain reset")||r.includes("chainid mismatch")||r.includes("applied > highest"))return{exitCode:Ht,errorCode:oe.STALE_CACHE};if(r.includes("failed to prove"))return{exitCode:Ht,errorCode:oe.PROOF_FAILURE};if(r.includes("wallet sync timed out")||r.includes("sync timed out")||r.includes("timed out waiting for dust")||r.includes("did not respond within")||r.includes("did not produce a block")||r.includes("did not report funds"))return{exitCode:cn,errorCode:oe.SYNC_TIMEOUT};if(r.includes("no dust")||r.includes("dust")&&(r.includes("required")||r.includes("available")||r.includes("insufficient")))return{exitCode:hs,errorCode:oe.DUST_REQUIRED};if(r.includes("insufficient")||r.includes("not enough"))return{exitCode:hs,errorCode:oe.INSUFFICIENT_BALANCE};if(r.includes("rejected")||r.includes("transaction failed"))return{exitCode:Ht,errorCode:oe.TX_REJECTED};if(r.includes("econnrefused")||r.includes("enotfound")||r.includes("etimedout")||r.includes("websocket")||r.includes("connection refused")||r.includes("request to ")&&r.includes(" failed, reason:")||r.includes("network")&&r.includes("error"))return{exitCode:cn,errorCode:oe.NETWORK_ERROR};return{exitCode:Zu,errorCode:oe.UNKNOWN}}function li(e){let t=e.split(`
|
|
1317
1320
|
|
|
1318
1321
|
`)[0].trim(),r=t.split(`
|
|
1319
1322
|
`),n=[];for(let s of r){if(/(?:^|\s)(midnight|mn)\s+[a-z]/i.test(s))break;if(/^(Try|Run|See|Open):\s/i.test(s.trim()))break;n.push(s)}return n.join(`
|
|
1320
|
-
`).trim()||t}var nn={name:"midnight-wallet-cli",version:"0.6.0-rc.2",type:"module",description:"Git-style CLI wallet for the Midnight blockchain",license:"Apache-2.0",author:"Norman Lopez (https://github.com/nel349)",homepage:"https://github.com/nel349/midnight-wallet-cli#readme",repository:{type:"git",url:"git+https://github.com/nel349/midnight-wallet-cli.git"},bugs:{url:"https://github.com/nel349/midnight-wallet-cli/issues"},keywords:["midnight","blockchain","wallet","cli","zk","zero-knowledge","compact","mcp","ai-agent"],workspaces:["packages/connector"],bin:{midnight:"dist/wallet.js",mn:"dist/wallet.js","midnight-wallet-cli":"dist/wallet.js","midnight-wallet-mcp":"dist/mcp-server.js"},files:["dist","docs/SKILL.md","docs/SKILL-CORE.md","NOTICE"],engines:{node:">=20",bun:">=1.3.0"},scripts:{wallet:"tsx src/wallet.ts",build:'bun build src/wallet.ts --outfile dist/wallet.js --target node --format esm --packages external --minify --banner "#!/usr/bin/env node" && bun build src/mcp-server.ts --outfile dist/mcp-server.js --target node --format esm --packages external --minify --banner "#!/usr/bin/env node"',mcp:"tsx src/mcp-server.ts",link:"bun link",prepublishOnly:"npm run build && npm run test",test:"vitest run","test:watch":"vitest",typecheck:"tsc --noEmit"},dependencies:{"@midnight-ntwrk/compact-runtime":"0.20.0","@midnight-ntwrk/ledger-v8":"^8.1.0","@midnight-ntwrk/midnight-js-contracts":"5.0.0-rc.1","@midnight-ntwrk/midnight-js-http-client-proof-provider":"5.0.0-rc.1","@midnight-ntwrk/midnight-js-indexer-public-data-provider":"5.0.0-rc.1","@midnight-ntwrk/midnight-js-level-private-state-provider":"5.0.0-rc.1","@midnight-ntwrk/midnight-js-network-id":"5.0.0-rc.1","@midnight-ntwrk/midnight-js-node-zk-config-provider":"5.0.0-rc.1","@midnight-ntwrk/midnight-js-protocol":"5.0.0-rc.1","@midnight-ntwrk/midnight-js-types":"5.0.0-rc.1","@midnight-ntwrk/midnight-js-utils":"5.0.0-rc.1","@midnightntwrk/dapp-connector-api":"4.1.0-beta.1","@midnightntwrk/ledger-v9":"1.0.0-rc.5","@midnightntwrk/onchain-runtime-v4":"4.0.0-rc.3","@midnightntwrk/wallet-sdk":"2.0.0-rc.0","@modelcontextprotocol/sdk":"^1.27.1","@scure/bip39":"^2.0.1",rxjs:"^7.8.1",ws:"^8.19.0"},devDependencies:{"@types/node":"^22.19.13","@types/ws":"^8.18.1",tsx:"^4.21.0",typescript:"^5.9.3",vitest:"^3.2.4"}};var By=nn.name,ds=nn.version,jy=nn.description;import{randomUUID as _u}from"node:crypto";var Pu=300000;function zo(e={}){let t=e.ttlMs??Pu,r=e.now??(()=>Date.now()),n=new Map,s=(o)=>{let i=0;for(let[a,c]of n)if(c.expiresAt<=o)n.delete(a),i+=1;return i};return{create(o){let i=r();s(i);let a=_u(),c={token:a,tool:o.tool,args:o.args,description:o.description,createdAt:i,expiresAt:i+t};return n.set(a,c),c},redeem(o){let i=n.get(o);if(!i)return null;if(i.expiresAt<=r())return n.delete(o),null;return n.delete(o),i},sweep(o=r()){return s(o)},size(){return n.size}}}import $u from"node:v8";import Ou from"node:os";import{spawn as Mu}from"node:child_process";var Ss="MN_HEAP_BUMPED",Fu="MN_MAX_OLD_SPACE_MB",pi=1048576;function Lu(e){let t=e.desiredMb??ni,r=e.ramFraction??si,n=e.minGainMb??oi;if(!Number.isFinite(t)||t<=0)return null;if(!Number.isFinite(e.totalMb)||e.totalMb<=0)return null;let s=Math.floor(e.totalMb*r),o=Math.min(Math.floor(t),s);if(o<=e.currentLimitMb+n)return null;return o}async function fi(){if(process.env[Ss]){Wu();return}let e=process.env[Fu],t=e!==void 0?Number(e):void 0,r=Lu({totalMb:Math.floor(Ou.totalmem()/pi),currentLimitMb:Math.floor($u.getHeapStatistics().heap_size_limit/pi),desiredMb:t});if(r===null)return;return new Promise((n)=>{let s=Mu(process.execPath,[`--max-old-space-size=${r}`,...process.execArgv,process.argv[1],...process.argv.slice(2)],{stdio:"inherit",env:{...process.env,[Ss]:"1"}});Uu(s),s.on("error",()=>{process.env[Ss]="1",n()}),s.on("exit",(o,i)=>process.exit(i?1:o??0))})}function Uu(e,t=(r,n)=>{process.on(r,n)}){let r=["SIGINT","SIGTERM","SIGHUP"];for(let n of r)t(n,()=>{try{e.kill(n)}catch{}});t("exit",()=>{try{e.kill("SIGKILL")}catch{}})}function Wu(){let e=process.ppid;if(!e||e<=1)return;setInterval(()=>{if(process.ppid!==e)try{process.kill(process.pid,"SIGTERM")}catch{process.exit(0)}},2000).unref()}var ku="midnight-wallet://skill/core",Cu="midnight-wallet://skill/full",Cy="midnight-wallet://skill",Ey=vu(new URL("../docs/SKILL-CORE.md",import.meta.url)),xy=vu(new URL("../docs/SKILL.md",import.meta.url));function ye(e,t,r){let n={json:!0},s=[];for(let[o,i]of Object.entries(t)){if(i===void 0||i===null)continue;let a=o==="full"?gr:o;if(typeof i==="boolean"){if(i)n[a]=!0}else n[a]=String(i)}return{command:e,subcommand:r,positionals:s,flags:n}}var Ay={generate:()=>Promise.resolve().then(() => (Fi(),Mi)),info:()=>Promise.resolve().then(() => (Wi(),Ui)),balance:()=>Promise.resolve().then(() => (Ba(),Wa)),address:()=>Promise.resolve().then(() => (Ga(),Ha)),"genesis-address":()=>Promise.resolve().then(() => (Ja(),Va)),"inspect-cost":()=>Promise.resolve().then(() => (Ya(),Xa)),airdrop:()=>Promise.resolve().then(() => (rc(),tc)),transfer:()=>Promise.resolve().then(() => (ac(),ic)),dust:()=>Promise.resolve().then(() => (pc(),uc)),cache:()=>Promise.resolve().then(() => (gc(),mc)),config:()=>Promise.resolve().then(() => (yc(),wc)),localnet:()=>Promise.resolve().then(() => (Lc(),Fc)),wallet:()=>Promise.resolve().then(() => (Hc(),jc)),status:()=>Promise.resolve().then(() => (zc(),qc)),contract:()=>Promise.resolve().then(() => (Xd(),zd)),test:()=>Promise.resolve().then(() => (wu(),hu))};async function z(e){let t=Ay[e];if(!t)throw Error(`Unknown command handler: ${e}`);return(await t()).default}var Eu=[{name:"midnight_wallet_generate",description:"Create wallet.",annotations:{destructiveHint:!0},inputSchema:{type:"object",properties:{name:{type:"string"},network:{type:"string",enum:["preprod","preview","undeployed"]},seed:{type:"string",description:"64 or 128 hex chars (32-byte raw or 64-byte BIP-39)"},mnemonic:{type:"string",description:"BIP-39 24 words"},force:{type:"string"}},required:["name"]},async handler(e){let t=e.name,r=ye("wallet",e,"generate");if(r.positionals=[t],delete r.flags.name,e.force==="true"||e.force===!0)r.flags.force=!0;let n=await z("wallet");return J(n,r)}},{name:"midnight_wallet_list",description:"List wallets. Default: per-wallet { name, active, network, address, shieldedAddress } scoped to the active network. Pass { full: true } for the 3-network addresses + shieldedAddresses maps.",annotations:{readOnlyHint:!0,idempotentHint:!0},inputSchema:{type:"object",properties:{full:{type:"boolean",description:"Return full per-network addresses + shieldedAddresses maps (the same shape `mn wallet list --json` emits). Default false (slim)."}}},async handler({full:e}={}){let t={json:!0};if(e)t[gr]=!0;let r={command:"wallet",subcommand:"list",positionals:[],flags:t},n=await z("wallet");return J(n,r)}},{name:"midnight_wallet_use",description:"Set active wallet.",annotations:{idempotentHint:!0},inputSchema:{type:"object",properties:{name:{type:"string"}},required:["name"]},async handler(e){let r={command:"wallet",subcommand:"use",positionals:[e.name],flags:{json:!0}},n=await z("wallet");return J(n,r)}},{name:"midnight_wallet_info",description:"Show wallet details. Default: { name, active, network, address, shieldedAddress } scoped to the active network. Pass { full: true } for the per-network maps + createdAt + file path.",annotations:{readOnlyHint:!0,idempotentHint:!0},inputSchema:{type:"object",properties:{name:{type:"string"},full:{type:"boolean",description:"Return the full per-network addresses + shieldedAddresses maps and bookkeeping fields (matches `mn wallet info <name> --json`). Default false (slim)."}}},async handler(e){let{name:t,full:r}=e,n={json:!0};if(r)n[gr]=!0;let s={command:"wallet",subcommand:"info",positionals:t?[t]:[],flags:n},o=await z("wallet");return J(o,s)}},{name:"midnight_wallet_remove",description:"Remove wallet.",annotations:{destructiveHint:!0},inputSchema:{type:"object",properties:{name:{type:"string"}},required:["name"]},async handler(e){let r={command:"wallet",subcommand:"remove",positionals:[e.name],flags:{json:!0}},n=await z("wallet");return J(n,r)}},{name:"midnight_info",description:"Wallet metadata.",annotations:{readOnlyHint:!0,idempotentHint:!0},inputSchema:{type:"object",properties:{wallet:{type:"string"}}},async handler(e){let t=ye("info",e),r=await z("info");return J(r,t)}},{name:"midnight_balance",description:"NIGHT balance. Default: { network, unshielded, shielded } — no echoed addresses. Pass { full: true } for the human shape including address + shieldedAddress.",annotations:{readOnlyHint:!0,openWorldHint:!0},inputSchema:{type:"object",properties:{address:{type:"string"},wallet:{type:"string"},network:{type:"string",enum:["preprod","preview","undeployed"]},"indexer-ws":{type:"string"},full:{type:"boolean",description:"Include the queried address + shieldedAddress in the response (matches `mn balance --json`). Default false (slim)."}}},async handler(e){let t=e.address,r=ye("balance",e,t);delete r.flags.address;let n=await z("balance");return J(n,r)}},{name:"midnight_address",description:"Derive address from seed.",annotations:{readOnlyHint:!0,idempotentHint:!0},inputSchema:{type:"object",properties:{seed:{type:"string",description:"64 or 128 hex chars (32-byte raw or 64-byte BIP-39)"},network:{type:"string",enum:["preprod","preview","undeployed"]},index:{type:"string"}},required:["seed"]},async handler(e){let t=ye("address",e),r=await z("address");return J(r,t)}},{name:"midnight_genesis_address",description:"Genesis address.",annotations:{readOnlyHint:!0,idempotentHint:!0},inputSchema:{type:"object",properties:{network:{type:"string",enum:["preprod","preview","undeployed"]}}},async handler(e){let t=ye("genesis-address",e),r=await z("genesis-address");return J(r,t)}},{name:"midnight_inspect_cost",description:"Block limits.",annotations:{readOnlyHint:!0,idempotentHint:!0},inputSchema:{type:"object",properties:{}},async handler(){let e=ye("inspect-cost",{}),t=await z("inspect-cost");return J(t,e)}},{name:"midnight_airdrop",description:'Fund from genesis (undeployed). `wallet` accepts a wallet name, a wallet JSON path, or a raw bech32m address (mn_addr_… or mn_shield-addr_…). Add `shielded: "true"` to fund a shielded balance.',annotations:{destructiveHint:!0,openWorldHint:!0},inputSchema:{type:"object",properties:{amount:{type:"string",description:"NIGHT"},wallet:{type:"string",description:"Destination: wallet name, JSON path, or bech32m address"},shielded:{type:"string",description:'Set to "true" for shielded airdrop'}},required:["amount"]},async handler(e){let t=e.amount,r=ye("airdrop",e,t);delete r.flags.amount;let n=await z("airdrop");return J(n,r)}},{name:"midnight_transfer",description:"Send NIGHT (returns pending token; see skill).",annotations:{destructiveHint:!0,openWorldHint:!0},inputSchema:{type:"object",properties:{to:{type:"string",description:"bech32m"},amount:{type:"string",description:"NIGHT"},wallet:{type:"string"}},required:["to","amount"]},async handler(e){let{to:t,amount:r}=e,n=ye("transfer",e,t);n.positionals=[r],delete n.flags.to,delete n.flags.amount;let s=await z("transfer");return J(s,n)}},{name:"midnight_dust_register",description:"Register for dust.",annotations:{destructiveHint:!0,openWorldHint:!0},inputSchema:{type:"object",properties:{wallet:{type:"string"}}},async handler(e){let t=ye("dust",e,"register"),r=await z("dust");return J(r,t)}},{name:"midnight_dust_status",description:"Dust status. Default: { network, registered, registeredUtxos, unregisteredUtxos, dustBalance, dustAvailable }. Pass { full: true } for sync internals (eventsApplied, ownedUtxos, cached).",annotations:{readOnlyHint:!0,openWorldHint:!0},inputSchema:{type:"object",properties:{wallet:{type:"string"},"proof-server":{type:"string"},node:{type:"string"},"indexer-ws":{type:"string"},"no-cache":{type:"string"},full:{type:"boolean",description:"Include sync internals (eventsApplied, ownedUtxos, cached) in the response (matches `mn dust status --json`). Default false (slim)."}}},async handler(e){let t=ye("dust",e,"status"),r=await z("dust");return J(r,t)}},{name:"midnight_config_get",description:"Read config.",annotations:{readOnlyHint:!0,idempotentHint:!0},inputSchema:{type:"object",properties:{key:{type:"string"}},required:["key"]},async handler(e){let r={command:"config",subcommand:"get",positionals:[e.key],flags:{json:!0}},n=await z("config");return J(n,r)}},{name:"midnight_config_set",description:"Write config.",annotations:{idempotentHint:!0},inputSchema:{type:"object",properties:{key:{type:"string"},value:{type:"string"}},required:["key","value"]},async handler(e){let{key:t,value:r}=e,n={command:"config",subcommand:"set",positionals:[t,r],flags:{json:!0}},s=await z("config");return J(s,n)}},{name:"midnight_cache_clear",description:"Clear sync cache.",annotations:{destructiveHint:!0,idempotentHint:!0},inputSchema:{type:"object",properties:{network:{type:"string",enum:["preprod","preview","undeployed"]},wallet:{type:"string"}}},async handler(e){let t=ye("cache",e,"clear"),r=await z("cache");return J(r,t)}},{name:"midnight_config_unset",description:"Reset config.",annotations:{idempotentHint:!0},inputSchema:{type:"object",properties:{key:{type:"string"}},required:["key"]},async handler(e){let r={command:"config",subcommand:"unset",positionals:[e.key],flags:{json:!0}},n=await z("config");return J(n,r)}},{name:"midnight_localnet_up",description:"Refused on this ledger-9 build: mn's localnet is ledger 8 and no ledger-9 indexer image is published. Run a ledger-9 stack yourself and point mn at it (config_set node / indexer-ws / proof-server).",annotations:{openWorldHint:!0},inputSchema:{type:"object",properties:{}},async handler(){let e={command:"localnet",subcommand:"up",positionals:[],flags:{json:!0}},t=await z("localnet");return J(t,e)}},{name:"midnight_localnet_stop",description:"Stop localnet (preserves state).",annotations:{idempotentHint:!0,openWorldHint:!0},inputSchema:{type:"object",properties:{}},async handler(){let e={command:"localnet",subcommand:"stop",positionals:[],flags:{json:!0}},t=await z("localnet");return J(t,e)}},{name:"midnight_localnet_down",description:"Localnet teardown (volumes + undeployed cache).",annotations:{destructiveHint:!0,openWorldHint:!0},inputSchema:{type:"object",properties:{}},async handler(){let e={command:"localnet",subcommand:"down",positionals:[],flags:{json:!0}},t=await z("localnet");return J(t,e)}},{name:"midnight_localnet_status",description:"Localnet status.",annotations:{readOnlyHint:!0,openWorldHint:!0},inputSchema:{type:"object",properties:{}},async handler(){let e={command:"localnet",subcommand:"status",positionals:[],flags:{json:!0}},t=await z("localnet");return J(t,e)}},{name:"midnight_localnet_clean",description:"Remove stray containers.",annotations:{destructiveHint:!0,openWorldHint:!0},inputSchema:{type:"object",properties:{}},async handler(){let e={command:"localnet",subcommand:"clean",positionals:[],flags:{json:!0}},t=await z("localnet");return J(t,e)}},{name:"midnight_contract_inspect",description:"Inspect a compiled Compact contract: name, circuits (with arg/return types), witnesses, compiler/language/runtime versions. Reads managed/<name>/compiler/contract-info.json under the dapp dir. Returns a `siblings` array listing other contracts in the same project — call again with `name` to inspect a sibling.",annotations:{readOnlyHint:!0,idempotentHint:!0},inputSchema:{type:"object",properties:{path:{type:"string",description:"Path to dApp directory (defaults to cwd)"},managed:{type:"string",description:"Direct path to a managed/<name>/ directory (overrides path)"},name:{type:"string",description:"Specific contract name to inspect when the project has multiple (see siblings field)"}}},async handler(e){let t=ye("contract",e,"inspect"),r=await z("contract");return J(r,t)}},{name:"midnight_contract_state",description:"Read the current ledger state of a deployed contract. Returns the ledger fields as a JSON object.",annotations:{readOnlyHint:!0,openWorldHint:!0},inputSchema:{type:"object",properties:{address:{type:"string",description:"Contract address (hex)"},wallet:{type:"string"},network:{type:"string",enum:["preprod","preview","undeployed"]},path:{type:"string",description:"dApp directory (defaults to cwd; needed to find the compiled artifact for state decoding)"},managed:{type:"string",description:"Direct path to a managed/<name>/ directory (overrides path-based contract scan)"},name:{type:"string",description:"Specific contract name when the project has multiple"}},required:["address"]},async handler(e){let t=ye("contract",e,"state"),r=await z("contract");return J(r,t)}},{name:"midnight_contract_deploy",description:"Deploy a compiled Compact contract (returns pending token; agent must show the description and redeem via midnight_confirm_operation).",annotations:{destructiveHint:!0,openWorldHint:!0},inputSchema:{type:"object",properties:{wallet:{type:"string"},network:{type:"string",enum:["preprod","preview","undeployed"]},args:{type:"string",description:"JSON-encoded array or object of constructor arguments"},path:{type:"string",description:"dApp directory (defaults to cwd)"},managed:{type:"string",description:"Direct path to a managed/<name>/ directory (overrides path-based contract scan)"},name:{type:"string",description:"Specific contract name when the project has multiple"}}},async handler(e){let t=ye("contract",e,"deploy"),r=await z("contract");return J(r,t)}},{name:"midnight_contract_call",description:"Call a circuit on a deployed contract (returns pending token; agent must show the description and redeem via midnight_confirm_operation).",annotations:{destructiveHint:!0,openWorldHint:!0},inputSchema:{type:"object",properties:{address:{type:"string",description:"Contract address (hex)"},circuit:{type:"string",description:"Circuit name to invoke"},wallet:{type:"string"},network:{type:"string",enum:["preprod","preview","undeployed"]},args:{type:"string",description:"JSON-encoded array or object of circuit arguments"},path:{type:"string",description:"dApp directory (defaults to cwd)"},managed:{type:"string",description:"Direct path to a managed/<name>/ directory (overrides path-based contract scan)"},name:{type:"string",description:"Specific contract name when the project has multiple"}},required:["address","circuit"]},async handler(e){let t=ye("contract",e,"call"),r=await z("contract");return J(r,t)}},{name:"midnight_test_create",description:"Generate a test scaffold for the contract. Two paths: (1) AI-assisted — pass `goal` (and optionally `screen` for UI strategy) and the scaffold is generated by Claude reading the contract + screen source, producing a focused suite with realistic args / on-screen labels. (2) Deterministic — pass `no-ai: true` (or omit goal/screen in non-interactive mode) for boilerplate scaffolds that the user reviews. CLI strategy emits dapp.test.json + tests/suites/<name>/{suite,actions,assertions}.json. Browser strategy emits prompt.md instead of actions.json plus the browser fields in dapp.test.json — required: port, build-cmd. Use force:true to overwrite.",annotations:{destructiveHint:!0},inputSchema:{type:"object",properties:{path:{type:"string",description:"dApp directory (defaults to cwd)"},name:{type:"string",description:"Specific contract name when the project has multiple"},suite:{type:"string",description:"Suite directory name under tests/suites/ (auto-derived from circuit/screen when AI scaffolds)"},strategy:{type:"string",enum:["cli","browser"],description:"cli (default): drive contracts via actions.json. browser: drive a real UI via Claude + Chrome via prompt.md."},network:{type:"string",enum:["preprod","preview","undeployed"]},goal:{type:"string",description:'AI mode: one-line success criterion this suite should verify (e.g. "round goes from 0 to 1 after increment"). Triggers AI scaffolding.'},screen:{type:"string",description:'AI mode + browser strategy: name of the screen component to focus on (e.g. "loan-request-form" or "LoanRequestForm"). Auto-discovered from src/components, src/pages, src/screens.'},"no-ai":{type:"boolean",description:"Force deterministic scaffolder even when claude CLI is available."},port:{type:"string",description:'Browser strategy only — dev server port (e.g. "4173").'},"build-cmd":{type:"string",description:'Browser strategy only — shell command that builds + serves the UI (e.g. "npm run dev").'},"build-dir":{type:"string",description:"Browser strategy only — subdir the build runs in (monorepo case)."},url:{type:"string",description:"Browser strategy only — full URL Claude opens (default http://localhost:<port>/)."},"browser-mode":{type:"string",enum:["dom","vision","script"],description:"Browser strategy only — how Claude perceives the page. dom (HTML/React UIs, fast, needs chrome-devtools-mcp), vision (canvas games, slow), script (advanced, needs hooks). Default: dom for AI scaffolds."},force:{type:"boolean",description:"Overwrite existing files instead of aborting on collision"}}},async handler(e){let t=ye("test",e,"create"),r=await z("test");return J(r,t)}},{name:"midnight_localnet_logs",description:"Snapshot of recent localnet logs (last N lines per service, no streaming). Returns { tail, lines: string[] }.",annotations:{readOnlyHint:!0,openWorldHint:!0},inputSchema:{type:"object",properties:{tail:{type:"string",description:"Number of lines to retrieve (default 200)"}}},async handler(e){let t=ye("localnet",e,"logs");if(!t.flags.tail)t.flags.tail="200";let r=await z("localnet");return J(r,t)}},{name:"midnight_confirm_operation",description:"Redeem a pending token (confirm step).",annotations:{destructiveHint:!0,openWorldHint:!0},inputSchema:{type:"object",properties:{token:{type:"string"}},required:["token"]},async handler(){throw Error("midnight_confirm_operation reached the inner handler — this is an MCP wiring bug")}}],Ty=new Set(["midnight_transfer","midnight_contract_deploy","midnight_contract_call"]),Su=zo();function Ny(e,t){let r=t.network??"active network",n=t.wallet??"active wallet";switch(e){case"midnight_transfer":return`Send ${t.amount} NIGHT from ${n} to ${t.to} on ${r}`;case"midnight_contract_deploy":{let s=t.args?` with args ${t.args}`:"";return`Deploy contract from ${t.path??"current directory"} as ${n} on ${r}${s}`}case"midnight_contract_call":{let s=t.args?` with args ${t.args}`:"";return`Call circuit ${t.circuit} on contract ${t.address} as ${n} on ${r}${s}`}default:return`Execute ${e} with ${JSON.stringify(t)}`}}var Qr=new wy({name:"midnight-wallet-cli",version:ds},{capabilities:{tools:{},resources:{}}});Qr.setRequestHandler(vy,async()=>({resources:[{uri:ku,name:"midnight-wallet skill (core)",description:"Read this first. Intent routing table + non-negotiable safety rules. ~830 tokens. Fetch /full on demand for canonical flows, error recovery, and concept primers.",mimeType:"text/markdown"},{uri:Cu,name:"midnight-wallet skill (full)",description:"Canonical multi-step flows, error-recovery recipes, concept primers (NIGHT/DUST/shielded), network selection. Fetch on demand when you hit an error, start a multi-step flow, or need to explain a concept.",mimeType:"text/markdown"}]}));Qr.setRequestHandler(ky,async(e)=>{let t=e.params.uri;if(t===ku){let r=yu(Ey,"utf-8");return{contents:[{uri:t,mimeType:"text/markdown",text:r}]}}if(t===Cu||t===Cy){let r=yu(xy,"utf-8");return{contents:[{uri:t,mimeType:"text/markdown",text:r}]}}throw Error(`Unknown resource: ${t}`)});Qr.setRequestHandler(Sy,async()=>({tools:Eu.map((e)=>({name:e.name,description:e.description,inputSchema:e.inputSchema,...e.annotations?{annotations:e.annotations}:{}}))}));Qr.setRequestHandler(by,async(e)=>{let{name:t,arguments:r}=e.params,n=r??{};if(t==="midnight_confirm_operation"){let s=typeof n.token==="string"?n.token:"",o=Su.redeem(s);if(!o)return Ho(Error("Unknown or expired confirmation token. The first-step tool call may need to be re-issued."));return bu(o.tool,o.args)}if(Ty.has(t)){let s=Su.create({tool:t,args:n,description:Ny(t,n)});return{content:[{type:"text",text:JSON.stringify(Go({pending:!0,token:s.token,description:s.description,tool:s.tool,expiresAt:new Date(s.expiresAt).toISOString(),nextStep:"Show the description to the user, get explicit consent, then call midnight_confirm_operation with this token."}),null,2)}]}}return bu(t,n)});function Go(e){return{...e,_serverVersion:ds}}async function bu(e,t){let r=Eu.find((n)=>n.name===e);if(!r)return Ho(Error(`Unknown tool: ${e}`));try{let n=await r.handler(t);return{content:[{type:"text",text:JSON.stringify(Go(n),null,2)}]}}catch(n){return Ho(n instanceof Error?n:Error(String(n)))}}function Ho(e){let{errorCode:t}=Jo(e);return{content:[{type:"text",text:JSON.stringify(Go({error:!0,code:t,message:qo(e.message)}))}],isError:!0}}async function Ry(){await fi();let e=new yy;await Qr.connect(e)}Ry().catch((e)=>{process.stderr.write(`MCP server error: ${e.message}
|
|
1323
|
+
`).trim()||t}var dn={name:"midnight-wallet-cli",version:"0.6.0-rc.3",type:"module",description:"Git-style CLI wallet for the Midnight blockchain",license:"Apache-2.0",author:"Norman Lopez (https://github.com/nel349)",homepage:"https://github.com/nel349/midnight-wallet-cli#readme",repository:{type:"git",url:"git+https://github.com/nel349/midnight-wallet-cli.git"},bugs:{url:"https://github.com/nel349/midnight-wallet-cli/issues"},keywords:["midnight","blockchain","wallet","cli","zk","zero-knowledge","compact","mcp","ai-agent"],workspaces:["packages/connector"],bin:{midnight:"dist/wallet.js",mn:"dist/wallet.js","midnight-wallet-cli":"dist/wallet.js","midnight-wallet-mcp":"dist/mcp-server.js"},files:["dist","docs/SKILL.md","docs/SKILL-CORE.md","NOTICE"],engines:{node:">=20",bun:">=1.3.0"},scripts:{wallet:"tsx src/wallet.ts",build:'bun build src/wallet.ts --outfile dist/wallet.js --target node --format esm --packages external --minify --banner "#!/usr/bin/env node" && bun build src/mcp-server.ts --outfile dist/mcp-server.js --target node --format esm --packages external --minify --banner "#!/usr/bin/env node"',mcp:"tsx src/mcp-server.ts",link:"bun link",prepublishOnly:"npm run build && npm run test",test:"vitest run","test:watch":"vitest",typecheck:"tsc --noEmit"},dependencies:{"@midnight-ntwrk/compact-runtime":"0.20.0","@midnight-ntwrk/ledger-v8":"^8.1.0","@midnight-ntwrk/midnight-js-contracts":"5.0.0-rc.1","@midnight-ntwrk/midnight-js-http-client-proof-provider":"5.0.0-rc.1","@midnight-ntwrk/midnight-js-indexer-public-data-provider":"5.0.0-rc.1","@midnight-ntwrk/midnight-js-level-private-state-provider":"5.0.0-rc.1","@midnight-ntwrk/midnight-js-network-id":"5.0.0-rc.1","@midnight-ntwrk/midnight-js-node-zk-config-provider":"5.0.0-rc.1","@midnight-ntwrk/midnight-js-protocol":"5.0.0-rc.1","@midnight-ntwrk/midnight-js-types":"5.0.0-rc.1","@midnight-ntwrk/midnight-js-utils":"5.0.0-rc.1","@midnightntwrk/dapp-connector-api":"4.1.0-beta.1","@midnightntwrk/ledger-v9":"1.0.0-rc.5","@midnightntwrk/onchain-runtime-v4":"4.0.0-rc.3","@midnightntwrk/wallet-sdk":"2.0.0-rc.0","@modelcontextprotocol/sdk":"^1.27.1","@scure/bip39":"^2.0.1",rxjs:"^7.8.1",ws:"^8.19.0"},devDependencies:{"@types/node":"^22.19.13","@types/ws":"^8.18.1",tsx:"^4.21.0",typescript:"^5.9.3",vitest:"^3.2.4"}};var vS=dn.name,ws=dn.version,kS=dn.description;import{randomUUID as np}from"node:crypto";var sp=300000;function ui(e={}){let t=e.ttlMs??sp,r=e.now??(()=>Date.now()),n=new Map,s=(o)=>{let i=0;for(let[a,c]of n)if(c.expiresAt<=o)n.delete(a),i+=1;return i};return{create(o){let i=r();s(i);let a=np(),c={token:a,tool:o.tool,args:o.args,description:o.description,createdAt:i,expiresAt:i+t};return n.set(a,c),c},redeem(o){let i=n.get(o);if(!i)return null;if(i.expiresAt<=r())return n.delete(o),null;return n.delete(o),i},sweep(o=r()){return s(o)},size(){return n.size}}}import op from"node:v8";import ip from"node:os";import{spawn as ap}from"node:child_process";var Ts="MN_HEAP_BUMPED",cp="MN_MAX_OLD_SPACE_MB",Ti=1048576;function dp(e){let t=e.desiredMb??Si,r=e.ramFraction??bi,n=e.minGainMb??vi;if(!Number.isFinite(t)||t<=0)return null;if(!Number.isFinite(e.totalMb)||e.totalMb<=0)return null;let s=Math.floor(e.totalMb*r),o=Math.min(Math.floor(t),s);if(o<=e.currentLimitMb+n)return null;return o}async function Ni(){if(process.env[Ts]){up();return}let e=process.env[cp],t=e!==void 0?Number(e):void 0,r=dp({totalMb:Math.floor(ip.totalmem()/Ti),currentLimitMb:Math.floor(op.getHeapStatistics().heap_size_limit/Ti),desiredMb:t});if(r===null)return;return new Promise((n)=>{let s=ap(process.execPath,[`--max-old-space-size=${r}`,...process.execArgv,process.argv[1],...process.argv.slice(2)],{stdio:"inherit",env:{...process.env,[Ts]:"1"}});lp(s),s.on("error",()=>{process.env[Ts]="1",n()}),s.on("exit",(o,i)=>process.exit(i?1:o??0))})}function lp(e,t=(r,n)=>{process.on(r,n)}){let r=["SIGINT","SIGTERM","SIGHUP"];for(let n of r)t(n,()=>{try{e.kill(n)}catch{}});t("exit",()=>{try{e.kill("SIGKILL")}catch{}})}function up(){let e=process.ppid;if(!e||e<=1)return;setInterval(()=>{if(process.ppid!==e)try{process.kill(process.pid,"SIGTERM")}catch{process.exit(0)}},2000).unref()}var Gu="midnight-wallet://skill/core",Ku="midnight-wallet://skill/full",tS="midnight-wallet://skill",rS=Hu(new URL("../docs/SKILL-CORE.md",import.meta.url)),nS=Hu(new URL("../docs/SKILL.md",import.meta.url));function ye(e,t,r){let n={json:!0},s=[];for(let[o,i]of Object.entries(t)){if(i===void 0||i===null)continue;let a=o==="full"?Sr:o;if(typeof i==="boolean"){if(i)n[a]=!0}else n[a]=String(i)}return{command:e,subcommand:r,positionals:s,flags:n}}var sS={generate:()=>Promise.resolve().then(() => (Zi(),Xi)),info:()=>Promise.resolve().then(() => (ta(),ea)),balance:()=>Promise.resolve().then(() => (sc(),nc)),address:()=>Promise.resolve().then(() => (ac(),ic)),"genesis-address":()=>Promise.resolve().then(() => (lc(),dc)),"inspect-cost":()=>Promise.resolve().then(() => (hc(),gc)),airdrop:()=>Promise.resolve().then(() => (vc(),bc)),transfer:()=>Promise.resolve().then(() => (Ac(),Ec)),dust:()=>Promise.resolve().then(() => (Ic(),Dc)),cache:()=>Promise.resolve().then(() => (_c(),Pc)),config:()=>Promise.resolve().then(() => (Fc(),Mc)),localnet:()=>Promise.resolve().then(() => (sd(),nd)),wallet:()=>Promise.resolve().then(() => (dd(),cd)),status:()=>Promise.resolve().then(() => (gd(),md)),contract:()=>Promise.resolve().then(() => (yl(),wl)),test:()=>Promise.resolve().then(() => (Uu(),Lu))};async function Y(e){let t=sS[e];if(!t)throw Error(`Unknown command handler: ${e}`);return(await t()).default}var Vu=[{name:"midnight_wallet_generate",description:"Create wallet.",annotations:{destructiveHint:!0},inputSchema:{type:"object",properties:{name:{type:"string"},network:{type:"string",enum:["preprod","preview","undeployed"]},seed:{type:"string",description:"64 or 128 hex chars (32-byte raw or 64-byte BIP-39)"},mnemonic:{type:"string",description:"BIP-39 24 words"},force:{type:"string"}},required:["name"]},async handler(e){let t=e.name,r=ye("wallet",e,"generate");if(r.positionals=[t],delete r.flags.name,e.force==="true"||e.force===!0)r.flags.force=!0;let n=await Y("wallet");return z(n,r)}},{name:"midnight_wallet_list",description:"List wallets. Default: per-wallet { name, active, network, address, shieldedAddress } scoped to the active network. Pass { full: true } for the 3-network addresses + shieldedAddresses maps.",annotations:{readOnlyHint:!0,idempotentHint:!0},inputSchema:{type:"object",properties:{full:{type:"boolean",description:"Return full per-network addresses + shieldedAddresses maps (the same shape `mn wallet list --json` emits). Default false (slim)."}}},async handler({full:e}={}){let t={json:!0};if(e)t[Sr]=!0;let r={command:"wallet",subcommand:"list",positionals:[],flags:t},n=await Y("wallet");return z(n,r)}},{name:"midnight_wallet_use",description:"Set active wallet.",annotations:{idempotentHint:!0},inputSchema:{type:"object",properties:{name:{type:"string"}},required:["name"]},async handler(e){let r={command:"wallet",subcommand:"use",positionals:[e.name],flags:{json:!0}},n=await Y("wallet");return z(n,r)}},{name:"midnight_wallet_info",description:"Show wallet details. Default: { name, active, network, address, shieldedAddress } scoped to the active network. Pass { full: true } for the per-network maps + createdAt + file path.",annotations:{readOnlyHint:!0,idempotentHint:!0},inputSchema:{type:"object",properties:{name:{type:"string"},full:{type:"boolean",description:"Return the full per-network addresses + shieldedAddresses maps and bookkeeping fields (matches `mn wallet info <name> --json`). Default false (slim)."}}},async handler(e){let{name:t,full:r}=e,n={json:!0};if(r)n[Sr]=!0;let s={command:"wallet",subcommand:"info",positionals:t?[t]:[],flags:n},o=await Y("wallet");return z(o,s)}},{name:"midnight_wallet_remove",description:"Remove wallet.",annotations:{destructiveHint:!0},inputSchema:{type:"object",properties:{name:{type:"string"}},required:["name"]},async handler(e){let r={command:"wallet",subcommand:"remove",positionals:[e.name],flags:{json:!0}},n=await Y("wallet");return z(n,r)}},{name:"midnight_info",description:"Wallet metadata.",annotations:{readOnlyHint:!0,idempotentHint:!0},inputSchema:{type:"object",properties:{wallet:{type:"string"}}},async handler(e){let t=ye("info",e),r=await Y("info");return z(r,t)}},{name:"midnight_balance",description:"NIGHT balance. Default: { network, unshielded, shielded } — no echoed addresses. Pass { full: true } for the human shape including address + shieldedAddress.",annotations:{readOnlyHint:!0,openWorldHint:!0},inputSchema:{type:"object",properties:{address:{type:"string"},wallet:{type:"string"},network:{type:"string",enum:["preprod","preview","undeployed"]},"indexer-ws":{type:"string"},full:{type:"boolean",description:"Include the queried address + shieldedAddress in the response (matches `mn balance --json`). Default false (slim)."}}},async handler(e){let t=e.address,r=ye("balance",e,t);delete r.flags.address;let n=await Y("balance");return z(n,r)}},{name:"midnight_address",description:"Derive address from seed.",annotations:{readOnlyHint:!0,idempotentHint:!0},inputSchema:{type:"object",properties:{seed:{type:"string",description:"64 or 128 hex chars (32-byte raw or 64-byte BIP-39)"},network:{type:"string",enum:["preprod","preview","undeployed"]},index:{type:"string"}},required:["seed"]},async handler(e){let t=ye("address",e),r=await Y("address");return z(r,t)}},{name:"midnight_genesis_address",description:"Genesis address.",annotations:{readOnlyHint:!0,idempotentHint:!0},inputSchema:{type:"object",properties:{network:{type:"string",enum:["preprod","preview","undeployed"]}}},async handler(e){let t=ye("genesis-address",e),r=await Y("genesis-address");return z(r,t)}},{name:"midnight_inspect_cost",description:"The chain's current block limits, from its latest block's ledger parameters.",annotations:{readOnlyHint:!0,idempotentHint:!0},inputSchema:{type:"object",properties:{network:{type:"string",description:"Network to read (default: the selected one)"}}},async handler(e){let t=ye("inspect-cost",e.network?{network:e.network}:{}),r=await Y("inspect-cost");return z(r,t)}},{name:"midnight_airdrop",description:'Fund from genesis (undeployed). `wallet` accepts a wallet name, a wallet JSON path, or a raw bech32m address (mn_addr_… or mn_shield-addr_…). Add `shielded: "true"` to fund a shielded balance.',annotations:{destructiveHint:!0,openWorldHint:!0},inputSchema:{type:"object",properties:{amount:{type:"string",description:"NIGHT"},wallet:{type:"string",description:"Destination: wallet name, JSON path, or bech32m address"},shielded:{type:"string",description:'Set to "true" for shielded airdrop'}},required:["amount"]},async handler(e){let t=e.amount,r=ye("airdrop",e,t);delete r.flags.amount;let n=await Y("airdrop");return z(n,r)}},{name:"midnight_transfer",description:"Send NIGHT (returns pending token; see skill).",annotations:{destructiveHint:!0,openWorldHint:!0},inputSchema:{type:"object",properties:{to:{type:"string",description:"bech32m"},amount:{type:"string",description:"NIGHT"},wallet:{type:"string"}},required:["to","amount"]},async handler(e){let{to:t,amount:r}=e,n=ye("transfer",e,t);n.positionals=[r],delete n.flags.to,delete n.flags.amount;let s=await Y("transfer");return z(s,n)}},{name:"midnight_dust_register",description:"Register for dust.",annotations:{destructiveHint:!0,openWorldHint:!0},inputSchema:{type:"object",properties:{wallet:{type:"string"}}},async handler(e){let t=ye("dust",e,"register"),r=await Y("dust");return z(r,t)}},{name:"midnight_dust_status",description:"Dust status. Default: { network, registered, registeredUtxos, unregisteredUtxos, dustBalance, dustAvailable }. Pass { full: true } for sync internals (eventsApplied, ownedUtxos, cached).",annotations:{readOnlyHint:!0,openWorldHint:!0},inputSchema:{type:"object",properties:{wallet:{type:"string"},"proof-server":{type:"string"},node:{type:"string"},"indexer-ws":{type:"string"},"no-cache":{type:"string"},full:{type:"boolean",description:"Include sync internals (eventsApplied, ownedUtxos, cached) in the response (matches `mn dust status --json`). Default false (slim)."}}},async handler(e){let t=ye("dust",e,"status"),r=await Y("dust");return z(r,t)}},{name:"midnight_config_get",description:"Read config.",annotations:{readOnlyHint:!0,idempotentHint:!0},inputSchema:{type:"object",properties:{key:{type:"string"},network:{type:"string",description:"For node / indexer-ws / proof-server: the network to read or write them for (default: the selected network)"}},required:["key"]},async handler(e){let r={command:"config",subcommand:"get",positionals:[e.key],flags:{json:!0,...e.network?{network:e.network}:{}}},n=await Y("config");return z(n,r)}},{name:"midnight_config_set",description:"Write config.",annotations:{idempotentHint:!0},inputSchema:{type:"object",properties:{key:{type:"string"},network:{type:"string",description:"For node / indexer-ws / proof-server: the network to read or write them for (default: the selected network)"},value:{type:"string"}},required:["key","value"]},async handler(e){let{key:t,value:r}=e,n={command:"config",subcommand:"set",positionals:[t,r],flags:{json:!0,...e.network?{network:e.network}:{}}},s=await Y("config");return z(s,n)}},{name:"midnight_cache_clear",description:"Clear sync cache.",annotations:{destructiveHint:!0,idempotentHint:!0},inputSchema:{type:"object",properties:{network:{type:"string",enum:["preprod","preview","undeployed"]},wallet:{type:"string"}}},async handler(e){let t=ye("cache",e,"clear"),r=await Y("cache");return z(r,t)}},{name:"midnight_config_unset",description:"Reset config.",annotations:{idempotentHint:!0},inputSchema:{type:"object",properties:{key:{type:"string"},network:{type:"string",description:"For node / indexer-ws / proof-server: the network to read or write them for (default: the selected network)"}},required:["key"]},async handler(e){let r={command:"config",subcommand:"unset",positionals:[e.key],flags:{json:!0,...e.network?{network:e.network}:{}}},n=await Y("config");return z(n,r)}},{name:"midnight_localnet_up",description:"Refused on this ledger-9 build: mn's localnet is ledger 8 and no ledger-9 indexer image is published. Run a ledger-9 stack yourself and point mn at it (config_set node / indexer-ws / proof-server).",annotations:{openWorldHint:!0},inputSchema:{type:"object",properties:{}},async handler(){let e={command:"localnet",subcommand:"up",positionals:[],flags:{json:!0}},t=await Y("localnet");return z(t,e)}},{name:"midnight_localnet_stop",description:"Stop localnet (preserves state).",annotations:{idempotentHint:!0,openWorldHint:!0},inputSchema:{type:"object",properties:{}},async handler(){let e={command:"localnet",subcommand:"stop",positionals:[],flags:{json:!0}},t=await Y("localnet");return z(t,e)}},{name:"midnight_localnet_down",description:"Localnet teardown (volumes + undeployed cache).",annotations:{destructiveHint:!0,openWorldHint:!0},inputSchema:{type:"object",properties:{}},async handler(){let e={command:"localnet",subcommand:"down",positionals:[],flags:{json:!0}},t=await Y("localnet");return z(t,e)}},{name:"midnight_localnet_status",description:"Localnet status.",annotations:{readOnlyHint:!0,openWorldHint:!0},inputSchema:{type:"object",properties:{}},async handler(){let e={command:"localnet",subcommand:"status",positionals:[],flags:{json:!0}},t=await Y("localnet");return z(t,e)}},{name:"midnight_localnet_clean",description:"Remove stray containers.",annotations:{destructiveHint:!0,openWorldHint:!0},inputSchema:{type:"object",properties:{}},async handler(){let e={command:"localnet",subcommand:"clean",positionals:[],flags:{json:!0}},t=await Y("localnet");return z(t,e)}},{name:"midnight_contract_inspect",description:"Inspect a compiled Compact contract: name, circuits (with arg/return types), witnesses, compiler/language/runtime versions. Reads managed/<name>/compiler/contract-info.json under the dapp dir. Returns a `siblings` array listing other contracts in the same project — call again with `name` to inspect a sibling.",annotations:{readOnlyHint:!0,idempotentHint:!0},inputSchema:{type:"object",properties:{path:{type:"string",description:"Path to dApp directory (defaults to cwd)"},managed:{type:"string",description:"Direct path to a managed/<name>/ directory (overrides path)"},name:{type:"string",description:"Specific contract name to inspect when the project has multiple (see siblings field)"}}},async handler(e){let t=ye("contract",e,"inspect"),r=await Y("contract");return z(r,t)}},{name:"midnight_contract_state",description:"Read the current ledger state of a deployed contract. Returns the ledger fields as a JSON object.",annotations:{readOnlyHint:!0,openWorldHint:!0},inputSchema:{type:"object",properties:{address:{type:"string",description:"Contract address (hex)"},wallet:{type:"string"},network:{type:"string",enum:["preprod","preview","undeployed"]},path:{type:"string",description:"dApp directory (defaults to cwd; needed to find the compiled artifact for state decoding)"},managed:{type:"string",description:"Direct path to a managed/<name>/ directory (overrides path-based contract scan)"},name:{type:"string",description:"Specific contract name when the project has multiple"}},required:["address"]},async handler(e){let t=ye("contract",e,"state"),r=await Y("contract");return z(r,t)}},{name:"midnight_contract_deploy",description:"Deploy a compiled Compact contract (returns pending token; agent must show the description and redeem via midnight_confirm_operation).",annotations:{destructiveHint:!0,openWorldHint:!0},inputSchema:{type:"object",properties:{wallet:{type:"string"},network:{type:"string",enum:["preprod","preview","undeployed"]},args:{type:"string",description:"JSON-encoded array or object of constructor arguments"},path:{type:"string",description:"dApp directory (defaults to cwd)"},managed:{type:"string",description:"Direct path to a managed/<name>/ directory (overrides path-based contract scan)"},name:{type:"string",description:"Specific contract name when the project has multiple"}}},async handler(e){let t=ye("contract",e,"deploy"),r=await Y("contract");return z(r,t)}},{name:"midnight_contract_call",description:"Call a circuit on a deployed contract (returns pending token; agent must show the description and redeem via midnight_confirm_operation).",annotations:{destructiveHint:!0,openWorldHint:!0},inputSchema:{type:"object",properties:{address:{type:"string",description:"Contract address (hex)"},circuit:{type:"string",description:"Circuit name to invoke"},wallet:{type:"string"},network:{type:"string",enum:["preprod","preview","undeployed"]},args:{type:"string",description:"JSON-encoded array or object of circuit arguments"},path:{type:"string",description:"dApp directory (defaults to cwd)"},managed:{type:"string",description:"Direct path to a managed/<name>/ directory (overrides path-based contract scan)"},name:{type:"string",description:"Specific contract name when the project has multiple"}},required:["address","circuit"]},async handler(e){let t=ye("contract",e,"call"),r=await Y("contract");return z(r,t)}},{name:"midnight_test_create",description:"Generate a test scaffold for the contract. Two paths: (1) AI-assisted — pass `goal` (and optionally `screen` for UI strategy) and the scaffold is generated by Claude reading the contract + screen source, producing a focused suite with realistic args / on-screen labels. (2) Deterministic — pass `no-ai: true` (or omit goal/screen in non-interactive mode) for boilerplate scaffolds that the user reviews. CLI strategy emits dapp.test.json + tests/suites/<name>/{suite,actions,assertions}.json. Browser strategy emits prompt.md instead of actions.json plus the browser fields in dapp.test.json — required: port, build-cmd. Use force:true to overwrite.",annotations:{destructiveHint:!0},inputSchema:{type:"object",properties:{path:{type:"string",description:"dApp directory (defaults to cwd)"},name:{type:"string",description:"Specific contract name when the project has multiple"},suite:{type:"string",description:"Suite directory name under tests/suites/ (auto-derived from circuit/screen when AI scaffolds)"},strategy:{type:"string",enum:["cli","browser"],description:"cli (default): drive contracts via actions.json. browser: drive a real UI via Claude + Chrome via prompt.md."},network:{type:"string",enum:["preprod","preview","undeployed"]},goal:{type:"string",description:'AI mode: one-line success criterion this suite should verify (e.g. "round goes from 0 to 1 after increment"). Triggers AI scaffolding.'},screen:{type:"string",description:'AI mode + browser strategy: name of the screen component to focus on (e.g. "loan-request-form" or "LoanRequestForm"). Auto-discovered from src/components, src/pages, src/screens.'},"no-ai":{type:"boolean",description:"Force deterministic scaffolder even when claude CLI is available."},port:{type:"string",description:'Browser strategy only — dev server port (e.g. "4173").'},"build-cmd":{type:"string",description:'Browser strategy only — shell command that builds + serves the UI (e.g. "npm run dev").'},"build-dir":{type:"string",description:"Browser strategy only — subdir the build runs in (monorepo case)."},url:{type:"string",description:"Browser strategy only — full URL Claude opens (default http://localhost:<port>/)."},"browser-mode":{type:"string",enum:["dom","vision","script"],description:"Browser strategy only — how Claude perceives the page. dom (HTML/React UIs, fast, needs chrome-devtools-mcp), vision (canvas games, slow), script (advanced, needs hooks). Default: dom for AI scaffolds."},force:{type:"boolean",description:"Overwrite existing files instead of aborting on collision"}}},async handler(e){let t=ye("test",e,"create"),r=await Y("test");return z(r,t)}},{name:"midnight_localnet_logs",description:"Snapshot of recent localnet logs (last N lines per service, no streaming). Returns { tail, lines: string[] }.",annotations:{readOnlyHint:!0,openWorldHint:!0},inputSchema:{type:"object",properties:{tail:{type:"string",description:"Number of lines to retrieve (default 200)"}}},async handler(e){let t=ye("localnet",e,"logs");if(!t.flags.tail)t.flags.tail="200";let r=await Y("localnet");return z(r,t)}},{name:"midnight_confirm_operation",description:"Redeem a pending token (confirm step).",annotations:{destructiveHint:!0,openWorldHint:!0},inputSchema:{type:"object",properties:{token:{type:"string"}},required:["token"]},async handler(){throw Error("midnight_confirm_operation reached the inner handler — this is an MCP wiring bug")}}],oS=new Set(["midnight_transfer","midnight_contract_deploy","midnight_contract_call"]),Bu=ui();function iS(e,t){let r=t.network??"active network",n=t.wallet??"active wallet";switch(e){case"midnight_transfer":return`Send ${t.amount} NIGHT from ${n} to ${t.to} on ${r}`;case"midnight_contract_deploy":{let s=t.args?` with args ${t.args}`:"";return`Deploy contract from ${t.path??"current directory"} as ${n} on ${r}${s}`}case"midnight_contract_call":{let s=t.args?` with args ${t.args}`:"";return`Call circuit ${t.circuit} on contract ${t.address} as ${n} on ${r}${s}`}default:return`Execute ${e} with ${JSON.stringify(t)}`}}var nn=new zy({name:"midnight-wallet-cli",version:ws},{capabilities:{tools:{},resources:{}}});nn.setRequestHandler(Qy,async()=>({resources:[{uri:Gu,name:"midnight-wallet skill (core)",description:"Read this first. Intent routing table + non-negotiable safety rules. ~830 tokens. Fetch /full on demand for canonical flows, error recovery, and concept primers.",mimeType:"text/markdown"},{uri:Ku,name:"midnight-wallet skill (full)",description:"Canonical multi-step flows, error-recovery recipes, concept primers (NIGHT/DUST/shielded), network selection. Fetch on demand when you hit an error, start a multi-step flow, or need to explain a concept.",mimeType:"text/markdown"}]}));nn.setRequestHandler(eS,async(e)=>{let t=e.params.uri;if(t===Gu){let r=Wu(rS,"utf-8");return{contents:[{uri:t,mimeType:"text/markdown",text:r}]}}if(t===Ku||t===tS){let r=Wu(nS,"utf-8");return{contents:[{uri:t,mimeType:"text/markdown",text:r}]}}throw Error(`Unknown resource: ${t}`)});nn.setRequestHandler(Xy,async()=>({tools:Vu.map((e)=>({name:e.name,description:e.description,inputSchema:e.inputSchema,...e.annotations?{annotations:e.annotations}:{}}))}));nn.setRequestHandler(Zy,async(e)=>{let{name:t,arguments:r}=e.params,n=r??{};if(t==="midnight_confirm_operation"){let s=typeof n.token==="string"?n.token:"",o=Bu.redeem(s);if(!o)return ni(Error("Unknown or expired confirmation token. The first-step tool call may need to be re-issued."));return ju(o.tool,o.args)}if(oS.has(t)){let s=Bu.create({tool:t,args:n,description:iS(t,n)});return{content:[{type:"text",text:JSON.stringify(si({pending:!0,token:s.token,description:s.description,tool:s.tool,expiresAt:new Date(s.expiresAt).toISOString(),nextStep:"Show the description to the user, get explicit consent, then call midnight_confirm_operation with this token."}),null,2)}]}}return ju(t,n)});function si(e){return{...e,_serverVersion:ws}}async function ju(e,t){let r=Vu.find((n)=>n.name===e);if(!r)return ni(Error(`Unknown tool: ${e}`));try{let n=await r.handler(t);return{content:[{type:"text",text:JSON.stringify(si(n),null,2)}]}}catch(n){return ni(n instanceof Error?n:Error(String(n)))}}function ni(e){let{errorCode:t}=di(e);return{content:[{type:"text",text:JSON.stringify(si({error:!0,code:t,message:li(e.message)}))}],isError:!0}}async function aS(){await Ni();let e=new Yy;await nn.connect(e)}aS().catch((e)=>{process.stderr.write(`MCP server error: ${e.message}
|
|
1321
1324
|
`),process.exit(1)});
|