<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Arun Nadarasa</title>
    <description>The latest articles on DEV Community by Arun Nadarasa (@socialprescribing).</description>
    <link>https://dev.to/socialprescribing</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4070239%2F0310037e-825a-4b3e-a815-4d2715fcfafd.jpg</url>
      <title>DEV Community: Arun Nadarasa</title>
      <link>https://dev.to/socialprescribing</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/socialprescribing"/>
    <language>en</language>
    <item>
      <title>Don't update Compact maps on Midnight Undeployed</title>
      <dc:creator>Arun Nadarasa</dc:creator>
      <pubDate>Mon, 17 Aug 2026 21:58:51 +0000</pubDate>
      <link>https://dev.to/socialprescribing/dont-update-compact-maps-on-midnight-undeployed-35dl</link>
      <guid>https://dev.to/socialprescribing/dont-update-compact-maps-on-midnight-undeployed-35dl</guid>
      <description>&lt;p&gt;I spent an afternoon chasing &lt;code&gt;SubmissionError&lt;/code&gt; / &lt;code&gt;FiberFailure&lt;/code&gt; wrapping:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RpcError 1010: Invalid Transaction: Custom error: 117
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and a WASM panic that looks like &lt;code&gt;feesWithMargin&lt;/code&gt; / &lt;code&gt;transaction_merge&lt;/code&gt; &lt;strong&gt;Unreachable&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The circuit compiled. The proof server was up. The genesis wallet had tDUST. The bug was in how I used Compact &lt;code&gt;Map&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This post is the lesson: &lt;strong&gt;on Midnight Local Undeployed, do not update an existing Map key.&lt;/strong&gt; Insert a new key. If a value must become public, &lt;code&gt;disclose()&lt;/code&gt; it. And hashing a witness then checking &lt;code&gt;!= empty&lt;/code&gt; is not access control.&lt;/p&gt;

