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