midnight-wallet-cli 0.6.0-rc.4 → 0.6.0-rc.6
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 +251 -251
- package/dist/wallet.js +346 -346
- package/package.json +1 -1
package/dist/mcp-server.js
CHANGED
|
@@ -1,39 +1,39 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{createRequire as
|
|
2
|
+
import{createRequire as kp}from"node:module";var Sp=Object.defineProperty;var bp=(e)=>e;function vp(e,t){this[e]=bp.bind(null,t)}var be=(e,t)=>{for(var r in t)Sp(e,r,{get:t[r],enumerable:!0,configurable:!0,set:vp.bind(t,r)})};var A=(e,t,r)=>()=>{if(e)try{t=e(e=0)}catch(n){r=[n]}if(r)throw r[0];return t};var Si=kp(import.meta.url);function bi(e){return e instanceof _}var _;var ve=A(()=>{_=class _ extends Error{constructor(e){super(e);this.name="UsageError",Object.setPrototypeOf(this,_.prototype)}}});function x(e,t){let r=e.flags[t];if(r===void 0)return;if(r===!0)throw new _(`--${t} needs a value, e.g. --${t} <value>`);return r}function N(e,t){return t in e.flags}function Ke(e){return N(e,"verbose")}function ht(e){return N(e,un)&&!N(e,kr)}function Ht(e){if(N(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
4
|
`+"To reset: midnight cache clear --wallet <name> --network <name>")}function Cr(e,t,r){let n=x(e,t);if(n===void 0)throw Error(`Missing required flag: --${t} <${r}>`);return n}var un="_minimal",kr="_full";var oe=A(()=>{ve()});function Cs(e){ks=e}function I(e){let t=JSON.stringify(e)+`
|
|
5
|
-
`;if(ks)ks(t);else process.stdout.write(t)}var ks=null;function Tt(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 ot="0000000000000000000000000000000000000000000000000000000000000001",xr="0000000000000000000000000000000000000000000000000000000000000000",Er="/api/v4/graphql",Kt="/api/v4/graphql/ws",As=6,Ts=1e6,
|
|
6
|
-
`)){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
|
|
5
|
+
`;if(ks)ks(t);else process.stdout.write(t)}var ks=null;function Tt(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 ot="0000000000000000000000000000000000000000000000000000000000000001",xr="0000000000000000000000000000000000000000000000000000000000000000",Er="/api/v4/graphql",Kt="/api/v4/graphql/ws",As=6,Ts=1e6,Ei=300000000000000n,Ai=5,Ar=900000000000000n,Ti=5000000000n,Ni=8267n,Ri=10800n,Ii=300000,mn=30000,Di=1e4,Ns=120000,gn=300000,Rs=60000,$i=16384,Pi=0.7,_i=512,hn=10,Oi=3,Mi=600000,Is=15000,Fi=115,ce=".midnight",wn="wallet.json",Li="config.json",Re=448,Ie=384,Ds="localnet",$s=2,Le="cache",yn="wallets",Ps="default",_s=10,Os=3000,Ui=120000,Tr=9932,Sn="https://midnight-comp-tracker.vercel.app";import{execSync as Fp}from"child_process";import{ProtocolVersion as Lp}from"@midnightntwrk/wallet-sdk";function xe(e){return ji.includes(e)}function Nr(e){return{...Up[e]}}function Rr(){return ji}function Wp(e){let t={node:new Set,indexer:new Set,proofServer:new Set};for(let n of e.split(`
|
|
6
|
+
`)){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 jp(e,t=Bp){if(t.node&&e.node.length>1||t.indexer&&e.indexer.length>1||t.proofServer&&e.proofServer.length>1)throw new Hi(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 Hp(){if(process.env.MN_NO_LOCAL_DETECT==="1")return{node:[],indexer:[],proofServer:[]};try{return Wp(Fp('docker ps --format "{{.Image}}|{{.Ports}}"',{encoding:"utf-8",timeout:5000}))}catch{return{node:[],indexer:[],proofServer:[]}}}function Gi(e,t={}){let r=Nr(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=jp((t.detect??Hp)(),s);if(o.indexerPort)r.indexer=`http://localhost:${o.indexerPort}${Er}`,r.indexerWS=`ws://localhost:${o.indexerPort}${Kt}`;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=Ki(n.indexerWS);return r}function Ki(e){return e.replace(/^wss:/,"https:").replace(/^ws:/,"http:").replace(/\/ws$/,"")}function bn(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=Oe(n),o=Ir(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=Ki(e.indexerWS);return e}var it,Up,ji,Hi,Bp;var ye=A(()=>{Vt();it=Lp.V9NativeForkSchedule,Up={preprod:{indexer:`https://indexer.preprod.midnight.network${Er}`,indexerWS:`wss://indexer.preprod.midnight.network${Kt}`,node:"wss://rpc.preprod.midnight.network",proofServer:"http://localhost:6300",networkId:"PreProd"},preview:{indexer:`https://indexer.preview.midnight.network${Er}`,indexerWS:`wss://indexer.preview.midnight.network${Kt}`,node:"wss://rpc.preview.midnight.network",proofServer:"http://localhost:6300",networkId:"Preview"},undeployed:{indexer:`http://localhost:8088${Er}`,indexerWS:`ws://localhost:8088${Kt}`,node:"ws://localhost:9944",proofServer:"http://localhost:6300",networkId:"Undeployed"}},ji=["preprod","preview","undeployed"];Hi=class Hi 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.
|
|
7
7
|
Pick one per command: --node ws://localhost:<port> --indexer-ws ws://localhost:<port>${Kt} --proof-server http://localhost:<port>
|
|
8
8
|
or once: midnight config set network undeployed, then midnight config set node / indexer-ws / proof-server <url>
|
|
9
|
-
Commands without endpoint flags (cache, test, dev) use the saved config. MN_NO_LOCAL_DETECT=1 turns detection off.`);this.name="AmbiguousLocalStacksError"}}
|
|
10
|
-
`,{mode:Ie})}function
|
|
11
|
-
Valid keys: ${vn.join(", ")}`)}function
|
|
12
|
-
Valid networks: preprod, preview, undeployed`);
|
|
13
|
-
Wallet name must be a simple name (no path separators, .json suffix, or special characters).`);o.wallet=t}else if(Nt.has(s)){if(!
|
|
9
|
+
Commands without endpoint flags (cache, test, dev) use the saved config. MN_NO_LOCAL_DETECT=1 turns detection off.`);this.name="AmbiguousLocalStacksError"}};Bp={node:!0,indexer:!0,proofServer:!0}});import*as at from"fs";import*as Fs from"path";import{homedir as Gp}from"os";function Ls(e){return Kp[e]??e}function Vp(e){return/^(https?|wss?):\/\/\S+/.test(e)}function Vi(e){return e??Fs.join(Gp(),ce)}function Ji(e){return Fs.join(Vi(e),Li)}function Jp(e){let t=Vi(e);if(!at.existsSync(t))at.mkdirSync(t,{recursive:!0,mode:Re})}function Oe(e){let t=Ji(e);if(!at.existsSync(t))return{...Dr};let r;try{r=at.readFileSync(t,"utf-8")}catch{return{...Dr}}let n;try{n=JSON.parse(r)}catch{return{...Dr}}let s={network:n.network&&xe(n.network)?n.network:Dr.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(!xe(i)||!a||typeof a!=="object")continue;let c={};for(let d of Nt){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 Ir(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 kn(e,t){Jp(t);let r=Ji(t);at.writeFileSync(r,JSON.stringify(e,null,2)+`
|
|
10
|
+
`,{mode:Ie})}function qi(e,t,r){let n=Ls(e),s=Oe(t);if(Us(n,r),n==="network")return s.network;if(n==="wallet")return s.wallet??"(not set)";if(Nt.has(n)){let i=Ir(s,r??s.network)[n];return typeof i==="string"?i:"(not set)"}throw Error(`Unknown config key: "${e}"
|
|
11
|
+
Valid keys: ${vn.join(", ")}`)}function qp(e,t){let r={...e.networks?.[t]??{}},n=!1;for(let s of Nt){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 zi(e,t,r,n){let s=Ls(e),o=Oe(r);if(Us(s,n),s==="network"){if(!xe(t))throw Error(`Invalid network: "${t}"
|
|
12
|
+
Valid networks: preprod, preview, undeployed`);qp(o,o.network),o.network=t}else if(s==="wallet"){if(!Tt(t))throw Error(`Invalid wallet name: "${t}"
|
|
13
|
+
Wallet name must be a simple name (no path separators, .json suffix, or special characters).`);o.wallet=t}else if(Nt.has(s)){if(!Vp(t))throw Error(`Invalid URL for "${e}": "${t}"
|
|
14
14
|
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}"
|
|
15
|
-
Valid keys: ${vn.join(", ")}`);kn(o,r)}function
|
|
16
|
-
Valid keys: ${vn.join(", ")}`);kn(s,t)}function
|
|
17
|
-
`,{mode:Ie})}catch{}}function
|
|
18
|
-
Wallet name must be a simple name (no path separators, .json suffix, or special characters).`);let t=Ae.join(
|
|
19
|
-
Run "midnight wallet list" to see available wallets.`);let r=Oe();r.wallet=e,kn(r)}function
|
|
20
|
-
Wallet name must be a simple name (no path separators, .json suffix, or special characters).`);let t=
|
|
15
|
+
Valid keys: ${vn.join(", ")}`);kn(o,r)}function Yi(e,t,r){let n=Ls(e),s=Oe(t);if(Us(n,r),n==="network")s.network=Dr.network;else if(n==="wallet")delete s.wallet;else if(Nt.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}"
|
|
16
|
+
Valid keys: ${vn.join(", ")}`);kn(s,t)}function Us(e,t){if(t!==void 0&&!Nt.has(e))throw new _(`--network only applies to the endpoint keys (${[...Nt].join(", ")}), not "${e}".`)}function Ws(){return vn}var Dr,vn,Kp,Nt;var Vt=A(()=>{ye();ve();Dr={network:"undeployed"},vn=["network","proof-server","node","indexer-ws","wallet"],Kp={"network-id":"network"};Nt=new Set(["proof-server","node","indexer-ws"])});import{HDWallet as zp,Roles as Bs}from"@midnightntwrk/wallet-sdk/hd";function js(e,t){let r=zp.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 Rt(e){return js(e,Bs.Zswap)}function Xi(e){return js(e,Bs.NightExternal)}function wt(e){return js(e,Bs.Dust)}var It=()=>{};import{NetworkId as Jt}from"@midnightntwrk/wallet-sdk";function Ue(e){let t=Yp[e];if(t===void 0)throw Error(`Unknown networkId: ${e}`);return t}function qt(e){return Xp[e]}var Yp,Xp;var ct=A(()=>{Yp={PreProd:Jt.NetworkId.PreProd,Preview:Jt.NetworkId.Preview,Undeployed:Jt.NetworkId.Undeployed},Xp={preprod:Jt.NetworkId.PreProd,preview:Jt.NetworkId.Preview,undeployed:Jt.NetworkId.Undeployed}});import{HDWallet as Zp,Roles as Qp}from"@midnightntwrk/wallet-sdk/hd";import{createKeystore as ef,PublicKey as tf}from"@midnightntwrk/wallet-sdk/unshielded";import{MidnightBech32m as rf,ShieldedAddress as nf,ShieldedCoinPublicKey as sf,ShieldedEncryptionPublicKey as of}from"@midnightntwrk/wallet-sdk/address-format";import*as Zi from"@midnightntwrk/ledger-v9";function Ee(e,t,r=0){let n=qt(t),s=Zp.fromSeed(e);if(s.type!=="seedOk")throw Error("Invalid seed for HD wallet");let o=s.hdWallet.selectAccount(0).selectRole(Qp.NightExternal).deriveKeyAt(r);if(o.type==="keyOutOfBounds")throw Error(`Key index ${r} out of bounds`);let i=ef({kind:"schnorr",secret:o.key},n);return tf.fromKeyStore(i).address}function Dt(e,t=0){let r={};for(let n of Rr())r[n]=Ee(e,n,t);return r}function $r(e){let t=Pr(e),r={};for(let n of Rr()){let s=qt(n);r[n]=rf.encode(s,t).asString()}return r}function Pr(e){let t=Rt(e),r=Zi.ZswapSecretKeys.fromSeed(t);return new nf(new sf(Buffer.from(r.coinPublicKey,"hex")),new of(Buffer.from(r.encryptionPublicKey,"hex")))}var Ve=A(()=>{ye();It();ct()});import*as ee from"fs";import*as Ae from"path";import{homedir as af}from"os";function zt(e,t,r){let n=Ae.resolve(e);if(!ee.existsSync(n))return;try{let s=JSON.parse(ee.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;ee.writeFileSync(n,JSON.stringify(s,null,2)+`
|
|
17
|
+
`,{mode:Ie})}catch{}}function Hs(){return Ae.join(af(),ce)}function _r(){return Ae.join(Hs(),yn)}function ea(){return Ae.join(Hs(),wn)}function cf(){let e=Hs();if(!ee.existsSync(e))ee.mkdirSync(e,{recursive:!0,mode:Re})}function df(e){return e.includes("/")||e.includes("\\")||e.endsWith(".json")}function re(e){if(e!==void 0){if(df(e))return Ae.resolve(e);return Ae.join(_r(),`${e}.json`)}let r=Oe().wallet??Ps;return Ae.join(_r(),`${r}.json`)}function Yt(){return Oe().wallet??Ps}function Gs(e){if(!Tt(e))throw Error(`Invalid wallet name: "${e}"
|
|
18
|
+
Wallet name must be a simple name (no path separators, .json suffix, or special characters).`);let t=Ae.join(_r(),`${e}.json`);if(!ee.existsSync(t))throw Error(`Wallet "${e}" not found.
|
|
19
|
+
Run "midnight wallet list" to see available wallets.`);let r=Oe();r.wallet=e,kn(r)}function Ks(){let e=_r();if(!ee.existsSync(e))return[];let t=Yt();return ee.readdirSync(e).filter((n)=>n.endsWith(".json")).sort().map((n)=>{let s=n.replace(/\.json$/,""),o=Ae.join(e,n);try{let i=JSON.parse(ee.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=Dt(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=$r(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 lf(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 ta(e){return lf(Ks(),e)}function ra(e){if(!Tt(e))throw Error(`Invalid wallet name: "${e}"
|
|
20
|
+
Wallet name must be a simple name (no path separators, .json suffix, or special characters).`);let t=_r(),r=Ae.join(t,`${e}.json`);if(!ee.existsSync(r))throw Error(`Wallet "${e}" not found.
|
|
21
21
|
Run "midnight wallet list" to see available wallets.`);let n=Yt();if(e===n)throw Error(`Cannot remove the active wallet "${e}".
|
|
22
22
|
Switch to another wallet first: midnight wallet use <other-wallet>`);if(ee.readdirSync(t).filter((o)=>o.endsWith(".json")).length<=1)throw Error(`Cannot remove "${e}" — it is the only wallet.
|
|
23
|
-
`+"Create another wallet first: midnight wallet generate <name>");ee.unlinkSync(r)}function ne(e){let t=e?Ae.resolve(e):
|
|
23
|
+
`+"Create another wallet first: midnight wallet generate <name>");ee.unlinkSync(r)}function ne(e){let t=e?Ae.resolve(e):ea();if(!ee.existsSync(t))throw Error(`Wallet file not found: ${t}
|
|
24
24
|
Generate a wallet first: midnight wallet generate <name> --network <name>`);let r;try{r=ee.readFileSync(t,"utf-8")}catch(c){throw Error(`Failed to read wallet file: ${t}
|
|
25
|
-
${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=Dt(c),u={seed:n.seed,addresses:d,createdAt:n.createdAt};if(n.mnemonic)u.mnemonic=n.mnemonic;let l=
|
|
26
|
-
`,{mode:Ie}),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=
|
|
27
|
-
`,{mode:Ie})}catch{}return s}function
|
|
25
|
+
${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=Dt(c),u={seed:n.seed,addresses:d,createdAt:n.createdAt};if(n.mnemonic)u.mnemonic=n.mnemonic;let l=Qi(n,c);if(l)u.shieldedAddresses=l;let f={...n,addresses:d};if(l)f.shieldedAddresses=l,delete f.shieldedAddress;return ee.writeFileSync(t,JSON.stringify(f,null,2)+`
|
|
26
|
+
`,{mode:Ie}),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=Qi(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,ee.writeFileSync(t,JSON.stringify(c,null,2)+`
|
|
27
|
+
`,{mode:Ie})}catch{}return s}function Qi(e,t){let r;try{r=$r(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 Cn(e,t){let r=t?Ae.resolve(t):ea();if(!t)cf();else{let n=Ae.dirname(r);if(!ee.existsSync(n))ee.mkdirSync(n,{recursive:!0,mode:Re})}return ee.writeFileSync(r,JSON.stringify(e,null,2)+`
|
|
28
28
|
`,{mode:Ie}),r}var De=A(()=>{Vt();Ve()});function Se(e){let t=x(e.args,"network");if(t!==void 0){if(!xe(t))throw Error(`Invalid network: "${t}"
|
|
29
|
-
Valid networks: ${
|
|
29
|
+
Valid networks: ${Rr().join(", ")}`);return t}let r=Oe(e.configDir);if(r.network&&xe(r.network))return r.network;return"undeployed"}function pe(e){let t=Se(e),r=Ir(Oe(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=Gi(t,{given:n});return{name:t,config:s}}var ke=A(()=>{oe();ye();Vt()});function Or(e,t){let r=e.trim().replace(/^0x/,"");if(r.length!==64&&r.length!==128||!/^[0-9a-fA-F]+$/.test(r))throw new _(`${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 Vs(e,t={}){let r=x(e,"seed"),n=r??process.env.MN_SEED;if(n)return{seed:Or(n,r?"--seed":"MN_SEED"),walletPath:null,config:null};let s=x(e,"wallet");if(s===void 0&&t.requireExplicit)throw new _(`${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=ne(o);return{seed:Buffer.from(i.seed,"hex"),walletPath:o,config:i}}function xn(e,t){return
|
|
33
|
-
`);for(let p of f)o.push(...
|
|
32
|
+
--wallet <name> derive from a saved wallet`);let o=re(s),i=ne(o);return{seed:Buffer.from(i.seed,"hex"),walletPath:o,config:i}}function xn(e,t){return Vs(e,t).seed}var Xt=A(()=>{oe();ve();De()});function Mr(){return!("NO_COLOR"in process.env)}function Fr(e,t){if(!Mr())return e;return`\x1B[38;5;${t}m${e}\x1B[0m`}function P(e){if(!Mr())return e;return`\x1B[1m${e}\x1B[0m`}function m(e){if(!Mr())return e;return`\x1B[2m${e}\x1B[0m`}function K(e){return Fr(e,38)}function de(e){return Fr(e,196)}function W(e){return Fr(e,40)}function Q(e){return Fr(e,226)}function Lr(e){return Fr(e,245)}function B(e,t=sa){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=sa){return m("─".repeat(e))}function E(e,t,r=16){let n=(e+":").padEnd(r);return` ${Lr(n)}${t}`}function $t(e){let t=e<0n,r=t?-e:e,n=BigInt(10**As),s=r/n,i=(r%n).toString().padStart(As,"0");return`${t?"-":""}${s}.${i}`}function En(e){return`${$t(e)} NIGHT`}function le(e){let t=e<0n,r=t?-e:e,n=10n**BigInt(na),s=r/n,a=(r%n).toString().padStart(na,"0").replace(/0+$/,"").padEnd(6,"0");return`${t?"-":""}${s}.${a}`}function Ur(e){return`${le(e)} DUST`}function te(e,t=!1){let r=t&&e.length>20?e.slice(0,10)+"…"+e.slice(-8):e;return K(r)}function uf(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 pf(e,t){if(Zt(e).length<=t)return[e];let n=e.split(/(\s+)/).flatMap((a)=>Zt(a).length>t?uf(a,t):[a]),s=[],o="",i=0;for(let a of n){let c=Zt(a).length;if(i+c>t&&i>0)s.push(o),o=a.trimStart(),i=Zt(o).length;else o+=a,i+=c}if(o.length>0)s.push(o);return s}function oa(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(...pf(p,s))}let i=Math.max(...o.map((l)=>Zt(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=Zt(l).length,p=a-f-2;return`${n.v} ${l}${" ".repeat(Math.max(0,p))} ${n.v}`});return[c,...u,d].join(`
|
|
34
34
|
`)}function yt(e,t){let n=[`${W("✓")} ${e}`];if(t)n.push(E("Transaction",K(t)));return n.join(`
|
|
35
|
-
`)}var
|
|
36
|
-
Use --force to overwrite, or --output <file> to save to a different path.`);let c,d;if(o!==void 0)c=
|
|
35
|
+
`)}var sa=60,na=15,Zt=(e)=>e.replace(/\x1b\[[0-9;]*m/g,"");var fe=()=>{};var la={};be(la,{default:()=>da});import*as ca from"fs";import*as An from"path";import{homedir as ff}from"os";import{generateMnemonic as mf,mnemonicToSeedSync as ia,validateMnemonic as gf}from"@scure/bip39";import{wordlist as aa}from"@scure/bip39/wordlists/english.js";async function da(e){let t=Se({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?An.resolve(r):An.join(ff(),ce,wn);if(ca.existsSync(a)&&!N(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=Or(o,n!==void 0?"--seed":"MN_SEED");else if(i!==void 0){if(!gf(i,aa))throw Error("Invalid BIP-39 mnemonic. Expected 12 or 24 words from the English wordlist.");d=i,c=Buffer.from(ia(d))}else d=mf(aa,256),c=Buffer.from(ia(d));let u=Dt(c),l=u[t],f={seed:c.toString("hex"),addresses:u,createdAt:new Date().toISOString()};if(d)f.mnemonic=d;let p=Cn(f,r);if(N(e,"json")){let h={addresses:u,activeAddress:l,activeNetwork:t,seed:c.toString("hex"),file:p,createdAt:f.createdAt};if(d)h.mnemonic=d;I(h);return}if(process.stdout.write(l+`
|
|
37
37
|
`),process.stderr.write(`
|
|
38
38
|
`+B("Wallet Generated")+`
|
|
39
39
|
|
|
@@ -51,7 +51,7 @@ Use --force to overwrite, or --output <file> to save to a different path.`);let
|
|
|
51
51
|
`),process.stderr.write(m(" Next: midnight info | midnight balance")+`
|
|
52
52
|
|
|
53
53
|
`),process.stderr.write(W("✓")+` Wallet saved
|
|
54
|
-
`)}var
|
|
54
|
+
`)}var ua=A(()=>{oe();Ve();ke();De();Xt();fe()});var fa={};be(fa,{default:()=>pa});async function pa(e){let t=re(x(e,"wallet")),r=ne(t),n=Se({args:e}),s=r.addresses[n];if(N(e,"json")){let i={addresses:r.addresses,activeNetwork:n,activeAddress:s,createdAt:r.createdAt,file:t};if(r.shieldedAddresses)i.shieldedAddresses=r.shieldedAddresses;I(i);return}process.stdout.write(s+`
|
|
55
55
|
`),process.stderr.write(`
|
|
56
56
|
`+B("Wallet Info")+`
|
|
57
57
|
|
|
@@ -66,8 +66,8 @@ Use --force to overwrite, or --output <file> to save to a different path.`);let
|
|
|
66
66
|
`),process.stderr.write(` ${m("created")} ${r.createdAt}
|
|
67
67
|
`),process.stderr.write(` ${m("file ")} ${t}
|
|
68
68
|
|
|
69
|
-
`)}var
|
|
70
|
-
`)}var
|
|
69
|
+
`)}var ma=A(()=>{oe();De();ke();fe();fe()});function Je(){ga=!0}function L(e,t){if(!ga)return;let r=new Date().toISOString().slice(11,23);process.stderr.write(m(` [${r}] ${e}: ${t}`)+`
|
|
70
|
+
`)}var ga=!1;var St=()=>{};function wf(e){return!hf.includes(e)}function Tn(e,t=!1){return wf(e)||t}function Nn(e){return`Shielded is unavailable on ${e} (no faucet). Use --force-shielded to sync anyway, or --network undeployed.`}var hf;var Js=A(()=>{hf=["preview","preprod"]});import yf from"ws";function Qt(e,t,r){return new Promise((n,s)=>{let o=new yf(t,["graphql-transport-ws"]),i=new Map,a=0,c=0,d=0,u=!1,l=!1,f,p=()=>{let S=new Map,y=0,w=0,k=0;for(let T of i.values())if(!T.spent){y++;let R=S.get(T.tokenType)??0n;if(S.set(T.tokenType,R+T.value),T.tokenType===xr)if(T.registeredForDustGeneration)w++;else k++}return{balances:S,utxoCount:y,txCount:a,highestTxId:c,registeredUtxos:w,unregisteredUtxos:k}},h=()=>{clearTimeout(f)},g=()=>{if(!l&&u&&(c===0||d>=c))l=!0,h(),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",(S)=>{let y=JSON.parse(S.toString());switch(y.type){case"connection_ack":o.send(JSON.stringify({id:"1",type:"subscribe",payload:{query:Sf,variables:{address:e}}}));break;case"next":{if(y.payload?.errors){let k=y.payload.errors[0]?.message||"Unknown GraphQL error";if(!l)l=!0,h(),o.close(),s(Error(`GraphQL error: ${k}`));return}let w=y.payload?.data?.unshieldedTransactions;if(!w)return;if(w.__typename==="UnshieldedTransaction"){a++;let k=w;d=Math.max(d,k.transaction.id);for(let T of k.createdUtxos){let R=`${T.intentHash}:${T.outputIndex}`;i.set(R,{value:BigInt(T.value),tokenType:T.tokenType,spent:!1,registeredForDustGeneration:T.registeredForDustGeneration===!0})}for(let T of k.spentUtxos){let R=`${T.intentHash}:${T.outputIndex}`,U=i.get(R);if(U)U.spent=!0}if(r)r(d,c);g()}else if(w.__typename==="UnshieldedTransactionsProgress")c=w.highestTransactionId,u=!0,g();break}case"error":if(!l)l=!0,h(),o.close(),s(Error(`GraphQL subscription error: ${JSON.stringify(y.payload)}`));break;case"complete":break}}),o.on("error",(S)=>{if(!l){l=!0,h();let y=S.message?.trim()?S.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,h(),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 ${Rs/1000}s. Indexer: ${t}`))},Rs)})}function Wr(e){return e===xr}var Sf=`
|
|
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 L("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 Br=()=>{};function ha({owed:e,coinCount:t,choose:r,feeWith:n}){let s=e;for(let o=0;o<=t;o++){let i=s>0n?r(s):[];if(i===void 0)return{kind:"short",atFirstChoice:o===0};let a=n(i),c=i.reduce((d,u)=>d+u.value,0n);if(a<=c)return{kind:"covered",fee:a,inputs:i};s=a}return{kind:"short",atFirstChoice:!1}}function wa(e,t){let r=t;return e.map((n)=>{let s=r>=n.value?n.value:r;return r-=s,{...n,value:s}})}import*as ba from"@midnightntwrk/ledger-v9";import{Imbalances as bf,InsufficientFundsError as ya,getBalanceRecipe as vf,makeIndexerChainVersionProbe as kf}from"@midnightntwrk/wallet-sdk/capabilities";import{CustomForkingDustWallet as Cf,asV8DustParameters as xf}from"@midnightntwrk/wallet-sdk/dust";import{V1Builder as Ef}from"@midnightntwrk/wallet-sdk/dust/v1";import{Migration as Af,Transacting as Sa,V2Builder as Tf,WalletError as Nf}from"@midnightntwrk/wallet-sdk/dust/v2";import{LedgerOps as qs}from"@midnightntwrk/wallet-sdk/utilities";function zs(e){let t=e.dustParameters??ba.LedgerParameters.initialParameters().dust,r={...e,chainVersionProbe:e.chainVersionProbe??kf(e)};return Cf(r,{builder:new Ef().withDefaults(),configuration:{...e,dustParameters:xf(t)}},{builder:new Tf().withDefaults().withTransacting(Rf).withMigration(()=>Af.makeCrossLedgerMigration({dustParameters:t})),configuration:e})}var va,Rf=(e,t)=>new va(e.networkId,e.costParameters,()=>t().coinSelection,()=>t().coinsAndBalancesCapability,()=>t().keysCapability);var ka=A(()=>{va=class va extends Sa.TransactingCapabilityImplementation{computeBalancingRecipe(...e){let[t,r,n,s,o,i]=e,a;try{let c=-n.reduce((u,l)=>u+Sa.TransactingCapabilityImplementation.feeImbalance(l,this.calculateFee(l,i)),0n),d=this.getCoins().getAvailableCoinsWithGeneratedDust(r,o);a=ha({owed:c,coinCount:d.length,choose:(u)=>this.#e(d,u),feeWith:(u)=>this.dryRunFee(u,n,t,r,s,o,i)})}catch(c){return qs.ledgerTry(()=>{throw c})}if(a.kind==="covered"){let{fee:c,inputs:d}=a;return qs.ledgerTry(()=>({fee:c,recipeInputs:wa(d,c)}))}if(a.atFirstChoice)return super.computeBalancingRecipe(...e);return qs.ledgerTry(()=>{throw new Nf.InsufficientFundsError({message:new ya("dust").message,tokenType:"dust"})})}#e(e,t){try{return vf({coins:e.map((n)=>({type:"dust",value:n.value,token:n.token})),initialImbalances:bf.fromEntry("dust",-t),feeTokenType:"dust",coinSelection:this.getCoinSelection(),transactionCostModel:{inputFeeOverhead:0n,outputFeeOverhead:0n},createOutput:(n)=>n,isCoinEqual:(n,s)=>n.token.nonce===s.token.nonce}).inputs.map(({token:n,value:s})=>({token:n,value:s}))}catch(r){if(r instanceof ya)return;throw r}}}});import{existsSync as jr,mkdirSync as If,writeFileSync as Df,readFileSync as Ca,unlinkSync as Rn,readdirSync as Ys,renameSync as $f}from"node:fs";import{join as Pt,dirname as Pf}from"node:path";import{homedir as xa}from"node:os";import{randomBytes as _f}from"node:crypto";import*as In from"@midnightntwrk/ledger-v9";function Xs(e){return e.toString(16).padStart(64,"0")}function Qe(e){let t=wt(e),r=In.DustSecretKey.fromSeed(t);return Xs(r.publicKey)}function Zs(e,t){let r=t??Pt(xa(),ce,Le);return Pt(r,e)}function Qs(e,t,r){let n=t.slice(0,20);return Pt(Zs(e,r),`dust-${n}.json`)}function Hr(e,t,r){let n=Qs(e,t,r);if(!jr(n))return null;try{let s=JSON.parse(Ca(n,"utf-8"));if(s.version!==Ea)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:In.DustLocalState.deserialize(o),lastAppliedEventId:s.lastAppliedEventId,retention:{ownedGenerationIndices:s.ownedGenerationIndices,generationFrontier:s.generationFrontier}}}catch{return null}}function eo(e,t,r,n,s,o,i=Of){let a={version:Ea,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=Qs(e,t,s),d=Pf(c);if(!jr(d))If(d,{recursive:!0,mode:Re});let u=c+`.tmp.${_f(4).toString("hex")}`;try{Df(u,JSON.stringify(a),{mode:Ie}),$f(u,c)}catch(l){try{Rn(u)}catch{}throw l}}function Aa(e,t,r){if(!t)return[];let n=Zs(e,r);if(!jr(n))return[];let s=[],o;try{o=Ys(n)}catch{return[]}for(let i of o){if(!i.startsWith("dust-")||!i.endsWith(".json"))continue;let a=Pt(n,i);try{let c=JSON.parse(Ca(a,"utf-8"));if(!c.chainId)continue;if(c.chainId!==t)Rn(a),s.push(a)}catch{}}return s}function dt(e,t,r){let n=r??Pt(xa(),ce,Le);if(e&&t){let o=Qs(e,t,r);try{Rn(o)}catch{}return}let s=(o)=>{if(!jr(o))return;try{for(let i of Ys(o))if(i.startsWith("dust-")&&i.endsWith(".json"))try{Rn(Pt(o,i))}catch{}}catch{}};if(e){s(Zs(e,r));return}if(!jr(n))return;try{for(let o of Ys(n))s(Pt(n,o))}catch{}}var Ea=3,Of;var _t=A(()=>{It();Of={ownedGenerationIndices:[],generationFrontier:0}});import{ShieldedWallet as Ta}from"@midnightntwrk/wallet-sdk/shielded";import{UnshieldedWallet as Na,createKeystore as Mf,PublicKey as Ff}from"@midnightntwrk/wallet-sdk/unshielded";import{WalletFacade as Ra,WalletEntrySchema as Lf,mergeWalletEntries as Uf}from"@midnightntwrk/wallet-sdk/facade";import*as Ia from"@midnightntwrk/ledger-v9";import{InMemoryTransactionHistoryStorage as Wf}from"@midnightntwrk/wallet-sdk";import*as Me from"rxjs";async function et(e,t,r){let n=Ue(t.networkId);L("facade",`Building facade for network ${t.networkId}`),L("facade",`Node: ${t.node}`),L("facade",`Indexer: ${t.indexerWS}`),L("facade",`Proof server: ${t.proofServer}`);let s={shielded:Rt(e),unshielded:Xi(e),dust:wt(e)},o=Mf({kind:"schnorr",secret:s.unshielded},n),i={networkId:n,forks:it,indexerClientConnection:{indexerHttpUrl:t.indexer,indexerWsUrl:t.indexerWS},costParameters:{additionalFeeOverhead:Ei,feeBlocksMargin:Ai},txHistoryStorage:new Wf(Lf,Uf),provingServerUrl:new URL(t.proofServer),relayURL:new URL(t.node)},a,c,d=()=>Ra.init({configuration:i,shielded:async(h)=>a=await Ta(h).startWithSeed(s.shielded),unshielded:(h)=>Na(h).startWithPublicKey(Ff.fromKeyStore(o)),dust:async(h)=>c=await zs(h).startWithSeed(s.dust)}),u=Ia.DustSecretKey.fromSeed(s.dust).publicKey,l=r?jf(r,t,u):null,f=!1,p;if(l){L("facade","Restoring from cache...");try{p=await Ra.init({configuration:i,shielded:(h)=>a=Ta(h).restore(l.shielded),unshielded:(h)=>Na(h).restore(l.unshielded),dust:(h)=>c=zs(h).restore(l.dust)}),f=!0,L("facade","Cache restore successful")}catch(h){L("facade",`Cache restore failed: ${h.message}`),process.stderr.write(` Cache restore failed, building from scratch: ${h.message}
|
|
85
|
+
`),p=await d()}}else L("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 Bf(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 ro(e,t){let r=JSON.parse(e);if(BigInt(r.protocolVersion)<it.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 ${it.v9}).`);return r.state=Buffer.from(t.state.serialize()).toString("hex"),r.offset=t.lastAppliedEventId.toString(),JSON.stringify(r)}function jf(e,t,r){try{let n=t.networkId.toLowerCase(),s=Xs(r),o=Hr(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 L("facade",`Facade dust offset=${a} >= dust-direct offset=${o.lastAppliedEventId}; skipping bridge`),e;return L("facade",`Bridged dust-direct cache (facade offset ${a} → dust-direct offset ${o.lastAppliedEventId})`),{...e,dust:ro(e.dust,o)}}catch(n){return L("facade",`Dust-direct bridge skipped: ${n.message}`),e}}function Da(e,t){if(e.isStrictlyComplete())return!0;if(e.highestRelevantWalletIndex>0n&&e.appliedIndex>=e.highestRelevantWalletIndex)return!0;return $a(e)&&t}function $a(e){return e.highestRelevantWalletIndex===0n&&e.appliedIndex===0n}function to(e,t="full"){let r=e.unshielded.progress.isStrictlyComplete(),n=t==="no-dust"||Da(e.dust.progress,r);if(t==="lite")return r&&n;let s=e.shielded.progress;return(s.isStrictlyComplete()||r&&$a(s))&&r&&n}function Hf(e){return!Da(e.dust.progress,e.unshielded.progress.isStrictlyComplete())}async function bt(e,t={}){let{onProgress:r,onSyncDetail:n,timeoutMs:s,syncMode:o="full",requireStrictSync:i=!1}=t,{facade:a}=e;L("sync","Starting facade (connecting to node and indexer)..."),await Bf(e),L("sync","Facade started, subscribing to state...");let c=s??Ii;L("sync",`Sync timeout: ${c/1000}s, mode: ${o}`);let d=!i&&e.restoredFromCache,u=Date.now();return new Promise((l,f)=>{let p=!1,h=0,g="",S=null,y=setTimeout(()=>{if(!p){if(L("sync",`Sync timed out after ${c/1000}s (${h} emissions)`),S)try{let w=S.unshielded.progress;L("sync",` unshielded: applied=${w.appliedId} highest=${w.highestTransactionId} complete=${w.isStrictlyComplete()}`);let k=S.dust.progress;if(L("sync",` dust: applied=${k.appliedIndex} highest=${k.highestRelevantWalletIndex} complete=${k.isStrictlyComplete()} connected=${k.isConnected}`),o==="full"){let T=S.shielded.progress;L("sync",` shielded: complete=${T.isStrictlyComplete()}`)}}catch{}f(Error("Wallet sync timed out"))}},c);e.keepAlive=a.state().subscribe({next:(w)=>{if(p)return;if(h++,S=w,e.restoredFromCache){let T=Kf(w);if(T){p=!0,clearTimeout(y),L("sync",`Stale cache detected: ${T}`),f(new Dn(T));return}}if(r){let T=w.unshielded.progress;if(T){let R=Number(T.appliedId),U=Number(T.highestTransactionId);r(Math.min(R,U),U)}}let k=[];try{if((o==="full"||o==="no-dust")&&!w.shielded.progress.isStrictlyComplete())k.push("shielded");if(o!=="no-dust"&&Hf(w))k.push("dust");if(!w.unshielded.progress.isStrictlyComplete())k.push("unshielded")}catch{}if(k.length>0){n?.(k.join(", "));let T=k.join(",");if(h===1||T!==g||h%100===0)L("sync",`Waiting on: ${k.join(", ")} (emission #${h})`),g=T}if(to(w,o)){p=!0,clearTimeout(y),L("sync",`Sync complete after ${h} emissions`),l(w);return}if(d){let T=Date.now()-u;if(T>=Gf&&to(w,"no-dust"))p=!0,clearTimeout(y),L("sync",`Sync resolved via cached-restore grace (${T}ms, ${h} emissions)`),l(w)}},error:(w)=>{if(!p)L("sync",`Sync error: ${w.message}`),clearTimeout(y),f(w)}})})}function Kf(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 Pa(e){let t=(r)=>{let n=r.unshielded.progress.isStrictlyComplete(),s=r.dust.progress.isStrictlyComplete();return n&&s};try{return await Me.firstValueFrom(e.facade.state().pipe(Me.filter(t),Me.timeout(15000)))}catch{return await Me.firstValueFrom(e.facade.state())}}function Ot(e){return e.dust.availableCoins.length>0||e.dust.balance(new Date)>0n}async function $n(e,t=60000){try{return await Me.firstValueFrom(e.facade.state().pipe(Me.filter(Ot),Me.timeout(t)))}catch{return await Me.firstValueFrom(e.facade.state())}}async function no(e,t="full"){return Me.firstValueFrom(e.facade.state().pipe(Me.filter((r)=>to(r,t)),Me.timeout(Di)))}async function We(e){e.keepAlive?.unsubscribe(),await Promise.race([e.facade.stop(),new Promise((t)=>setTimeout(t,5000))])}function $e(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 Gf=1e4,Dn;var qe=A(()=>{ka();ye();ct();It();_t();St();Dn=class Dn 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 Vf(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 so(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[Jf],s.error,s.defect,s.left,s.right)}return!1}function Pn(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")||Vf(e)}function _a(e){let t=e?.message?.toLowerCase()??"";if(e?._tag==="Wallet.InsufficientFunds")return!0;return t==="insufficient funds"||t.startsWith("insufficient funds")}function _n(e){return _a(e)&&!so(e)}var Jf;var Gr=A(()=>{Jf=Symbol.for("effect/Runtime/FiberFailure/Cause")});import{existsSync as Vr,mkdirSync as qf,writeFileSync as zf,readFileSync as Oa,unlinkSync as Kr,readdirSync as On,renameSync as Yf}from"node:fs";import{join as tt,dirname as Xf}from"node:path";import{homedir as oo}from"node:os";import{randomBytes as Zf}from"node:crypto";function io(e,t,r){let n=r??tt(oo(),ce,Le),s=e.slice(0,20);return tt(n,t,`${s}.json`)}function vt(e,t,r){let n=io(e,t,r);if(!Vr(n))return null;try{let s=Oa(n,"utf-8"),o=JSON.parse(s);if(o.version!==$s)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 lt(e,t,r,n,s){let[o,i,a]=await Promise.all([r.shielded.serializeState(),r.unshielded.serializeState(),r.dust.serializeState()]),c={version:$s,network:t,address:e,timestamp:new Date().toISOString(),wallets:{shielded:o,unshielded:i,dust:a},...s?{chainId:s}:{}},d=io(e,t,n),u=Xf(d);if(!Vr(u))qf(u,{recursive:!0,mode:Re});let l=d+`.tmp.${Zf(4).toString("hex")}`;try{zf(l,JSON.stringify(c),{mode:Ie}),Yf(l,d)}catch(f){try{Kr(l)}catch{}throw f}}function Ma(e,t,r){if(!t)return[];let n=r??tt(oo(),ce,Le),s=tt(n,e);if(!Vr(s))return[];let o=[],i;try{i=On(s)}catch{return[]}for(let a of i){if(!a.endsWith(".json"))continue;let c=tt(s,a);try{let d=JSON.parse(Oa(c,"utf-8"));if(!d.chainId)continue;if(d.chainId!==t)Kr(c),o.push(c)}catch{}}return o}function ze(e,t,r){let n=r??tt(oo(),ce,Le);if(e&&t){let s=io(e,t,r);try{Kr(s)}catch{}return}if(t){let s=tt(n,t);if(!Vr(s))return;try{for(let o of On(s))if(o.endsWith(".json"))Kr(tt(s,o))}catch{}return}if(!Vr(n))return;try{for(let s of On(n)){let o=tt(n,s);try{for(let i of On(o))if(i.endsWith(".json"))Kr(tt(o,i))}catch{}}}catch{}}var Mt=()=>{};import Qf from"ws";async function er(e,t,r=[]){let n=e.timeoutMs??em;return new Promise((s,o)=>{let i=new Qf(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 em=5000;var Mn=()=>{};async function tr(e){let t=Fa.get(e);if(t&&Date.now()-t.fetchedAt<tm)return t.hash;try{let r=await er({url:e,timeoutMs:5000},"chain_getBlockHash",[0]);if(typeof r!=="string"||!r.startsWith("0x"))return null;return Fa.set(e,{hash:r,fetchedAt:Date.now()}),r}catch{return null}}var Fa,tm=60000;var Fn=A(()=>{Mn();Fa=new Map});async function kt(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 Ft(i.message)}if(!s.ok)throw new Ft(`HTTP ${s.status} ${s.statusText}`.trim());let o;try{o=await s.json()}catch(i){throw new Ft(`the answer is not JSON: ${i.message}`)}if(o.errors?.length)throw new Ft(o.errors.map((i)=>i.message).join("; "));if(o.data==null)throw new Ft("the answer has no data");return o.data}var Ft;var Jr=A(()=>{Ft=class Ft extends Error{constructor(e){super(e);this.name="IndexerQueryError",Object.setPrototypeOf(this,Ft.prototype)}}});function Ua(e,t){if(t!==null&&t<it.v9)throw new La(e,t)}async function Ln(e){try{let r=(await kt(e,"{ block { protocolVersion } }",void 0,rm)).block?.protocolVersion;return typeof r==="number"?BigInt(r):null}catch{return null}}async function He(e,t,r=Ln){Ua(e,await r(t.indexer))}async function Wa(e,t,r={}){let n=await(r.fetchVersion??Ln)(t.indexer);if(n===null)throw new ao("indexer",t.indexer);if(Ua(e,n),await(r.fetchGenesis??tr)(t.node)===null)throw new ao("node",t.node)}function Ba(e){return["shielded","unshielded","dust"].filter((t)=>e[t]<it.v9)}var La,rm=5000,ao;var Lt=A(()=>{ye();Fn();Jr();La=class La 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"}};ao=class ao 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 nm(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 Un(e,t,r){let n=nm(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 sm from"ws";function rr(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 sm(e,["graphql-transport-ws"]),h=!1,g=!1,S,y,w,k=()=>{if(clearTimeout(S),y)clearTimeout(y);if(w)clearTimeout(w);try{p.close()}catch{}u?.removeEventListener("abort",U)},T=(q,H)=>{if(g)return;g=!0,k();try{l(o(H))}catch(M){f(M instanceof Error?M:Error(String(M)))}},R=(q)=>{if(g)return;g=!0,k(),f(q)},U=()=>R(Error("Operation cancelled"));u?.addEventListener("abort",U,{once:!0});let X=()=>{if(y)clearTimeout(y);y=setTimeout(()=>{if(!g&&(h||c))T("idle",!1)},a)};p.on("open",()=>{p.send(JSON.stringify({type:"connection_init"}))}),p.on("message",(q)=>{let H;try{H=JSON.parse(q.toString())}catch{return}if(H.type==="connection_ack"){if(p.send(JSON.stringify({id:"1",type:"subscribe",payload:{query:r,variables:n}})),c)X();if(d&&d>0)w=setTimeout(()=>{if(!h&&!g)T("initial-silence",!1)},d);return}if(H.type==="error"){R(Error(`GraphQL subscription error: ${JSON.stringify(H.payload)?.slice(0,300)}`));return}if(H.type!=="next")return;if(H.payload?.errors){R(Error(`GraphQL error: ${H.payload.errors[0]?.message||"unknown"}`));return}if(h=!0,w)clearTimeout(w),w=void 0;let M;try{M=s(H.payload?.data)}catch(O){R(O instanceof Error?O:Error(String(O)));return}if(X(),M)T("caught-up",!1)}),p.on("error",(q)=>R(Error(`WebSocket error: ${q.message}`))),p.on("close",()=>{if(g)return;T(h?"closed-early":"graceful-close",h)}),S=setTimeout(()=>T("timeout",!0),i)})}var Wn=()=>{};import*as nr from"@midnightntwrk/ledger-v9";function im(){let e=new nr.DustParameters(Ti,Ni,Ri);return new nr.DustLocalState(e)}function ja(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[co]!=="1",h=500,g=d??im(),S=[],y=e.publicKey,w=new Set((l?.ownedGenerationIndices??[]).map(BigInt)),k=BigInt(l?.generationFrontier??0),T=(M)=>{let O=M.content;if(O?.tag!=="dustInitialUtxo"||O.generationIndex===void 0)return;let se=O.generationIndex;if(se+1n>k)k=se+1n;if(O.generation?.owner===y)w.add(se)},R=()=>({ownedGenerationIndices:[...w].map(Number),generationFrontier:Number(k)}),U=0,X=u-1,q=-1,H=()=>{if(S.length===0)return;if(g=g.replayEvents(e,S),U+=S.length,S.length=0,p)g=Un(g,w,k).state;if(s&&X>=0)try{s(g,X,R())}catch{}};return rr(t,{query:om,variables:{id:u},idleMs:i,timeoutMs:o,initialSilenceMs:d?a:0,signal:c,onNext:(M)=>{let O=M?.dustLedgerEvents;if(!O)return!1;let se;try{se=nr.Event.deserialize(Buffer.from(O.raw,"hex"))}catch(me){throw Error(`Failed to deserialize dust event ${O.id}: ${me.message}`)}if(T(se),S.push(se),X=O.id,O.maxId>q)q=O.maxId;if(S.length>=500)try{H()}catch(me){throw Error(`Failed applying dust events: ${me.message}`)}return n?.(U+S.length,q),X>=q},buildResult:(M)=>{try{H();let O=new Date;return g=g.processTtls(O),{balance:g.walletBalance(O),availableCoins:g.utxos.length,eventCount:U,ownedUtxoCount:g.utxos.length,syncTime:g.syncTime,state:g,retention:R(),lastAppliedEventId:X,partial:M}}catch(O){throw Error(`Failed to build dust state: ${O.message}`)}}})}var co="MN_DISABLE_DUST_COLLAPSE",om=`
|
|
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
|
|
101
|
-
`),l.stdin.end();let h="",g="";l.stdout.on("data",(
|
|
102
|
-
`).filter(Boolean).pop(),w=y?JSON.parse(y):JSON.parse(
|
|
100
|
+
`;var lo=A(()=>{Wn()});import{spawn as am}from"node:child_process";import{existsSync as Ut,mkdirSync as cm,readFileSync as Va,readdirSync as Ha,unlinkSync as Ga,writeFileSync as dm}from"node:fs";import{homedir as Ja}from"node:os";import{dirname as Ka,join as ut}from"node:path";import{fileURLToPath as lm}from"node:url";import*as qa from"@midnightntwrk/ledger-v9";function za(){let e=process.env.MN_DUST_SYNC_BIN;if(e&&Ut(e))return e;let t=process.platform==="win32"?"dust-sync.exe":"dust-sync",r=Ka(lm(import.meta.url));for(let n of[["..",".."],[".."]]){let s=ut(r,...n,"sidecar","dust-sync","target","release",t);if(Ut(s))return s}try{let n=`@nel349/dust-sync-${process.platform}-${process.arch}`,s=um(import.meta.url),o=ut(Ka(s.resolve(`${n}/package.json`)),t);if(Ut(o))return o}catch{}return null}function um(e){return globalThis.require??Si("node:module").createRequire(e)}function Ya(){if(pm!==fm)return!1;if(process.env.MN_DISABLE_NATIVE_DUST==="1")return!1;return za()!==null}function mm(e,t,r){if(e+1>=t)return"existing";if(r)return"seed";return"fresh"}function gm(e){if(!Ut(e))return-2;try{let t=JSON.parse(Va(e,"utf-8"));return typeof t.last_applied_event_id==="number"?t.last_applied_event_id:-2}catch{return-2}}function hm(e,t){let r=ut(Ja(),ce,Le,e);if(!Ut(r))cm(r,{recursive:!0,mode:Re});return ut(r,`dust-native-${t.slice(0,20)}.json`)}function Bn(e,t){let r=ut(Ja(),ce,Le);if(e&&t){try{Ga(ut(r,e,`dust-native-${t.slice(0,20)}.json`))}catch{}return}let n=(s)=>{if(!Ut(s))return;try{for(let o of Ha(s))if(o.startsWith("dust-native-")&&o.endsWith(".json"))try{Ga(ut(s,o))}catch{}}catch{}};if(e){n(ut(r,e));return}if(!Ut(r))return;try{for(let s of Ha(r))n(ut(r,s))}catch{}}function Xa(e,t,r){return new Promise((n,s)=>{let o=za();if(!o){s(Error("dust-sync sidecar not found"));return}let i=t.networkId.toLowerCase(),a=Qe(e),c=hm(i,a),d=["--indexer-ws",t.indexerWS,"--out",c],u=mm(gm(c),r.startFromId,!!r.initialState);if(u==="seed"){let S={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};dm(c,JSON.stringify(S),{mode:Ie})}if(u!=="fresh")d.push("--resume",c);let l=am(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(wt(e)).toString("hex");l.stdin.write(p+`
|
|
101
|
+
`),l.stdin.end();let h="",g="";l.stdout.on("data",(S)=>{h+=S.toString()}),l.stderr.on("data",(S)=>{let y=S.toString();g=(g+y).slice(-2000);for(let w of y.matchAll(/applied (\d+) \/ (\d+)/g))r.onProgress?.(Number(w[1]),Number(w[2]))}),l.on("error",(S)=>{r.signal?.removeEventListener("abort",f),s(S)}),l.on("close",(S)=>{if(r.signal?.removeEventListener("abort",f),S!==0){s(Error(`dust-sync exited ${S}: ${g.trim().slice(-300)}`));return}try{let y=h.trim().split(`
|
|
102
|
+
`).filter(Boolean).pop(),w=y?JSON.parse(y):JSON.parse(Va(c,"utf-8"));n(wm(w))}catch(y){s(Error(`dust-sync output parse failed: ${y.message}`))}})})}function wm(e){let t=new Date,r=qa.DustLocalState.deserialize(new Uint8Array(Buffer.from(e.dust_state,"hex")));if(process.env[co]!=="1"){let s=new Set(e.owned_generation_indices.map((o)=>BigInt(o)));r=Un(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 pm=8,fm=9;var uo=A(()=>{It();lo();_t()});async function jn(e,t){let r=ym[t],n=null;try{return await rr(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 Hn(e,t){return t!==null&&e>t}var ym;var po=A(()=>{Wn();ym={dust:"dustLedgerEvents",zswap:"zswapLedgerEvents"}});import*as Qa from"@midnightntwrk/ledger-v9";class ec{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??xm,this.fetchUnshielded=e.fetchUnshielded??Em,this.fetchDust=e.fetchDust??Tm,this.fetchChainId=e.fetchChainId??tr,this.fetchEventTip=e.fetchEventTip??jn,this.fetchProtocolVersion=e.fetchProtocolVersion??Ln,this.cacheDir=e.cacheDir}async dust(e,t,r={}){let n=Gn(t);await He(n,t,this.fetchProtocolVersion);let s=Qe(e),o=`${n}:${s}`;if(!r.forceFresh){let h=await this.tryMemo(o,t,this.dustMemo,r.signal);if(h)return{...h,fromCache:!0,eventsApplied:0}}let i=await this.fetchChainId(t.node).catch(()=>null);Aa(n,i,this.cacheDir);let a=i??void 0,c=r.forceFresh?null:Hr(n,s,this.cacheDir);if(c&&Hn(c.lastAppliedEventId,await this.fetchEventTip(t.indexerWS,"dust")))dt(n,s,this.cacheDir),c=null;let d=c!==null,u=0,l=c?.lastAppliedEventId??-1,f=null;for(let h=0;h<bm;h++){if(r.signal?.aborted)throw Error("Operation cancelled");let g=c?c.lastAppliedEventId+1:0;if(r.onStatus?.(h>0?`Resuming dust from event ${g} (continuation ${h+1})…`:c?`Resuming dust from event ${g}…`:"Reading dust events…"),f=await this.fetchDust(e,t,{startFromId:g,initialState:c?.state,initialRetention:c?.retention,signal:r.signal,onProgress:(S,y)=>{let w=Math.max(1,y+1-g);r.onStatus?.(`Reading dust events… ${S}/${w}`),r.onProgress?.(S,y)},onCheckpoint:(S,y,w)=>{try{eo(n,s,S,y,this.cacheDir,a,w)}catch{}}}),l=f.lastAppliedEventId>=0?f.lastAppliedEventId:c?.lastAppliedEventId??-1,f.lastAppliedEventId>=0||!c)try{eo(n,s,f.state,l,this.cacheDir,a,f.retention)}catch{}if(u+=f.eventCount,!f.partial)break;c=Hr(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=Gn(t),s=typeof e==="string"?e:Ee(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=Gn(t),c=Ee(e,a),d=t.networkId!=="Undeployed",u=n.syncTimeoutMs??(d?km:vm);await He(a,t,this.fetchProtocolVersion);let l=await this.fetchChainId(t.node).catch(()=>null);Ma(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,h,g=!1,S=async()=>{if(g||!p)return;g=!0;try{await We(p)}catch{}};try{for(let k=1;k<=qr;k++){if(n.signal?.aborted)throw Error("Operation cancelled");let T=n.forceFresh?null:vt(c,a,this.cacheDir);p=await et(e,t,T);try{h=await bt(p,{onProgress:n.onSyncProgress,onSyncDetail:n.onSyncDetail,timeoutMs:u,syncMode:s,requireStrictSync:o});break}catch(R){if(n.signal?.aborted)throw Error("Operation cancelled");if(R instanceof Dn&&k<qr&&i){n.onStatus?.(`Cache is stale, clearing and rebuilding (attempt ${k+1}/${qr})...`),await We(p).catch(()=>{}),p=void 0,ze(c,a,this.cacheDir),dt(a,Qe(e),this.cacheDir);try{await this.dust(e,t,{signal:n.signal,onStatus:n.onStatus})}catch{}continue}if(k<qr&&String(R?.message??"").includes("timed out")){try{await lt(c,a,p.facade,this.cacheDir,f)}catch{}n.onStatus?.(`Sync timed out, retrying (attempt ${k+1}/${qr})...`),await We(p).catch(()=>{}),p=void 0;continue}throw R}}if(!p||!h)throw Error("Sync failed: no facade state after retries");let y,w=0;while(!0){if(w++,n.signal?.aborted)throw Error("Operation cancelled");try{y=await r({bundle:p,state:h});break}catch(k){if(!(i&&w<Za&&_n(k)))throw k;if(n.onStatus?.(`Refreshing wallet state (attempt ${w+1}/${Za})...`),await We(p).catch(()=>{}),p=void 0,await new Promise((U)=>setTimeout(U,Cm)),n.signal?.aborted)throw Error("Operation cancelled");let R=vt(c,a,this.cacheDir);p=await et(e,t,R),h=await bt(p,{onProgress:n.onSyncProgress,onSyncDetail:n.onSyncDetail,timeoutMs:u,syncMode:s,requireStrictSync:o})}}if(!n.skipAutoSave)try{await lt(c,a,p.facade,this.cacheDir,f)}catch{}if(!n.readOnly)this.invalidate({network:t,seed:e});return y}finally{await S()}}invalidate(e){let t=Gn(e.network),r=e.kinds??["dust","unshielded","facade"];if(r.includes("dust"))if(e.seed){let n=Qe(e.seed);this.dustMemo.delete(`${t}:${n}`)}else this.deleteByPrefix(this.dustMemo,`${t}:`);if(r.includes("unshielded")){let n=e.address??(e.seed?Ee(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=Ee(e.seed,t);try{ze(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{L("repo",`tip unavailable; skipping memo for ${t}`)}}async getTip(e,t){let r=this.tipMemo.get(e.networkId);if(r&&this.now()-r.fetchedAt<Sm)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 xm(e){return er({url:e.node,timeoutMs:3000},"chain_getBlockHash",[])}function Em(e,t,r){return Qt(e,t.indexerWS,r)}function Am(e,t,r){let n=wt(e),s=Qa.DustSecretKey.fromSeed(n);return ja(s,t.indexerWS,r)}async function Tm(e,t,r){if(Ya())try{return await Xa(e,t,r)}catch(n){L("dust",`native sidecar failed, using WASM: ${n.message}`)}return Am(e,t,r)}function Gn(e){let t=e.networkId.toLowerCase();if(xe(t))return t;throw Error(`Unsupported network: ${e.networkId}`)}function Te(){if(!fo)fo=new ec;return fo}var Sm=5000,bm=6,vm=30000,km=120000,qr=3,Za=5,Cm=5000,fo=null;var Ct=A(()=>{ye();qe();Gr();_t();Mt();Fn();Lt();Br();lo();uo();St();Mn();It();Ve();po()});import*as sr from"@midnightntwrk/ledger-v9";function Rm(e){let t=sr.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 tc(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 sr.ZswapLocalState,p=[],h=0,g=u-1,S=-1,y=()=>{if(p.length===0)return;if(f=f.replayEventsWithChanges(e,p).state,h+=p.length,p.length=0,s&&g>=0)try{s(f,g)}catch{}};return rr(t,{query:Nm,variables:{id:u},idleMs:i,timeoutMs:o,initialSilenceMs:d?a:0,signal:c,onNext:(w)=>{let k=w?.zswapLedgerEvents;if(!k)return!1;let T;try{T=sr.Event.deserialize(new Uint8Array(Buffer.from(k.raw,"hex")))}catch(R){throw Error(`Failed to deserialize zswap event ${k.id}: ${R.message}`)}if(p.push(T),g=k.id,k.maxId>S)S=k.maxId;if(p.length>=500)try{y()}catch(R){throw Error(`Failed applying zswap events: ${R.message}`)}return n?.(h+p.length,S),g>=S},buildResult:(w)=>{try{y();let{balance:k,count:T}=Rm(f);return{balance:k,availableCoins:T,eventCount:h,state:f,lastAppliedEventId:g,partial:w}}catch(k){throw Error(`Failed to build shielded state: ${k.message}`)}}})}var Nm=`
|
|
103
103
|
subscription ZswapLedgerEvents($id: Int) {
|
|
104
104
|
zswapLedgerEvents(id: $id) {
|
|
105
105
|
id
|
|
@@ -107,20 +107,20 @@ 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
|
-
Available: ${
|
|
112
|
-
${n}`)}async function qn(e,t,r,n){let s=new Date,o=e.balance(s);if(o===0n||o>=t)return;let i=
|
|
113
|
-
Expected a bech32m address for network "${t.networkId}"`)}}function
|
|
110
|
+
`;var rc=A(()=>{Wn()});import{existsSync as Kn,mkdirSync as Im,writeFileSync as Dm,readFileSync as $m,unlinkSync as go,readdirSync as nc,renameSync as Pm}from"node:fs";import{join as or,dirname as _m}from"node:path";import{homedir as sc}from"node:os";import{randomBytes as Om}from"node:crypto";import*as zr from"@midnightntwrk/ledger-v9";function ic(e){return zr.ZswapSecretKeys.fromSeed(Rt(e)).coinPublicKey}function ac(e,t){let r=t??or(sc(),ce,Le);return or(r,e)}function ho(e,t,r){let n=t.slice(0,20);return or(ac(e,r),`shielded-${n}.json`)}function Mm(e,t,r,n){let s=ho(e,t,r);if(!Kn(s))return null;try{let o=JSON.parse($m(s,"utf-8"));if(o.version!==oc)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:zr.ZswapLocalState.deserialize(new Uint8Array(Buffer.from(o.zswapState,"hex"))),lastAppliedEventId:o.lastAppliedEventId}}catch{return null}}function mo(e,t,r,n,s,o){let i={version:oc,network:e,coinPublicKeyHex:t,lastAppliedEventId:n,timestamp:new Date().toISOString(),zswapState:Buffer.from(r.serialize()).toString("hex"),...o?{chainId:o}:{}},a=ho(e,t,s),c=_m(a);if(!Kn(c))Im(c,{recursive:!0,mode:Re});let d=a+`.tmp.${Om(4).toString("hex")}`;try{Dm(d,JSON.stringify(i),{mode:Ie}),Pm(d,a)}catch(u){try{go(d)}catch{}throw u}}function Yr(e,t,r){let n=r??or(sc(),ce,Le);if(e&&t){let o=ho(e,t,r);try{go(o)}catch{}return}let s=(o)=>{if(!Kn(o))return;try{for(let i of nc(o))if(i.startsWith("shielded-")&&i.endsWith(".json"))try{go(or(o,i))}catch{}}catch{}};if(e){s(ac(e,r));return}if(!Kn(n))return;try{for(let o of nc(n))s(or(n,o))}catch{}}async function cc(e,t,r,n={}){let s=zr.ZswapSecretKeys.fromSeed(Rt(e)),o=s.coinPublicKey,i=n.forceFresh?null:Mm(t,o,void 0,n.chainId);if(i&&Hn(i.lastAppliedEventId,await jn(r,"zswap")))Yr(t,o),i=null;let a=i?i.lastAppliedEventId+1:0,c=await tc(s,r,{initialState:i?.state,startFromId:a,onProgress:n.onProgress,signal:n.signal,timeoutMs:n.timeoutMs,onCheckpoint:(d,u)=>{try{mo(t,o,d,u,void 0,n.chainId)}catch{}}});if(c.lastAppliedEventId>=0)mo(t,o,c.state,c.lastAppliedEventId,void 0,n.chainId);else if(!i)mo(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 oc=2;var wo=A(()=>{It();rc();po()});function dc(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 lc(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 ${Fm(e.etaSec)}`);if(e.ratePerSec!==null&&e.ratePerSec>0)r.push(`${Math.round(e.ratePerSec)} evt/s`);return r.join(" · ")}function Fm(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 uc(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 pt(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 Vn;var Jn=A(()=>{fe();Vn=class Vn extends Error{code="DUST_GENERATING";constructor(e,t){let r=`Registering for Dust costs a ${le(e.fee)} DUST fee, paid from the Dust this wallet's NIGHT generates`,n=`It has generated ${le(e.generated)} DUST so far`;super(e.waitMs===null?`${r}, but it can never generate that much: its NIGHT holds at most ${le(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 ${pt(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,Vn.prototype)}}});async function pc(e){try{let r=(await kt(e,"{ block { timestamp } }",void 0,5000)).block?.timestamp;return typeof r==="number"?new Date(r):null}catch{return null}}function fc(e,t){if(t.getTime()-e.getTime()>Lm)throw new yo(e,t)}var Lm=120000,yo;var mc=A(()=>{Jr();Jn();yo=class yo extends Error{code="CHAIN_CLOCK_BEHIND";constructor(e,t){super(`This chain's clock is ${pt(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,yo.prototype)}}});function Bm(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 jm(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 ${pt(r)}; retry then.`;return Error(`Insufficient dust for transaction fees.
|
|
111
|
+
Available: ${le(e)} DUST, need ≥${le(t)} DUST.
|
|
112
|
+
${n}`)}async function qn(e,t,r,n){let s=new Date,o=e.balance(s);if(o===0n||o>=t)return;let i=Bm(e,t,s,Wm);if(i===null||i>Um)throw jm(o,t,i);r?.(`Waiting ${pt(i)} for Dust to cover the fee (${le(o)} of ${le(t)} DUST)...`),await Xr(i,n)}function Xr(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 Um=120000,Wm=86400000;var So=A(()=>{Jn();fe()});import*as ko from"@midnightntwrk/ledger-v9";import{MidnightBech32m as Hm,UnshieldedAddress as Gm}from"@midnightntwrk/wallet-sdk/address-format";function ir(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 zn(e){let t=e.trim(),r=/^(\d*)(?:\.(\d*))?$/.exec(t);if(!r||r[1]===""&&!r[2])throw new _(`Invalid amount: "${e}" — must be a positive number, e.g. 1.5`);let n=r[2]??"";if(n.length>bo)throw new _(`Invalid amount: "${e}" — NIGHT has ${bo} decimals, this has ${n.length}`);let s=Number(t);if(s<=0)throw new _(`Invalid amount: "${e}" — must be greater than 0`);let o=BigInt((r[1]||"0")+n.padEnd(bo,"0"));if(ir(s)!==o)throw new _(`Invalid amount: "${e}" — too many digits to handle exactly`);return s}function Km(e,t){let r=Ue(t.networkId);try{return Hm.parse(e).decode(Gm,r)}catch(n){throw Error(`Invalid recipient address: ${n.message}
|
|
113
|
+
Expected a bech32m address for network "${t.networkId}"`)}}function vo(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 Pe(){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 Vm(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")),mn))]);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 Jm(e,t,r,n){let s=Date.now(),o=s+Mi,i,a=!1,c=e.indexerHttpUrl?await pc(e.indexerHttpUrl):null;if(c)fc(c,new Date);let{fee:d,dustGenerationEstimations:u}=await e.facade.estimateRegistration(t),l=uc(d,u);if(l.waitMs===null||l.waitMs>o-Date.now())throw new Vn(l,new Date);let f=l.waitMs>0?`, fee covered in ${pt(l.waitMs)}`:"";if(l.waitMs>0)n?.(`Waiting for the NIGHT to generate the ${le(l.fee)} DUST registration fee (${pt(l.waitMs)})...`);let p=setInterval(()=>{if(a&&n){let h=vo(Date.now()-s);n(`Waiting for dust generation capacity (${h} elapsed${f})...`)}},1000);try{while(Date.now()<o)try{return await Vm(e,t,r,o-Date.now())}catch(h){if(i=h,Pn(h)&&Date.now()+Is<o){a=!0;let g=vo(Date.now()-s);n?.(`Waiting for dust generation capacity (${g} elapsed${f})...`),await new Promise((S)=>setTimeout(S,Is));continue}throw h}throw i??Error("Dust registration timed out")}finally{clearInterval(p)}}async function rt(e,t,r){let n=r??await e.facade.waitForSyncedState();if(Ot(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 Jm(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<Ns){try{if((await Promise.race([e.facade.waitForSyncedState(),new Promise((c,d)=>setTimeout(()=>d(Error("Poll sync timed out")),mn))])).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 qm(e,t,r,n,s,o,i,a){let c=Date.now(),d=c+Ns,u,l=0;while(!0)try{if(u)await no(e,"lite");let f=new Date(Date.now()+hn*60*1000);L("transfer","Building transfer transaction...");let p=await e.facade.transferTransaction([{type:"unshielded",outputs:[{amount:r,receiverAddress:t,type:ko.unshieldedToken().raw}]}],{ttl:f,payFees:!0});L("transfer","Signing recipe...");let h=await e.facade.signRecipe(p,e.keystore.signDataAsync);L("transfer","Generating ZK proof..."),n?.();let g=await Promise.race([e.facade.finalizeRecipe(h),new Promise((k,T)=>{setTimeout(()=>T(Error("ZK proof generation timed out")),gn)})]);L("transfer","Submitting transaction to node..."),s?.();let S=Date.now(),y=i?setInterval(()=>i(Date.now()-S),1000):void 0,w;try{w=await e.facade.submitTransaction(g)}finally{if(y)clearInterval(y)}return L("transfer",`Transaction submitted: ${w}`),w}catch(f){if(u=f,(f?.code===Fi||f?.message?.includes("115")||f?.message?.toLowerCase().includes("stale"))&&++l<Oi)continue;if(_n(f))throw f;if(Pn(f)&&Date.now()<d){let h=vo(Date.now()-c);o?.(`Dust insufficient, re-ensuring (${h} elapsed)...`);try{let g=await no(e,"lite");if(await qn(g.dust,Ar,o,a),g.dust.balance(new Date)>=Ar)o?.(`Dust is short of this transaction's fee; waiting ${gc/1000} s for more...`),await Xr(gc,a);await rt(e,o,g)}catch(g){if(String(g?.message).startsWith("Insufficient dust"))throw g;await new Promise((S)=>setTimeout(S,5000))}continue}throw f}}async function ar(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=ir(s),h=Km(n,r),g=$e(f),S=Pe();try{return await Te().withFacade(t,r,async({bundle:y,state:w})=>{if(o?.aborted)throw Error("Operation cancelled");L("transfer","Sync complete, checking balance...");let k=w.unshielded.balances[ko.unshieldedToken().raw]??0n,T=w.unshielded.availableCoins?.length??0;if(L("transfer",`Balance: ${Number(k)/Ts} NIGHT, coins: ${T}`),k<p){let X=Number(k)/Ts;throw Error(`Insufficient balance: ${X.toFixed(6)} NIGHT available, ${s} NIGHT requested`)}if(await qn(w.dust,Ar,c,o),o?.aborted)throw Error("Operation cancelled");if(L("transfer","Ensuring dust availability..."),!(await rt(y,c,w)).alreadyAvailable){let X,q=await Promise.race([y.facade.waitForSyncedState(),new Promise((H)=>{X=setTimeout(()=>H(null),mn)})]).finally(()=>clearTimeout(X));if(q)await qn(q.dust,Ar,c,o)}if(L("transfer","Dust available"),o?.aborted)throw Error("Operation cancelled");return L("transfer","Building and submitting transaction..."),{txHash:await qm(y,h,p,d,u,c,l,o),amountMicroNight:p}},{syncMode:"lite",requireStrictSync:!0,signal:o,onStatus:c,onSyncProgress:i,onSyncDetail:a,onSyncWarning:f})}finally{S(),g()}}var bo=6,gc=1e4;var xt=A(()=>{ct();qe();Ct();St();ve();Gr();Gr();Jn();mc();So();fe()});function wc(e){return e.replace(/\x1b\[[0-9;]*m/g,"")}function V(e){let t=!1;if(!Mr()){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,cr=null,process.stderr.write(`\r✓ ${d??a}\x1B[K
|
|
114
114
|
`)},fail(d){if(t)return;t=!0,cr=null,process.stderr.write(`\r✗ ${d??a}\x1B[K
|
|
115
115
|
`)},log(d){process.stderr.write(`\r\x1B[K${d}
|
|
116
|
-
`),process.stderr.write(`⠋ ${a}`)}};return cr=c,c}let r=0,n=e,s=()=>{let a=K(
|
|
116
|
+
`),process.stderr.write(`⠋ ${a}`)}};return cr=c,c}let r=0,n=e,s=()=>{let a=K(hc[r]),d=(process.stderr.columns||80)-4,u=n;if(wc(u).length>d)u=wc(u).slice(0,d);process.stderr.write(`\r${a} ${u}\x1B[K`),r=(r+1)%hc.length};s();let o=setInterval(s,zm),i={update(a){n=a},stop(a){if(t)return;t=!0,clearInterval(o),cr=null;let c=a??n;process.stderr.write(`\r\x1B[32m✓\x1B[0m ${c}\x1B[K
|
|
117
117
|
`)},fail(a){if(t)return;t=!0,clearInterval(o),cr=null;let c=a??n;process.stderr.write(`\r\x1B[31m✗\x1B[0m ${c}\x1B[K
|
|
118
118
|
`)},log(a){process.stderr.write(`\r\x1B[K${a}
|
|
119
|
-
`),s()}};return cr=i,i}async function Yn(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
|
|
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}=
|
|
119
|
+
`),s()}};return cr=i,i}async function Yn(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 hc,zm=80,cr=null;var ft=A(()=>{hc=["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"]});var vc={};be(vc,{default:()=>Sc});import*as yc from"@midnightntwrk/ledger-v9";import{MidnightBech32m as Ym}from"@midnightntwrk/wallet-sdk/address-format";async function Sc(e){if(e.subcommand)return Zm(e);return bc(e)}function Xm(e){let t=e.match(/^mn_addr_([a-z]+)1/);if(!t)return null;let r=t[1];return xe(r)?r:null}async function Zm(e){if(Ke(e))Je();let t=e.subcommand;L("balance",`address=${t}`);let r=Xm(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}=pe({args:e});if(N(e,"shielded")){let a=ta(t);if(a){L("balance",`shielded positional → wallet ${a.wallet.name} on ${a.network}`);let c={...e,flags:{...e.flags,wallet:a.wallet.file,network:a.network}};return bc(c)}throw Error("Shielded balances are private — they can only be read with the wallet's secret key, "+`not from an address alone.
|
|
121
121
|
This address isn't one of your wallets. Check its shielded balance from the wallet that owns it:
|
|
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=V(`Checking balance on ${s}...`);try{let a=await Te().unshielded(t,o,{forceFresh:N(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`),N(e,"json")){let c={};for(let[u,l]of a.balances){let f=
|
|
123
|
-
`);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=V(`Checking balance on ${s}...`);try{let a=await Te().unshielded(t,o,{forceFresh:N(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`),N(e,"json")){let c={};for(let[u,l]of a.balances){let f=Wr(u)?"NIGHT":u;c[f]=Wr(u)?$t(l):l.toString()}let d=c.NIGHT!==void 0?{NIGHT:c.NIGHT}:{};if(ht(e)){I({network:s,balances:c,...d,utxoCount:a.utxoCount});return}I({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(`${Wr(c)?"NIGHT":c}=${d}
|
|
124
124
|
`);if(process.stderr.write(`
|
|
125
125
|
`+B("Balance")+`
|
|
126
126
|
|
|
@@ -130,12 +130,12 @@ This address isn't one of your wallets. Check its shielded balance from the wall
|
|
|
130
130
|
`),process.stderr.write(E("Transactions",a.txCount.toString())+`
|
|
131
131
|
`),process.stderr.write(`
|
|
132
132
|
`),a.balances.size===0)process.stderr.write(` ${m("No balance found")}
|
|
133
|
-
`);else for(let[c,d]of a.balances)if(
|
|
133
|
+
`);else for(let[c,d]of a.balances)if(Wr(c))process.stderr.write(E("NIGHT",P(En(d)))+`
|
|
134
134
|
`);else{let u=c.slice(0,8)+"…"+c.slice(-8);process.stderr.write(E(`Token ${u}`,P(d.toString()))+`
|
|
135
135
|
`)}process.stderr.write(`
|
|
136
136
|
`+J()+`
|
|
137
137
|
|
|
138
|
-
`)}catch(a){throw i.fail("Failed"),a}}async function
|
|
138
|
+
`)}catch(a){throw i.fail("Failed"),a}}async function bc(e){if(Ke(e))Je();let{name:t,config:r}=pe({args:e});L("balance",`network=${t} indexerWS=${r.indexerWS}`);let{seed:n,walletPath:s,config:o}=Vs(e);L("balance",`wallet path=${s??"(from --seed/MN_SEED)"}`);let i=o?.addresses[t]??Ee(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=$e(),d=Pe(),u=N(e,"no-cache"),l=N(e,"json"),f=yc.unshieldedToken().raw,p=null;try{if(!l){if(process.stderr.write(`
|
|
139
139
|
`+B("Balance")+`
|
|
140
140
|
|
|
141
141
|
`),process.stderr.write(E("Address",te(i))+`
|
|
@@ -143,21 +143,21 @@ This address isn't one of your wallets. Check its shielded balance from the wall
|
|
|
143
143
|
`);process.stderr.write(E("Network",t)+`
|
|
144
144
|
`),process.stderr.write(`
|
|
145
145
|
`+P("Unshielded")+`
|
|
146
|
-
`)}if(!l)p=V("Checking unshielded...");L("balance",`phase=unshielded forceFresh=${u}`);let h=await Te().unshielded(i,r,{forceFresh:u}),g=h.balances.get(f)??0n,
|
|
147
|
-
`),process.stderr.write(E(" UTXOs",
|
|
146
|
+
`)}if(!l)p=V("Checking unshielded...");L("balance",`phase=unshielded forceFresh=${u}`);let h=await Te().unshielded(i,r,{forceFresh:u}),g=h.balances.get(f)??0n,S=h.utxoCount;if(L("balance",`unshielded fromCache=${h.fromCache} utxos=${S} txs=${h.txCount}`),p)if(p.stop("Unshielded ready"),p=null,g>0n)process.stderr.write(E(" NIGHT",P(En(g)))+`
|
|
147
|
+
`),process.stderr.write(E(" UTXOs",S.toString())+`
|
|
148
148
|
`);else process.stderr.write(` ${m("No unshielded balance")}
|
|
149
149
|
`);if(!l)process.stdout.write(`NIGHT=${g}
|
|
150
150
|
`),process.stderr.write(`
|
|
151
151
|
`+P("Shielded")+`
|
|
152
|
-
`);let y=Tn(t,N(e,"force-shielded")),w=a,k=0n,T=0,R=0;if(y){if(!l)p=V("Syncing shielded...");let U=
|
|
152
|
+
`);let y=Tn(t,N(e,"force-shielded")),w=a,k=0n,T=0,R=0;if(y){if(!l)p=V("Syncing shielded...");let U=dc(),X=Ue(r.networkId);if(w=Ym.encode(X,Pr(n)).asString(),s)zt(s,t,w);await He(t,r);let q=await tr(r.node).catch(()=>null)??void 0,H=await cc(n,t,r.indexerWS,{forceFresh:u,chainId:q,onProgress:(M,O)=>{if(!p)return;let se=U.sample({applied:M,highest:O,t:Date.now()});p.update(lc(se,"Syncing shielded"))}});if(k=H.balance,T=H.availableCoins,R=0,p)if(p.stop("Shielded ready"),p=null,k>0n)process.stderr.write(E(" NIGHT",P(En(k)))+`
|
|
153
153
|
`),process.stderr.write(E(" Coins",`${T} available, ${R} pending`)+`
|
|
154
154
|
`);else process.stderr.write(` ${m("No shielded balance")}
|
|
155
155
|
`)}else if(!l)process.stderr.write(` ${m("Skipped — "+Nn(t))}
|
|
156
|
-
`);if(l){if(ht(e)){I({network:t,unshielded:{NIGHT:$t(g),utxoCount:
|
|
156
|
+
`);if(l){if(ht(e)){I({network:t,unshielded:{NIGHT:$t(g),utxoCount:S},shielded:{NIGHT:$t(k),availableCoins:T,pendingCoins:R},shieldedSynced:y});return}I({address:i,shieldedAddress:w,network:t,unshielded:{NIGHT:$t(g),utxoCount:S},shielded:{NIGHT:$t(k),availableCoins:T,pendingCoins:R},shieldedSynced:y});return}process.stdout.write(`SHIELDED_NIGHT=${y?k:"skipped"}
|
|
157
157
|
`),process.stderr.write(`
|
|
158
158
|
`+J()+`
|
|
159
159
|
|
|
160
|
-
`)}catch(h){throw p?.fail("Failed"),h}finally{d(),c()}}var
|
|
160
|
+
`)}catch(h){throw p?.fail("Failed"),h}finally{d(),c()}}var kc=A(()=>{oe();St();ye();De();Xt();ke();ye();Js();ct();Br();Ct();wo();Lt();Ve();Fn();qe();xt();fe();ft()});var xc={};be(xc,{default:()=>Cc});async function Cc(e){let t=xn(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=Se({args:e}),o=Ee(t,s,n),i=`m/44'/2400'/0'/NightExternal/${n}`;if(N(e,"json")){I({address:o,network:s,index:n,path:i});return}process.stdout.write(o+`
|
|
161
161
|
`),process.stderr.write(`
|
|
162
162
|
`),process.stderr.write(E("Network",s)+`
|
|
163
163
|
`),process.stderr.write(E("Index",n.toString())+`
|
|
@@ -165,36 +165,36 @@ This address isn't one of your wallets. Check its shielded balance from the wall
|
|
|
165
165
|
`),process.stderr.write(E("Path",m(i))+`
|
|
166
166
|
`),process.stderr.write(J()+`
|
|
167
167
|
|
|
168
|
-
`)}var
|
|
168
|
+
`)}var Ec=A(()=>{oe();Xt();Ve();ke();fe()});var Tc={};be(Tc,{default:()=>Ac});async function Ac(e){let t=Se({args:e}),r=Buffer.from(ot,"hex"),n=Ee(r,t);if(N(e,"json")){I({address:n,network:t});return}process.stdout.write(n+`
|
|
169
169
|
`),process.stderr.write(`
|
|
170
170
|
`),process.stderr.write(E("Network",t)+`
|
|
171
171
|
`),process.stderr.write(E("Address",te(n))+`
|
|
172
172
|
`),process.stderr.write(E("Seed",m("0x01 (genesis)"))+`
|
|
173
173
|
`),process.stderr.write(J()+`
|
|
174
174
|
|
|
175
|
-
`)}var
|
|
175
|
+
`)}var Nc=A(()=>{oe();Ve();ke();fe()});import*as Rc from"@midnightntwrk/ledger-v9";async function Ic(e){let t=await kt(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:Rc.LedgerParameters.deserialize(Buffer.from(r,"hex"))}}var Dc=A(()=>{Jr()});var Pc={};be(Pc,{default:()=>$c});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 Qm(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 $c(e){let{name:t,config:r}=pe({args:e});await He(t,r);let{height:n,params:s}=await Ic(r.indexer),o=Qm(s);if(N(e,"json")){I({...o,network:t,height:n});return}for(let[i,a]of Object.entries(o))process.stdout.write(`${i}=${a}
|
|
176
176
|
`);process.stderr.write(`
|
|
177
177
|
`+B("Block Limits")+`
|
|
178
178
|
|
|
179
179
|
`),process.stderr.write(m(` From the ledger parameters of block ${n} on ${t}`)+`
|
|
180
180
|
|
|
181
|
-
`);for(let[i,a]of Object.entries(o)){let c=
|
|
181
|
+
`);for(let[i,a]of Object.entries(o)){let c=eg[i]??"";process.stderr.write(E(i,`${P(a.toLocaleString())} ${m(c)}`)+`
|
|
182
182
|
`)}process.stderr.write(`
|
|
183
183
|
`+J()+`
|
|
184
184
|
`),process.stderr.write(m(" bytesWritten is typically the tightest constraint")+`
|
|
185
185
|
`),process.stderr.write(m(" for large contract deployments.")+`
|
|
186
186
|
|
|
187
|
-
`)}var
|
|
187
|
+
`)}var eg;var _c=A(()=>{oe();fe();ke();Dc();Lt();eg={readTime:"picoseconds",computeTime:"picoseconds",blockUsage:"bytes",bytesWritten:"bytes",bytesChurned:"bytes"}});var Lc={};be(Lc,{default:()=>Fc});import*as Oc from"@midnightntwrk/ledger-v9";import{MidnightBech32m as Mc,ShieldedAddress as tg}from"@midnightntwrk/wallet-sdk/address-format";async function Fc(e,t){Ht(e);let r=e.subcommand;if(!r)throw Error(`Missing amount.
|
|
188
188
|
Usage: midnight airdrop <amount> [--wallet <name|file|address>]
|
|
189
189
|
Example: midnight airdrop 1000
|
|
190
190
|
Example: midnight airdrop 1000 --wallet alice
|
|
191
|
-
Example: midnight airdrop 1000 --wallet mn_addr_undeployed1...`);let n=zn(r),{name:s,config:o}=
|
|
191
|
+
Example: midnight airdrop 1000 --wallet mn_addr_undeployed1...`);let n=zn(r),{name:s,config:o}=pe({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).
|
|
192
192
|
Current network: "${s}"
|
|
193
|
-
On preprod/preview, use a faucet or transfer from another wallet.`);let i=x(e,"wallet"),a=N(e,"shielded")||i!==void 0&&i.startsWith("mn_shield-addr_"),c=
|
|
193
|
+
On preprod/preview, use a faucet or transfer from another wallet.`);let i=x(e,"wallet"),a=N(e,"shielded")||i!==void 0&&i.startsWith("mn_shield-addr_"),c=ng(e,s,o,a);if(a)return ig(e,c,n,s,o,t);return og(e,c,n,s,o,t)}function rg(e){return e.startsWith("mn_addr_")||e.startsWith("mn_shield-addr_")}function ng(e,t,r,n){let s=x(e,"wallet");if(s!==void 0&&rg(s))return sg(s,t,r,n);let o=re(s),i=ne(o);if(n){let a=Ue(r.networkId),c=Buffer.from(i.seed,"hex"),d=Pr(c),u=Mc.encode(a,d).asString();return{kind:"wallet",raw:d,bech32m:u,walletPath:o}}return{kind:"address",address:i.addresses[t]}}function sg(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.
|
|
194
194
|
Pass a shielded address (mn_shield-addr_...) or drop --shielded.
|
|
195
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}".
|
|
196
196
|
Expected prefix: ${o}
|
|
197
|
-
Got: ${e}`);if(n){let i=Ue(r.networkId),a;try{a=
|
|
197
|
+
Got: ${e}`);if(n){let i=Ue(r.networkId),a;try{a=Mc.parse(e).decode(tg,i)}catch(c){throw Error(`Invalid shielded address: ${c.message}`)}return{kind:"address",raw:a,bech32m:e}}return{kind:"address",address:e}}async function og(e,t,r,n,s,o){if(Ke(e))Je();let i=t.address,a=Buffer.from(ot,"hex");process.stderr.write(`
|
|
198
198
|
`+B("Airdrop")+`
|
|
199
199
|
|
|
200
200
|
`),process.stderr.write(E("Network",n)+`
|
|
@@ -215,7 +215,7 @@ Got: ${e}`);if(n){let i=Ue(r.networkId),a;try{a=Nc.parse(e).decode(Mm,i)}catch(c
|
|
|
215
215
|
`)}catch(d){if(c.fail("Failed"),d instanceof Error&&d.message.toLowerCase().includes("dust"))throw Error(`${d.message}
|
|
216
216
|
|
|
217
217
|
On a fresh localnet, the minimum airdrop is ~1 NIGHT.
|
|
218
|
-
Try: midnight airdrop 1`);throw d}}async function
|
|
218
|
+
Try: midnight airdrop 1`);throw d}}async function ig(e,t,r,n,s,o){let i=ir(r);if(Ke(e))Je();let a=Buffer.from(ot,"hex"),c=Oc.unshieldedToken().raw,{raw:d,bech32m:u}=t;if(t.kind==="wallet")zt(t.walletPath,n,u);process.stderr.write(`
|
|
219
219
|
`+B("Shielded Airdrop")+`
|
|
220
220
|
|
|
221
221
|
`),process.stderr.write(E("Network",n)+`
|
|
@@ -223,22 +223,22 @@ Try: midnight airdrop 1`);throw d}}async function Bm(e,t,r,n,s,o){let i=ir(r);if
|
|
|
223
223
|
`),process.stderr.write(E("To",te(u,!0))+`
|
|
224
224
|
`),process.stderr.write(E("Amount",P(r+" NIGHT (shielded)"))+`
|
|
225
225
|
`),process.stderr.write(`
|
|
226
|
-
`);let l=$e(),f=Pe(),p=V("Syncing genesis wallet...");try{let h=await Te().withFacade(a,s,async({bundle:g,state:
|
|
226
|
+
`);let l=$e(),f=Pe(),p=V("Syncing genesis wallet...");try{let h=await Te().withFacade(a,s,async({bundle:g,state:S})=>{let y=S.shielded.balances[c]??0n;if(y<i){let U=Number(y)/1e6;throw Error(`Genesis wallet has insufficient shielded balance: ${U.toFixed(6)} NIGHT available, ${r} NIGHT requested`)}if(p.update("Checking dust..."),await rt(g,(U)=>p.update(U)),o?.aborted)throw Error("Operation cancelled");p.update("Building shielded transaction...");let w=await g.facade.transferTransaction([{type:"shielded",outputs:[{type:c,amount:i,receiverAddress:d}]}],{ttl:new Date(Date.now()+3600000)});p.update("Signing...");let k=await g.facade.signRecipe(w,g.keystore.signDataAsync);p.update("Generating ZK proof (this may take a few minutes)...");let T=await g.facade.finalizeRecipe(k),R=await Yn(p,"Submitting and waiting for finalization (typically 12 to 30s)...",g.facade.submitTransaction(T));return String(R)},{syncMode:"full",requireStrictSync:!0,signal:o,onStatus:(g)=>p.update(g),onSyncProgress:(g,S)=>{if(S>0){let y=Math.min(Math.round(g/S*100),100);p.update(y>=100?"Syncing genesis wallet...":`Syncing genesis wallet... ${y}%`)}},onSyncDetail:(g)=>p.update(`Syncing genesis wallet... (waiting on: ${g})`)});if(p.stop("Transaction submitted"),N(e,"json")){I({txHash:h,amount:r,shieldedAddress:u,network:n,type:"shielded"});return}process.stdout.write(h+`
|
|
227
227
|
`),process.stderr.write(`
|
|
228
228
|
`+yt(`Airdropped ${r} shielded NIGHT to your wallet`,h)+`
|
|
229
229
|
`),process.stderr.write(`
|
|
230
230
|
`+J()+`
|
|
231
231
|
`),process.stderr.write(m(" Verify: midnight balance --shielded")+`
|
|
232
232
|
|
|
233
|
-
`)}catch(h){throw p.fail("Failed"),h}finally{f(),l()}}var
|
|
233
|
+
`)}catch(h){throw p.fail("Failed"),h}finally{f(),l()}}var Uc=A(()=>{oe();St();De();ke();ye();ct();Ve();xt();qe();Ct();fe();ft()});import{MidnightBech32m as Wc,ShieldedAddress as ag,UnshieldedAddress as cg}from"@midnightntwrk/wallet-sdk/address-format";function Xn(e){let t=e.subcommand,r=e.positionals[0];if(!t)throw new _(`Missing recipient address.
|
|
234
234
|
Usage: midnight transfer <to> <amount>
|
|
235
235
|
Example: midnight transfer mn_addr_undeployed1... 100
|
|
236
236
|
Example: midnight transfer alice 100`);if(!r)throw new _(`Missing amount.
|
|
237
237
|
Usage: midnight transfer <to> <amount>
|
|
238
|
-
Example: midnight transfer mn_addr_undeployed1... 100`);let n=N(e,"shielded"),s=
|
|
239
|
-
Expected a shielded address (mn_shield-addr_...) for network "${t}"`)}}function
|
|
240
|
-
Expected a bech32m address (mn_addr_...) for network "${t}"`)}}function
|
|
241
|
-
Regenerate the wallet or run "midnight balance --shielded" first.`);return i}let o=n.addresses[s];if(!o)throw Error(`Wallet "${e}" has no address for network "${s}". Regenerate the wallet to derive one.`);return o}var
|
|
238
|
+
Example: midnight transfer mn_addr_undeployed1... 100`);let n=N(e,"shielded"),s=lg(t,e,n),o=zn(r),i=re(x(e,"wallet")),a=ne(i),c=Se({args:e});if(n){if(!Tn(c,N(e,"force-shielded")))throw Error(Nn(c));Co(s,c)}else dg(s,c);return{walletPath:i,walletConfig:a,networkName:c,recipientAddress:s,amountNight:o,shielded:n}}function Co(e,t){try{return Wc.parse(e).decode(ag,qt(t))}catch(r){throw new _(`Invalid shielded address: ${r.message}
|
|
239
|
+
Expected a shielded address (mn_shield-addr_...) for network "${t}"`)}}function dg(e,t){try{return Wc.parse(e).decode(cg,qt(t))}catch(r){throw new _(`Invalid recipient address: ${r.message}
|
|
240
|
+
Expected a bech32m address (mn_addr_...) for network "${t}"`)}}function lg(e,t,r){if(e.startsWith("mn_addr_")||e.startsWith("mn_shield-addr_"))return e;let n=ne(re(e)),s=Se({args:t});if(r){let i=n.shieldedAddresses?.[s];if(!i)throw Error(`Wallet "${e}" has no shielded address for network "${s}".
|
|
241
|
+
Regenerate the wallet or run "midnight balance --shielded" first.`);return i}let o=n.addresses[s];if(!o)throw Error(`Wallet "${e}" has no address for network "${s}". Regenerate the wallet to derive one.`);return o}var xo=A(()=>{oe();ve();De();ke();ct();Js();xt()});var Hc={};be(Hc,{default:()=>jc});import*as Bc from"@midnightntwrk/ledger-v9";import{MidnightBech32m as ug}from"@midnightntwrk/wallet-sdk/address-format";async function jc(e,t){Ht(e);let r=Xn(e);return r.shielded?fg(e,r,t):pg(e,r,t)}async function pg(e,{walletConfig:t,recipientAddress:r,amountNight:n},s){let o=Buffer.from(t.seed,"hex"),{name:i,config:a}=pe({args:e}),c=t.addresses[i];if(_e(a,{proofServer:x(e,"proof-server"),node:x(e,"node"),indexerWS:x(e,"indexer-ws")},i),process.stderr.write(`
|
|
242
242
|
`+B("Transfer")+`
|
|
243
243
|
|
|
244
244
|
`),process.stderr.write(E("Network",i)+`
|
|
@@ -253,29 +253,29 @@ Regenerate the wallet or run "midnight balance --shielded" first.`);return i}let
|
|
|
253
253
|
`+J()+`
|
|
254
254
|
`),process.stderr.write(m(" Verify: midnight balance")+`
|
|
255
255
|
|
|
256
|
-
`)}catch(u){throw d.fail("Failed"),u}}async function
|
|
256
|
+
`)}catch(u){throw d.fail("Failed"),u}}async function fg(e,{walletPath:t,walletConfig:r,recipientAddress:n,amountNight:s},o){let i=ir(s),a=Buffer.from(r.seed,"hex"),{name:c,config:d}=pe({args:e}),u=Ue(d.networkId),l=Bc.unshieldedToken().raw;_e(d,{proofServer:x(e,"proof-server"),node:x(e,"node"),indexerWS:x(e,"indexer-ws")},c);let f=Co(n,c);if(process.stderr.write(`
|
|
257
257
|
`+B("Shielded Transfer")+`
|
|
258
258
|
|
|
259
259
|
`),process.stderr.write(E("Network",c)+`
|
|
260
260
|
`),process.stderr.write(E("To",te(n,!0))+`
|
|
261
261
|
`),process.stderr.write(E("Amount",P(s+" NIGHT (shielded)"))+`
|
|
262
262
|
`),process.stderr.write(`
|
|
263
|
-
`),Ke(e))Je();let p=$e(),h=Pe(),g=V("Syncing wallet...");try{let
|
|
264
|
-
Fund shielded balance: midnight airdrop ${s} --shielded`)}if(g.update("Checking dust..."),await rt(y,(H)=>g.update(H)),o?.aborted)throw Error("Operation cancelled");g.update("Building shielded transaction...");let R=await y.facade.transferTransaction([{type:"shielded",outputs:[{type:l,amount:i,receiverAddress:f}]}],{ttl:new Date(Date.now()+3600000)});g.update("Signing...");let U=await y.facade.signRecipe(R,y.keystore.signDataAsync);g.update("Generating ZK proof (this may take a few minutes)...");let
|
|
263
|
+
`),Ke(e))Je();let p=$e(),h=Pe(),g=V("Syncing wallet...");try{let S=await Te().withFacade(a,d,async({bundle:y,state:w})=>{let k=ug.encode(u,w.shielded.address).asString();zt(t,c,k);let T=w.shielded.balances[l]??0n;if(T<i){let H=Number(T)/1e6;throw Error(`Insufficient shielded balance: ${H.toFixed(6)} NIGHT available, ${s} NIGHT requested.
|
|
264
|
+
Fund shielded balance: midnight airdrop ${s} --shielded`)}if(g.update("Checking dust..."),await rt(y,(H)=>g.update(H)),o?.aborted)throw Error("Operation cancelled");g.update("Building shielded transaction...");let R=await y.facade.transferTransaction([{type:"shielded",outputs:[{type:l,amount:i,receiverAddress:f}]}],{ttl:new Date(Date.now()+3600000)});g.update("Signing...");let U=await y.facade.signRecipe(R,y.keystore.signDataAsync);g.update("Generating ZK proof (this may take a few minutes)...");let X=await y.facade.finalizeRecipe(U),q=await Yn(g,"Submitting and waiting for finalization (typically 12 to 30s)...",y.facade.submitTransaction(X));return String(q)},{syncMode:"full",requireStrictSync:!0,signal:o,onStatus:(y)=>g.update(y),onSyncProgress:(y,w)=>{if(w>0){let k=Math.min(Math.round(y/w*100),100);g.update(k>=100?"Syncing wallet...":`Syncing wallet... ${k}%`)}},onSyncDetail:(y)=>g.update(`Syncing wallet... (waiting on: ${y})`)});if(g.stop("Transaction submitted"),N(e,"json")){I({txHash:S,amount:s,recipient:n,network:c,type:"shielded"});return}process.stdout.write(S+`
|
|
265
265
|
`),process.stderr.write(`
|
|
266
|
-
`+yt(`Transferred ${s} shielded NIGHT`,
|
|
266
|
+
`+yt(`Transferred ${s} shielded NIGHT`,S)+`
|
|
267
267
|
`),process.stderr.write(`
|
|
268
268
|
`+J()+`
|
|
269
269
|
`),process.stderr.write(m(" Verify: midnight balance --shielded")+`
|
|
270
270
|
|
|
271
|
-
`)}catch(
|
|
271
|
+
`)}catch(S){throw g.fail("Failed"),S}finally{h(),p()}}var Gc=A(()=>{oe();St();De();ke();ye();ct();xo();xt();qe();Ct();fe();ft()});async function mg(e,t){let r=await et(e,t,null);try{return await r.facade.dust.serializeState()}finally{await We(r)}}async function Kc(e,t,r,n={}){let s=Qe(e),i=await(n.repository??Te()).dust(e,r,{signal:n.signal,onProgress:n.onProgress}),a=await(n.buildBaseDust??mg)(e,r),c=i.lastAppliedEventId>=0?ro(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 Vc=A(()=>{_t();qe();Ct()});var qc={};be(qc,{default:()=>Jc});async function Jc(e,t){let r=e.subcommand;if(!r||r!=="register"&&r!=="status"&&r!=="export")throw new _(`Missing or invalid subcommand.
|
|
272
272
|
Usage:
|
|
273
273
|
midnight dust register Register NIGHT UTXOs for dust generation
|
|
274
274
|
midnight dust status Check dust registration status
|
|
275
|
-
midnight dust export Export a restorable dust snapshot (dustSerializedState)`);let{name:n,config:s}=
|
|
275
|
+
midnight dust export Export a restorable dust snapshot (dustSerializedState)`);let{name:n,config:s}=pe({args:e});if(_e(s,{proofServer:x(e,"proof-server"),node:x(e,"node"),indexerWS:x(e,"indexer-ws")},n),Ke(e))Je();let o=N(e,"json"),i=ht(e);if(r==="export"){let p=Pe();try{await gg(xn(e),n,s,o,i,t)}finally{p()}return}let a=ne(re(x(e,"wallet"))),c=Buffer.from(a.seed,"hex"),d=a.addresses[n];if(r==="status"){let p=await hg(d,n,s.indexerWS,t);if(!p.isRegistered){wg(n,p,o,i);return}let h=!N(e,"no-cache");await Sg(c,s,p,o,i,h,t);return}Ht(e);let u={},l=$e((p,h)=>u.current?.(p,h)),f=Pe();try{await yg(c,s,o,t,u)}finally{f(),l()}}async function gg(e,t,r,n,s,o){let i=V(`Reading dust events from ${t}...`);try{let a=await Kc(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){I({subcommand:"export",network:a.network,dustPublicKey:a.dustPublicKey,offset:a.offset,dustBalance:le(a.balance),eventCount:a.eventCount,fromCache:a.fromCache,partial:a.partial,snapshot:a.snapshot});return}if(process.stdout.write(a.snapshot+`
|
|
276
276
|
`),s)return;if(process.stderr.write(`
|
|
277
277
|
`+E("Network",a.network)+`
|
|
278
|
-
`),process.stderr.write(E("Dust balance",
|
|
278
|
+
`),process.stderr.write(E("Dust balance",Ur(a.balance))+`
|
|
279
279
|
`),process.stderr.write(E("Snapshot offset",String(a.offset))+`
|
|
280
280
|
`),a.partial)process.stderr.write(`
|
|
281
281
|
`+Q(P("⚠ Snapshot is INCOMPLETE — the sync did not reach the chain tip."))+`
|
|
@@ -283,12 +283,12 @@ Usage:
|
|
|
283
283
|
`+m(" Re-run `mn dust export` to resume from this checkpoint and finish.")+`
|
|
284
284
|
`);process.stderr.write(`
|
|
285
285
|
`+m("Restore with the wallet SDK dustSerializedState to skip the cold dust sync.")+`
|
|
286
|
-
`)}catch(a){throw i.fail("Failed"),a}}async function
|
|
286
|
+
`)}catch(a){throw i.fail("Failed"),a}}async function hg(e,t,r,n){process.stderr.write(`
|
|
287
287
|
`+B("Dust Status")+`
|
|
288
288
|
|
|
289
289
|
`),process.stderr.write(E("Network",t)+`
|
|
290
290
|
|
|
291
|
-
`);let s=V(`Checking registration on ${t}...`);try{let o=await Qt(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
|
|
291
|
+
`);let s=V(`Checking registration on ${t}...`);try{let o=await Qt(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 wg(e,t,r,n){let{registeredUtxos:s,unregisteredUtxos:o}=t,i=s+o;if(r){if(n){I({network:e,registered:!1,registeredUtxos:s,unregisteredUtxos:o});return}I({subcommand:"status",registered:!1,registeredUtxos:s,unregisteredUtxos:o,network:e});return}if(process.stdout.write(`registered=no
|
|
292
292
|
`),process.stdout.write(`registered_utxos=${s}
|
|
293
293
|
`),process.stdout.write(`unregistered_utxos=${o}
|
|
294
294
|
`),process.stderr.write(E("Registered",P("no"))+`
|
|
@@ -300,22 +300,22 @@ Usage:
|
|
|
300
300
|
`);process.stderr.write(`
|
|
301
301
|
`+J()+`
|
|
302
302
|
|
|
303
|
-
`)}async function
|
|
303
|
+
`)}async function yg(e,t,r,n,s){let o=t.networkId.toLowerCase();process.stderr.write(`
|
|
304
304
|
`+B("Dust Register")+`
|
|
305
305
|
|
|
306
306
|
`),process.stderr.write(E("Network",o)+`
|
|
307
307
|
|
|
308
|
-
`);let i=V("Syncing wallet...");if(s)s.current=(a,c)=>i.update(`Syncing wallet... (${c}, retrying)`);try{let{result:a,dustBal:c}=await Te().withFacade(e,t,async({bundle:d,state:u})=>{if(n?.aborted)throw Error("Operation cancelled");i.update("Checking dust status...");let l=await rt(d,(p)=>i.update(p),u);if(n?.aborted)throw Error("Operation cancelled");let f=await
|
|
308
|
+
`);let i=V("Syncing wallet...");if(s)s.current=(a,c)=>i.update(`Syncing wallet... (${c}, retrying)`);try{let{result:a,dustBal:c}=await Te().withFacade(e,t,async({bundle:d,state:u})=>{if(n?.aborted)throw Error("Operation cancelled");i.update("Checking dust status...");let l=await rt(d,(p)=>i.update(p),u);if(n?.aborted)throw Error("Operation cancelled");let f=await Pa(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:le(c)};if(a.txHash)d.txHash=a.txHash;I(d);return}process.stdout.write(c.toString()+`
|
|
309
309
|
`),process.stderr.write(`
|
|
310
|
-
`+yt(a.alreadyAvailable?`Dust tokens already available: ${
|
|
310
|
+
`+yt(a.alreadyAvailable?`Dust tokens already available: ${Ur(c)}`:`Dust tokens available: ${Ur(c)}`)+`
|
|
311
311
|
|
|
312
|
-
`)}catch(a){throw i.fail("Failed"),a}}async function
|
|
312
|
+
`)}catch(a){throw i.fail("Failed"),a}}async function Sg(e,t,r,n,s,o,i){let a=t.networkId.toLowerCase(),c=V(`Reading dust events from ${a}...`);try{let d=await Te().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){I({network:a,registered:!0,registeredUtxos:u,unregisteredUtxos:l,dustBalance:le(d.balance),dustAvailable:d.availableCoins>0});return}I({subcommand:"status",registered:!0,registeredUtxos:u,unregisteredUtxos:l,dustBalance:le(d.balance),dustAvailable:d.availableCoins>0,eventsApplied:d.eventsApplied,ownedUtxos:d.ownedUtxoCount,cached:d.fromCache,network:a});return}if(process.stdout.write(`registered=yes
|
|
313
313
|
`),process.stdout.write(`dust=${d.balance}
|
|
314
314
|
`),process.stdout.write(`registered_utxos=${u}
|
|
315
315
|
`),process.stdout.write(`unregistered_utxos=${l}
|
|
316
316
|
`),process.stderr.write(E("Registered",P("yes"))+`
|
|
317
317
|
`),process.stderr.write(E("UTXOs",`${u} registered, ${l} unregistered`)+`
|
|
318
|
-
`),process.stderr.write(E("Dust Balance",P(
|
|
318
|
+
`),process.stderr.write(E("Dust Balance",P(Ur(d.balance)))+`
|
|
319
319
|
`),process.stderr.write(E("Dust Available",d.availableCoins>0?"yes":"no")+`
|
|
320
320
|
`),process.stderr.write(E("Events applied",d.eventsApplied.toString()+(d.fromCache?" (delta)":""))+`
|
|
321
321
|
`),l>0)process.stderr.write(`
|
|
@@ -323,23 +323,23 @@ Usage:
|
|
|
323
323
|
`);process.stderr.write(`
|
|
324
324
|
`+J()+`
|
|
325
325
|
|
|
326
|
-
`)}catch(d){throw c.fail("Failed"),d}}var
|
|
327
|
-
`)}else if(n){if(ze(void 0,n),dt(n),Bn(n),
|
|
328
|
-
`)}else{if(ze(),dt(),Bn(),
|
|
329
|
-
`)}}var
|
|
330
|
-
Valid keys: ${
|
|
331
|
-
Valid keys: ${
|
|
332
|
-
Valid networks: preprod, preview, undeployed`);let s=n;if(t==="get"){let o=
|
|
333
|
-
`)}else if(t==="unset"){
|
|
326
|
+
`)}catch(d){throw c.fail("Failed"),d}}var zc=A(()=>{oe();ve();St();De();Xt();ke();ye();qe();xt();Br();Vc();Ct();fe();ft()});var Xc={};be(Xc,{default:()=>Yc});async function Yc(e){if(e.subcommand!=="clear")throw new _("Usage: midnight cache clear [--network <name>] [--wallet <name|file>]");let r=x(e,"wallet"),n=x(e,"network"),s=N(e,"json");if(r){let o=re(r),i=ne(o),a=Se({args:e}),c=i.addresses[a];ze(c,a);let d=Qe(Buffer.from(i.seed,"hex"));dt(a,d),Bn(a,d);let u=ic(Buffer.from(i.seed,"hex"));if(Yr(a,u),s){I({action:"clear",scope:"wallet",wallet:r,network:a});return}process.stderr.write(W("✓")+` Cache cleared for wallet "${r}" on ${a}
|
|
327
|
+
`)}else if(n){if(ze(void 0,n),dt(n),Bn(n),Yr(n),s){I({action:"clear",scope:"network",network:n});return}process.stderr.write(W("✓")+` Cache cleared for network "${n}"
|
|
328
|
+
`)}else{if(ze(),dt(),Bn(),Yr(),s){I({action:"clear",scope:"all"});return}process.stderr.write(W("✓")+` Cache cleared
|
|
329
|
+
`)}}var Zc=A(()=>{oe();ve();Mt();_t();wo();uo();De();ke()});var ed={};be(ed,{default:()=>Qc});async function Qc(e){let t=e.subcommand;if(!t||!["get","set","unset"].includes(t))throw new _(`Usage: midnight config <get|set|unset> <key> [value]
|
|
330
|
+
Valid keys: ${Ws().join(", ")}`);let r=e.positionals[0];if(!r)throw new _(`Missing config key.
|
|
331
|
+
Valid keys: ${Ws().join(", ")}`);let n=x(e,"network");if(n!==void 0&&!xe(n))throw new _(`Invalid network: "${n}"
|
|
332
|
+
Valid networks: preprod, preview, undeployed`);let s=n;if(t==="get"){let o=qi(r,void 0,s);if(N(e,"json")){I({action:"get",key:r,value:o});return}process.stdout.write(o+`
|
|
333
|
+
`)}else if(t==="unset"){Yi(r,void 0,s);let o=r==="network"?"(default)":"(removed)";if(N(e,"json")){I({action:"unset",key:r,value:o});return}process.stderr.write(W("✓")+` ${r} ${o}
|
|
334
334
|
`)}else{let o=e.positionals[1];if(o===void 0)throw new _(`Missing value for config set.
|
|
335
|
-
Usage: midnight config set ${r} <value>`);if(
|
|
336
|
-
`)}}var
|
|
335
|
+
Usage: midnight config set ${r} <value>`);if(zi(r,o,void 0,s),N(e,"json")){I({action:"set",key:r,value:o});return}process.stderr.write(W("✓")+` ${r} = ${o}
|
|
336
|
+
`)}}var td=A(()=>{oe();ye();ve();Vt()});import{execSync as dr}from"child_process";import{existsSync as rd,mkdirSync as bg,readFileSync as vg,writeFileSync as nd}from"fs";import{homedir as kg}from"os";import{join as Ao}from"path";function id(){try{return dr("docker compose version",{...Qr,timeout:1e4}).trim()}catch{try{throw dr("docker --version",{...Qr,timeout:5000}),Error(`Docker Compose v2 is required.
|
|
337
337
|
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.
|
|
338
|
-
Install Docker from https://docs.docker.com/get-docker/`)}}}function
|
|
339
|
-
`),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:
|
|
340
|
-
`).find((a)=>a.startsWith(`${s}|`));if(i)e.push({name:s,project:i.slice(s.length+1).trim()})}let{remove:t,keep:r}=
|
|
338
|
+
Install Docker from https://docs.docker.com/get-docker/`)}}}function No(){if(!Tg)throw new ad}function cd(){if(No(),rd(Eo)&&rd(Zn)&&vg(Eo,"utf-8").trim()===sd)return!1;return bg(To,{recursive:!0,mode:Re}),nd(Zn,Ag,"utf-8"),nd(Eo,sd,"utf-8"),!0}function lr(e){return dr(`docker compose -f "${Zn}" ${e}`,Qr)}function Qn(){try{let e=lr("ps --format json");if(!e.trim())return[];let t=e.trim().split(`
|
|
339
|
+
`),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:Ng[o]??"",image:s.Image??""})}catch{}}return r}catch{return[]}}function dd(e=120000,t=3000){let r=Date.now()+e;while(Date.now()<r){let n=Qn();if(n.length===3&&n.every((o)=>o.state==="running")){if(n.every((i)=>i.health==="healthy"||i.health===""))return!0}dr(`sleep ${t/1000}`,{timeout:t+1000})}return!1}function Ro(){return Zn}function Ig(e){return{remove:e.filter((t)=>t.project===od).map((t)=>t.name),keep:e.filter((t)=>t.project!==od)}}function ld(){let e=[];for(let s of Rg){let o;try{o=dr(`docker ps -a --filter "name=^/${s}$" --format '{{.Names}}|{{.Label "com.docker.compose.project"}}'`,{...Qr,timeout:1e4}).toString()}catch{e.push({name:s,project:"(unknown: docker ps failed)"});continue}let i=o.split(`
|
|
340
|
+
`).find((a)=>a.startsWith(`${s}|`));if(i)e.push({name:s,project:i.slice(s.length+1).trim()})}let{remove:t,keep:r}=Ig(e),n=[];for(let s of t)try{dr(`docker rm -f "${s}"`,{...Qr,timeout:1e4}),n.push(s)}catch{}return{removed:n,kept:r}}var sd="3.0.6",Cg="midnightntwrk/midnight-node:1.0.0",xg="midnightntwrk/indexer-standalone:4.3.3",Eg="midnightntwrk/proof-server:8.1.0",To,Zn,Eo,Ag,Qr,Tg=!1,ad,Ng,Rg,od;var ud=A(()=>{To=Ao(kg(),ce,Ds),Zn=Ao(To,"compose.yml"),Eo=Ao(To,".version"),Ag=`services:
|
|
341
341
|
proof-server:
|
|
342
|
-
image: '${
|
|
342
|
+
image: '${Eg}'
|
|
343
343
|
container_name: "proof-server"
|
|
344
344
|
# Self-heal across Docker Desktop restarts and transient stops. Without this,
|
|
345
345
|
# a stopped node/proof-server never comes back while the indexer (below) does,
|
|
@@ -350,7 +350,7 @@ Install Docker from https://docs.docker.com/get-docker/`)}}}function Eo(){if(!cg
|
|
|
350
350
|
- "6300:6300"
|
|
351
351
|
|
|
352
352
|
indexer:
|
|
353
|
-
image: '${
|
|
353
|
+
image: '${xg}'
|
|
354
354
|
container_name: "indexer"
|
|
355
355
|
# unless-stopped covers two cases: (1) indexer >=4.3.x runs an SPO sub-indexer
|
|
356
356
|
# that queries block #1 at startup and exits the whole process if it isn't there
|
|
@@ -386,7 +386,7 @@ Install Docker from https://docs.docker.com/get-docker/`)}}}function Eo(){if(!cg
|
|
|
386
386
|
condition: service_started
|
|
387
387
|
|
|
388
388
|
node:
|
|
389
|
-
image: '${
|
|
389
|
+
image: '${Cg}'
|
|
390
390
|
container_name: "node"
|
|
391
391
|
# Self-heal across Docker Desktop restarts / transient stops (see proof-server).
|
|
392
392
|
restart: unless-stopped
|
|
@@ -400,26 +400,26 @@ Install Docker from https://docs.docker.com/get-docker/`)}}}function Eo(){if(!cg
|
|
|
400
400
|
start_period: 5s
|
|
401
401
|
environment:
|
|
402
402
|
CFG_PRESET: "dev"
|
|
403
|
-
`,Qr={encoding:"utf-8",timeout:30000};
|
|
403
|
+
`,Qr={encoding:"utf-8",timeout:30000};ad=class ad extends Error{code="LOCALNET_UNAVAILABLE";constructor(){super(`mn localnet can't start a ledger-9 network yet: no published indexer image runs ledger 9.
|
|
404
404
|
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:
|
|
405
405
|
per command: --node ws://localhost:9944 --indexer-ws ws://localhost:8088/api/v4/graphql/ws --proof-server http://localhost:6300
|
|
406
|
-
or once: midnight config set node <url>; midnight config set indexer-ws <url>; midnight config set proof-server <url>`);this.name="LocalnetUnavailableError"}};
|
|
407
|
-
`)}async function
|
|
408
|
-
`);let r=V("Starting local network...");try{if(lr("up -d"),r.update("Waiting for services to be healthy..."),!
|
|
406
|
+
or once: midnight config set node <url>; midnight config set indexer-ws <url>; midnight config set proof-server <url>`);this.name="LocalnetUnavailableError"}};Ng={node:"9944",indexer:"8088","proof-server":"6300"};Rg=["node","indexer","proof-server"],od=Ds});async function pd(e,t={}){let r=t.timeoutMs??30000,n=t.pollIntervalMs??1000,s=Date.now()+r;while(Date.now()<s){try{let o=await er({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 fd=A(()=>{Mn()});async function md(e,t,r={}){let n=r.timeoutMs??30000,s=r.pollIntervalMs??1000,o=Date.now()+n;while(Date.now()<o){try{if((await Qt(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 gd=A(()=>{Br()});async function hd(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 vd={};be(vd,{default:()=>bd});import{spawn as wd}from"child_process";import{existsSync as Dg,rmSync as $g}from"node:fs";import{resolve as Pg}from"node:path";function _g(e){return yd.includes(e)}function Sd(e){let t=[];for(let r of e){let n=r.state==="running"?W:de,s=r.health?` (${r.health})`:"",o=r.port?`:${r.port}`:"",i=r.image?` ${m(r.image)}`:"";if(t.push(` ${r.name.padEnd(16)}${n(r.state)}${m(s)}${m(o)}`),i)t.push(i)}return t.join(`
|
|
407
|
+
`)}async function Og(e){if(cd())process.stderr.write(m(` Wrote compose.yml to ${Ro()}`)+`
|
|
408
|
+
`);let r=V("Starting local network...");try{if(lr("up -d"),r.update("Waiting for services to be healthy..."),!dd(120000))r.stop(Q("Services started but not all healthy yet")),process.stderr.write(`
|
|
409
409
|
`+m(" Tip: run ")+P("midnight localnet logs")+m(" to check for errors")+`
|
|
410
|
-
`);else{r.update("Waiting for chain to produce first block...");try{await Promise.resolve().then(() =>
|
|
410
|
+
`);else{r.update("Waiting for chain to produce first block...");try{await Promise.resolve().then(() => fd());await Promise.resolve().then(() => gd());await Promise.resolve();await Promise.resolve().then(() => ye());await Promise.resolve().then(() => Ve());await Promise.resolve();let l=Nr("undeployed");await pd(l.node,{timeoutMs:30000}),r.update("Waiting for indexer to ingest genesis state...");let f=Ee(Buffer.from(ot,"hex"),"undeployed");await md(l.indexerWS,f,{timeoutMs:30000}),r.update("Waiting for proof server..."),await hd(l.proofServer,{timeoutMs:30000}),r.stop("Local network is running")}catch(o){r.stop(Q("Services running but chain/indexer/proof-server not fully ready yet")),process.stderr.write(`
|
|
411
411
|
`+m(" Tip: give it a few more seconds then retry. Run ")+P("midnight localnet logs")+m(" if this persists.")+`
|
|
412
412
|
`)}}}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.
|
|
413
413
|
|
|
414
414
|
`+`If an earlier mn localnet created them, "midnight localnet clean" removes them;
|
|
415
415
|
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.
|
|
416
416
|
`+"Check ports 9944, 8088, and 6300, then try again.")}throw s}let n=Qn();if(e){I({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(`
|
|
417
|
-
`+
|
|
417
|
+
`+Sd(n)+`
|
|
418
418
|
`);for(let s of n)process.stdout.write(`${s.name}=${s.state}:${s.port}
|
|
419
419
|
`);process.stderr.write(`
|
|
420
420
|
`+m(" Next: ")+P("midnight wallet generate dev --network undeployed")+`
|
|
421
|
-
`)}async function
|
|
422
|
-
`)}catch(r){throw t.fail("Failed to tear down local network"),r}}function
|
|
421
|
+
`)}async function Mg(e){let t=V("Stopping local network...");try{if(lr("stop"),t.stop("Local network stopped (containers preserved)"),e){I({subcommand:"stop",status:"stopped"});return}}catch(r){throw t.fail("Failed to stop local network"),r}}async function Fg(e){let t=V("Tearing down local network...");try{lr("down --volumes");await Promise.resolve().then(() => Mt());await Promise.resolve().then(() => _t());ze(void 0,"undeployed"),dt("undeployed");let s=Lg();if(t.stop("Local network removed (containers, networks, volumes, caches)"),e){I({subcommand:"down",status:"removed",cachesCleared:!0,dappLevelDbWiped:s});return}if(s)process.stderr.write(m(" Also cleared dapp leveldb at ./midnight-level-db (private state from old chain)")+`
|
|
422
|
+
`)}catch(r){throw t.fail("Failed to tear down local network"),r}}function Lg(){let e=Pg(process.cwd(),"midnight-level-db");if(!Dg(e))return!1;try{return $g(e,{recursive:!0,force:!0}),!0}catch{return!1}}async function Ug(e){let t=Qn();if(e){I({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(`
|
|
423
423
|
`+B("Localnet Status")+`
|
|
424
424
|
|
|
425
425
|
`),process.stderr.write(m(" No services running.")+`
|
|
@@ -428,14 +428,14 @@ it leaves containers from anything else alone and lists them.`);if(s.message.inc
|
|
|
428
428
|
`);return}process.stderr.write(`
|
|
429
429
|
`+B("Localnet Status")+`
|
|
430
430
|
|
|
431
|
-
`),process.stderr.write(
|
|
431
|
+
`),process.stderr.write(Sd(t)+`
|
|
432
432
|
`),process.stderr.write(`
|
|
433
433
|
`+J()+`
|
|
434
434
|
|
|
435
435
|
`);for(let r of t)process.stdout.write(`${r.name}=${r.state}:${r.port}
|
|
436
|
-
`)}async function
|
|
437
|
-
`)}catch(r){throw t.fail("Failed to clean up"),r}}async function
|
|
438
|
-
`).filter(Boolean)});else process.stdout.write(a);d()}),i.on("error",u)})}let s=
|
|
436
|
+
`)}async function Wg(e){let t=V("Removing conflicting containers...");try{try{lr("down")}catch{}let{removed:r,kept:n}=ld();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){I({subcommand:"clean",status:"cleaned",removed:r,kept:n});return}for(let s of n)process.stderr.write(m(` 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.`)+`
|
|
437
|
+
`)}catch(r){throw t.fail("Failed to clean up"),r}}async function Bg(e){let t=Ro(),r=x(e,"tail"),n=N(e,"json");if(r!==void 0||n){let o=r??"200",i=wd("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)I({tail:Number(o),lines:a.split(`
|
|
438
|
+
`).filter(Boolean)});else process.stdout.write(a);d()}),i.on("error",u)})}let s=wd("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 bd(e){let t=e.subcommand;if(!t||!_g(t))throw new _(`Usage: midnight localnet <${yd.join("|")}>
|
|
439
439
|
|
|
440
440
|
Subcommands:
|
|
441
441
|
up Start the local network (refused on this ledger-9 build)
|
|
@@ -445,15 +445,15 @@ Subcommands:
|
|
|
445
445
|
logs Stream service logs
|
|
446
446
|
clean Remove conflicting containers
|
|
447
447
|
|
|
448
|
-
Example: midnight localnet status`);if(t==="up")
|
|
448
|
+
Example: midnight localnet status`);if(t==="up")No();id();let r=N(e,"json");switch(process.stderr.write(`
|
|
449
449
|
`+B("Localnet")+`
|
|
450
450
|
|
|
451
|
-
`),t){case"up":return
|
|
451
|
+
`),t){case"up":return Og(r);case"stop":return Mg(r);case"down":return Fg(r);case"status":return Ug(r);case"logs":return Bg(e);case"clean":return Wg(r)}}var yd;var kd=A(()=>{oe();ve();ud();fe();ft();yd=["up","stop","down","status","logs","clean"]});var Ad={};be(Ad,{default:()=>Ed});import*as xd from"fs";import*as Io from"path";import{homedir as jg}from"os";import{generateMnemonic as Hg,mnemonicToSeedSync as Cd,mnemonicToEntropy as Gg,validateMnemonic as Kg}from"@scure/bip39";import{wordlist as Do}from"@scure/bip39/wordlists/english.js";async function Ed(e){let t=e.subcommand;switch(t){case"generate":return Vg(e);case"list":case"ls":return Jg(e);case"use":return qg(e);case"info":return zg(e);case"remove":case"rm":return Yg(e);case"seed":return Xg(e);default:throw new _(`Unknown wallet subcommand: "${t??"(none)"}"
|
|
452
452
|
Available: generate, list, use, info, remove, seed
|
|
453
|
-
Run "midnight help wallet" for usage.`)}}async function
|
|
453
|
+
Run "midnight help wallet" for usage.`)}}async function Vg(e){let t=e.positionals[0];if(!t)throw Error(`Missing wallet name.
|
|
454
454
|
Usage: midnight wallet generate <name> [--network <name>]`);if(!Tt(t))throw Error(`Invalid wallet name: "${t}"
|
|
455
|
-
Wallet name must be a simple name (no path separators, .json suffix, or special characters).`);let r=Se({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=
|
|
456
|
-
Use --force to overwrite.`);let a,c;if(n!==void 0)a=
|
|
455
|
+
Wallet name must be a simple name (no path separators, .json suffix, or special characters).`);let r=Se({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=Io.join(jg(),ce,yn),i=Io.join(o,`${t}.json`);if(xd.existsSync(i)&&!N(e,"force"))throw Error(`Wallet "${t}" already exists: ${i}
|
|
456
|
+
Use --force to overwrite.`);let a,c;if(n!==void 0)a=Or(n,"--seed");else if(s!==void 0){if(!Kg(s,Do))throw Error("Invalid BIP-39 mnemonic. Expected 12 or 24 words from the English wordlist.");c=s,a=Buffer.from(Cd(c))}else c=Hg(Do,256),a=Buffer.from(Cd(c));let d=Dt(a),u=$r(a),l=d[r],f={seed:a.toString("hex"),addresses:d,shieldedAddresses:u,createdAt:new Date().toISOString()};if(c)f.mnemonic=c;let p=Cn(f,i);if(Gs(t),N(e,"json")){let g={name:t,addresses:d,shieldedAddresses:u,activeAddress:l,activeNetwork:r,seed:a.toString("hex"),file:p,createdAt:f.createdAt,active:!0};if(c)g.mnemonic=c;I(g);return}process.stdout.write(l+`
|
|
457
457
|
`),process.stderr.write(`
|
|
458
458
|
`+B("Wallet Generated")+`
|
|
459
459
|
|
|
@@ -474,7 +474,7 @@ Use --force to overwrite.`);let a,c;if(n!==void 0)a=Mr(n,"--seed");else if(s!==v
|
|
|
474
474
|
`),process.stderr.write(m(" Next: midnight wallet list | midnight balance")+`
|
|
475
475
|
|
|
476
476
|
`),process.stderr.write(W("✓")+` Wallet saved
|
|
477
|
-
`)}async function
|
|
477
|
+
`)}async function Jg(e){let t=Ks(),r=Se({args:e});if(N(e,"json")){if(ht(e)){I({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}I({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
478
|
No wallets found.
|
|
479
479
|
`),process.stderr.write(m(" Create one: midnight wallet generate <name> --network <name>")+`
|
|
480
480
|
|
|
@@ -487,9 +487,9 @@ Use --force to overwrite.`);let a,c;if(n!==void 0)a=Mr(n,"--seed");else if(s!==v
|
|
|
487
487
|
`+J()+`
|
|
488
488
|
`),process.stderr.write(m(` ● = active wallet · network: ${r} · details: midnight wallet info <name>`)+`
|
|
489
489
|
|
|
490
|
-
`)}async function
|
|
491
|
-
Usage: midnight wallet use <name>`);if(
|
|
492
|
-
`)}async function
|
|
490
|
+
`)}async function qg(e){let t=e.positionals[0];if(!t)throw Error(`Missing wallet name.
|
|
491
|
+
Usage: midnight wallet use <name>`);if(Gs(t),N(e,"json")){I({wallet:t,active:!0});return}process.stderr.write(W("✓")+` Active wallet set to "${t}"
|
|
492
|
+
`)}async function zg(e){let t=x(e,"wallet")??e.positionals[0]??Yt(),r=re(t),n=ne(r),s=t===Yt(),o=Se({args:e}),i=n.addresses[o];if(N(e,"json")){if(ht(e)){I({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;I(c);return}process.stdout.write(i+`
|
|
493
493
|
`),process.stderr.write(`
|
|
494
494
|
`+B(`Wallet: ${t}`)+`
|
|
495
495
|
|
|
@@ -505,15 +505,15 @@ Usage: midnight wallet use <name>`);if(Hs(t),N(e,"json")){I({wallet:t,active:!0}
|
|
|
505
505
|
`),process.stderr.write(` ${m("file ")} ${r}
|
|
506
506
|
`),process.stderr.write(` ${m("active ")} ${s?W("yes"):"no"}
|
|
507
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(
|
|
508
|
+
`)}async function Yg(e){let t=e.positionals[0];if(!t)throw Error(`Missing wallet name.
|
|
509
|
+
Usage: midnight wallet remove <name>`);if(ra(t),N(e,"json")){I({wallet:t,removed:!0});return}process.stderr.write(W("✓")+` Wallet "${t}" removed
|
|
510
|
+
`)}async function Xg(e){let t=x(e,"wallet")??e.positionals[0]??Yt(),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=N(e,"entropy"),i;if(o){if(!s.mnemonic)throw Error(`Wallet "${t}" has no mnemonic on file — cannot derive BIP-39 entropy.
|
|
511
|
+
`+"The 32-byte entropy can only be computed from the original 24-word mnemonic.");i=Buffer.from(Gg(s.mnemonic,Do)).toString("hex")}if(N(e,"json")){let c={name:t,seed:s.seed};if(s.mnemonic)c.mnemonic=s.mnemonic;if(i)c.entropy=i;I(c);return}if(process.stderr.write(`
|
|
512
512
|
`),process.stderr.write(Q(P(" ⚠ WARNING: This will display your wallet seed and mnemonic."))+`
|
|
513
513
|
`),process.stderr.write(Q(" Anyone with this seed can access your funds.")+`
|
|
514
514
|
`),process.stderr.write(Q(" Never share it. Never paste it into a website.")+`
|
|
515
515
|
`),process.stderr.write(`
|
|
516
|
-
`),!await
|
|
516
|
+
`),!await Zg(" Show seed? (y/N) ")){process.stderr.write(m(" Cancelled.")+`
|
|
517
517
|
|
|
518
518
|
`);return}if(process.stdout.write(s.seed+`
|
|
519
519
|
`),process.stderr.write(`
|
|
@@ -526,58 +526,58 @@ Usage: midnight wallet remove <name>`);if(Qi(t),N(e,"json")){I({wallet:t,removed
|
|
|
526
526
|
`),process.stderr.write(m(" Note: seed and entropy derive DIFFERENT Midnight wallets from the")+`
|
|
527
527
|
`),process.stderr.write(m(" same mnemonic. Use the value your target project accepts.")+`
|
|
528
528
|
`);process.stderr.write(`
|
|
529
|
-
`)}function
|
|
529
|
+
`)}function Zg(e){return new Promise((t)=>{let r=Si("readline"),n=r.createInterface({input:process.stdin,output:process.stderr});n.question(e,(s)=>{n.close(),t(s.trim().toLowerCase()==="y")})})}var Td=A(()=>{oe();ve();Ve();ke();Xt();De();fe()});var $d={};be($d,{default:()=>Dd});function Po(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 $o(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 es(e){let t=`${Sn}${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 rh(e){let t=x(e,"network");if(t)return t;try{await Promise.resolve().then(() => Vt());let n=Oe();if(n.network&&xe(n.network))return n.network}catch{}return}async function rs(e,t={}){let r=new AbortController,n=setTimeout(()=>r.abort(),th),s=Date.now();try{return{response:await fetch(e,{...t,signal:r.signal}),latencyMs:Date.now()-s}}finally{clearTimeout(n)}}async function nh(e){let t=new Date().toISOString();try{let{response:r,latencyMs:n}=await rs(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>ts?"degraded":"up",latencyMs:n,lastChecked:t,...o!==void 0?{blockHeight:o}:{},...n>ts?{notes:`Slow (${n}ms)`}:{}}}catch(r){return{status:"down",latencyMs:0,lastChecked:t,notes:r.message}}}async function sh(e){let t=new Date().toISOString(),r=e.replace(/^wss:/,"https:").replace(/^ws:/,"http:");try{let{response:n,latencyMs:s}=await rs(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 oh(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 rs(e);if(!r.ok)return{status:"down",latencyMs:n,lastChecked:t,notes:`HTTP ${r.status}`};return{status:n>Rd?"degraded":"up",latencyMs:n,lastChecked:t,...n>Rd?{notes:`Slow (${n}ms)`}:{}}}catch(r){return{status:"down",latencyMs:0,lastChecked:t,notes:r.message}}}async function ih(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 rs(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>ts?"degraded":"up",latencyMs:n,lastChecked:t,...n>ts?{notes:`Slow (${n}ms)`}:{}}}catch(r){return{status:"down",latencyMs:0,lastChecked:t,notes:r.message}}}async function Id(e){if(!xe(e))return{};let t=Nr(e),r=Qg[e];if(!r)return{};let[n,s,o,i]=await Promise.all([nh(t.indexer),sh(t.node),oh(r.faucet),ih(r.explorer)]);return{indexer:n,rpc:s,faucet:o,explorer:i}}function ah(e,t,r){process.stderr.write(`
|
|
530
530
|
`+P(e)+`
|
|
531
531
|
`),process.stderr.write(m(" "+"─".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
|
|
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=(eh[s]??s).padEnd(18);if(o){let c=Nd[o.status]??m("—"),d=o.latencyMs>0?m(` ${o.latencyMs}ms`):"",u=o.notes?m(` — ${o.notes}`):"",l="";if(i&&i.status!==o.status&&i.status!=="unknown")l=m(` (canary: ${i.status}${i.lastChecked?" "+Po(i.lastChecked):""})`);process.stderr.write(` ${Lr(a)}${c}${d}${u}${l}
|
|
533
|
+
`)}else if(i){let c=Nd[i.status]??m("—"),d=i.latencyMs>0?m(` ${i.latencyMs}ms`):"",u=i.lastChecked?m(` (${Po(i.lastChecked)})`):"",l=i.notes?m(` — ${i.notes}`):"";process.stderr.write(` ${Lr(a)}${c}${d}${u}${l}
|
|
534
|
+
`)}}}function ch(e,t){let r=t?e.filter((n)=>n.affects.toLowerCase().includes(t.toLowerCase())):e;if(r.length===0)return;process.stderr.write(`
|
|
535
535
|
`+B("Known Issues")+`
|
|
536
536
|
|
|
537
|
-
`);for(let n of r)process.stderr.write(` ${
|
|
537
|
+
`);for(let n of r)process.stderr.write(` ${de(n.id.padEnd(28))}${n.summary}
|
|
538
538
|
`),process.stderr.write(` ${" ".repeat(28)}${m(n.status)}
|
|
539
|
-
`)}async function
|
|
539
|
+
`)}async function Dd(e){let t=N(e,"json"),r=N(e,"all"),n=N(e,"watch"),s=await rh(e)??"preprod",o=V("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([es("/api/status"),es("/api/issues")]).catch((g)=>(c=g.message,null)),...d.map((g)=>Id(g))]);if(u)[i,a]=u;o.stop("Done");let f={};for(let g=0;g<d.length;g++)f[d[g]]=l[g];if(t){let g={lastUpdated:i?.lastUpdated??null,dashboard:Sn,canaryAvailable:i!==null,networks:{}};for(let y of d){let w=f[y]??{},k=i?.networks[y],T={...k,...w};g.networks[y]={overall:$o(T),live:w,canary:k??null}}if(a){let y=r?void 0:d[0];g.issues=y?a.issues.filter((w)=>w.affects.toLowerCase().includes(y.toLowerCase())):a.issues}if(c)g.canaryError=c;I(g);let S=d.reduce((y,w)=>{let k={...i?.networks[w]??{},...f[w]??{}},T=$o(k);if(T==="down")return"down";if(T==="degraded"&&y!=="down")return"degraded";return y},"up");if(S==="down")process.exitCode=2;else if(S==="degraded")process.exitCode=1;return}let p=()=>{if(process.stderr.write(`
|
|
540
540
|
`+B("Midnight Network Status")+`
|
|
541
|
-
`),i?.lastUpdated)process.stderr.write(m(` Canary: ${
|
|
541
|
+
`),i?.lastUpdated)process.stderr.write(m(` Canary: ${Po(i.lastUpdated)}`)+" ");if(process.stderr.write(m("Live: just now")+`
|
|
542
542
|
`),c)process.stderr.write(m(` (Dashboard unreachable: ${c})`)+`
|
|
543
543
|
`);if(d.length===0){process.stderr.write(`
|
|
544
544
|
`+m("No network data available.")+`
|
|
545
545
|
|
|
546
|
-
`);return}for(let g of d)
|
|
546
|
+
`);return}for(let g of d)ah(g,i?.networks[g],f[g]??{});if(a){let g=r?void 0:d[0];ch(a.issues,g)}process.stderr.write(`
|
|
547
547
|
`+J()+`
|
|
548
548
|
`),process.stderr.write(m(" Dashboard: ")+K(Sn)+`
|
|
549
549
|
|
|
550
|
-
`)};if(p(),n){let g=setInterval(async()=>{try{let[
|
|
551
|
-
`)}},30000);await new Promise(()=>{process.on("SIGINT",()=>{clearInterval(g),process.exit(0)})})}let h=d.reduce((g,
|
|
552
|
-
Available: ${i.join(", ")}`);a=t}else a=i[0];let c=i.filter((u)=>u!==a),d=ur(s,a,"compiler",ss);return
|
|
550
|
+
`)};if(p(),n){let g=setInterval(async()=>{try{let[S,...y]=await Promise.all([Promise.all([es("/api/status"),es("/api/issues")]).catch(()=>null),...d.map((w)=>Id(w))]);if(S)[i,a]=S;for(let w=0;w<d.length;w++)f[d[w]]=y[w];process.stderr.write("\x1B[2J\x1B[H"),p()}catch{process.stderr.write(m(" Refresh failed — retrying in 30s")+`
|
|
551
|
+
`)}},30000);await new Promise(()=>{process.on("SIGINT",()=>{clearInterval(g),process.exit(0)})})}let h=d.reduce((g,S)=>{let y={...i?.networks[S]??{},...f[S]??{}},w=$o(y);if(w==="down")return"down";if(w==="degraded"&&g!=="down")return"degraded";return g},"up");if(h==="down")process.exitCode=2;else if(h==="degraded")process.exitCode=1}var Qg,eh,Nd,th=15000,ts=5000,Rd=1e4;var Pd=A(()=>{oe();ye();fe();ft();Qg={preprod:{faucet:"https://faucet.preprod.midnight.network/",explorer:"https://preprod.midnightexplorer.com/"},preview:{faucet:"https://faucet.preview.midnight.network/",explorer:null},undeployed:{faucet:"",explorer:""}},eh={indexer:"Indexer",rpc:"RPC Node",faucet:"Faucet",explorer:"Explorer",chain:"Chain",dust:"Dust Generation",wallet:"Wallet Ops",dapp:"DApp Flow"},Nd={up:W("UP"),down:de("DOWN"),degraded:P("\x1B[33mDEGRADED\x1B[0m"),unknown:m("—")}});function ns(e){if(!/^[0-9a-fA-F]{64}$/.test(e))throw new _(`A contract address is 64 hex characters (32 bytes); got "${e}" (${e.length} characters).`)}function _d(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 _(`${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 _(`${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 _(`${t} takes ${o} argument${o===1?"":"s"}${o>0?` (${i})`:""}; --args gave ${r.length}.`)}}var _o=A(()=>{ve()});import{existsSync as Oo,readFileSync as dh,readdirSync as lh}from"node:fs";import{join as ur,basename as uh}from"node:path";function nt(e,t){let r=ur(e,"compiler",ss);if(Oo(r))return Md(r,e,[]);for(let n of Od){let s=n?ur(e,n,"managed"):ur(e,"managed");if(!Oo(s))continue;let o;try{o=lh(s).sort()}catch{continue}let i=o.filter((u)=>Oo(ur(s,u,"compiler",ss)));if(i.length===0)continue;let a;if(t){if(!i.includes(t))throw Error(`Contract "${t}" not found in ${s}
|
|
552
|
+
Available: ${i.join(", ")}`);a=t}else a=i[0];let c=i.filter((u)=>u!==a),d=ur(s,a,"compiler",ss);return Md(d,ur(s,a),c)}throw Error(`No compiled contract found in ${e}
|
|
553
553
|
Expected: managed/<name>/compiler/${ss}
|
|
554
|
-
Searched: ${
|
|
555
|
-
Run "compact compile" first, or use --managed <path> to specify the managed directory.`)}function
|
|
556
|
-
`)}var os,
|
|
554
|
+
Searched: ${Od.map((n)=>n?`${n}/managed/`:"managed/").join(", ")}
|
|
555
|
+
Run "compact compile" first, or use --managed <path> to specify the managed directory.`)}function Md(e,t,r){let n;try{n=JSON.parse(dh(e,"utf-8"))}catch(o){throw Error(`Failed to parse ${e}: ${o.message}`)}return{info:ph(n,e,t,r),infoPath:e}}function ph(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:uh(r),managedDir:r,compilerVersion:o,languageVersion:i,runtimeVersion:a,circuits:c,witnesses:d,siblings:n}}function Be(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(Be).join(", ")}]`;case"Boolean":return"boolean";case"String":return"string";case"Vector":return e.types?.[0]?`${Be(e.types[0])}[]`:"unknown[]";case"Map":if(e.types&&e.types.length>=2)return`Map<${Be(e.types[0])}, ${Be(e.types[1])}>`;return"Map<unknown, unknown>";case"Set":return e.types?.[0]?`Set<${Be(e.types[0])}>`:"Set<unknown>";case"Option":return e.types?.[0]?`${Be(e.types[0])} | null`:"unknown | null";default:return e["type-name"]??"unknown"}}function Fd(e){let t=e.arguments.map((r)=>`${r.name}: ${Be(r.type)}`).join(", ");return`${e.name}(${t})`}function Ld(e){if(e.pure)return"pure";let t=["impure"];if(e.proof)t.push("proof");return t.join(", ")}function Ud(e){let t=e.arguments.map((s)=>`${s.name}: ${Be(s.type)}`).join(", "),r=Be(e["result type"]),n=r!=="void"?` → ${r}`:"";return`${e.name}(${t})${n}`}function Wd(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:Be(r.type)})),returnType:Be(t["result-type"])})),witnesses:e.witnesses.map((t)=>({name:t.name,arguments:t.arguments.map((r)=>({name:r.name,type:Be(r.type)})),returnType:Be(t["result type"])}))}}var ss="contract-info.json",Od;var en=A(()=>{Od=["","contract/src","contract","contracts/src","contracts","src"]});import{existsSync as Bd}from"node:fs";import{join as jd}from"node:path";function Hd(e){for(let t of os){let r=jd(e,t);if(Bd(r))return r}return null}function mh(e){for(let t of fh){let r=jd(e,t);if(Bd(r))return r}return null}function Gd(e){let{projectRoot:t,witnessNames:r}=e,n=mh(t),s=[`Contract declares ${r.length} witness(es): ${r.join(", ")}`,"but no compiled witnesses module was found.","",`Searched (relative to ${t}):`,...os.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(`
|
|
556
|
+
`)}var os,fh;var Mo=A(()=>{os=["dist/witnesses.js","src/witnesses.js","contract/dist/witnesses.js","contract/src/witnesses.js"],fh=["src/witnesses.ts","contract/src/witnesses.ts"]});import{resolve as Fo}from"node:path";function tn(e){return Fo(x(e,"managed")??x(e,"path")??process.cwd())}function is(e){let t=Fo(x(e,"path")??process.cwd()),{info:r}=nt(tn(e),x(e,"name")),n=r.witnesses.map((i)=>i.name);if(n.length>0&&!Hd(t))throw Error(Gd({projectRoot:t,witnessNames:n}));let s=Kd(x(e,"args")),o=x(e,"secret-key");if(o!==void 0&&!/^[0-9a-fA-F]{64}$/.test(o))throw new _("--secret-key must be 32 bytes of hex (64 chars)");return{dappDir:t,info:r,constructorArgs:s,privateStateSecretKey:o}}function as(e){let t=Fo(x(e,"path")??process.cwd()),r=Cr(e,"address","contract address"),n=Cr(e,"circuit","circuit name"),{info:s}=nt(tn(e),x(e,"name")),o=Kd(x(e,"args"));return ns(r),_d(s,n,o),{dappDir:t,info:s,address:r,circuit:n,callArgs:o}}function Kd(e){if(!e)return[];let t;try{t=JSON.parse(e)}catch(r){throw new _(`Invalid --args JSON: ${r.message}`)}if(Array.isArray(t))return t;if(t!==null&&typeof t==="object")return Object.values(t);throw new _(`Invalid --args JSON: expected an array or an object, got ${JSON.stringify(t)}`)}var cs=A(()=>{oe();ve();en();Mo();_o()});import*as Vd from"node:readline";function wh(e){return gh.has(e)}function yh(e){return hh.has(e)}function Sh(e){let t=[],r=e.dappName?`Request from "${e.dappName}"`:"DApp Request";if(t.push(P(r)),t.push(""),t.push(` ${m("Action:")} ${K(e.method)}`),t.push(` ${m("Network:")} ${e.network}`),e.details.length>0){t.push("");for(let n of e.details)t.push(` ${m(n.label+":")} ${n.value}`)}return t.push(""),t.push(` ${W("[A]pprove")} ${de("[R]eject")}`),oa(t,"heavy")}function bh(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`${yh(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 Jd(e,t={}){if(t.approveAll)return process.stderr.write(m(` Auto-approved: ${e.method}`)+`
|
|
557
557
|
`),"approve";if(t.approveFees&&e.feeOnly)return process.stderr.write(m(` Auto-approved (fee-only): ${e.method}`)+`
|
|
558
|
-
`),"approve";if(t.autoApproveReads&&
|
|
559
|
-
`),"approve";if(!process.stdin.isTTY)return process.stderr.write(
|
|
560
|
-
`),process.stderr.write(m(` ${
|
|
561
|
-
`),"reject";if(rn)return process.stderr.write(
|
|
558
|
+
`),"approve";if(t.autoApproveReads&&wh(e.method))return process.stderr.write(m(` Auto-approved (read-only): ${e.method}`)+`
|
|
559
|
+
`),"approve";if(!process.stdin.isTTY)return process.stderr.write(de(" Cannot prompt for approval: stdin is not a TTY")+`
|
|
560
|
+
`),process.stderr.write(m(` ${bh(e,t)}`)+`
|
|
561
|
+
`),"reject";if(rn)return process.stderr.write(de(" Rejected: another approval prompt is active")+`
|
|
562
562
|
`),"reject";process.stderr.write(`
|
|
563
|
-
`+
|
|
563
|
+
`+Sh(e)+`
|
|
564
564
|
|
|
565
|
-
`),rn=!0;let r;try{r=
|
|
566
|
-
`),"reject"}return new Promise((n)=>{let s=(o)=>{rn=!1,r.close(),n(o)};r.on("close",()=>{if(rn)s("reject")}),r.question(Q(" Approve? [A/r] "),(o)=>{let i=o.trim().toLowerCase();if(i==="r"||i==="reject")s("reject");else s("approve")})})}var
|
|
567
|
-
`)}),c.on("connection",(l)=>{let f=`conn_${++
|
|
565
|
+
`),rn=!0;let r;try{r=Vd.createInterface({input:process.stdin,output:process.stderr})}catch{return rn=!1,process.stderr.write(de(" Cannot create readline interface")+`
|
|
566
|
+
`),"reject"}return new Promise((n)=>{let s=(o)=>{rn=!1,r.close(),n(o)};r.on("close",()=>{if(rn)s("reject")}),r.question(Q(" Approve? [A/r] "),(o)=>{let i=o.trim().toLowerCase();if(i==="r"||i==="reject")s("reject");else s("approve")})})}var gh,hh,rn=!1;var qd=A(()=>{fe();gh=new Set(["getShieldedBalances","getUnshieldedBalances","getDustBalance","getShieldedAddresses","getUnshieldedAddress","getDustAddress","getTxHistory","getConfiguration","getConnectionStatus"]),hh=new Set(["balanceUnsealedTransaction","balanceSealedTransaction"])});import{WebSocketServer as vh}from"ws";function Ch(e){if(Lo(e))return kh[e.code]??-32603;return-32603}function Lo(e){return typeof e==="object"&&e!==null&&"type"in e&&e.type==="DAppConnectorAPIError"}function xh(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 ds(e,t){if(typeof t==="bigint")return t.toString();return t}function Eh(e,t){return t}function Ah(e){let t;try{t=JSON.parse(e,Eh)}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 zd(e){let{port:t,handlers:r,onConnect:n,onDisconnect:s,onRequest:o,onResponse:i}=e,a=new Map,c=new vh({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}
|
|
567
|
+
`)}),c.on("connection",(l)=>{let f=`conn_${++Th}`,p={ws:l,id:f,connectedAt:new Date,authenticated:!1,requestCount:0,notify(S,y){if(l.readyState!==l.OPEN)return;let w={jsonrpc:"2.0",method:S,...y&&{params:y}};l.send(JSON.stringify(w,ds))}};a.set(f,p),n?.(p);let h=!1,g=()=>{if(h)return;h=!0,a.delete(f),s?.(p)};l.on("message",async(S)=>{let y=null,w,k,T=Date.now();try{w=Ah(S.toString("utf-8")),y=w.id,p.requestCount++,o?.(p,w);let R=Object.hasOwn(r,w.method)?r[w.method]:void 0;if(!R){let H={jsonrpc:"2.0",id:w.id,error:{code:-32601,message:`Method not found: ${w.method}`}};l.send(JSON.stringify(H,ds));return}k={notify:p.notify.bind(p),connectionId:f,requestId:w.id,metadata:{}};let U=await R(w.params??{},k),X=Date.now()-T;if(w.method==="connect"&&U&&typeof U==="object")p.authenticated=!0,p.networkId=U.networkId;let q={jsonrpc:"2.0",id:w.id,result:U};l.send(JSON.stringify(q,ds)),i?.(p,w,X,U,void 0,k.metadata)}catch(R){let U=Date.now()-T,X=R?.rpcCode??Ch(R),q=R instanceof Error?R.message:"Internal error",H=Lo(R)?{type:R.type,code:R.code}:xh(R),M={jsonrpc:"2.0",id:y,error:{code:X,message:q,data:H}};if(l.send(JSON.stringify(M,ds)),w){let O={message:q,code:Lo(R)?R.code:void 0};i?.(p,w,U,void 0,O,k?.metadata)}}}),l.on("close",g),l.on("error",()=>{g();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 G(e,t){let r=Error(t);return r.type="DAppConnectorAPIError",r.code=e,r.reason=t,r}var kh,Th=0;var Uo=A(()=>{kh={Rejected:-32000,PermissionRejected:-32001,Disconnected:-32002,InvalidRequest:-32602,InternalError:-32603}});function Yd(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 Xd(e){return Buffer.from(e).toString("hex")}function Wt(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 Qd(e,t){if(e<=t.maxFeeSpecks)return;return`the estimated fee ${le(e)} DUST is over --max-fee ${le(t.maxFeeSpecks)} DUST`}function el(e,t){if(e<t.maxPending)return;return`${e} balanced transactions are still waiting to be submitted (--max-pending ${t.maxPending})`}var Nh,Zd;var tl=A(()=>{ve();fe();Nh=10n**15n,Zd={maxFeeSpecks:10n*Nh,maxPending:2}});import{Transaction as Rh}from"@midnightntwrk/ledger-v9";function Wo(e,t){let r=[];r.push({label:"Tx size",value:Ph(e.length/2)});let n=Ih(e,t);if(n){let s=Dh(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 Ih(e,t){let r=$h(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 Rh.deserialize(s,o,i,r).toString(!0)}catch{}return null}function Dh(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 $h(e){return new Uint8Array(Buffer.from(e,"hex"))}function Ph(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 rl=()=>{};import{Transaction as nl,addressFromKey as sl}from"@midnightntwrk/ledger-v9";function pr(e,t){return t==="unsealed"?nl.deserialize("signature","proof","pre-binding",e):nl.deserialize("signature","proof","binding",e)}function Bo(e){return new Set([_h,...e.intents?.keys()??[],...e.fallibleOffer?.keys()??[]])}function ol(e,t){return[...e.intents??new Map].filter(([,r])=>r.ttl.getTime()<=t.getTime()).map(([r,n])=>({segment:r,ttl:n.ttl}))}function jo(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 il(e,t){if(e.rewards!==void 0)return["it is a rewards claim, not a standard transaction"];let r=[],n=sl(t);for(let{where:s,owner:o,signed:i}of jo(e)){if(sl(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 Bo(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 _h=0;var Ho=()=>{};function al(e){let t=jo(e),r=t.filter((n)=>n.signed).length;if(r===0)return"none";return r===t.length?"all":"some"}function Oh(e){return[...Bo(e)].filter((t)=>[...e.imbalances(t)].some(([r,n])=>r.tag==="unshielded"&&n!==0n))}function cl(e,t){let r=al(e);if(r==="some")throw new fr;if(r==="all"&&t){let n=Oh(e);if(n.length>0)throw new Go(n)}}async function dl(e,t,r){if(t.type!=="UNBOUND_TRANSACTION")return e.signRecipe(t,r);let n=pr(t.baseTransaction.serialize(),"unsealed"),s=al(n);if(s==="none")return e.signRecipe(t,r);if(s==="some")throw new fr;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 fr,Go;var ll=A(()=>{Ho();fr=class fr 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,fr.prototype)}};Go=class Go 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,Go.prototype)}}});function ul(e,t){switch(t){case"hex":try{return Wt(e)}catch(r){throw Error(`data is not valid hex: ${r.message}`)}case"base64":if(!Mh.test(e))throw Error("data is not valid base64 (standard alphabet, padded)");return new Uint8Array(Buffer.from(e,"base64"));case"text":return new Uint8Array(Buffer.from(e,"utf-8"));default:throw Error(`Unknown encoding: ${t} (use hex, base64 or text)`)}}function pl(e){let t=Buffer.from(`midnight_signed_message:${e.length}:`,"utf-8");return new Uint8Array(Buffer.concat([t,e]))}var Mh;var fl=A(()=>{Mh=/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/});async function ml(e,t){let r;try{r=await kt(e,Lh,{hash:t},Fh)}catch(o){throw new nn(t,o.message)}let n=r.transactions?.find((o)=>o.__typename==="RegularTransaction");if(!n)throw new nn(t,"the indexer has no such transaction");let s=n.transactionResult?.status;if(s!=="PARTIAL_SUCCESS")throw new nn(t,`the indexer reports it as ${s??"having no result"}, not a partial success`);return n.transactionResult?.segments??[]}var Fh=1e4,Lh=`query ($hash: HexEncoded!) {
|
|
568
568
|
transactions(offset: { hash: $hash }) {
|
|
569
569
|
__typename
|
|
570
570
|
... on RegularTransaction { transactionResult { status segments { id success } } }
|
|
571
571
|
}
|
|
572
|
-
}`,nn;var
|
|
573
|
-
`)},
|
|
574
|
-
`)}function w(){return new Date(Date.now()+hn*60*1000)}async function k(v,
|
|
575
|
-
`);let D=
|
|
576
|
-
`)
|
|
577
|
-
`)}};function
|
|
578
|
-
${r}`)}}async function fs(e){let t=
|
|
579
|
-
${n}`)}}async function ms(e){let t=
|
|
580
|
-
${r}`)}}function
|
|
572
|
+
}`,nn;var gl=A(()=>{Jr();nn=class nn 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,nn.prototype)}}});import*as mr from"rxjs";import{MidnightBech32m as hl,UnshieldedAddress as Uh,ShieldedAddress as Wh}from"@midnightntwrk/wallet-sdk/address-format";function Et(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 yl(e,t){switch(e.lifecycle.status){case"finalized":return{txHash:e.hash,txStatus:{status:"finalized",executionStatus:Bh(e,t)}};case"rejected":return{txHash:e.hash,txStatus:{status:"discarded"}};case"pending":return{txHash:e.hash,txStatus:{status:"pending"}}}}function Bh(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 jh(e){if(e!=="schnorr")throw Error(`Unexpected signature scheme "${e}": mn signs with BIP-340 Schnorr only`);return"schnorr_bip340"}function Sl(e){let{bundle:t,networkConfig:r,approvalOptions:n,callbacks:s}=e,o=e.feeLimits??Zd,{facade:i,keystore:a}=t,c=Ue(r.networkId),d,u,l=i.state().subscribe((v)=>{if(u=v.protocolVersion,v.isSynced)d=v});function f(){if(!d)throw G("Disconnected","Wallet not synced yet");return d}function p(){if(!u)throw G("Disconnected","Wallet not synced yet");let v=Ba(u);if(v.length>0){let b=v.map((C)=>`${C} at ${u[C]}`).join(", ");throw G("Disconnected",`This wallet can't take transactions until all three of its wallets are on ledger 9 (fork at ${it.v9}); still behind: ${b}. Wait for them to sync past the fork and retry.`)}}let h=new Map;function g(v,b,C,D=!1){let F=h.get(v);if(!F)F=new Map,h.set(v,F);let Z=setTimeout(async()=>{if(F.delete(b),F.size===0)h.delete(v);try{await i.revert(C)}catch{}process.stderr.write(m(` abandoned tx reverted (${v})`)+`
|
|
573
|
+
`)},Ui);F.set(b,{finalized:C,timer:Z,feeOnly:D})}function S(v,b){let C=h.get(v);if(!C)return;let D=C.get(b);if(D)clearTimeout(D.timer),C.delete(b);if(C.size===0)h.delete(v)}async function y(v){let b=h.get(v);if(!b||b.size===0)return;h.delete(v);for(let[,C]of b){clearTimeout(C.timer);try{await i.revert(C.finalized)}catch{}}process.stderr.write(m(` reverted ${b.size} pending tx(s) on disconnect`)+`
|
|
574
|
+
`)}function w(){return new Date(Date.now()+hn*60*1000)}async function k(v,b){b?.start("signing");let C;try{C=await dl(i,v,a.signDataAsync)}catch(j){try{await i.revert(v)}catch{}if(j instanceof fr)throw G("InvalidRequest",j.message);throw j}b?.start("proving");let D,F,Z=i.finalizeRecipe(C);try{F=await Promise.race([Z,new Promise((j,ue)=>{D=setTimeout(()=>ue(Error("ZK proof generation timed out")),gn)})])}catch(j){try{await i.revert(v)}catch{}throw Z.then((ue)=>i.revert(ue)).catch(()=>{}),j}finally{clearTimeout(D)}return b?.complete(),{hex:Xd(F.serialize()),finalized:F}}function T(v,b){try{return i.adoptTransaction(Wt(v),b)}catch(C){throw G("InvalidRequest",`The transaction could not be read at stage ${b} as this wallet's ledger version: ${Et(C)}`)}}async function R(v,b=[],C,D=!1){C?.notify("approval:pending",{method:v});let F=await Jd({method:v,network:r.networkId,details:b,dappName:C?.connectionId,feeOnly:D},n),Z=F==="reject"?"rejected":"approved";if(C?.notify("approval:resolved",{method:v,result:Z}),F==="reject")throw G("Rejected",n.approveFees?`${wl}: 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`:wl)}function U(v,b,C){if(C===!1)throw G("InvalidRequest","This wallet is a fee wallet (--approve-fees): it only pays the Dust fee, so payFees: false leaves it nothing to do");let D;try{D=pr(Wt(v),b)}catch(Z){throw G("InvalidRequest",`The transaction could not be read as a proven ledger-9 ${b} transaction: ${Et(Z)}`)}let F=il(D,a.getPublicKey());if(F.length>0)throw G("Rejected",`This wallet is a fee wallet (--approve-fees) and pays only the Dust fee; it refuses this transaction because ${F.join("; ")}`)}function X(v,b){let C;try{C=ol(pr(Wt(v),b),new Date)}catch(D){throw G("InvalidRequest",Et(D))}if(C.length>0){let D=C.map(({segment:F,ttl:Z})=>`intent ${F}'s TTL (${Z.toISOString()})`).join(", ");throw G("InvalidRequest",`The transaction has expired: ${D} has passed. Build it again with a later TTL.`)}}function q(v,b){try{cl(pr(Wt(v),"unsealed"),b)}catch(C){throw G("InvalidRequest",Et(C))}}function H(){let v=0;for(let[,b]of h)v+=b.size;return v}function M(v){return G("Rejected",`This wallet is a fee wallet (--approve-fees) and refuses this transaction: ${v}`)}let O=0;function se(){let v=el(H()+O,o);if(v)throw M(v);O++;let b=!1;return()=>{if(!b)b=!0,O--}}async function me(v,b){let C=await je(()=>i.estimateTransactionFee(v,{ttl:b}));process.stderr.write(m(` fee-only: estimated fee ${le(C)} DUST (limit ${le(o.maxFeeSpecks)})`)+`
|
|
575
|
+
`);let D=Qd(C,o);if(D)throw M(D)}async function ln(v,b,C,D){let F=String(C.tx??"");if(!F)throw G("InvalidRequest","tx is required");p();let Z=C.options?.payFees,j=n.approveFees===!0;if(j)U(F,b,Z);let ue=j?["dust"]:Z===!1?["shielded","unshielded"]:"all",Fe=w(),Xe=b==="unsealed"?T(F,"Unbound"):T(F,"Finalized");if(X(F,b),b==="unsealed")q(F,ue==="all"||ue.includes("unshielded"));let Ze=j?se():void 0;try{if(j)await me(Xe,Fe);let jt=vr(v,D);jt.start("approve"),await R(v,Wo(F,b),D,j),jt.start("building");let wi={ttl:Fe,tokenKindsToBalance:ue},bs;if(b==="unsealed"){let vs=Xe;bs=await je(()=>i.balanceUnboundTransaction(vs,wi))}else{let vs=Xe;bs=await je(()=>i.balanceFinalizedTransaction(vs,wi))}let{hex:yi,finalized:yp}=await k(bs,jt);return g(D.connectionId,yi,yp,j),D.metadata.phases=jt.getTimings(),{tx:yi}}finally{Ze?.()}}function mt(v){return hl.encode(c,v).asString()}function ge(v,b){let C;try{if(typeof v!=="string"&&typeof v!=="number"&&typeof v!=="bigint")throw TypeError();C=BigInt(v)}catch{throw G("InvalidRequest",`Invalid ${b}: "${String(v)}" — must be a whole number of the token's smallest unit`)}if(C<=0n)throw G("InvalidRequest",`Invalid ${b}: ${C} — must be greater than 0`);return C}function br(v,b){if(v!=="shielded"&&v!=="unshielded")throw G("InvalidRequest",`Invalid ${b} kind: "${v}" — must be "shielded" or "unshielded"`);return v}function At(v){if(typeof v!=="string"||!/^[0-9a-fA-F]{64}$/.test(v))throw G("InvalidRequest",`Invalid token type: "${v}" — must be 64 hex characters`);return v}function Ne(v){if(!Array.isArray(v))throw G("InvalidRequest","desiredInputs must be an array");let b={};for(let C of v){let D=br(C?.kind,"input");b[D]??={},b[D][At(C.type)]=ge(C.value,"value")}return b}function gt(v){if(!Array.isArray(v))throw G("InvalidRequest","desiredOutputs must be an array");let b={};for(let C of v){let D=br(C?.kind,"output");b[D]??=[];let F=At(C.type),Z=ge(C.value,"value"),j;try{j=hl.parse(String(C.recipient)).decode(D==="unshielded"?Uh:Wh,c)}catch(ue){throw G("InvalidRequest",`Invalid recipient: "${C.recipient}" is not ${D==="unshielded"?"an":"a"} ${D} address on ${r.networkId} (${Et(ue)})`)}b[D].push({type:F,receiverAddress:j,amount:Z})}return Object.entries(b).map(([C,D])=>({type:C,outputs:D}))}function vr(v,b){return Yd({onStart:(C)=>{let D=b?.connectionId??"unknown";s?.onPhaseStart?.(D,v,C),b?.notify("progress",{method:v,phase:C,status:"started"})},onComplete:(C,D)=>{let F=b?.connectionId??"unknown";s?.onPhaseComplete?.(F,v,C,D),b?.notify("progress",{method:v,phase:C,status:"completed",durationMs:D})}})}function we(){return d!==void 0&&Ot(d)}async function Ce(v){return new Promise((b)=>{if(we()){b("already");return}let C=i.state().pipe(mr.filter(()=>we()),mr.take(1),mr.timeout(v)).subscribe({next:()=>{C.unsubscribe(),b("appeared")},error:()=>{C.unsubscribe(),b("timeout")}})})}function st(v){return G("InternalError",`No Dust is free to pay the fee (${Et(v)}). Each balanced transaction reserves a whole Dust coin until it is submitted and on chain, or released when its connection closes or it expires; ${H()} 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 je(v){for(let b=1;;b++)try{return await v()}catch(C){let D=String(C?.message??C??"");if(!so(C))throw C;if(b>=_s)throw st(C);if(process.stderr.write(m(` dust unavailable, waiting for recovery (${b}/${_s})... [${D.slice(0,60)}]`)+`
|
|
576
|
+
`),await Ce(Os)!=="appeared")await Xr(Os)}}let Ge={connect:async(v)=>{let b=String(v.networkId??"");if(b.toLowerCase()!==r.networkId.toLowerCase())throw G("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 v=f();return{unshieldedAddress:mt(v.unshielded.address)}},getShieldedAddresses:async()=>{let b=f().shielded.address;return{shieldedAddress:mt(b),shieldedCoinPublicKey:b.coinPublicKeyString(),shieldedEncryptionPublicKey:b.encryptionPublicKeyString()}},getDustAddress:async()=>{let v=f();return{dustAddress:mt(v.dust.address)}},getTxHistory:async(v)=>{f();let b=v.pageNumber??0,C=v.pageSize??20;if(!Number.isSafeInteger(b)||b<0)throw G("InvalidRequest",`Invalid pageNumber: ${JSON.stringify(b)} — must be a whole number, 0 or more`);if(!Number.isSafeInteger(C)||C<1)throw G("InvalidRequest",`Invalid pageSize: ${JSON.stringify(C)} — must be a whole number, 1 or more`);let D=b*C,F=await i.getAllFromTxHistory(),Z=[];for(let j of F.slice(D,D+C)){if(j.lifecycle.status!=="finalized"||j.status!=="PARTIAL_SUCCESS"){Z.push(yl(j));continue}try{Z.push(yl(j,await ml(r.indexer,j.hash)))}catch(ue){throw G("InternalError",Et(ue))}}return Z},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(v,b)=>{let C=v.desiredOutputs;if(!Array.isArray(C)||C.length===0)throw G("InvalidRequest","desiredOutputs must be a non-empty array");p();let D=gt(C),F=vr("makeTransfer",b),Z=C.map((Ze,jt)=>({label:`Output ${jt+1}`,value:`${Ze.value} → ${String(Ze.recipient).slice(0,20)}... (${Ze.kind})`}));F.start("approve"),await R("makeTransfer",Z,b),F.start("building");let j=v.options?.payFees??!0,ue=await je(()=>i.transferTransaction(D,{ttl:w(),payFees:j})),{hex:Fe,finalized:Xe}=await k(ue,F);return g(b.connectionId,Fe,Xe),b.metadata.phases=F.getTimings(),{tx:Fe}},submitTransaction:async(v,b)=>{let C=String(v.tx??"");if(!C)throw G("InvalidRequest","tx is required");p();let D=vr("submitTransaction",b),F=n.approveFees===!0&&h.get(b.connectionId)?.get(C)?.feeOnly===!0;D.start("approve");try{await R("submitTransaction",Wo(C,"sealed"),b,F)}catch(j){let Fe=h.get(b.connectionId)?.get(C);if(Fe)try{await i.revert(Fe.finalized)}catch{}throw S(b.connectionId,C),j}let Z=T(C,"Finalized");D.start("submitting");try{let j=await i.submitTransaction(Z);return D.complete(),S(b.connectionId,C),b.metadata.phases=D.getTimings(),{txHash:j}}catch(j){D.complete();let Fe=h.get(b.connectionId)?.get(C);if(Fe)try{await i.revert(Fe.finalized)}catch{}S(b.connectionId,C);let Xe=Et(j),Ze=Error(`Transaction submission failed: ${Xe}`);throw Ze.cause=j,Ze}},balanceUnsealedTransaction:(v,b)=>ln("balanceUnsealedTransaction","unsealed",v,b),balanceSealedTransaction:(v,b)=>ln("balanceSealedTransaction","sealed",v,b),makeIntent:async(v,b)=>{let{desiredInputs:C,desiredOutputs:D,options:F}=v;if(!F)throw G("InvalidRequest","options is required for makeIntent");p();let Z=Ne(C??[]),j=gt(D??[]),ue=vr("makeIntent",b);ue.start("approve"),await R("makeIntent",[],b),ue.start("building");let Fe=await je(()=>i.initSwap(Z,j,{ttl:w(),payFees:F.payFees??!0})),{hex:Xe,finalized:Ze}=await k(Fe,ue);return g(b.connectionId,Xe,Ze),b.metadata.phases=ue.getTimings(),{tx:Xe}},signData:async(v,b)=>{let C=String(v.data??""),D=v.options;if(!C||!D?.encoding)throw G("InvalidRequest","data and options.encoding are required");if(D.keyType&&D.keyType!=="unshielded")throw G("InvalidRequest",`Unsupported keyType: "${D.keyType}" — only "unshielded" is supported`);let F;try{F=ul(C,D.encoding)}catch(ue){throw G("InvalidRequest",ue.message)}await R("signData",[{label:"Encoding",value:D.encoding},{label:"Data",value:C.length>64?C.slice(0,64)+"...":C}],b);let Z=await a.signDataAsync(pl(F)),j=a.getPublicKey();return{data:C,signature:Z.value,verifyingKey:j.value,scheme:jh(Z.tag)}},getProvingProvider:async()=>({provingProvider:"ready",proverServerUri:r.proofServer}),hintUsage:async(v)=>{let b=v.methodNames??[];if(!Array.isArray(b)||!b.every((C)=>typeof C==="string"&&/^[A-Za-z]\w*$/.test(C)))throw G("InvalidRequest","methodNames must be an array of connector method names");process.stderr.write(m(` DApp hints usage: ${b.join(", ")}`)+`
|
|
577
|
+
`)}};function hp(){l.unsubscribe();for(let[,v]of h)for(let[,b]of v)clearTimeout(b.timer);h.clear()}function wp(){for(let[,v]of h)if(v.size>0)return!0;return!1}return{handlers:Ge,revertPendingTxs:y,hasPendingTxs:wp,dispose:hp}}var wl="User rejected the request";var bl=A(()=>{qe();ye();qd();Uo();ct();Gr();tl();rl();Ho();ll();fl();So();gl();Lt();fe()});import{Socket as Hh}from"node:net";function vl(e){let{name:t,config:r}=pe({args:{command:"serve",subcommand:void 0,positionals:[],flags:{...e.network?{network:e.network}:{},...bn(e.endpoints??{})}}});return _e(r,e.endpoints??{},t),{networkName:t,networkConfig:r}}function Gh(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 Kh(e){return new Promise((t)=>{let r=new Hh;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 Vh(e){let r=(await kl(e,"getConnectionStatus"))?.networkId;return typeof r==="string"?r:null}async function Jh(e){let t=await kl(e,"getConfiguration");return t&&typeof t==="object"?t:null}async function kl(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 ls(e){let t=e.port??Tr,r=(e.network??"undeployed").toLowerCase(),n=e.onMessage??(()=>{});if(await Kh(t)){let s=await Vh(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 Jh(t),a=i?Gh(i,vl(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 qh(e)}async function qh(e){let t=e.port??Tr,r=e.onMessage??(()=>{}),n=ne(re(e.wallet)),s=Buffer.from(n.seed,"hex"),{networkName:o,networkConfig:i}=vl(e);await He(o,i);let a=n.addresses[o],c=$e((h,g)=>{r(`SDK: ${g}`)}),d=Pe();r("Building wallet facade...");let u=vt(a,o),l=await et(s,i,u);r("Syncing wallet..."),await bt(l,{onProgress:(h,g)=>{if(g>0){let S=Math.min(Math.round(h/g*100),100);r(`Syncing wallet... ${S}%`)}}}),r("Wallet synced"),r("Waiting for dust..."),await $n(l),r("Dust ready");try{await lt(a,o,l.facade)}catch{}let f=Sl({bundle:l,networkConfig:i,approvalOptions:{approveAll:!0,autoApproveReads:!0},callbacks:{onPhaseStart:(h,g,S)=>{r(`${S}...`)},onPhaseComplete:(h,g,S,y)=>{r(`${S} ${Math.round(y)}ms`)}}}),p=zd({port:t,handlers:f.handlers,onConnect:(h)=>{r(`connected ${h.id}`)},onDisconnect:(h)=>{r(`disconnected ${h.id}`),f.revertPendingTxs(h.id).catch(()=>{})},onRequest:(h,g)=>{r(`${h.id} → ${g.method}`)},onResponse:(h,g,S,y,w)=>{if(w)r(`${h.id} ← ${g.method} FAILED: ${w.message}`);else r(`${h.id} ← ${g.method} (${Math.round(S)}ms)`)}});try{await p.ready}catch(h){throw f.dispose(),await p.close(),await We(l),c(),d(),Error(`Could not start mn serve on port ${t}: ${h.message}`)}return r(`Server ready on ws://localhost:${t}`),{port:t,async stop(){p.close(),f.dispose(),d(),c();try{await We(l)}catch{}}}}var Ko=A(()=>{De();ke();Lt();ye();qe();Mt();xt();bl();Uo()});function us(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(us)}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]=us(e[r]);return t}return e}function Cl(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 zh}from"node:child_process";import{writeFileSync as Yh,unlinkSync as xl,existsSync as ps,symlinkSync as El}from"node:fs";import{join as sn,dirname as Al}from"node:path";import{fileURLToPath as Xh}from"node:url";function Zh(){let e=Al(Xh(import.meta.url));for(let t=0;t<8;t++){let r=sn(e,"node_modules");if(ps(r))return r;let n=Al(e);if(n===e)break;e=n}return null}async function gr(e){let t=nw(e),r=await zo(e.dappDir,t,e.onMessage);try{return JSON.parse(r)}catch{throw Error(`State script returned unexpected output:
|
|
578
|
+
${r}`)}}async function fs(e){let t=tw(e),r=e.privateStateSecretKey?{MN_PRIVATE_STATE_SECRET:e.privateStateSecretKey}:void 0,n=await zo(e.dappDir,t,e.onMessage,r);try{return JSON.parse(n)}catch{throw Error(`Deploy script returned unexpected output:
|
|
579
|
+
${n}`)}}async function ms(e){let t=rw(e),r=await zo(e.dappDir,t,e.onMessage);try{return JSON.parse(r)}catch{throw Error(`Call script returned unexpected output:
|
|
580
|
+
${r}`)}}function Tl(e){return`
|
|
581
581
|
import WebSocket from 'ws';
|
|
582
582
|
|
|
583
583
|
const RPC_URL = 'ws://127.0.0.1:${e}';
|
|
@@ -618,7 +618,7 @@ function rpcCall(method, params = {}) {
|
|
|
618
618
|
function rpcClose() {
|
|
619
619
|
if (rpcWs) rpcWs.close();
|
|
620
620
|
}
|
|
621
|
-
`}function
|
|
621
|
+
`}function Rl(){return`
|
|
622
622
|
const walletState = await rpcCall('getShieldedAddresses', {});
|
|
623
623
|
|
|
624
624
|
const walletProvider = createWalletProvider({
|
|
@@ -635,7 +635,7 @@ const midnightProvider = createMidnightProvider(async (tx) => {
|
|
|
635
635
|
await rpcCall('submitTransaction', { tx: toHex(tx.serialize()) });
|
|
636
636
|
return tx.identifiers()[0];
|
|
637
637
|
});
|
|
638
|
-
`}function
|
|
638
|
+
`}function Il(e,t){return`
|
|
639
639
|
import { pathToFileURL } from 'node:url';
|
|
640
640
|
import { resolve } from 'node:path';
|
|
641
641
|
import { CompiledContract } from '@midnight-ntwrk/compact-js';
|
|
@@ -680,7 +680,7 @@ if (!witnesses) {
|
|
|
680
680
|
// Uses a deterministic seed derived from the wallet so post/takeDown use the same key.
|
|
681
681
|
// The private state provider (leveldb) persists between calls, but initialPrivateState
|
|
682
682
|
// is the fallback when no stored state exists yet.
|
|
683
|
-
${
|
|
683
|
+
${Qh}
|
|
684
684
|
function makeInitialPrivateState() {
|
|
685
685
|
if (createPrivateState) {
|
|
686
686
|
// Secret precedence (see resolvePrivateStateSecretKey, injected above via
|
|
@@ -706,7 +706,7 @@ const compiled = witnesses
|
|
|
706
706
|
CompiledContract.withVacantWitnesses,
|
|
707
707
|
(c) => CompiledContract.withCompiledFileAssets(c, MANAGED_DIR),
|
|
708
708
|
);
|
|
709
|
-
`}function
|
|
709
|
+
`}function Dl(e,t){return`
|
|
710
710
|
const zkConfigProvider = new NodeZkConfigProvider(MANAGED_DIR);
|
|
711
711
|
|
|
712
712
|
const providers = {
|
|
@@ -724,24 +724,24 @@ const providers = {
|
|
|
724
724
|
walletProvider,
|
|
725
725
|
midnightProvider,
|
|
726
726
|
};
|
|
727
|
-
`}function
|
|
727
|
+
`}function ew(e,t){let r=new RegExp(`^${Jo} (.*)$`,"m").exec(e);if(r)try{return JSON.parse(r[1])}catch{return r[1]}return e.trim()||`Script exited with code ${t}`}function tw(e){let t=e.privateStateKey??`${e.contractName}PrivateState`,r=JSON.stringify(e.args??[]);return`${qo}
|
|
728
728
|
import { setNetworkId } from '@midnight-ntwrk/midnight-js-network-id';
|
|
729
729
|
setNetworkId(${JSON.stringify(e.networkConfig.networkId.toLowerCase())});
|
|
730
730
|
|
|
731
|
-
${
|
|
732
|
-
${
|
|
731
|
+
${Tl(e.servePort)}
|
|
732
|
+
${Il(e.contractName,e.managedDir)}
|
|
733
733
|
|
|
734
734
|
process.stderr.write('Connecting to mn serve...\\n');
|
|
735
735
|
await rpcConnect();
|
|
736
736
|
process.stderr.write('Connected\\n');
|
|
737
737
|
|
|
738
|
-
${
|
|
739
|
-
${
|
|
740
|
-
${
|
|
738
|
+
${Nl}
|
|
739
|
+
${Rl()}
|
|
740
|
+
${Dl(e.networkConfig,t)}
|
|
741
741
|
|
|
742
742
|
import { deployContract } from '@midnight-ntwrk/midnight-js-contracts';
|
|
743
743
|
|
|
744
|
-
${
|
|
744
|
+
${$l}
|
|
745
745
|
const constructorArgs = (${r}).map(coerceArg);
|
|
746
746
|
process.stderr.write('Deploying contract' + (constructorArgs.length ? ' with ' + constructorArgs.length + ' constructor arg(s)...' : '...') + '\\n');
|
|
747
747
|
const deployed = await deployContract(providers, {
|
|
@@ -757,20 +757,20 @@ process.stderr.write('Deploy complete: ' + address + '\\n');
|
|
|
757
757
|
console.log(JSON.stringify({ contractAddress: address }));
|
|
758
758
|
rpcClose();
|
|
759
759
|
process.exit(0);
|
|
760
|
-
`}function
|
|
760
|
+
`}function rw(e){let t=e.privateStateKey??`${e.contractName}PrivateState`;return`${qo}
|
|
761
761
|
import { setNetworkId } from '@midnight-ntwrk/midnight-js-network-id';
|
|
762
762
|
setNetworkId(${JSON.stringify(e.networkConfig.networkId.toLowerCase())});
|
|
763
763
|
|
|
764
|
-
${
|
|
765
|
-
${
|
|
764
|
+
${Tl(e.servePort)}
|
|
765
|
+
${Il(e.contractName,e.managedDir)}
|
|
766
766
|
|
|
767
767
|
process.stderr.write('Connecting to mn serve...\\n');
|
|
768
768
|
await rpcConnect();
|
|
769
769
|
process.stderr.write('Connected\\n');
|
|
770
770
|
|
|
771
|
-
${
|
|
772
|
-
${
|
|
773
|
-
${
|
|
771
|
+
${Nl}
|
|
772
|
+
${Rl()}
|
|
773
|
+
${Dl(e.networkConfig,t)}
|
|
774
774
|
|
|
775
775
|
import { findDeployedContract } from '@midnight-ntwrk/midnight-js-contracts';
|
|
776
776
|
|
|
@@ -783,14 +783,14 @@ const deployed = await findDeployedContract(providers, {
|
|
|
783
783
|
});
|
|
784
784
|
|
|
785
785
|
process.stderr.write('Calling ${e.circuit}...\\n');
|
|
786
|
-
${
|
|
786
|
+
${$l}
|
|
787
787
|
const args = (${JSON.stringify(e.args??[])}).map(coerceArg);
|
|
788
788
|
await deployed.callTx.${e.circuit}(...args);
|
|
789
789
|
|
|
790
790
|
console.log(JSON.stringify({ status: 'success', circuit: ${JSON.stringify(e.circuit)} }));
|
|
791
791
|
rpcClose();
|
|
792
792
|
process.exit(0);
|
|
793
|
-
`}function
|
|
793
|
+
`}function nw(e){return`${qo}
|
|
794
794
|
import { setNetworkId } from '@midnight-ntwrk/midnight-js-network-id';
|
|
795
795
|
setNetworkId(${JSON.stringify(e.networkConfig.networkId.toLowerCase())});
|
|
796
796
|
|
|
@@ -851,32 +851,32 @@ for (const key of Object.keys(state)) {
|
|
|
851
851
|
|
|
852
852
|
console.log(JSON.stringify({ fields, maps }));
|
|
853
853
|
process.exit(0);
|
|
854
|
-
`}function
|
|
854
|
+
`}function ow(e){if(!Vo)return[];let t=[];if(!ps(e)){try{El(Vo,e),t.push(e)}catch{}return t}for(let r of sw){let n=sn(Vo,r),s=sn(e,r);if(!ps(n)||ps(s))continue;try{El(n,s),t.push(s)}catch{}}return t}async function zo(e,t,r,n){let s=sn(e,"node_modules"),o=ow(s),i=sn(e,`.mn-contract-${Date.now()}.mjs`);Yh(i,t);let a=()=>{try{xl(i)}catch{}for(let c of o.slice().reverse())try{xl(c)}catch{}};return new Promise((c,d)=>{let u=zh("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 h=p.toString().trim();if(h&&!h.includes(Jo))r?.(h)}),u.on("close",(p)=>{if(a(),p!==0){d(Error(ew(f,p)));return}c(l.trim())}),u.on("error",(p)=>{a(),d(p)})})}var Vo,Nl=`
|
|
855
855
|
import { createWalletProvider, createMidnightProvider, Transaction } from '@midnight-ntwrk/midnight-js-types';
|
|
856
856
|
import { toHex, fromHex } from '@midnight-ntwrk/midnight-js-utils';
|
|
857
857
|
import { NodeZkConfigProvider } from '@midnight-ntwrk/midnight-js-node-zk-config-provider';
|
|
858
858
|
import { httpClientProofProvider } from '@midnight-ntwrk/midnight-js-http-client-proof-provider';
|
|
859
859
|
import { indexerPublicDataProvider } from '@midnight-ntwrk/midnight-js-indexer-public-data-provider';
|
|
860
860
|
import { levelPrivateStateProvider } from '@midnight-ntwrk/midnight-js-level-private-state-provider';
|
|
861
|
-
`,
|
|
862
|
-
const resolvePrivateStateSecretKey = (${
|
|
863
|
-
|
|
861
|
+
`,Qh,$l,Jo="__MN_ERROR__",qo,sw;var on=A(()=>{Mo();Vo=Zh();Qh=`
|
|
862
|
+
const resolvePrivateStateSecretKey = (${Cl.toString()});
|
|
863
|
+
`;$l=`
|
|
864
864
|
const coerceArg = (${us.toString()});
|
|
865
|
-
`,
|
|
865
|
+
`,qo=`
|
|
866
866
|
const fail = (e) => {
|
|
867
|
-
process.stderr.write('\\n${
|
|
867
|
+
process.stderr.write('\\n${Jo} ' + JSON.stringify(String(e?.message ?? e)) + '\\n');
|
|
868
868
|
process.exit(1);
|
|
869
869
|
};
|
|
870
870
|
process.on('uncaughtException', fail);
|
|
871
871
|
process.on('unhandledRejection', fail);
|
|
872
|
-
`;
|
|
872
|
+
`;sw=["@midnight-ntwrk","ws"]});import{indexerPublicDataProvider as iw}from"@midnight-ntwrk/midnight-js-indexer-public-data-provider";function Pl(e){return iw({queryURL:e.indexer,subscriptionURL:e.indexerWS??e.indexer.replace("http","ws")})}var _l=()=>{};var Ul={};be(Ul,{default:()=>Ml});import{resolve as aw}from"node:path";function an(){return{update(){},stop(){},fail(){},log(){}}}function cw(e){return Ol.includes(e)}async function Ml(e,t){let r=e.subcommand;if(!r||!cw(r))throw new _(`Usage: midnight contract <${Ol.join("|")}>
|
|
873
873
|
|
|
874
874
|
inspect Show circuits, witnesses, and types for a compiled contract
|
|
875
875
|
deploy Deploy a contract to the network
|
|
876
876
|
call Call a circuit on a deployed contract
|
|
877
877
|
state Read the ledger state of a deployed contract
|
|
878
878
|
|
|
879
|
-
Run "midnight help contract" for more info.`);switch(r){case"inspect":return
|
|
879
|
+
Run "midnight help contract" for more info.`);switch(r){case"inspect":return dw(e);case"deploy":return lw(e);case"call":return pw(e);case"state":return fw(e)}}async function dw(e){let t=N(e,"json"),r=tn(e),n=x(e,"name"),{info:s}=nt(r,n);if(t){I(Wd(s));return}if(process.stderr.write(`
|
|
880
880
|
`+B(`Contract: ${s.name}`)+`
|
|
881
881
|
|
|
882
882
|
`),process.stderr.write(E("Compiler",s.compilerVersion)+`
|
|
@@ -885,56 +885,56 @@ Run "midnight help contract" for more info.`);switch(r){case"inspect":return Gh(
|
|
|
885
885
|
`),process.stderr.write(`
|
|
886
886
|
`+P(" Circuits")+`
|
|
887
887
|
`),s.circuits.length===0)process.stderr.write(m(" (none)")+`
|
|
888
|
-
`);else for(let o of s.circuits){let i=
|
|
888
|
+
`);else for(let o of s.circuits){let i=Fd(o),a=Ld(o),c=o.pure?K(a):Q(a);process.stderr.write(` ${i} ${m("—")} ${c}
|
|
889
889
|
`)}if(process.stderr.write(`
|
|
890
890
|
`+P(" Witnesses")+`
|
|
891
891
|
`),s.witnesses.length===0)process.stderr.write(m(" (none)")+`
|
|
892
|
-
`);else for(let o of s.witnesses)process.stderr.write(` ${
|
|
892
|
+
`);else for(let o of s.witnesses)process.stderr.write(` ${Ud(o)}
|
|
893
893
|
`);if(s.siblings.length>0){process.stderr.write(`
|
|
894
894
|
`+P(" Other contracts in this project")+`
|
|
895
895
|
`);for(let o of s.siblings)process.stderr.write(` ${K(o)}
|
|
896
896
|
`);process.stderr.write(`
|
|
897
897
|
`+m(" Inspect a sibling: mn contract inspect --name <name>")+`
|
|
898
898
|
`)}process.stderr.write(`
|
|
899
|
-
`)}async function
|
|
899
|
+
`)}async function Yo(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}=pe({args:{command:"contract",subcommand:t,positionals:[],flags:{network:n,...bn(s)}}});return _e(i,s,o),{network:n,networkConfig:i,endpoints:s}}async function Fl({network:e,networkConfig:t},r,n){await Promise.resolve().then(() => De());await Promise.resolve().then(() => Ct());await Promise.resolve();let c=ne(re(n)),d=Buffer.from(c.seed,"hex"),u=c.addresses[e],l=r?an():V("Checking wallet..."),f=Te();try{let h=(await f.unshielded(u,t)).balances.get(xr)??0n;if(h===0n)throw l.fail("No NIGHT balance"),Error(`Wallet has 0 NIGHT on ${e}.
|
|
900
900
|
|
|
901
901
|
Fund your wallet before deploying:
|
|
902
902
|
Address: ${u}
|
|
903
903
|
`+(e==="undeployed"?` Run: midnight airdrop 1000
|
|
904
904
|
`:` Use the Midnight faucet or transfer from another wallet.
|
|
905
|
-
`));let g=await f.dust(d,t,{onStatus:(
|
|
905
|
+
`));let g=await f.dust(d,t,{onStatus:(S)=>l.update(S)});if(g.balance===0n&&g.availableCoins===0)throw l.fail("No dust available"),Error(`Wallet has no dust on ${e}. Dust is required to pay transaction fees.
|
|
906
906
|
|
|
907
907
|
Register for dust generation:
|
|
908
908
|
Run: midnight dust register --network ${e}
|
|
909
909
|
Then wait: midnight dust status --network ${e}
|
|
910
|
-
`);l.stop(`Wallet OK (${h} NIGHT, dust available)`)}catch(p){throw l.fail("Wallet check failed"),p}}async function
|
|
910
|
+
`);l.stop(`Wallet OK (${h} NIGHT, dust available)`)}catch(p){throw l.fail("Wallet check failed"),p}}async function Ll({network:e,endpoints:t},r,n){await Promise.resolve().then(() => Ko());let o=r?an():V("Starting mn serve..."),i=await ls({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 lw(e){let t=N(e,"json"),{dappDir:r,info:n,constructorArgs:s,privateStateSecretKey:o}=is(e);await Promise.resolve().then(() => on());if(!t)process.stderr.write(`
|
|
911
911
|
`+B("Contract Deploy")+`
|
|
912
912
|
|
|
913
|
-
`);let a=await
|
|
913
|
+
`);let a=await Yo(e,"deploy"),{network:c,networkConfig:d}=a;if(!t){if(process.stderr.write(E("Contract",n.name)+`
|
|
914
914
|
`),process.stderr.write(E("Network",c)+`
|
|
915
915
|
`),s.length>0)process.stderr.write(E("Constructor args",String(s.length))+`
|
|
916
916
|
`);process.stderr.write(`
|
|
917
|
-
`)}await
|
|
917
|
+
`)}await Fl(a,t,x(e,"wallet"));let u=await Ll(a,t,x(e,"wallet")),l=t?an():V("Deploying contract...");try{let f=await fs({dappDir:r,networkConfig:d,managedDir:n.managedDir,contractName:n.name,servePort:u.port,args:s,privateStateSecretKey:o,onMessage:(p)=>l.update(p)});if(l.stop(W("✓")+" Contract deployed"),t)I({subcommand:"deploy",contractName:n.name,address:f.contractAddress,network:c});else process.stderr.write(`
|
|
918
918
|
`),process.stderr.write(E("Address",f.contractAddress)+`
|
|
919
919
|
`),process.stderr.write(`
|
|
920
920
|
`+W(" ✓ Deploy successful")+`
|
|
921
|
-
`),
|
|
922
|
-
`)}catch(f){throw l.fail("Deploy failed"),f}finally{await u.stop()}}function
|
|
921
|
+
`),uw(f.contractAddress,n.circuits,c),process.stdout.write(f.contractAddress+`
|
|
922
|
+
`)}catch(f){throw l.fail("Deploy failed"),f}finally{await u.stop()}}function uw(e,t,r){let n=r==="undeployed"?"":` --network ${r}`;process.stderr.write(`
|
|
923
923
|
`+m(" Next:")+`
|
|
924
924
|
`),process.stderr.write(m(" mn contract state --address ")+K(e)+m(n)+`
|
|
925
925
|
`);let s=t.find((o)=>o.arguments.length===0);if(s)process.stderr.write(m(" mn contract call --address ")+K(e)+m(" --circuit ")+K(s.name)+m(n)+`
|
|
926
926
|
`);process.stderr.write(`
|
|
927
|
-
`)}async function
|
|
927
|
+
`)}async function pw(e){let t=N(e,"json"),{dappDir:r,info:n,address:s,circuit:o,callArgs:i}=as(e);await Promise.resolve().then(() => on());if(!t)process.stderr.write(`
|
|
928
928
|
`+B("Contract Call")+`
|
|
929
929
|
|
|
930
|
-
`);let c=await
|
|
930
|
+
`);let c=await Yo(e,"call"),{network:d,networkConfig:u}=c;if(!t)process.stderr.write(E("Contract",n.name)+`
|
|
931
931
|
`),process.stderr.write(E("Circuit",o)+`
|
|
932
932
|
`),process.stderr.write(E("Address",s.slice(0,20)+"...")+`
|
|
933
933
|
|
|
934
|
-
`);await
|
|
934
|
+
`);await Fl(c,t,x(e,"wallet"));let l=await Ll(c,t,x(e,"wallet")),f=t?an():V(`Calling ${o}...`);try{let p=await ms({dappDir:r,networkConfig:u,managedDir:n.managedDir,contractName:n.name,contractAddress:s,circuit:o,args:i,servePort:l.port,onMessage:(h)=>f.update(h)});if(f.stop(W("✓")+` ${o} called`),t)I({subcommand:"call",contractName:n.name,circuit:o,address:s,network:d,status:p.status});else process.stderr.write(`
|
|
935
935
|
`+W(" ✓ Circuit call successful")+`
|
|
936
936
|
|
|
937
|
-
`)}catch(p){throw f.fail("Call failed"),p}finally{await l.stop()}}async function
|
|
937
|
+
`)}catch(p){throw f.fail("Call failed"),p}finally{await l.stop()}}async function fw(e){let t=N(e,"json"),r=aw(x(e,"path")??process.cwd()),n=tn(e),s=x(e,"name"),o=Cr(e,"address","contract address");ns(o);await Promise.resolve().then(() => on());let{network:a,networkConfig:c}=await Yo(e,"state");if(!t)process.stderr.write(`
|
|
938
938
|
`+B("Contract State")+`
|
|
939
939
|
|
|
940
940
|
`),process.stderr.write(E("Address",o.slice(0,20)+"...")+`
|
|
@@ -945,25 +945,25 @@ Run "midnight help contract" for more info.`);switch(r){case"inspect":return Gh(
|
|
|
945
945
|
`);for(let[h,g]of Object.entries(l.maps))process.stderr.write(` ${h}: ${m(`Map (${g.size} entries)`)}
|
|
946
946
|
`)}else process.stderr.write(m(" (no ledger fields found)")+`
|
|
947
947
|
`);process.stderr.write(`
|
|
948
|
-
`)}}catch(u){d.stop(Q("⚠")+" Parsed state unavailable, showing raw");await Promise.resolve().then(() =>
|
|
948
|
+
`)}}catch(u){d.stop(Q("⚠")+" Parsed state unavailable, showing raw");await Promise.resolve().then(() => _l());let p=await Pl(c).queryContractState(o);if(!p)throw Error(`No contract found at address ${o} on ${a}`);let h=p.data??p;if(t)I({subcommand:"state",address:o,network:a,raw:h});else process.stderr.write(P(" Raw State")+`
|
|
949
949
|
`),process.stderr.write(m(" (run from dApp root for parsed ledger fields)")+`
|
|
950
950
|
`),process.stderr.write(` ${JSON.stringify(h).slice(0,200)}
|
|
951
951
|
|
|
952
|
-
`)}}var
|
|
953
|
-
Run this command from the root of a dApp project, or create a ${
|
|
954
|
-
Check the build log: ${i}`);if(await
|
|
955
|
-
Check the build log: ${i}`)}function
|
|
952
|
+
`)}}var Ol;var Wl=A(()=>{ye();oe();ve();fe();ft();_o();cs();en();Ol=["inspect","deploy","call","state"]});import{existsSync as hr,readFileSync as cn,readdirSync as mw}from"node:fs";import{join as Bt,resolve as gw}from"node:path";function gs(e){let t=gw(e??process.cwd()),r=Bt(t,Xo);if(!hr(r))throw Error(`No ${Xo} found in ${t}
|
|
953
|
+
Run this command from the root of a dApp project, or create a ${Xo} file.`);let n;try{n=JSON.parse(cn(r,"utf-8"))}catch(o){throw Error(`Failed to parse ${r}: ${o.message}`)}return{config:yw(n,r),configPath:r,dappDir:t}}function Zo(e){let t=Bt(e,hw);if(!hr(t))return[];let r=mw(t,{withFileTypes:!0}),n=[];for(let s of r){if(!s.isDirectory())continue;let o=Bt(t,s.name),i=Bt(o,"suite.json");if(!hr(i))continue;let a;try{a=JSON.parse(cn(i,"utf-8"))}catch(c){throw Error(`Failed to parse ${i}: ${c.message}`)}n.push({suite:Sw(a,i),suiteDir:o})}return n}function Kl(e){let t=Bt(e,"assertions.json");if(!hr(t))return null;let r;try{r=JSON.parse(cn(t,"utf-8"))}catch(n){throw Error(`Failed to parse ${t}: ${n.message}`)}return bw(r,t)}function Vl(e){let t=Bt(e,"actions.json");if(!hr(t))return null;let r;try{r=JSON.parse(cn(t,"utf-8"))}catch(n){throw Error(`Failed to parse ${t}: ${n.message}`)}return vw(r,t)}function Jl(e){let t=Bt(e,"prompt.md");if(!hr(t))return null;return cn(t,"utf-8")}function yw(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&&!Bl.includes(r.network))throw Error(`${t}: "network" must be one of: ${Bl.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"||!ww.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 Sw(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(!jl.includes(r.strategy))throw Error(`${t}: "strategy" must be one of: ${jl.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&&!Hl.includes(r.browserMode))throw Error(`${t}: "browserMode" must be one of: ${Hl.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 bw(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 vw(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"||!Gl.includes(s.type))throw Error(`${t}: action "${s.id}" has invalid type "${s.type}". Valid: ${Gl.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 Xo="dapp.test.json",hw="tests/suites",Bl,jl,Hl,ww,Gl;var ql=A(()=>{Bl=["undeployed","preprod","preview"],jl=["browser","cli","hybrid"],Hl=["dom","script","vision","auto"],ww=/^(cache-clear|localnet-up|balance:\d+|dust|dust-register|dust-wait|mn-serve|build-and-serve)$/;Gl=["contract-deploy","contract-call","contract-state","wallet-cmd"]});function zl(){let e=[];return{cleanups:e,addCleanup(t){e.push(t)}}}import{spawn as kw}from"node:child_process";import{createWriteStream as Cw}from"node:fs";import{join as xw}from"node:path";import Ew from"node:http";import Aw from"node:net";async function Xl(e){let{dappDir:t,buildCmd:r,buildDir:n=".",port:s,url:o,logFile:i,timeoutMs:a=240000,onMessage:c=()=>{}}=e;if(await Tw(s)){if(await Yl(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 Nw(s),await new Promise((g)=>setTimeout(g,2000))}let d=xw(t,n),u=Cw(i,{flags:"a"}),l=kw("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",(g)=>{f=!0,p=g}),c(`Building (${r})...`);let h=Date.now()+a;while(Date.now()<h){if(f)throw Error(`Build process exited with code ${p} before the UI was ready.
|
|
954
|
+
Check the build log: ${i}`);if(await Yl(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((g)=>setTimeout(g,2000))}throw l.kill("SIGTERM"),u.end(),Error(`UI did not start within ${Math.round(a/1000)}s at ${o}
|
|
955
|
+
Check the build log: ${i}`)}function Tw(e){return new Promise((t)=>{let r=new Aw.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 Nw(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 Yl(e){return new Promise((t)=>{let r=Ew.get(e,{timeout:3000},(n)=>{t(n.statusCode===200),n.resume()});r.on("error",()=>t(!1)),r.on("timeout",()=>{r.destroy(),t(!1)})})}var Zl=()=>{};import*as eu from"@midnightntwrk/ledger-v9";import{join as Rw}from"node:path";async function tu(e,t,r,n){let s=[];for(let o of e.prep){let i=Date.now();n.onStepStart(o);try{await Iw(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 Iw(e,t,r,n,s){if(e==="cache-clear")return Dw(t);if(e==="localnet-up")return $w(t,s);if(e.startsWith("balance:")){let o=parseInt(e.split(":")[1],10);return Pw(o,t,s)}if(e==="dust"||e==="dust-register"||e==="dust-wait")return _w(t,s);if(e==="mn-serve")return Ow(t,n,s);if(e==="build-and-serve")return Mw(t,r,n,s);throw Error(`Unknown prep step: ${e}`)}async function Dw(e){let t=e.network??"undeployed";ze(void 0,t)}async function $w(e,t){let r=e.network??"undeployed",{config:n}=pe({args:{command:"test",subcommand:void 0,positionals:[],flags:{network:r}}});await Wa(r,n),t.onMessage(`Using the ledger-9 stack at ${n.node} (indexer ${n.indexer})`)}async function Pw(e,t,r){let n=t.network??"undeployed",{config:s}=pe({args:{command:"test",subcommand:void 0,positionals:[],flags:{network:n}}});await He(n,s);let o=ne(re()),i=Buffer.from(o.seed,"hex"),a=o.addresses[n];r.onMessage("Checking balance...");let c=$e((h,g)=>{r.onMessage(`SDK: ${g}`)}),d=Pe(),u=vt(a,n),l=await et(i,s,u);try{let h=await bt(l,{syncMode:"lite",onProgress:(y,w)=>{if(w>0){let k=Math.min(Math.round(y/w*100),100);r.onMessage(`Syncing wallet... ${k}%`)}},onSyncDetail:(y)=>{r.onMessage(`Syncing wallet... (${y})`)}}),g=eu.unshieldedToken().raw,S=h.unshielded.balances[g]??0n;if(S>0n){r.onMessage(`Balance OK: ${S}`);try{await lt(a,n,l.facade)}catch{}return}}finally{d(),c();try{await We(l)}catch{}}if(n!=="undeployed")throw Error(`Wallet has 0 NIGHT on ${n}. Fund your wallet before running tests:
|
|
956
956
|
mn airdrop ${e} (if faucet available)
|
|
957
|
-
Or transfer NIGHT from another wallet.`);r.onMessage(`Balance is 0. Airdropping ${e} NIGHT from genesis...`);let f=Buffer.from(ot,"hex"),p=Ee(f,n);await ar({seedBuffer:f,networkConfig:s,recipientAddress:a,amountNight:e,onSync(h,g){},onDust(h){r.onMessage(`Dust: ${h}`)},onProving(){r.onMessage("Generating ZK proof...")},onSubmitting(){r.onMessage("Submitting airdrop transaction...")},onSyncWarning(h,g){r.onMessage(`Syncing genesis... (${g})`)}}),r.onMessage(`Airdropped ${e} NIGHT`)}async function
|
|
957
|
+
Or transfer NIGHT from another wallet.`);r.onMessage(`Balance is 0. Airdropping ${e} NIGHT from genesis...`);let f=Buffer.from(ot,"hex"),p=Ee(f,n);await ar({seedBuffer:f,networkConfig:s,recipientAddress:a,amountNight:e,onSync(h,g){},onDust(h){r.onMessage(`Dust: ${h}`)},onProving(){r.onMessage("Generating ZK proof...")},onSubmitting(){r.onMessage("Submitting airdrop transaction...")},onSyncWarning(h,g){r.onMessage(`Syncing genesis... (${g})`)}}),r.onMessage(`Airdropped ${e} NIGHT`)}async function _w(e,t){let r=e.network??"undeployed",{config:n}=pe({args:{command:"test",subcommand:void 0,positionals:[],flags:{network:r}}});await He(r,n);let s=ne(re()),o=Buffer.from(s.seed,"hex"),i=s.addresses[r],a=$e(),c=Pe(),d=vt(i,r),u=await et(o,n,d);try{if(t.onMessage("Syncing wallet..."),await bt(u,{syncMode:"lite"}),t.onMessage("Ensuring dust..."),(await rt(u,(h)=>t.onMessage(`Dust: ${h}`))).alreadyAvailable){t.onMessage("Dust already available");try{await lt(i,r,u.facade)}catch{}return}t.onMessage("Dust registered. Waiting for coins to become available...");let f=await $n(u,Ql);if(!Ot(f)){if(r!=="undeployed")throw Error(`Dust not available on ${r}. Register dust and wait for it to generate:
|
|
958
958
|
mn dust register
|
|
959
|
-
mn dust status (check until dustAvailable: true)`);throw Error(`Dust not available after ${
|
|
960
|
-
`).filter(Boolean);e(`Found ${r.length} orphan chrome-devtools-mcp Chrome process(es), killing`);for(let n of r)try{
|
|
959
|
+
mn dust status (check until dustAvailable: true)`);throw Error(`Dust not available after ${Ql/1000}s. The chain may be slow — try again.`)}t.onMessage("Dust is available");try{await lt(i,r,u.facade)}catch{}}finally{c(),a();try{await We(u)}catch{}}}async function Ow(e,t,r){r.onMessage("Starting mn serve...");let n=await ls({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 Mw(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=Rw(t,"tests","results",`build_${Date.now()}.log`),a=await Xl({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 Ql=90000;var ru=A(()=>{Mt();De();ke();Lt();qe();Mt();xt();Ve();Ko();Zl()});import{execSync as nu,spawn as Fw}from"node:child_process";import{createWriteStream as Lw,existsSync as Uw,mkdirSync as Ww,readFileSync as Bw}from"node:fs";import{dirname as jw,join as Hw}from"node:path";import{homedir as Gw}from"node:os";function Kw(){let e=Hw(Gw(),".claude.json");if(!Uw(e))return!1;try{let t=JSON.parse(Bw(e,"utf-8"));return Boolean(t.mcpServers?.["chrome-devtools"])}catch{return!1}}function Jw(e){let t;try{t=nu(`ps -ax -o pid,command | grep "${Vw}" | grep -v grep | awk '{print $1}'`,{encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim()}catch{return}if(!t)return;let r=t.split(`
|
|
960
|
+
`).filter(Boolean);e(`Found ${r.length} orphan chrome-devtools-mcp Chrome process(es), killing`);for(let n of r)try{nu(`kill ${n}`,{stdio:"pipe"})}catch{}}function Qo(e){let t=e.browserMode??"vision";if(t==="auto")return"vision";return t}async function su(e){let{suite:t,prompt:r,dappDir:n,logFile:s,onMessage:o=()=>{}}=e,i=(t.timeout??600)*1000,a=Qo(t);if(a==="dom"||a==="script"){if(!Kw())throw Error(`Browser mode "${a}" requires the chrome-devtools MCP server, which is not registered in ~/.claude.json.
|
|
961
961
|
|
|
962
962
|
Install it:
|
|
963
963
|
claude mcp add chrome-devtools --scope user npx chrome-devtools-mcp@latest
|
|
964
964
|
|
|
965
|
-
Then re-run the suite. Alternatively, switch the suite to "browserMode": "vision" `+"(no MCP needed, but slower — uses screenshots).");
|
|
966
|
-
`),s}function
|
|
965
|
+
Then re-run the suite. Alternatively, switch the suite to "browserMode": "vision" `+"(no MCP needed, but slower — uses screenshots).");Jw(o)}Ww(jw(s),{recursive:!0});let c=Lw(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=qw+r;else if(a==="script")u=zw+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=Fw("claude",d,{cwd:n,stdio:["inherit","pipe","inherit"]}),p=!1;f.stdout?.on("data",(g)=>{process.stdout.write(g),c.write(g)});let h=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",(g)=>{clearTimeout(h),c.end(),l({exitCode:g??1,logFile:s,timedOut:p})}),f.on("error",(g)=>{clearTimeout(h),c.end(),o(`Claude process error: ${g.message}`),l({exitCode:1,logFile:s,timedOut:!1})})})}var Vw="chrome-devtools-mcp/chrome-profile",qw="## 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",zw="## 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 ou=()=>{};import{existsSync as Yw,readFileSync as Xw}from"node:fs";import Zw from"node:net";async function iu(e,t){let r=[];for(let n of e)try{let s=await Qw(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 Qw(e,t){switch(e.type){case"balance-changed":return ey(e,t);case"process-exit-code":return ty(e,t);case"port-listening":return ry(e);case"agent-report-no-failure":return sy(e,t);default:throw Error(`Unsupported assertion type: "${e.type}" (available in v2)`)}}function ey(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 ty(e,t){if(t.processExitCode===void 0)throw Error("Process exit code not available");let r=e.params.code;return t.processExitCode===r}function ry(e){let t=e.params.port;return new Promise((r)=>{let n=new Zw.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 sy(e,t){let r=e.params??{},n=r.logPath??t.agentLogPath;if(!n||!Yw(n))return!0;let s;try{s=Xw(n,"utf-8")}catch{return!0}let o=iy(s),i=r.markers??ny;for(let a of i)if(oy(o,a))return!1;return!0}function oy(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 iy(e){return e.replace(/```[\s\S]*?```/g,"").replace(/`[^`]*`/g,"")}var ny;var au=A(()=>{ny=["FAILED","❌","did not pass","test failed","overall: fail","result: fail"]});import{existsSync as ay,mkdirSync as cy,writeFileSync as dy,readFileSync as ly,readdirSync as uy}from"node:fs";import{join as hs}from"node:path";function du(e,t){let r=hs(t,cu);cy(r,{recursive:!0});let n=`${e.suite}_${e.timestamp.replace(/[:.]/g,"-")}.json`,s=hs(r,n);return dy(s,JSON.stringify(e,null,2)+`
|
|
966
|
+
`),s}function lu(e,t){let r=ei(e,t);return r.length>0?r[0]:null}function ei(e,t){let r=hs(e,cu);if(!ay(r))return[];let n=uy(r).filter((o)=>o.endsWith(".json")).filter((o)=>!t||o.startsWith(t+"_")),s=[];for(let o of n)try{let i=ly(hs(r,o),"utf-8");s.push(JSON.parse(i))}catch{}return s.sort((o,i)=>i.timestamp.localeCompare(o.timestamp)),s}var cu="tests/results";var uu=()=>{};import{execSync as py}from"node:child_process";async function ti(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)fy(e.buildHandle.port,t)}function fy(e,t){try{py(`osascript -e 'tell application "Google Chrome"
|
|
967
967
|
repeat with theWindow in every window
|
|
968
968
|
repeat with theTab in every tab of theWindow
|
|
969
969
|
if URL of theTab contains "localhost:${e}" then
|
|
@@ -971,7 +971,7 @@ Then re-run the suite. Alternatively, switch the suite to "browserMode": "vision
|
|
|
971
971
|
end if
|
|
972
972
|
end repeat
|
|
973
973
|
end repeat
|
|
974
|
-
end tell'`,{timeout:5000,stdio:"pipe"}),t?.(`Closed Chrome tabs for localhost:${e}`)}catch{}}var
|
|
974
|
+
end tell'`,{timeout:5000,stdio:"pipe"}),t?.(`Closed Chrome tabs for localhost:${e}`)}catch{}}var pu=()=>{};function fu(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(fu);default:return null}}function ri(e){let t={};for(let r of e.arguments)t[r.name]=fu(r.type);return t}function ni(e,t){if((t.strategy??"cli")==="browser"){if(!t.browser)throw Error("Browser strategy requires browser options (port, buildCmd, buildDir?, url?)");return by(t,t.browser)}return Sy(e,t)}function Sy(e,t){let r=t.suiteName??my,n=t.network??mu,s=t.servePort??gu;return{dappConfig:{name:t.contractName,network:n,prep:hu},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??hy},actions:{actions:ky(e)},assertions:{post:[wu(s)]},prompt:null,suiteName:r}}function by(e,t){let r=e.suiteName??gy,n=e.network??mu,s=e.servePort??gu,o=t.url??`http://localhost:${t.port}/`,i={name:e.contractName,network:n,port:t.port,buildCmd:t.buildCmd,url:o,prep:yy};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??wy,...t.browserMode?{browserMode:t.browserMode}:{}},actions:null,assertions:{post:[{id:"claude-exit-ok",type:"process-exit-code",params:{code:0},expect:"pass"},wu(s),{id:"agent-no-failure",type:"agent-report-no-failure",params:{},expect:"pass"}]},prompt:vy(e.contractName,o),suiteName:r}}function wu(e){return{id:"serve-port-listening",type:"port-listening",params:{port:e},expect:"pass"}}function vy(e,t){return`You are running an automated E2E test of ${e}.
|
|
975
975
|
|
|
976
976
|
The UI is at ${t} — open it in Chrome.
|
|
977
977
|
mn serve is running with --approve-all so contract calls will auto-approve.
|
|
@@ -1001,44 +1001,44 @@ Follow these steps:
|
|
|
1001
1001
|
|
|
1002
1002
|
If any step fails, report exactly what you see on screen and stop.
|
|
1003
1003
|
Take screenshots at each major step to document the test.
|
|
1004
|
-
`}function
|
|
1004
|
+
`}function ky(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=ri(n);t.push(s)}return t.push({id:"check-final",type:"contract-state"}),t}var mu="undeployed",my="cli-default",gy="ui-default",hy=300,wy=600,gu=9932,hu,yy;var si=A(()=>{hu=["cache-clear","localnet-up","balance:1000","dust","mn-serve"],yy=[...hu,"build-and-serve"]});import{existsSync as Su,mkdirSync as Cy,readFileSync as xy,writeFileSync as yu}from"node:fs";import{join as wr}from"node:path";function bu(e,t){let{dappDir:r,force:n=!1}=t,s=wr(r,"tests","suites",e.suiteName),o=wr(r,"dapp.test.json"),i=[{path:wr(s,"suite.json"),kind:"json",body:e.suite},{path:wr(s,"assertions.json"),kind:"json",body:e.assertions}];if(e.actions)i.push({path:wr(s,"actions.json"),kind:"json",body:e.actions});if(e.prompt)i.push({path:wr(s,"prompt.md"),kind:"text",body:e.prompt});if(!n){let u=i.filter((l)=>Su(l.path)).map((l)=>l.path);if(u.length>0)throw Error(`Suite "${e.suiteName}" already exists at ${s}.
|
|
1005
1005
|
Pick a different suite name (--suite <name>) or pass --force to overwrite.
|
|
1006
1006
|
Existing files:
|
|
1007
1007
|
`+u.map((l)=>` - ${l}`).join(`
|
|
1008
|
-
`))}let a=
|
|
1008
|
+
`))}let a=Ey(o,e,n);Cy(s,{recursive:!0});let c=[],d=[];if(a.action==="write")yu(o,JSON.stringify(e.dappConfig,null,2)+`
|
|
1009
1009
|
`),c.push(o);else d.push(o);for(let u of i){let l=u.kind==="json"?JSON.stringify(u.body,null,2)+`
|
|
1010
|
-
`:u.body;
|
|
1011
|
-
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
|
|
1010
|
+
`:u.body;yu(u.path,l),c.push(u.path)}return{written:c,preserved:d}}function Ey(e,t,r){if(r||!Su(e))return{action:"write"};let n;try{n=JSON.parse(xy(e,"utf-8"))}catch(s){let o=s instanceof Error?s.message:String(s);throw Error(`${e} exists but is not valid JSON: ${o}
|
|
1011
|
+
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 vu=()=>{};import{existsSync as Cu,readdirSync as Ay,readFileSync as Ty,statSync as Ny}from"node:fs";import{basename as Ry,extname as Iy,join as xu,relative as Dy}from"node:path";function Eu(e){let t=new Map;for(let r of $y){let n=xu(e,r);if(!Cu(n))continue;oi(n,e,t)}return[...t.values()].sort((r,n)=>r.name.localeCompare(n.name))}function Au(e,t=e){if(!Cu(e))return[];let r=new Map;return oi(e,t,r),[...r.values()].sort((n,s)=>n.name.localeCompare(s.name))}function oi(e,t,r){let n;try{n=Ay(e)}catch{return}for(let s of n){let o=xu(e,s),i;try{i=Ny(o)}catch{continue}if(i.isDirectory()){if(Py.has(s.toLowerCase()))continue;oi(o,t,r);continue}if(Iy(s)!==ku)continue;if(s.endsWith(".test.tsx")||s.endsWith(".spec.tsx"))continue;let a=Ry(s,ku);if(!_y(a,o))continue;let c=My(a);if(r.has(c))continue;r.set(c,{name:c,component:a,path:o,relativePath:Dy(t,o)})}}function _y(e,t){if(!/^[A-Z][A-Za-z0-9]*$/.test(e))return!1;let r;try{r=Ty(t,"utf-8")}catch{return!1}return Oy.test(r)}function My(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1-$2").toLowerCase()}var $y,ku=".tsx",Py,Oy;var ii=A(()=>{$y=["src/components","src/pages","src/screens","src/views"];Py=new Set(["layout","layouts","shared","common","ui","icons","styles"]);Oy=/\bexport\s+(default\b|const\s+[A-Z]|function\s+[A-Z])/});import{existsSync as Fy,statSync as Ly}from"node:fs";import*as Tu from"node:readline";function Nu(){return process.stdin.isTTY===!0}function Ye(e,t){let r=Tu.createInterface({input:process.stdin,output:process.stderr}),n=t!==void 0?m(` [${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 Ru(){process.stderr.write(`
|
|
1012
1012
|
`+K("Test scaffold setup")+`
|
|
1013
1013
|
`);for(;;){let e=(await Ye("Strategy? cli or ui","cli")).toLowerCase();if(e==="cli")return"cli";if(e==="ui"||e==="browser")return"browser";process.stderr.write(m(` Unknown strategy "${e}". Pick "cli" or "ui".
|
|
1014
|
-
`))}}async function
|
|
1014
|
+
`))}}async function Iu(e={}){process.stderr.write(`
|
|
1015
1015
|
`+m("Browser test scaffold needs your dApp UI details:")+`
|
|
1016
|
-
`);let t=e.port!==void 0?String(e.port):await Ye("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 Ye("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 Ye("Build dir (blank for project root)",""),o=s===""?void 0:s,i=e.url??await Ye("URL",`http://localhost:${r}/`),a=e.browserMode??await
|
|
1016
|
+
`);let t=e.port!==void 0?String(e.port):await Ye("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 Ye("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 Ye("Build dir (blank for project root)",""),o=s===""?void 0:s,i=e.url??await Ye("URL",`http://localhost:${r}/`),a=e.browserMode??await Uy();return{port:r,buildCmd:n,buildDir:o,url:i,browserMode:a}}async function Uy(){process.stderr.write(`
|
|
1017
1017
|
`+K("Browser mode — how should Claude perceive the page?")+`
|
|
1018
1018
|
`),process.stderr.write(` ${m("1.")} dom ${m("— accessibility tree (text). Fast. HTML / React / Vue UIs.")}
|
|
1019
1019
|
`),process.stderr.write(` ${m("2.")} vision ${m("— screenshots. Slow. Canvas games (no DOM).")}
|
|
1020
1020
|
`),process.stderr.write(` ${m("3.")} script ${m("— direct JS. Fastest. Needs dApp-side hooks (advanced).")}
|
|
1021
1021
|
`),process.stderr.write(m(` dom and script need chrome-devtools-mcp installed.
|
|
1022
1022
|
`));for(;;){let e=(await Ye("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(Q(` Pick 1 (dom), 2 (vision), or 3 (script).
|
|
1023
|
-
`))}}async function
|
|
1023
|
+
`))}}async function Du(e){let t=e.filter((r)=>!r.pure);if(t.length===0){process.stderr.write(m(` No impure circuits in this contract — nothing to test as a write path.
|
|
1024
1024
|
`));return}process.stderr.write(`
|
|
1025
1025
|
`+K("Pick the circuit this suite will exercise:")+`
|
|
1026
1026
|
`);for(let r=0;r<t.length;r++)process.stderr.write(` ${m(`${r+1}.`)} ${t[r].name}
|
|
1027
1027
|
`);process.stderr.write(m(` (or type "skip" to scaffold all circuits without AI)
|
|
1028
1028
|
`));for(;;){let r=(await Ye("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(m(` Pick a number 1–${t.length}, the circuit name, or "skip".
|
|
1029
|
-
`))}}async function
|
|
1029
|
+
`))}}async function ai(e){if(e.length===0)return Wy();process.stderr.write(`
|
|
1030
1030
|
`+K("Pick the screen this suite will test:")+`
|
|
1031
1031
|
`);for(let t=0;t<e.length;t++)process.stderr.write(` ${m(`${t+1}.`)} ${e[t].name} ${m(`(${e[t].relativePath})`)}
|
|
1032
1032
|
`);process.stderr.write(m(` (or type "skip" to scaffold a generic prompt.md without AI)
|
|
1033
1033
|
`));for(;;){let t=(await Ye("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(m(` Pick a number 1–${e.length}, the screen name, or "skip".
|
|
1034
|
-
`))}}async function
|
|
1034
|
+
`))}}async function Wy(){process.stderr.write(m(`
|
|
1035
1035
|
Could not auto-discover screens (no src/components, src/pages, or src/screens under the build dir).
|
|
1036
|
-
`));for(;;){let e=(await Ye('Path to a .tsx file or a UI directory (or "skip")')).trim();if(e.toLowerCase()==="skip"||e==="")return;if(!
|
|
1037
|
-
`));continue}let t;try{t=
|
|
1038
|
-
`));continue}if(t.isDirectory()){let r=
|
|
1039
|
-
`));continue}return
|
|
1040
|
-
`));continue}return
|
|
1041
|
-
`))}}function
|
|
1036
|
+
`));for(;;){let e=(await Ye('Path to a .tsx file or a UI directory (or "skip")')).trim();if(e.toLowerCase()==="skip"||e==="")return;if(!Fy(e)){process.stderr.write(m(` No such path: ${e}
|
|
1037
|
+
`));continue}let t;try{t=Ly(e)}catch{process.stderr.write(m(` Cannot stat: ${e}
|
|
1038
|
+
`));continue}if(t.isDirectory()){let r=Au(e);if(r.length===0){process.stderr.write(m(` No PascalCase .tsx components in ${e}
|
|
1039
|
+
`));continue}return ai(r)}if(!e.endsWith(".tsx")){process.stderr.write(m(` Not a .tsx file: ${e}
|
|
1040
|
+
`));continue}return jy(e)}}async function $u(){let e=(await Ye("What does success look like? (one line, optional)")).trim();return e===""?void 0:e}async function ci(e){for(;;){let t=(await Ye("Suite name",e)).trim();if(By(t))return t;process.stderr.write(Q(` Suite names must be kebab-case (a–z, 0–9, dashes, underscores). Try again.
|
|
1041
|
+
`))}}function By(e){return/^[a-z0-9][a-z0-9_-]{0,63}$/.test(e)}function jy(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 Pu=A(()=>{ii()});function Mu(e){let{contractName:t,contractSummary:r,contractSource:n,targetCircuit:s,goal:o,witnessDependentCircuits:i}=e,a=i&&i.size>0?`
|
|
1042
1042
|
## Circuits NOT testable from a CLI suite
|
|
1043
1043
|
|
|
1044
1044
|
These circuits call witnesses that read from private state. In a
|
|
@@ -1143,9 +1143,9 @@ Args coercion the runner applies (so JSON arg values can be):
|
|
|
1143
1143
|
- [0..255] int array → Uint8Array for Bytes<N>
|
|
1144
1144
|
- object → recurses into Struct fields
|
|
1145
1145
|
|
|
1146
|
-
${
|
|
1146
|
+
${Ou}
|
|
1147
1147
|
|
|
1148
|
-
Now produce the JSON.`}function
|
|
1148
|
+
Now produce the JSON.`}function Fu(e){let{contractName:t,contractSummary:r,screenComponent:n,screenSource:s,relatedSources:o,url:i,goal:a}=e,c=(o??[]).map((l)=>`
|
|
1149
1149
|
--- ${l.path} ---
|
|
1150
1150
|
${l.source}
|
|
1151
1151
|
--- end ${l.path} ---`).join(`
|
|
@@ -1222,25 +1222,25 @@ A JSON object with three keys:
|
|
|
1222
1222
|
chain (e.g. ledger-field on a contract-state read).
|
|
1223
1223
|
- description: one short sentence summarising what this suite verifies.
|
|
1224
1224
|
|
|
1225
|
-
${
|
|
1225
|
+
${Ou}
|
|
1226
1226
|
|
|
1227
|
-
Now produce the JSON.`}function
|
|
1228
|
-
`)}var
|
|
1227
|
+
Now produce the JSON.`}function di(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(`
|
|
1228
|
+
`)}var _u="```json",Ou;var Lu=A(()=>{Ou=`Output rules:
|
|
1229
1229
|
- Reply with EXACTLY one ${"```json"} ... \`\`\` fenced code block.
|
|
1230
1230
|
- Inside the fence: valid JSON, nothing else (no comments, no trailing text).
|
|
1231
1231
|
- Fields you don't know about: omit them. Don't invent fields.
|
|
1232
1232
|
- Use only the circuit / ledger field names that appear in the inputs below.
|
|
1233
|
-
- Be concise — fewer, well-named actions beat many vague ones.`});function yr(e,t){if(t.length===0)return{byCircuit:new Map};let r=Ay(e),n=Ty(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 Ry(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 Ay(e){return e.replace(Ey,"").replace(xy,"")}function Ty(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=Ny(i);t.set(o,{body:l,argNames:f,isCircuit:s==="circuit"})}return t}function Ny(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 Ry(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(Iy.has(o)||t.has(o))continue;r.add(o)}return r}var xy,Ey,Iy;var ws=A(()=>{xy=/\/\/[^\n]*/g,Ey=/\/\*[\s\S]*?\*\//g;Iy=new Set(["if","for","while","switch","return","new","assert","disclose","transientHash","persistentHash","ownPublicKey","publicKey","Map","Set","Vector","Tuple","Option","Bytes","Field","Uint","Boolean"])});var Uu={};be(Uu,{claudeSubprocessRunner:()=>ci,findContractSourcePath:()=>di,generateCliScaffoldWithAI:()=>jy,generateUiScaffoldWithAI:()=>Hy,isClaudeAvailable:()=>Fy});import{execFileSync as Dy,spawn as $y}from"node:child_process";import{existsSync as ai,readdirSync as Py,readFileSync as $u}from"node:fs";import{dirname as Sr,join as ys}from"node:path";function Fy(){try{return Dy("claude",["--version"],{stdio:"ignore",timeout:5000}),!0}catch{return!1}}function Mu(e){let r=new RegExp("```json\\s*\\n([\\s\\S]*?)\\n```").exec(e);if(!r)throw Error(`Claude response did not contain a ${Eu} ... \`\`\` 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 Ly(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=Wy(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)"}`);Uy(s,o)}return{actions:r}}function Uy(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 Wy(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 jy(e,t=ci){let r=e.contractSourcePath&&ai(e.contractSourcePath)?$u(e.contractSourcePath,"utf-8"):void 0,n=e.contract.witnesses.map((y)=>y.name),s=r?yr(r,n).byCircuit:new Map,o=e.targetCircuit?Qo(e.targetCircuit):void 0,i=Tu({contractName:e.contract.name,contractSummary:ii({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=Mu(a),d=Ly(c,e.contract),u=e.suiteName??(e.targetCircuit?`cli-${e.targetCircuit.name.toLowerCase().replace(/_/g,"-")}`:`cli-${Lu(e.goal)??"ai"}`),l=e.network??Pu,f=e.servePort??_u,p={name:e.contract.name,network:l,prep:Ou},h={name:u,description:c.description,strategy:"cli",timeout:_y},g=Gy(c.assertions,f),b=[...s.entries()].filter(([y])=>y!==e.targetCircuit?.name).map(([y,w])=>({name:y,reason:`uses witness ${w.join(", ")} (private state — UI-only)`}));return{dappConfig:p,suite:h,actions:d,assertions:g,prompt:null,suiteName:u,excludedCircuits:b.length>0?b:void 0}}async function Hy(e,t=ci){let r=e.screen?$u(e.screen.path,"utf-8"):void 0,n=Nu({contractName:e.contract.name,contractSummary:ii({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=Mu(s);By(o);let i=e.suiteName??(e.screen?`ui-${e.screen.name}`:`ui-${Lu(e.goal)??"ai"}`),a=e.network??Pu,c=e.servePort??_u,d=e.url,u={name:e.contract.name,network:a,port:e.port,buildCmd:e.buildCmd,url:d,prep:My};if(e.buildDir)u.buildDir=e.buildDir;let l={name:i,description:o.description,strategy:"browser",timeout:Oy,...e.browserMode?{browserMode:e.browserMode}:{}},f=Ky(o.assertions,c);return{dappConfig:u,suite:l,actions:null,assertions:f,prompt:o.prompt,suiteName:i}}function Fu(e){let t=e.params;return typeof t?.port==="number"?t.port:void 0}function Gy(e,t){if(e.post.some((n)=>n.type==="port-listening"&&Fu(n)===t))return e;return{...e,post:[...e.post,{id:"serve-port-listening",type:"port-listening",params:{port:t},expect:"pass"}]}}function Ky(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"&&Fu(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 Lu(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 di(e){let t=e.split("/").pop(),r=[Sr(e),ys(Sr(e),"src"),Sr(Sr(e)),ys(Sr(Sr(e)),"src")];for(let n of r){if(!ai(n))continue;if(t){let i=ys(n,`${t}.compact`);if(ai(i))return i}let s;try{s=Py(n)}catch{continue}let o=s.find((i)=>i.endsWith(".compact"));if(o)return ys(n,o)}return}var Pu="undeployed",_u=9932,_y=300,Oy=600,Ou,My,Iu=300000,Du=4194304,ci=(e)=>new Promise((t,r)=>{let n=$y("claude",["--print"],{stdio:["pipe","pipe","pipe"]}),s="",o="",i=0,a=!1,c=setTimeout(()=>{n.kill("SIGTERM"),r(Error(`claude --print timed out after ${Iu/1000}s`))},Iu);n.stdout?.on("data",(d)=>{if(i+=d.length,i>Du){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 ${Du/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 li=A(()=>{Ru();ti();ws();Ou=["cache-clear","localnet-up","balance:1000","dust","mn-serve"],My=[...Ou,"build-and-serve"]});import{existsSync as Wu,readFileSync as Bu,writeFileSync as Vy,mkdirSync as Jy}from"node:fs";import{join as ju}from"node:path";async function Hu(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=eS(n,s,f);let{info:h}=nt(n),g=Qy(h),b;for(let y of t){c?.(y);let w=Date.now();if(b&&(y.type==="contract-call"||y.type==="contract-state")){let k={id:y.id,type:y.type,status:"skip",duration:0,message:`cascaded skip — depends on ${b}`};l.push(k),d?.(y,k);continue}try{let k=await qy(y,{dappDir:n,networkConfig:o,managedDir:h.managedDir,contractName:h.name,servePort:i,contractAddress:p,witnessDeps:g,onMessage:u});if(k.contractAddress){if(p=k.contractAddress,tS(n,s,f,p),y.type==="contract-deploy")b=void 0}let T=Date.now()-w,R={...k,duration:T};if(l.push(R),d?.(y,R),k.status==="skip"&&y.type==="contract-call")b=`skipped action "${y.id}"`}catch(k){let T=Date.now()-w,R={id:y.id,type:y.type,status:"fail",duration:T,message:k.message};l.push(R),d?.(y,R);break}}return l}async function qy(e,t){switch(e.type){case"contract-deploy":return zy(e,t);case"contract-call":return Yy(e,t);case"contract-state":return Xy(e,t);case"wallet-cmd":return Zy(e,t);default:throw Error(`Unknown action type: ${e.type}`)}}async function zy(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 fs({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 Yy(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 gr({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 ms({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 gr({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 Xy(e,t){if(!t.contractAddress)throw Error(`Action "${e.id}": no contract address. Add a contract-deploy action first.`);let r=await gr({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)ui(s,BigInt(a.size),o,n);else n.push(`Field "${s}" not found in ledger state`);continue}try{let a=BigInt(i);ui(s,a,o,n)}catch{ui(s,i,o,n)}}if(n.length>0)throw Error(`State assertion failed:
|
|
1233
|
+
- Be concise — fewer, well-named actions beat many vague ones.`});function yr(e,t){if(t.length===0)return{byCircuit:new Map};let r=Ky(e),n=Vy(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 qy(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 Ky(e){return e.replace(Gy,"").replace(Hy,"")}function Vy(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=Jy(i);t.set(o,{body:l,argNames:f,isCircuit:s==="circuit"})}return t}function Jy(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 qy(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(zy.has(o)||t.has(o))continue;r.add(o)}return r}var Hy,Gy,zy;var ws=A(()=>{Hy=/\/\/[^\n]*/g,Gy=/\/\*[\s\S]*?\*\//g;zy=new Set(["if","for","while","switch","return","new","assert","disclose","transientHash","persistentHash","ownPublicKey","publicKey","Map","Set","Vector","Tuple","Option","Bytes","Field","Uint","Boolean"])});var qu={};be(qu,{claudeSubprocessRunner:()=>ui,findContractSourcePath:()=>pi,generateCliScaffoldWithAI:()=>aS,generateUiScaffoldWithAI:()=>cS,isClaudeAvailable:()=>rS});import{execFileSync as Yy,spawn as Xy}from"node:child_process";import{existsSync as li,readdirSync as Zy,readFileSync as Bu}from"node:fs";import{dirname as Sr,join as ys}from"node:path";function rS(){try{return Yy("claude",["--version"],{stdio:"ignore",timeout:5000}),!0}catch{return!1}}function Ku(e){let r=new RegExp("```json\\s*\\n([\\s\\S]*?)\\n```").exec(e);if(!r)throw Error(`Claude response did not contain a ${_u} ... \`\`\` 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 nS(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=oS(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)"}`);sS(s,o)}return{actions:r}}function sS(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 oS(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 iS(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 aS(e,t=ui){let r=e.contractSourcePath&&li(e.contractSourcePath)?Bu(e.contractSourcePath,"utf-8"):void 0,n=e.contract.witnesses.map((y)=>y.name),s=r?yr(r,n).byCircuit:new Map,o=e.targetCircuit?ri(e.targetCircuit):void 0,i=Mu({contractName:e.contract.name,contractSummary:di({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=Ku(a),d=nS(c,e.contract),u=e.suiteName??(e.targetCircuit?`cli-${e.targetCircuit.name.toLowerCase().replace(/_/g,"-")}`:`cli-${Ju(e.goal)??"ai"}`),l=e.network??ju,f=e.servePort??Hu,p={name:e.contract.name,network:l,prep:Gu},h={name:u,description:c.description,strategy:"cli",timeout:Qy},g=dS(c.assertions,f),S=[...s.entries()].filter(([y])=>y!==e.targetCircuit?.name).map(([y,w])=>({name:y,reason:`uses witness ${w.join(", ")} (private state — UI-only)`}));return{dappConfig:p,suite:h,actions:d,assertions:g,prompt:null,suiteName:u,excludedCircuits:S.length>0?S:void 0}}async function cS(e,t=ui){let r=e.screen?Bu(e.screen.path,"utf-8"):void 0,n=Fu({contractName:e.contract.name,contractSummary:di({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=Ku(s);iS(o);let i=e.suiteName??(e.screen?`ui-${e.screen.name}`:`ui-${Ju(e.goal)??"ai"}`),a=e.network??ju,c=e.servePort??Hu,d=e.url,u={name:e.contract.name,network:a,port:e.port,buildCmd:e.buildCmd,url:d,prep:tS};if(e.buildDir)u.buildDir=e.buildDir;let l={name:i,description:o.description,strategy:"browser",timeout:eS,...e.browserMode?{browserMode:e.browserMode}:{}},f=lS(o.assertions,c);return{dappConfig:u,suite:l,actions:null,assertions:f,prompt:o.prompt,suiteName:i}}function Vu(e){let t=e.params;return typeof t?.port==="number"?t.port:void 0}function dS(e,t){if(e.post.some((n)=>n.type==="port-listening"&&Vu(n)===t))return e;return{...e,post:[...e.post,{id:"serve-port-listening",type:"port-listening",params:{port:t},expect:"pass"}]}}function lS(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"&&Vu(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 Ju(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 pi(e){let t=e.split("/").pop(),r=[Sr(e),ys(Sr(e),"src"),Sr(Sr(e)),ys(Sr(Sr(e)),"src")];for(let n of r){if(!li(n))continue;if(t){let i=ys(n,`${t}.compact`);if(li(i))return i}let s;try{s=Zy(n)}catch{continue}let o=s.find((i)=>i.endsWith(".compact"));if(o)return ys(n,o)}return}var ju="undeployed",Hu=9932,Qy=300,eS=600,Gu,tS,Uu=300000,Wu=4194304,ui=(e)=>new Promise((t,r)=>{let n=Xy("claude",["--print"],{stdio:["pipe","pipe","pipe"]}),s="",o="",i=0,a=!1,c=setTimeout(()=>{n.kill("SIGTERM"),r(Error(`claude --print timed out after ${Uu/1000}s`))},Uu);n.stdout?.on("data",(d)=>{if(i+=d.length,i>Wu){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 ${Wu/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 fi=A(()=>{Lu();si();ws();Gu=["cache-clear","localnet-up","balance:1000","dust","mn-serve"],tS=[...Gu,"build-and-serve"]});import{existsSync as zu,readFileSync as Yu,writeFileSync as uS,mkdirSync as pS}from"node:fs";import{join as Xu}from"node:path";async function Zu(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=SS(n,s,f);let{info:h}=nt(n),g=yS(h),S;for(let y of t){c?.(y);let w=Date.now();if(S&&(y.type==="contract-call"||y.type==="contract-state")){let k={id:y.id,type:y.type,status:"skip",duration:0,message:`cascaded skip — depends on ${S}`};l.push(k),d?.(y,k);continue}try{let k=await fS(y,{dappDir:n,networkConfig:o,managedDir:h.managedDir,contractName:h.name,servePort:i,contractAddress:p,witnessDeps:g,onMessage:u});if(k.contractAddress){if(p=k.contractAddress,bS(n,s,f,p),y.type==="contract-deploy")S=void 0}let T=Date.now()-w,R={...k,duration:T};if(l.push(R),d?.(y,R),k.status==="skip"&&y.type==="contract-call")S=`skipped action "${y.id}"`}catch(k){let T=Date.now()-w,R={id:y.id,type:y.type,status:"fail",duration:T,message:k.message};l.push(R),d?.(y,R);break}}return l}async function fS(e,t){switch(e.type){case"contract-deploy":return mS(e,t);case"contract-call":return gS(e,t);case"contract-state":return hS(e,t);case"wallet-cmd":return wS(e,t);default:throw Error(`Unknown action type: ${e.type}`)}}async function mS(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 fs({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 gS(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 gr({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 ms({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 gr({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 hS(e,t){if(!t.contractAddress)throw Error(`Action "${e.id}": no contract address. Add a contract-deploy action first.`);let r=await gr({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)mi(s,BigInt(a.size),o,n);else n.push(`Field "${s}" not found in ledger state`);continue}try{let a=BigInt(i);mi(s,a,o,n)}catch{mi(s,i,o,n)}}if(n.length>0)throw Error(`State assertion failed:
|
|
1234
1234
|
${n.join(`
|
|
1235
|
-
`)}`)}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
|
|
1236
|
-
`)}var
|
|
1235
|
+
`)}`)}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 mi(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 wS(e,t){return{id:e.id,type:e.type,status:"pass",duration:0,message:`wallet-cmd: ${e.cmd??"no command"} (not yet implemented)`}}function yS(e){if(e.witnesses.length===0)return new Map;let t=pi(e.managedDir);if(!t||!zu(t))return new Map;let r=Yu(t,"utf-8"),n=e.witnesses.map((s)=>s.name);return yr(r,n).byCircuit}function Qu(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 ep(e,t){return Xu(e,"tests","results",`.contract-cache-${t}.json`)}function SS(e,t,r){let n=ep(e,t);if(!zu(n))return;try{let s=JSON.parse(Yu(n,"utf-8"));if(s.network!==r)return;return s.address}catch{return}}function bS(e,t,r,n){let s=ep(e,t);pS(Xu(e,"tests","results"),{recursive:!0});let o={address:n,network:r,timestamp:new Date().toISOString()};uS(s,JSON.stringify(o,null,2)+`
|
|
1236
|
+
`)}var tp=A(()=>{on();en();ws();fi()});var ip={};be(ip,{default:()=>sp});import{join as rp}from"node:path";import{mkdirSync as vS}from"node:fs";function kS(e){return np.includes(e)}async function sp(e,t){let r=e.subcommand;if(!r||!kS(r))throw new _(`Usage: midnight test <${np.join("|")}>
|
|
1237
1237
|
|
|
1238
1238
|
create Generate dapp.test.json + a CLI test suite from the contract
|
|
1239
1239
|
run Run test suites for the current dApp
|
|
1240
1240
|
list List available test suites
|
|
1241
1241
|
results Show latest test results
|
|
1242
1242
|
|
|
1243
|
-
Run from the root of a dApp project containing dapp.test.json.`);let n=N(e,"json");switch(r){case"create":return
|
|
1243
|
+
Run from the root of a dApp project containing dapp.test.json.`);let n=N(e,"json");switch(r){case"create":return TS(e,n);case"run":return DS(e,n,t);case"list":return $S(n);case"results":return PS(e,n)}}function CS(e){let t=(e??"").toLowerCase();if(t==="")return;if(t==="cli"||t==="browser")return t;if(t==="ui")return"browser";throw new _(`Unknown strategy "${e}". Use "cli" or "ui".`)}function xS(e){return e==="preprod"||e==="preview"||e==="undeployed"?e:void 0}function ES(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 _(`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 _(`Invalid --browser-mode "${i}" — must be dom, vision, or script.`);t.browserMode=i}return t}function AS(e){if(e.port===void 0||e.buildCmd===void 0)throw new _("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 TS(e,t){let{resolve:r}=await import("node:path");await Promise.resolve().then(() => en());await Promise.resolve().then(() => si());await Promise.resolve().then(() => vu());let i=await Promise.resolve().then(() => (Pu(),{}));await Promise.resolve();let g=await Promise.resolve().then(() => (fi(),qu));await Promise.resolve().then(() => ii());let y=r(x(e,"path")??process.cwd()),w=x(e,"name"),k=x(e,"suite"),T=xS(x(e,"network")),R=N(e,"force"),U=!t&&Nu(),X=x(e,"goal"),q=x(e,"screen"),H=N(e,"no-ai"),O=CS(x(e,"strategy"))??(U?await Ru():"cli"),se;if(O==="browser"){let Ne=ES(e);se=U?await Iu(Ne):AS(Ne)}let{info:me}=nt(y,w),ln=!H&&g.isClaudeAvailable(),mt=!H&&(X!==void 0||q!==void 0||U&&ln),ge=mt?await NS({strategy:O,info:me,dappDir:y,browser:se,network:T,suiteName:k,goalFlag:X,screenFlag:q,interactive:U,jsonMode:t,ai:g,promptCircuit:Du,promptScreen:ai,promptGoal:$u,promptSuiteName:ci,discoverScreens:Eu})??ni(me.circuits,{contractName:me.name,suiteName:k,strategy:O,browser:se,network:T}):ni(me.circuits,{contractName:me.name,suiteName:k,strategy:O,browser:se,network:T});if(U&&!k){let Ne=await ci(ge.suiteName);if(Ne!==ge.suiteName)ge.suiteName=Ne,ge.suite.name=Ne}let br=bu(ge,{dappDir:y,force:R});if(t){I({subcommand:"create",contractName:me.name,suiteName:ge.suiteName,strategy:O,aiAssisted:mt&&ge.suiteName!=="cli-default"&&ge.suiteName!=="ui-default",written:br.written,excludedCircuits:ge.excludedCircuits});return}process.stderr.write(`
|
|
1244
1244
|
`+B(`Test scaffold: ${me.name}`)+`
|
|
1245
1245
|
|
|
1246
1246
|
`);for(let Ne of br.written)process.stderr.write(` ${W("✓")} ${Ne}
|
|
@@ -1256,47 +1256,47 @@ Run from the root of a dApp project containing dapp.test.json.`);let n=N(e,"json
|
|
|
1256
1256
|
`),process.stderr.write(m(" Run ")+K(`mn test run --suite ${ge.suiteName}`)+`
|
|
1257
1257
|
`),process.stderr.write(m(" List ")+K("mn test list")+m(" (see every suite in this project)")+`
|
|
1258
1258
|
|
|
1259
|
-
`)}async function
|
|
1259
|
+
`)}async function NS(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 RS(e,t);return await IS(e,t)}catch(t){return process.stderr.write(`
|
|
1260
1260
|
${m("AI scaffold failed, falling back to deterministic:")} ${t.message}
|
|
1261
|
-
`),null}}async function
|
|
1261
|
+
`),null}}async function op(e,t,r){if(!r)return t();let n=V(e);try{let s=await t();return n.stop(),s}catch(s){throw n.fail("AI scaffold failed"),s}}async function RS(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(() => ws());let i=s(n,"utf-8"),a=e.info.witnesses.map((u)=>u.name),d=yr(i,a).byCircuit.get(r.name);if(d&&d.length>0)process.stderr.write(`
|
|
1262
1262
|
`+Q("!")+` ${r.name} calls ${d.join(", ")} — a witness that reads private state.
|
|
1263
1263
|
`),process.stderr.write(m(` The CLI suite will deploy + run, but expect a "Cannot read properties of undefined" failure
|
|
1264
1264
|
`)+m(` unless the dApp UI populates that state first. Consider --strategy ui instead.
|
|
1265
|
-
`))}return
|
|
1265
|
+
`))}return op("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 IS(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 op("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 DS(e,t,r){let{config:n,dappDir:s}=gs(),o=Zo(s),i=x(e,"suite"),a;if(i){if(a=o.find((p)=>p.suite.name===i),!a){let p=o.map((h)=>h.suite.name).join(", ")||"none found";throw new _(`Suite "${i}" not found. Available: ${p}`)}}else if(o.length>0)a=o[0];vS(rp(s,"tests","results"),{recursive:!0});let c=Date.now(),d=new Date().toISOString();if(!t){if(process.stderr.write(`
|
|
1266
1266
|
`+B(`E2E Test: ${n.name}`)+`
|
|
1267
1267
|
|
|
1268
1268
|
`),process.stderr.write(E("Network",n.network??"undeployed")+`
|
|
1269
1269
|
`),n.port)process.stderr.write(E("Port",String(n.port))+`
|
|
1270
1270
|
`);if(a){if(process.stderr.write(E("Suite",a.suite.name)+`
|
|
1271
1271
|
`),process.stderr.write(E("Strategy",a.suite.strategy)+`
|
|
1272
|
-
`),a.suite.strategy==="browser"){let p=
|
|
1272
|
+
`),a.suite.strategy==="browser"){let p=Qo(a.suite);process.stderr.write(E("Browser Mode",p)+`
|
|
1273
1273
|
`)}}process.stderr.write(`
|
|
1274
|
-
`)}let u=
|
|
1275
|
-
`)};r?.addEventListener("abort",()=>
|
|
1276
|
-
`));let p=V("Starting prep..."),h=await
|
|
1277
|
-
`);let g=0,
|
|
1274
|
+
`)}let u=zl(),l=[],f=(p)=>{if(!t)process.stderr.write(m(` [teardown] ${p}`)+`
|
|
1275
|
+
`)};r?.addEventListener("abort",()=>ti(u,f),{once:!0});try{if(!t)process.stderr.write(P(` Prep
|
|
1276
|
+
`));let p=V("Starting prep..."),h=await tu(n,s,u,{onStepStart(M){p.update(`[prep] ${M}...`)},onStepComplete(M,O,se,me){if(O==="pass")p.stop(`${W("✓")} ${M} (${_S(se)})`);else p.stop(`${de("✗")} ${M}: ${me??"failed"}`);p=V("")},onMessage(M){p.update(M)}});if(p.stop(""),l.push(...h),!t)process.stderr.write(`
|
|
1277
|
+
`);let g=0,S="";if(a){let M=a.suite;if(M.strategy==="browser"){let O=Jl(a.suiteDir);if(!O)throw Error(`No prompt.md found in ${a.suiteDir} — required for browser strategy`);if(S=rp(s,"tests","results",`${M.name}_${d.replace(/[:.]/g,"-")}_claude.log`),!t)process.stderr.write(P(` Browser Test
|
|
1278
1278
|
`)),process.stderr.write(m(` Claude will take over the terminal. Output is also logged.
|
|
1279
1279
|
|
|
1280
|
-
`));let se=await
|
|
1280
|
+
`));let se=await su({suite:M,prompt:O,dappDir:s,logFile:S,onMessage:(me)=>{if(!t)process.stderr.write(m(` ${me}`)+`
|
|
1281
1281
|
`)}});if(g=se.exitCode,!t)if(process.stderr.write(`
|
|
1282
|
-
`),se.timedOut)process.stderr.write(` ${
|
|
1283
|
-
`);else process.stderr.write(` ${g===0?W("✓"):
|
|
1284
|
-
`)}else if(M.strategy==="cli"){let O=
|
|
1282
|
+
`),se.timedOut)process.stderr.write(` ${de("✗")} Browser test timed out
|
|
1283
|
+
`);else process.stderr.write(` ${g===0?W("✓"):de("✗")} Claude exited with code ${g}
|
|
1284
|
+
`)}else if(M.strategy==="cli"){let O=Vl(a.suiteDir);if(!O)throw Error(`No actions.json found in ${a.suiteDir} — required for CLI strategy`);if(!t)process.stderr.write(P(` CLI Test
|
|
1285
1285
|
`)),process.stderr.write(m(` Executing ${O.actions.length} action(s)
|
|
1286
1286
|
|
|
1287
|
-
`));await Promise.resolve().then(() =>
|
|
1287
|
+
`));await Promise.resolve().then(() => tp());await Promise.resolve().then(() => ke());let mt=n.network??"undeployed",{config:ge}=pe({args:{command:"test",subcommand:"run",positionals:[],flags:{network:mt}}});await Promise.resolve();let At=u.serveHandle?.port??Tr,Ne=N(e,"redeploy"),gt=await Zu({actions:O.actions,config:n,dappDir:s,suiteName:M.name,networkConfig:ge,servePort:At,redeploy:Ne,onActionStart:(we)=>{if(!t){let Ce=V(`[${we.id}] ${we.type}${we.circuit?` ${we.circuit}`:""}...`);we._spinner=Ce}},onActionComplete:(we,Ce)=>{if(!t){let st=we._spinner;if(st)if(Ce.status==="pass")st.stop(`${W("✓")} ${we.id}: ${Ce.message??"pass"}`);else if(Ce.status==="skip")st.stop(`${Q("⊘")} ${we.id}: ${Ce.message??"skipped"}`);else st.stop(`${de("✗")} ${we.id}: ${Ce.message??"fail"}`);if(Ce.stateBefore&&Ce.stateAfter){let je=Qu(Ce.stateBefore,Ce.stateAfter);if(je.length>0)for(let Ge of je)process.stderr.write(m(` ${Ge.field}: ${Ge.before} → `)+K(Ge.after)+`
|
|
1288
1288
|
`)}}},onMessage:(we)=>{}});if(g=gt.some((we)=>we.status==="fail")?1:0,!t){process.stderr.write(`
|
|
1289
|
-
`);let we=gt.filter((Ge)=>Ge.status==="pass").length,Ce=gt.filter((Ge)=>Ge.status==="skip").length,st=gt.filter((Ge)=>Ge.status==="fail").length,je=W(String(we)+" passed");if(Ce>0)je+=`, ${Q(String(Ce)+" skipped")}`;if(st>0)je+=`, ${
|
|
1289
|
+
`);let we=gt.filter((Ge)=>Ge.status==="pass").length,Ce=gt.filter((Ge)=>Ge.status==="skip").length,st=gt.filter((Ge)=>Ge.status==="fail").length,je=W(String(we)+" passed");if(Ce>0)je+=`, ${Q(String(Ce)+" skipped")}`;if(st>0)je+=`, ${de(String(st)+" failed")}`;process.stderr.write(` Actions: ${je}
|
|
1290
1290
|
`)}u._actionResults=gt}}else if(!t)process.stderr.write(m(` No test suites found — only prep was run
|
|
1291
|
-
`));let y={processExitCode:g,agentLogPath:
|
|
1291
|
+
`));let y={processExitCode:g,agentLogPath:S},w=[];if(a){let M=Kl(a.suiteDir);if(M&&M.post.length>0){if(!t)process.stderr.write(`
|
|
1292
1292
|
`+P(` Assertions
|
|
1293
|
-
`));if(w=await
|
|
1294
|
-
`)}}}let k=Math.round((Date.now()-c)/1000),T=l.every((M)=>M.status==="pass"),R=w.every((M)=>M.status==="pass"),U=T&&R&&g===0?"pass":"fail",
|
|
1293
|
+
`));if(w=await iu(M.post,y),!t)for(let O of w){let se=O.status==="pass"?W("✓"):de("✗"),me=O.message?m(` — ${O.message}`):"";process.stderr.write(` ${se} ${O.id}${me}
|
|
1294
|
+
`)}}}let k=Math.round((Date.now()-c)/1000),T=l.every((M)=>M.status==="pass"),R=w.every((M)=>M.status==="pass"),U=T&&R&&g===0?"pass":"fail",X=u._actionResults,q={id:`${n.name}_${d}`,dapp:n.name,suite:a?.suite.name??"prep-only",timestamp:d,duration:k,network:n.network??"undeployed",strategy:a?.suite.strategy??"none",model:a?.suite.model,status:U,prep:l,actions:X?.map((M)=>({id:M.id,type:M.type,status:M.status,duration:M.duration,message:M.message,contractAddress:M.contractAddress})),assertions:w,testOutput:S?{exitCode:g,logFile:S}:void 0},H=du(q,s);if(t)I(q);else process.stderr.write(`
|
|
1295
1295
|
`+J()+`
|
|
1296
|
-
`),process.stderr.write(` ${U==="pass"?W(P("PASS")):
|
|
1296
|
+
`),process.stderr.write(` ${U==="pass"?W(P("PASS")):de(P("FAIL"))} — ${n.name} (${k}s)
|
|
1297
1297
|
`),process.stderr.write(m(` Results: ${H}`)+`
|
|
1298
1298
|
|
|
1299
|
-
`);if(U==="fail")process.exitCode=1}finally{await
|
|
1299
|
+
`);if(U==="fail")process.exitCode=1}finally{await ti(u,f)}}function $S(e){let{config:t,dappDir:r}=gs(),n=Zo(r);if(e){I({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(`
|
|
1300
1300
|
`+B(`Tests: ${t.name}`)+`
|
|
1301
1301
|
|
|
1302
1302
|
`),n.length===0)process.stderr.write(m(` No test suites found.
|
|
@@ -1306,20 +1306,20 @@ Run from the root of a dApp project containing dapp.test.json.`);let n=N(e,"json
|
|
|
1306
1306
|
`),process.stderr.write(m(` strategy: ${s.strategy}`)+(s.timeout?m(`, timeout: ${s.timeout}s`):"")+`
|
|
1307
1307
|
|
|
1308
1308
|
`);process.stderr.write(`
|
|
1309
|
-
`)}function
|
|
1309
|
+
`)}function PS(e,t){let{config:r,dappDir:n}=gs(),s=N(e,"all"),o=x(e,"suite"),i=s?ei(n,o):(()=>{let a=lu(n,o);return a?[a]:[]})();if(t){I(s?{dapp:r.name,results:i}:i[0]??{});return}if(process.stderr.write(`
|
|
1310
1310
|
`+B(`Results: ${r.name}`)+`
|
|
1311
1311
|
|
|
1312
1312
|
`),i.length===0)process.stderr.write(m(` No test results found.
|
|
1313
1313
|
`)),process.stderr.write(m(` Run "midnight test run" to generate results.
|
|
1314
|
-
`));else for(let a of i){let c=a.status==="pass"?W("✓"):
|
|
1314
|
+
`));else for(let a of i){let c=a.status==="pass"?W("✓"):de("✗"),d=a.status==="pass"?W(P("PASS")):de(P("FAIL"));process.stderr.write(` ${c} ${P(a.suite)} — ${d} (${a.duration}s)
|
|
1315
1315
|
`),process.stderr.write(m(` ${a.timestamp} | ${a.network} | ${a.strategy}`)+`
|
|
1316
|
-
`);let u=a.prep.filter((f)=>f.status==="fail");if(u.length>0)process.stderr.write(
|
|
1317
|
-
`);let l=a.assertions.filter((f)=>f.status==="fail");if(l.length>0)process.stderr.write(
|
|
1316
|
+
`);let u=a.prep.filter((f)=>f.status==="fail");if(u.length>0)process.stderr.write(de(` prep: ${u.length} failed`)+`
|
|
1317
|
+
`);let l=a.assertions.filter((f)=>f.status==="fail");if(l.length>0)process.stderr.write(de(` assertions: ${l.length} failed`)+`
|
|
1318
1318
|
`);process.stderr.write(`
|
|
1319
1319
|
`)}process.stderr.write(`
|
|
1320
|
-
`)}function
|
|
1320
|
+
`)}function _S(e){if(e<1000)return`${e}ms`;return`${(e/1000).toFixed(1)}s`}var np;var ap=A(()=>{oe();ve();fe();ft();ql();ru();ou();au();uu();pu();np=["run","list","results","create"]});import{readFileSync as cp}from"node:fs";import{fileURLToPath as fp}from"node:url";import{Server as OS}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as MS}from"@modelcontextprotocol/sdk/server/stdio.js";import{ListToolsRequestSchema as FS,CallToolRequestSchema as LS,ListResourcesRequestSchema as US,ReadResourceRequestSchema as WS}from"@modelcontextprotocol/sdk/types.js";oe();async function z(e,t,r){let n=[];Cs((s)=>n.push(s));try{if(t.flags.json=!0,!(un in t.flags))t.flags[un]=!0;await e(t,r);let s=n.join("").trim();if(!s)return{};return JSON.parse(s)}finally{Cs(null)}}ve();var Cp=1,vi=2,xp=3,pn=4,xs=5,Gt=6,Ep=7,ae={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"},Ap=new Set([ae.UNSUPPORTED_LEDGER,ae.LOCALNET_UNAVAILABLE,ae.LOCAL_STACK_UNREACHABLE,ae.AMBIGUOUS_LOCAL_STACKS]);function ki(e){if(bi(e))return{exitCode:vi,errorCode:ae.INVALID_ARGS};let t=e.code;if(typeof t==="string"&&Ap.has(t))return{exitCode:pn,errorCode:t};if(t===ae.DUST_GENERATING)return{exitCode:xs,errorCode:ae.DUST_GENERATING};if(t===ae.CHAIN_CLOCK_BEHIND)return{exitCode:pn,errorCode:ae.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:ae.CANCELLED};if(r.includes("wallet file not found")||r.includes("wallet")&&r.includes("not found"))return{exitCode:xp,errorCode:ae.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:vi,errorCode:ae.INVALID_ARGS};if(r.includes("proof")&&r.includes("timeout"))return{exitCode:Gt,errorCode:ae.PROOF_TIMEOUT};if(r.includes("stale utxo")||r.includes("error code 115")||r.includes("errorcode: 115"))return{exitCode:Gt,errorCode:ae.STALE_UTXO};if(r.includes("error 170")||r.includes("errorcode: 170")||r.includes("invaliddustspendproof"))return{exitCode:Gt,errorCode:ae.INVALID_DUST_PROOF};if(r.includes("stale cache")||r.includes("chain reset")||r.includes("chainid mismatch")||r.includes("applied > highest"))return{exitCode:Gt,errorCode:ae.STALE_CACHE};if(r.includes("failed to prove"))return{exitCode:Gt,errorCode:ae.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:pn,errorCode:ae.SYNC_TIMEOUT};if(r.includes("no dust")||r.includes("dust")&&(r.includes("required")||r.includes("available")||r.includes("insufficient")))return{exitCode:xs,errorCode:ae.DUST_REQUIRED};if(r.includes("insufficient")||r.includes("not enough"))return{exitCode:xs,errorCode:ae.INSUFFICIENT_BALANCE};if(r.includes("rejected")||r.includes("transaction failed"))return{exitCode:Gt,errorCode:ae.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:pn,errorCode:ae.NETWORK_ERROR};return{exitCode:Cp,errorCode:ae.UNKNOWN}}function Ci(e){let t=e.split(`
|
|
1321
1321
|
|
|
1322
1322
|
`)[0].trim(),r=t.split(`
|
|
1323
1323
|
`),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(`
|
|
1324
|
-
`).trim()||t}oe();var fn={name:"midnight-wallet-cli",version:"0.6.0-rc.4",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 HS=fn.name,Es=fn.version,GS=fn.description;import{randomUUID as Sp}from"node:crypto";var bp=300000;function vi(e={}){let t=e.ttlMs??bp,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=Sp(),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 vp from"node:v8";import kp from"node:os";import{spawn as Cp}from"node:child_process";var Os="MN_HEAP_BUMPED",xp="MN_MAX_OLD_SPACE_MB",Fi=1048576;function Ep(e){let t=e.desiredMb??Ri,r=e.ramFraction??Ii,n=e.minGainMb??Di;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 Li(){if(process.env[Os]){Tp();return}let e=process.env[xp],t=e!==void 0?Number(e):void 0,r=Ep({totalMb:Math.floor(kp.totalmem()/Fi),currentLimitMb:Math.floor(vp.getHeapStatistics().heap_size_limit/Fi),desiredMb:t});if(r===null)return;return new Promise((n)=>{let s=Cp(process.execPath,[`--max-old-space-size=${r}`,...process.execArgv,process.argv[1],...process.argv.slice(2)],{stdio:"inherit",env:{...process.env,[Os]:"1"}});Ap(s),s.on("error",()=>{process.env[Os]="1",n()}),s.on("exit",(o,i)=>process.exit(i?1:o??0))})}function Ap(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 Tp(){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 op="midnight-wallet://skill/core",ip="midnight-wallet://skill/full",kS="midnight-wallet://skill",CS=sp(new URL("../docs/SKILL-CORE.md",import.meta.url)),xS=sp(new URL("../docs/SKILL.md",import.meta.url));function he(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"?kr:o;if(typeof i==="boolean"){if(i)n[a]=!0}else n[a]=String(i)}return{command:e,subcommand:r,positionals:s,flags:n}}function ep(e){let t=he("transfer",e,e.to);return t.positionals=e.amount===void 0?[]:[String(e.amount)],delete t.flags.to,delete t.flags.amount,t}async function tp(e){await Promise.resolve().then(() => De());ne(re(e.wallet))}var ES={generate:()=>Promise.resolve().then(() => (ca(),aa)),info:()=>Promise.resolve().then(() => (ua(),la)),balance:()=>Promise.resolve().then(() => (mc(),fc)),address:()=>Promise.resolve().then(() => (wc(),hc)),"genesis-address":()=>Promise.resolve().then(() => (bc(),Sc)),"inspect-cost":()=>Promise.resolve().then(() => (Ac(),Ec)),airdrop:()=>Promise.resolve().then(() => (Dc(),Ic)),transfer:()=>Promise.resolve().then(() => (Mc(),Oc)),dust:()=>Promise.resolve().then(() => (Bc(),Wc)),cache:()=>Promise.resolve().then(() => (Gc(),Hc)),config:()=>Promise.resolve().then(() => (Jc(),Vc)),localnet:()=>Promise.resolve().then(() => (md(),fd)),wallet:()=>Promise.resolve().then(() => (Sd(),yd)),status:()=>Promise.resolve().then(() => (Ed(),xd)),contract:()=>Promise.resolve().then(() => (Dl(),Il)),test:()=>Promise.resolve().then(() => (Zu(),Xu))};async function X(e){let t=ES[e];if(!t)throw Error(`Unknown command handler: ${e}`);return(await t()).default}var pi=[{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=he("wallet",e,"generate");if(r.positionals=[t],delete r.flags.name,e.force==="true"||e.force===!0)r.flags.force=!0;let n=await X("wallet");return Y(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[kr]=!0;let r={command:"wallet",subcommand:"list",positionals:[],flags:t},n=await X("wallet");return Y(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 X("wallet");return Y(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[kr]=!0;let s={command:"wallet",subcommand:"info",positionals:t?[t]:[],flags:n},o=await X("wallet");return Y(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 X("wallet");return Y(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=he("info",e),r=await X("info");return Y(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=he("balance",e,t);delete r.flags.address;let n=await X("balance");return Y(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=he("address",e),r=await X("address");return Y(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=he("genesis-address",e),r=await X("genesis-address");return Y(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=he("inspect-cost",e.network?{network:e.network}:{}),r=await X("inspect-cost");return Y(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=he("airdrop",e,t);delete r.flags.amount;let n=await X("airdrop");return Y(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 t=await X("transfer");return Y(t,ep(e))},async check(e){await Promise.resolve().then(() => vo());Xn(ep(e))}},{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=he("dust",e,"register"),r=await X("dust");return Y(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=he("dust",e,"status"),r=await X("dust");return Y(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 X("config");return Y(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 X("config");return Y(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=he("cache",e,"clear"),r=await X("cache");return Y(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 X("config");return Y(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 X("localnet");return Y(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 X("localnet");return Y(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 X("localnet");return Y(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 X("localnet");return Y(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 X("localnet");return Y(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=he("contract",e,"inspect"),r=await X("contract");return Y(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=he("contract",e,"state"),r=await X("contract");return Y(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=he("contract",e,"deploy"),r=await X("contract");return Y(r,t)},async check(e){await Promise.resolve().then(() => cs());is(he("contract",e,"deploy")),await tp(e)}},{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=he("contract",e,"call"),r=await X("contract");return Y(r,t)},async check(e){await Promise.resolve().then(() => cs());as(he("contract",e,"call")),await tp(e)}},{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=he("test",e,"create"),r=await X("test");return Y(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=he("localnet",e,"logs");if(!t.flags.tail)t.flags.tail="200";let r=await X("localnet");return Y(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")}}],AS=new Set(["midnight_transfer","midnight_contract_deploy","midnight_contract_call"]),rp=vi();function TS(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 dn=new hS({name:"midnight-wallet-cli",version:Es},{capabilities:{tools:{},resources:{}}});dn.setRequestHandler(bS,async()=>({resources:[{uri:op,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:ip,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"}]}));dn.setRequestHandler(vS,async(e)=>{let t=e.params.uri;if(t===op){let r=Qu(CS,"utf-8");return{contents:[{uri:t,mimeType:"text/markdown",text:r}]}}if(t===ip||t===kS){let r=Qu(xS,"utf-8");return{contents:[{uri:t,mimeType:"text/markdown",text:r}]}}throw Error(`Unknown resource: ${t}`)});dn.setRequestHandler(yS,async()=>({tools:pi.map((e)=>({name:e.name,description:e.description,inputSchema:e.inputSchema,...e.annotations?{annotations:e.annotations}:{}}))}));dn.setRequestHandler(SS,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=rp.redeem(s);if(!o)return Ss(Error("Unknown or expired confirmation token. The first-step tool call may need to be re-issued."));return np(o.tool,o.args)}if(AS.has(t)){try{await pi.find((o)=>o.name===t)?.check?.(n)}catch(o){return Ss(o instanceof Error?o:Error(String(o)))}let s=rp.create({tool:t,args:n,description:TS(t,n)});return{content:[{type:"text",text:JSON.stringify(fi({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 np(t,n)});function fi(e){return{...e,_serverVersion:Es}}async function np(e,t){let r=pi.find((n)=>n.name===e);if(!r)return Ss(Error(`Unknown tool: ${e}`));try{let n=await r.handler(t);return{content:[{type:"text",text:JSON.stringify(fi(n),null,2)}]}}catch(n){return Ss(n instanceof Error?n:Error(String(n)))}}function Ss(e){let{errorCode:t}=Si(e);return{content:[{type:"text",text:JSON.stringify(fi({error:!0,code:t,message:bi(e.message)}))}],isError:!0}}async function NS(){await Li();let e=new wS;await dn.connect(e)}NS().catch((e)=>{process.stderr.write(`MCP server error: ${e.message}
|
|
1324
|
+
`).trim()||t}oe();var fn={name:"midnight-wallet-cli",version:"0.6.0-rc.6",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 cb=fn.name,Es=fn.version,db=fn.description;import{randomUUID as Np}from"node:crypto";var Rp=300000;function xi(e={}){let t=e.ttlMs??Rp,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 Ip from"node:v8";import Dp from"node:os";import{spawn as $p}from"node:child_process";var Ms="MN_HEAP_BUMPED",Pp="MN_MAX_OLD_SPACE_MB",Wi=1048576;function _p(e){let t=e.desiredMb??$i,r=e.ramFraction??Pi,n=e.minGainMb??_i;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 Bi(){if(process.env[Ms]){Mp();return}let e=process.env[Pp],t=e!==void 0?Number(e):void 0,r=_p({totalMb:Math.floor(Dp.totalmem()/Wi),currentLimitMb:Math.floor(Ip.getHeapStatistics().heap_size_limit/Wi),desiredMb:t});if(r===null)return;return new Promise((n)=>{let s=$p(process.execPath,[`--max-old-space-size=${r}`,...process.execArgv,process.argv[1],...process.argv.slice(2)],{stdio:"inherit",env:{...process.env,[Ms]:"1"}});Op(s),s.on("error",()=>{process.env[Ms]="1",n()}),s.on("exit",(o,i)=>process.exit(i?1:o??0))})}function Op(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 Mp(){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 mp="midnight-wallet://skill/core",gp="midnight-wallet://skill/full",BS="midnight-wallet://skill",jS=fp(new URL("../docs/SKILL-CORE.md",import.meta.url)),HS=fp(new URL("../docs/SKILL.md",import.meta.url));function he(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"?kr:o;if(typeof i==="boolean"){if(i)n[a]=!0}else n[a]=String(i)}return{command:e,subcommand:r,positionals:s,flags:n}}function dp(e){let t=he("transfer",e,e.to);return t.positionals=e.amount===void 0?[]:[String(e.amount)],delete t.flags.to,delete t.flags.amount,t}async function lp(e){await Promise.resolve().then(() => De());ne(re(e.wallet))}var GS={generate:()=>Promise.resolve().then(() => (ua(),la)),info:()=>Promise.resolve().then(() => (ma(),fa)),balance:()=>Promise.resolve().then(() => (kc(),vc)),address:()=>Promise.resolve().then(() => (Ec(),xc)),"genesis-address":()=>Promise.resolve().then(() => (Nc(),Tc)),"inspect-cost":()=>Promise.resolve().then(() => (_c(),Pc)),airdrop:()=>Promise.resolve().then(() => (Uc(),Lc)),transfer:()=>Promise.resolve().then(() => (Gc(),Hc)),dust:()=>Promise.resolve().then(() => (zc(),qc)),cache:()=>Promise.resolve().then(() => (Zc(),Xc)),config:()=>Promise.resolve().then(() => (td(),ed)),localnet:()=>Promise.resolve().then(() => (kd(),vd)),wallet:()=>Promise.resolve().then(() => (Td(),Ad)),status:()=>Promise.resolve().then(() => (Pd(),$d)),contract:()=>Promise.resolve().then(() => (Wl(),Ul)),test:()=>Promise.resolve().then(() => (ap(),ip))};async function Y(e){let t=GS[e];if(!t)throw Error(`Unknown command handler: ${e}`);return(await t()).default}var gi=[{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=he("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[kr]=!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[kr]=!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=he("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=he("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=he("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=he("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=he("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=he("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 t=await Y("transfer");return z(t,dp(e))},async check(e){await Promise.resolve().then(() => xo());Xn(dp(e))}},{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=he("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=he("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=he("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=he("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=he("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=he("contract",e,"deploy"),r=await Y("contract");return z(r,t)},async check(e){await Promise.resolve().then(() => cs());is(he("contract",e,"deploy")),await lp(e)}},{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=he("contract",e,"call"),r=await Y("contract");return z(r,t)},async check(e){await Promise.resolve().then(() => cs());as(he("contract",e,"call")),await lp(e)}},{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=he("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=he("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")}}],KS=new Set(["midnight_transfer","midnight_contract_deploy","midnight_contract_call"]),up=xi();function VS(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 dn=new OS({name:"midnight-wallet-cli",version:Es},{capabilities:{tools:{},resources:{}}});dn.setRequestHandler(US,async()=>({resources:[{uri:mp,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:gp,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"}]}));dn.setRequestHandler(WS,async(e)=>{let t=e.params.uri;if(t===mp){let r=cp(jS,"utf-8");return{contents:[{uri:t,mimeType:"text/markdown",text:r}]}}if(t===gp||t===BS){let r=cp(HS,"utf-8");return{contents:[{uri:t,mimeType:"text/markdown",text:r}]}}throw Error(`Unknown resource: ${t}`)});dn.setRequestHandler(FS,async()=>({tools:gi.map((e)=>({name:e.name,description:e.description,inputSchema:e.inputSchema,...e.annotations?{annotations:e.annotations}:{}}))}));dn.setRequestHandler(LS,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=up.redeem(s);if(!o)return Ss(Error("Unknown or expired confirmation token. The first-step tool call may need to be re-issued."));return pp(o.tool,o.args)}if(KS.has(t)){try{await gi.find((o)=>o.name===t)?.check?.(n)}catch(o){return Ss(o instanceof Error?o:Error(String(o)))}let s=up.create({tool:t,args:n,description:VS(t,n)});return{content:[{type:"text",text:JSON.stringify(hi({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 pp(t,n)});function hi(e){return{...e,_serverVersion:Es}}async function pp(e,t){let r=gi.find((n)=>n.name===e);if(!r)return Ss(Error(`Unknown tool: ${e}`));try{let n=await r.handler(t);return{content:[{type:"text",text:JSON.stringify(hi(n),null,2)}]}}catch(n){return Ss(n instanceof Error?n:Error(String(n)))}}function Ss(e){let{errorCode:t}=ki(e);return{content:[{type:"text",text:JSON.stringify(hi({error:!0,code:t,message:Ci(e.message)}))}],isError:!0}}async function JS(){await Bi();let e=new MS;await dn.connect(e)}JS().catch((e)=>{process.stderr.write(`MCP server error: ${e.message}
|
|
1325
1325
|
`),process.exit(1)});
|