&lt;p&gt;I verified this against a real local stack, not a sketch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Versions I actually ran
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Piece&lt;/th&gt;
&lt;th&gt;Pin&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Compact language&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pragma language_version 0.23&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compact toolchain&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0.31.x&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@midnight-ntwrk/compact-runtime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0.16.0&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;@midnight-ntwrk/midnight-js-*&lt;/code&gt; / &lt;code&gt;testkit-js&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;4.1.1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@midnight-ntwrk/wallet-sdk&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;1.2.0&lt;/code&gt; (&lt;strong&gt;not&lt;/strong&gt; &lt;code&gt;wallet@5&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;midnightntwrk/midnight-node:0.22.5&lt;/code&gt; &lt;code&gt;:9944&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Indexer&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;midnightntwrk/indexer-standalone:4.0.2&lt;/code&gt; &lt;code&gt;:8088&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Proof server&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;midnightntwrk/proof-server:8.0.3&lt;/code&gt; &lt;code&gt;:6300&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Local Undeployed writes are &lt;strong&gt;server-append&lt;/strong&gt;. Lace does not sign them. &lt;code&gt;setNetworkId("undeployed")&lt;/code&gt; is a &lt;strong&gt;string&lt;/strong&gt; at midnight-js 4.1.1. The standalone chain funds genesis seed &lt;code&gt;…0002&lt;/code&gt;, not &lt;code&gt;…0001&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If those pins drift, you get a different class of failure (often &lt;strong&gt;196&lt;/strong&gt; = verifier mismatch). Don't mix public-network proof-server &lt;code&gt;8.1.0&lt;/code&gt; with this indexer.&lt;/p&gt;

&lt;h2&gt;
  
  
  The mental model in one paragraph
&lt;/h2&gt;

&lt;p&gt;A Compact circuit has three kinds of data:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Witnesses&lt;/strong&gt; — private inputs (&lt;code&gt;localSecretKey()&lt;/code&gt;). They never land on the public ledger unless you move them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Circuit-local values&lt;/strong&gt; — hashes, asserts, math. Still private until disclosed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ledger&lt;/strong&gt; — public state. The only way a private value becomes public is &lt;code&gt;disclose(...)&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That is why a reviewer can ask "why does this circuit need &lt;code&gt;disclose()&lt;/code&gt; here?" Because &lt;code&gt;credits.insert(pk, amount)&lt;/code&gt; without &lt;code&gt;disclose&lt;/code&gt; would try to write a private value into public state. The compiler/runtime will not let that slide.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I wrote first (this panics on Undeployed)
&lt;/h2&gt;

&lt;p&gt;The EVM instinct is a &lt;code&gt;balances&lt;/code&gt; map you overwrite:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;pragma&lt;/span&gt; &lt;span class="nx"&gt;language_version&lt;/span&gt; &lt;span class="mf"&gt;0.23&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;CompactStandardLibrary&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;ledger&lt;/span&gt; &lt;span class="nx"&gt;balances&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Bytes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Uint&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;witness&lt;/span&gt; &lt;span class="nf"&gt;localSecretKey&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Bytes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;circuit&lt;/span&gt; &lt;span class="nf"&gt;transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Bytes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Uint&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;localSecretKey&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;persistentHash&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Bytes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nf"&gt;pad&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;musdc:signer:v1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;sk&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="c1"&gt;// WRONG on Undeployed: lookup + insert of the SAME key&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fromBal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;balances&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;balances&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;disclose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;disclose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fromBal&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;toBal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;balances&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;balances&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;disclose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;disclose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;toBal&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That compiles as Compact. On this Undeployed dust wallet it does &lt;strong&gt;not&lt;/strong&gt; survive &lt;code&gt;callTx&lt;/code&gt;. Updating an existing key trips the merge path. Symptom soup: &lt;code&gt;SubmissionError&lt;/code&gt;, &lt;code&gt;FiberFailure&lt;/code&gt;, Unreachable in &lt;code&gt;transaction_merge&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I hit the same class of bug twice: first on an NFT &lt;code&gt;owners&lt;/code&gt; map, then again on a token &lt;code&gt;balances&lt;/code&gt; map after I thought I had "fixed NFTs." Same ledger shape, same panic.&lt;/p&gt;

&lt;h2&gt;
  
  
  What works: insert-only credit log
&lt;/h2&gt;

&lt;p&gt;Treat the public ledger as an &lt;strong&gt;append-only journal&lt;/strong&gt;. Reconstruct demo balances off-chain if you need a UI number.&lt;/p&gt;

&lt;p&gt;This is the token circuit I compiled and ran (&lt;code&gt;MidnightUSDC.compact&lt;/code&gt;, Compact 0.23):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;pragma&lt;/span&gt; &lt;span class="nx"&gt;language_version&lt;/span&gt; &lt;span class="mf"&gt;0.23&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;CompactStandardLibrary&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;ledger&lt;/span&gt; &lt;span class="nx"&gt;credits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Bytes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Uint&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;ledger&lt;/span&gt; &lt;span class="nx"&gt;credit_to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Bytes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Bytes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;ledger&lt;/span&gt; &lt;span class="nx"&gt;faucet_claimed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Bytes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;ledger&lt;/span&gt; &lt;span class="nx"&gt;spent_nonces&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Bytes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;witness&lt;/span&gt; &lt;span class="nf"&gt;localSecretKey&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Bytes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;circuit&lt;/span&gt; &lt;span class="nf"&gt;faucet&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;localSecretKey&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;persistentHash&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Bytes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nf"&gt;pad&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;musdc:signer:v1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;sk&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="nf"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;faucet_claimed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;member&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;disclose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pk&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;already claimed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;faucet_claimed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;disclose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pk&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="nx"&gt;credits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;disclose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pk&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;disclose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10000000&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Uint&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="nx"&gt;credit_to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;disclose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pk&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;disclose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pk&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;circuit&lt;/span&gt; &lt;span class="nf"&gt;transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Bytes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Uint&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;nonce&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Bytes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;localSecretKey&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fromPk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;persistentHash&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Bytes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nf"&gt;pad&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;musdc:signer:v1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;sk&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="nf"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;spent_nonces&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;member&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;disclose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nonce&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nonce spent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Uint&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;amount zero&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;faucet_claimed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;member&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;disclose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fromPk&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;signer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;spent_nonces&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;disclose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nonce&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="nx"&gt;credits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;disclose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nonce&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;disclose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="nx"&gt;credit_to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;disclose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nonce&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;disclose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What changed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Faucet&lt;/strong&gt; inserts once, keyed by signer pk. Never updated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transfer&lt;/strong&gt; inserts a &lt;strong&gt;new&lt;/strong&gt; row keyed by a fresh &lt;code&gt;nonce&lt;/code&gt;. Never &lt;code&gt;balances[from] = old - amount&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Every value that hits a ledger &lt;code&gt;insert&lt;/code&gt; is &lt;code&gt;disclose(...)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Spend auth is &lt;code&gt;faucet_claimed.member(fromPk)&lt;/code&gt;, not "the hash exists."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;NFT list/buy on the same stack uses the same rule: &lt;code&gt;owners&lt;/code&gt; insert on mint only; &lt;code&gt;sales&lt;/code&gt; append with a fresh random id; cancel writes a &lt;strong&gt;new&lt;/strong&gt; listing id instead of overwriting the old price key. Circuit name is &lt;code&gt;listSale&lt;/code&gt; — &lt;code&gt;list&lt;/code&gt; is a Compact keyword.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why &lt;code&gt;disclose()&lt;/code&gt; is on the insert
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;fromPk&lt;/code&gt; is derived from a &lt;strong&gt;witness&lt;/strong&gt;. Left alone, it is private. &lt;code&gt;credits.insert&lt;/code&gt; writes &lt;strong&gt;public&lt;/strong&gt; Map state. &lt;code&gt;disclose(fromPk)&lt;/code&gt; is the explicit "this byte string may leave the circuit."&lt;/p&gt;

&lt;p&gt;Skip it and you either fail compile or you ship a circuit that cannot be proven against public ledger types. Skip &lt;code&gt;disclose&lt;/code&gt; on &lt;code&gt;nonce&lt;/code&gt; and the spent-nonce set cannot be checked by later transactions.&lt;/p&gt;

&lt;p&gt;That is the whole privacy model: private by default, public by &lt;code&gt;disclose&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The auth footgun that looks like privacy
&lt;/h2&gt;

&lt;p&gt;This also compiles, and it is not access control:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;persistentHash&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Bytes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nf"&gt;pad&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;movenft:minter:v1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;sk&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nf"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nf"&gt;pad&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;auth&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Any non-empty secret hashes to something that is not 32 zero bytes. I replaced it with a stored pk:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;persistentHash&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Bytes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nf"&gt;pad&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;movenft:minter:v1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;sk&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;empty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pad&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;minter_pk&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nx"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;minter_pk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;disclose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pk&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;          &lt;span class="c1"&gt;// first call bootstraps&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pk&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nx"&gt;minter_pk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;minter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// later calls bind the witness&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same shape as &lt;code&gt;assert(pk == buyer)&lt;/code&gt; on a mandate circuit: compare the derived pk to a value the ledger already knows.&lt;/p&gt;

&lt;p&gt;On the token, &lt;code&gt;assert(fromPk != empty)&lt;/code&gt; was the same undercut. &lt;code&gt;faucet_claimed.member(fromPk)&lt;/code&gt; is the bind.&lt;/p&gt;

&lt;h2&gt;
  
  
  SDK side: don't cache the genesis wallet
&lt;/h2&gt;

&lt;p&gt;Undeployed appends reuse the deploy-time LevelDB private state. Mismatch → &lt;strong&gt;117&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Keep seed, store name, and private-state id in &lt;strong&gt;one module&lt;/strong&gt; imported by deploy &lt;strong&gt;and&lt;/strong&gt; every &lt;code&gt;callTx&lt;/code&gt; path. Open &lt;code&gt;MidnightWalletProvider&lt;/code&gt;, prove, submit, &lt;code&gt;stop()&lt;/code&gt; in &lt;code&gt;finally&lt;/code&gt;. A cached provider holds LevelDB open and the next HTTP request dies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;setNetworkId&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@midnight-ntwrk/midnight-js-network-id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MidnightWalletProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@midnight-ntwrk/wallet-sdk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;setNetworkId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;undeployed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// string, not a runtime enum at 4.1.1&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wallet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;MidnightWalletProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;networkId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;undeployed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;seedHex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GENESIS_SEED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// …0002&lt;/span&gt;
  &lt;span class="na"&gt;indexerUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:8088/api/v4/graphql&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;indexerWsUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ws://localhost:8088/api/v4/graphql/ws&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;proofServerUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:6300&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;nodeUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ws://localhost:9944&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// CompiledContract + callTx&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Need &lt;code&gt;import WebSocket from "ws"&lt;/code&gt; in Node. Compact 0.31 emits &lt;code&gt;contract/index.js&lt;/code&gt; (not only &lt;code&gt;.cjs&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  How I proved it wasn't folklore
&lt;/h2&gt;

&lt;p&gt;After rewriting maps to insert-only and binding the faucet set:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;compact compile contracts/MidnightUSDC.compact contracts/managed/midnight-usdc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Wipe local private state, full genesis deploy&lt;/li&gt;
&lt;li&gt;Two sequential transfers succeeded&lt;/li&gt;
&lt;li&gt;Mint → list → buy e2e printed &lt;code&gt;E2E_OK&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you change circuits after deploy: compile → copy prover/verifier artefacts → wipe LevelDB → &lt;strong&gt;full&lt;/strong&gt; redeploy. Mixing new verifiers with old state is &lt;strong&gt;196&lt;/strong&gt;. Retrying the same UI click after 117 does not heal it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd tell my past self
&lt;/h2&gt;

&lt;p&gt;Design the public &lt;code&gt;Map&lt;/code&gt;s as journals &lt;strong&gt;before&lt;/strong&gt; the first Undeployed demo. Do not port ERC-20 storage slots into Compact and hope the dust wallet merges them. &lt;code&gt;disclose()&lt;/code&gt; is not ceremony — it is the privacy boundary. And &lt;code&gt;hash != empty&lt;/code&gt; is a compile-time-shaped lie.&lt;/p&gt;

&lt;p&gt;Working contracts and the insert-only token live in &lt;a href="https://github.com/arunnadarasa/zealymidnight" rel="noopener noreferrer"&gt;zealymidnight&lt;/a&gt; (&lt;code&gt;contracts/MidnightUSDC.compact&lt;/code&gt;, &lt;code&gt;contracts/MoveNft.compact&lt;/code&gt;).&lt;/p&gt;

</description>
      <category>midnight</category>
      <category>zkp</category>
      <category>compact</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>We generated ~32,000 self-contained build prompts for Midnight (and learned the hard way)</title>
      <dc:creator>Arun Nadarasa</dc:creator>
      <pubDate>Sun, 09 Aug 2026 21:01:09 +0000</pubDate>
      <link>https://dev.to/socialprescribing/we-generated-32000-self-contained-build-prompts-for-midnight-and-learned-the-hard-way-2koa</link>
      <guid>https://dev.to/socialprescribing/we-generated-32000-self-contained-build-prompts-for-midnight-and-learned-the-hard-way-2koa</guid>
      <description>&lt;h1&gt;
  
  
  We generated ~32,000 self-contained build prompts for Midnight
&lt;/h1&gt;

&lt;p&gt;Midnight is a zero-knowledge L1: private state stays on the user's device, public state lands on chain, and the bridge between them is a circuit you write in a language called Compact. It's genuinely interesting technology. It also has one of the harshest first hours I've met in web3.&lt;/p&gt;

&lt;p&gt;Not because the concepts are hard. Because the &lt;em&gt;environment&lt;/em&gt; is. A hackathon dev sits down with a good idea and spends the next four hours on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a package set where &lt;code&gt;@midnight-ntwrk/midnight-js-*&lt;/code&gt;, the proof server Docker tag, the ledger, and the wallet SDK all have to agree on a version, or nothing works;&lt;/li&gt;
&lt;li&gt;a local proof server that needs Docker, which on Windows needs WSL2, which needs virtualization enabled in BIOS;&lt;/li&gt;
&lt;li&gt;WASM + top-level &lt;code&gt;await&lt;/code&gt; + a missing &lt;code&gt;Buffer&lt;/code&gt; polyfill, which together turn any SSR framework into a wall of stack traces;&lt;/li&gt;
&lt;li&gt;a testnet wallet with no tDUST and no obvious way to get any.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of that is the idea. All of it is tax.&lt;/p&gt;

&lt;p&gt;So we built &lt;a href="https://midnightprompts.lovable.app/" rel="noopener noreferrer"&gt;Creative Midnight&lt;/a&gt; — a site whose entire job is to collapse that first hour into a copy-paste. This post is about how the prompt generator works, what the numbers actually are, and the failure modes we hit in the reference builds, with the fix for each.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the site is
&lt;/h2&gt;

&lt;p&gt;Three things, in order of usefulness:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. 1,996 hackathon ideas.&lt;/strong&gt; Ten creative disciplines — dance, music, visual art, video, photography, writing, film &amp;amp; animation, games, theater, fashion — each with a market anchor and a "quantum hook" (the private-state mechanic that makes ZK actually load-bearing rather than decorative). 996 of those are base ideas; the other 1,000 are agentic-commerce overlays (A2A/AP2 agent negotiation, UCP ZK-checkout, x402 paywalls with a mimic USDC), distributed across the same themes so you can filter within a discipline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. A build prompt per idea, per network.&lt;/strong&gt; Not a stub — a multi-thousand-line, fully self-contained prompt that includes the pinned package set, the Compact toolchain commands, the Vite config, the wallet boot code, the deploy script, and a list of red flags. You pick an idea, pick a network target, pick your OS, copy, paste into an AI coding tool, and the environment tax is pre-paid.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. The scar tissue.&lt;/strong&gt; Guides for the wallet, the proof server, the local (Undeployed) stack, Fly.io hosting, Android via the Kuira SDK, and a Known Issues page that exists purely so nobody re-debugs what we already debugged.&lt;/p&gt;

&lt;h2&gt;
  
  
  The interesting part: one idea, many prompts
&lt;/h2&gt;

&lt;p&gt;Each idea is a row in a per-theme JSON file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Idea&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;pitch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;subDiscipline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;quantumHook&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      &lt;span class="c1"&gt;// the private-state mechanic&lt;/span&gt;
  &lt;span class="nl"&gt;quantumRationale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// why ZK is load-bearing here&lt;/span&gt;
  &lt;span class="nl"&gt;tam&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;sam&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;som&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;protocol&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;a2a-ap2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ucp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;x402&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// agentic overlay, optional&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The prompt is not stored. It is &lt;em&gt;composed&lt;/em&gt;, by a single function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;buildVariant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;idea&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Idea&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Theme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;network&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NetworkVariant&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;OSTarget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;macos&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;buildVariant&lt;/code&gt; assembles shared blocks — &lt;code&gt;PACKAGES&lt;/code&gt;, &lt;code&gt;TOOLCHAIN_BY_OS&lt;/code&gt;, &lt;code&gt;VITE_CONFIG&lt;/code&gt;, &lt;code&gt;MIDNIGHTJS_BOOT&lt;/code&gt;, &lt;code&gt;SIGNING_STRATEGY&lt;/code&gt;, &lt;code&gt;WALLET_CLI_BLOCK&lt;/code&gt;, &lt;code&gt;REDFLAGS&lt;/code&gt;, plus protocol blocks for the agentic overlays — around the idea's own text. That means a lesson learned once gets written once and appears in every prompt on the site.&lt;/p&gt;

&lt;p&gt;The multiplier is the &lt;strong&gt;network variant&lt;/strong&gt;, because the network genuinely changes the architecture:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Variant&lt;/th&gt;
&lt;th&gt;What changes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Preview&lt;/td&gt;
&lt;td&gt;Public testnet, faucet tDUST, Lace signs everything&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Preproduction&lt;/td&gt;
&lt;td&gt;Same shape, different node/indexer, different faucet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Undeployed (Local)&lt;/td&gt;
&lt;td&gt;Whole stack in Docker; writes are signed server-side by the genesis wallet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Undeployed (Fly.io)&lt;/td&gt;
&lt;td&gt;Four Fly apps (node, indexer, proof, faucet); public HTTPS proof server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Undeployed (Mobile)&lt;/td&gt;
&lt;td&gt;Kotlin + Jetpack Compose via the Kuira Android SDK, on-device proving&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Five visible variants × 1,996 ideas = &lt;strong&gt;9,980 prompts&lt;/strong&gt; in the UI. (A Mainnet variant exists in the codebase and is hidden — independent devs shouldn't be shipping vibe-coded contracts to a live chain.)&lt;/p&gt;

&lt;p&gt;The OS toggle (macOS / Windows / Linux) is deliberately &lt;em&gt;not&lt;/em&gt; a UI multiplier: it swaps one block inside a prompt rather than creating a separate prompt. For the offline bundles, though, we do expand it — which is where the headline number comes from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ideaCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1996&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"networks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"preview"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"preprod"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"undeployed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"undeployed-fly"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"mainnet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"undeployed-mobile"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"oses"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"macos"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"windows"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"linux"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"variantCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;31936&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;31,936 prompt variants, ~2 GB of text, generated by a build script and downloadable as per-target &lt;code&gt;.txt&lt;/code&gt; bundles so you can feed them to your own model.&lt;/p&gt;

&lt;h3&gt;
  
  
  One file pins every version
&lt;/h3&gt;

&lt;p&gt;Every prompt quotes the &lt;a href="https://docs.midnight.network/relnotes/support-matrix" rel="noopener noreferrer"&gt;Midnight support matrix&lt;/a&gt;, which is the actual source of truth for compatible versions. Rather than sprinkling version strings through 2,000 lines of template, they live in one module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MIDNIGHT_MATRIX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;snapshotDate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2026-07-23&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;compact&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.23&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;toolchain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.31.1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.16.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;midnightJs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;4.1.1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;dappConnectorApi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;4.0.1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;walletSdk&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1.2.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;indexer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;4.3.3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;proofServer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;8.1.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;localStack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.22.5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;indexer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;4.0.2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;proofServer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;8.0.3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;ledgerV8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;8.1.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the matrix moves, one edit propagates to ~10,000 prompts, the setup guides, and the downloadable bundles. Note &lt;code&gt;localStack.proofServer&lt;/code&gt; is &lt;code&gt;8.0.3&lt;/code&gt; while the public one is &lt;code&gt;8.1.0&lt;/code&gt; — those are not interchangeable, and discovering that by trial and error costs an evening.&lt;/p&gt;

&lt;h3&gt;
  
  
  Don't ship 2 GB through a Worker
&lt;/h3&gt;

&lt;p&gt;First version of the download page imported the generated bundles as modules. The site is deployed on Cloudflare Workers and immediately returned &lt;strong&gt;Error 1102: Worker exceeded resource limits&lt;/strong&gt; — the isolate has a hard memory ceiling and a multi-hundred-megabyte string blows straight through it.&lt;/p&gt;

&lt;p&gt;Fix: the bundles never enter the bundle. Each is uploaded to a CDN and the repo holds only a pointer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;previewMacos&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../public/llms-prompts-preview-macos.txt.asset.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// { "url": "https://cdn.../llms-prompts-preview-macos.txt", "size": 127837211 }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The page renders a link and a human-readable size. The Worker stays small.&lt;/p&gt;

&lt;h2&gt;
  
  
  The failure modes, and the fixes
&lt;/h2&gt;

&lt;p&gt;These come from four reference builds (&lt;a href="https://github.com/arunnadarasa/choreokits" rel="noopener noreferrer"&gt;choreokits&lt;/a&gt;, &lt;a href="https://github.com/arunnadarasa/midnightfireside" rel="noopener noreferrer"&gt;midnightfireside&lt;/a&gt;, &lt;a href="https://github.com/arunnadarasa/flymidnight" rel="noopener noreferrer"&gt;flymidnight&lt;/a&gt;, and an Android one), and each fix is now baked into the prompts.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SSR build explodes on &lt;code&gt;@midnight-ntwrk/*&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;MidnightJS needs &lt;code&gt;window&lt;/code&gt;, &lt;code&gt;Buffer&lt;/code&gt;, WASM top-level await&lt;/td&gt;
&lt;td&gt;Stub the Midnight packages in the SSR pass; load them behind &lt;code&gt;ClientOnly&lt;/code&gt; + &lt;code&gt;useEffect&lt;/code&gt;. Never disable the server build to "escape SSR" — that emits chunks the Worker can't resolve at runtime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;Buffer is not defined&lt;/code&gt; in the browser&lt;/td&gt;
&lt;td&gt;Polyfill imported after something that needs it&lt;/td&gt;
&lt;td&gt;Async client entry that sets &lt;code&gt;globalThis.Buffer&lt;/code&gt; before any Midnight import&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Local writes fail with wallet errors&lt;/td&gt;
&lt;td&gt;The Undeployed genesis wallet isn't in the browser&lt;/td&gt;
&lt;td&gt;Undeployed writes go server-side: UI → &lt;code&gt;POST /api/append-entry&lt;/code&gt; → genesis wallet. Public nets go UI → wallet provider → on-chain submit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wallet "never ready" on Fly&lt;/td&gt;
&lt;td&gt;Readiness shape changed in WalletFacade 4.1.1&lt;/td&gt;
&lt;td&gt;Check &lt;code&gt;state.dust.state.progress.isStrictlyComplete()&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Proof server unreachable on Fly&lt;/td&gt;
&lt;td&gt;The proof-server binary is IPv4-only; Fly's private network is IPv6-only&lt;/td&gt;
&lt;td&gt;Point the browser at the app's &lt;strong&gt;public HTTPS&lt;/strong&gt; proof-server URL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;App writes to a dead contract&lt;/td&gt;
&lt;td&gt;Old address cached in &lt;code&gt;localStorage&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;VITE_DEFAULT_CONTRACT&lt;/code&gt; must override &lt;code&gt;localStorage&lt;/code&gt; on boot&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wallet sync stalls forever&lt;/td&gt;
&lt;td&gt;Transaction-history storage grinding on huge histories&lt;/td&gt;
&lt;td&gt;Serialize/restore wallet state and use &lt;code&gt;NoOpTransactionHistoryStorage&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compact compile fails on a string field&lt;/td&gt;
&lt;td&gt;Field widths are byte-bounded&lt;/td&gt;
&lt;td&gt;Keep opaque strings inside their declared UTF-8 byte width (32 is the common one); no recursion, no I/O inside circuits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"I have a seed, I need a bech32 address"&lt;/td&gt;
&lt;td&gt;Deriving it by hand is fiddly&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;npm i -g midnight-wallet-cli &amp;amp;&amp;amp; mn address --seed --network preprod&lt;/code&gt; (&lt;code&gt;mn balance&lt;/code&gt; to check funding)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Android passkey exceptions&lt;/td&gt;
&lt;td&gt;Credential Manager needs a real relying party&lt;/td&gt;
&lt;td&gt;Real domain &lt;code&gt;rpId&lt;/code&gt; + a live &lt;code&gt;assetlinks.json&lt;/code&gt;; full uninstall/reinstall after changing &lt;code&gt;rpId&lt;/code&gt;; emulator needs a signed-in Google account and a screen lock&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The one worth repeating: &lt;strong&gt;proofs are slow&lt;/strong&gt;. A k=14 circuit takes 30–120 seconds. Every prompt therefore mandates a visible "Proving… this can take 30–120s" state that keeps the UI usable. Designing for sub-second finality is the single most common way a Midnight demo ends up feeling broken when it's actually working fine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using it
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Pick a discipline, then an idea (filter by protocol if you want an agentic overlay).&lt;/li&gt;
&lt;li&gt;Pick a network tab. If you don't know, pick &lt;strong&gt;Undeployed (Local)&lt;/strong&gt; — no faucet, no waiting, and the genesis wallet is already funded.&lt;/li&gt;
&lt;li&gt;Pick your OS so the Docker/toolchain block matches your machine.&lt;/li&gt;
&lt;li&gt;Copy the prompt into your AI coding tool. Run the two toolchain commands it gives you in a terminal (installing Compact and starting the proof server are the only things a browser can't do for you).&lt;/li&gt;
&lt;li&gt;Ship.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There's also a downloadable skill file if you'd rather give your own agent the whole knowledge base instead of one prompt at a time.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd tell anyone building on a young ZK chain
&lt;/h2&gt;

&lt;p&gt;Write the environment down. Every hour we lost was recoverable exactly once — the second time it cost nothing, because the fix was in a template instead of in someone's memory. The prompt generator is, honestly, just a very elaborate way of refusing to debug the same thing twice.&lt;/p&gt;

&lt;p&gt;Links: &lt;a href="https://midnightprompts.lovable.app/" rel="noopener noreferrer"&gt;Creative Midnight&lt;/a&gt; · &lt;a href="https://docs.midnight.network/" rel="noopener noreferrer"&gt;Midnight docs&lt;/a&gt; · &lt;a href="https://docs.midnight.network/relnotes/support-matrix" rel="noopener noreferrer"&gt;support matrix&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Built during the Creative AI &amp;amp; Quantum Hackathon organised by StreetKode Fam during Indian Krump Festival 14.&lt;br&gt;
`&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`plaintext&lt;/p&gt;

&lt;p&gt;`&lt;code&gt;&lt;/code&gt;&lt;br&gt;
`&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>zeroknowledge</category>
      <category>webdev</category>
      <category>blockchain</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
