# 100 days of midnight

**URL:** <https://forum.midnight.network/t/100-days-of-midnight/1316>\
**Category:** General\
**Tags:** learning, community\
**Created:** [August 15, 2026, 9:25pm UTC](https://forum.midnight.network/t/100-days-of-midnight/1316 "2026-08-15T21:25:12Z")\
**Posts on this page:** 7\
**Page:** 2

<div class="post-metadata">

**Author:** ![Guto](https://avatars.discourse-cdn.com/v4/letter/g/ecd19e/32.png) [@Guto](https://forum.midnight.network/u/Guto)\
**Post date:** [September 29, 2026, 8:36pm UTC](https://forum.midnight.network/t/100-days-of-midnight/1316/21 "2026-09-29T20:36:41Z")

</div>

Day 34/100 — Splitting wallet, business, and investor registration into separate pages

Today was a structural day. Until now, BrowseMe had one screen doing everything: connecting the wallet, registering a business, and registering an investor. That was fine while I was chasing contract bugs, but it made the app confusing to use. A visitor had to work out which form was theirs, and wallet state sat tangled up with both registration flows.

I moved the app to client-side routing and gave each job its own page. There’s now a home page, a wallet page, a business registration page, and an investor registration page at `/register-investor`, with a nav bar linking between them. Each route renders its own component, so the investor form maps to `registerInvestor` and the business forms map to `registerBusinessTrackA/B`, instead of everything sharing one file.

 ![image](https://canada1.discourse-cdn.com/flex010/uploads/midnightnetwork/original/1X/f1c29d04ab73c665674ebebd81a10f0c02aff614.png)

---

<div class="post-metadata">

**Author:** ![Guto](https://avatars.discourse-cdn.com/v4/letter/g/ecd19e/32.png) [@Guto](https://forum.midnight.network/u/Guto)\
**Post date:** [October 1, 2026, 9:28pm UTC](https://forum.midnight.network/t/100-days-of-midnight/1316/22 "2026-10-01T21:28:54Z")

</div>

**Day 35/100 — Cleanup, a near-miss staging catch, and honest limitations documented**

A consolidation day on BrowseMe, fixing real issues and being honest about what’s still broken.

**Contract and tests** : fixed the duplicate-attester check and aligned the app’s private state with the updated contract. Removed `attesterType` and `attesterRand` from `deploy.ts` and corrected `emptyInvestorForm` to the contract’s actual fields, `name`, `region`, `businessId`, `taxId`. All 7 tests pass with `yarn test`. Pinned `compact compile` to `+0.31.1` in the root `package.json`.

**Frontend** : committed `WalletContext.tsx`, `pages/`, and the routing changes, my first staging list had missed them, which would have broken a fresh clone silently. Added `react-router-dom`. Reverted a `compact-runtime` bump to `0.19.0`, since the compiled contract calls `checkRuntimeVersion('0.16.0')`, so the frontend now matches the root and the compiler. Type check (`tsc --noEmit -p tsconfig.app.json`) is clean after installing frontend dependencies.

**License, README, and comments** : added the Apache 2.0 `LICENSE` and a `NOTICE`, set the license field in the root `package.json`. Updated the README with a license badge, the new files in the project tree, a routing status line, and a runtime-mismatch troubleshooting entry. Added `compact update 0.31.1` to the fresh-clone steps. Rewrote Known Limitations to honestly cover the silent 32-byte truncation in `toBytes32` and the empty `contactInfo`. Replaced stale “Stage 2” placeholder comments in both registration forms, since the pages now actually encode the fields and call `ContractAPI`.

**Merge** : the remote had its own README changes, conflicting in three places. Kept my license edits and the remote’s Privacy Model section. Rewrote the remote’s `placeholderCommitment()` paragraph, since that code doesn’t exist anymore, commitments are computed in-circuit now. Pasted extra commands into the merge message by accident, fixed with `git commit --amend`. Everything’s pushed to `origin/main`.

**Still open** :

- `deploy.ts` has 9 type errors, all from Midnight SDK drift (`URL` vs `string` for indexer URLs, a missing `waitForGeneratedDust` on the dust wallet, a new `args` requirement on `deployContract`). Pre-existing, haven’t touched them yet.

- Neither registration form validates input length. Business descriptions are the worst case, the form requires 20+ characters but only the first 32 bytes get committed. Need to decide between a length limit or hashing longer text down.

---

<div class="post-metadata">

**Author:** ![Guto](https://avatars.discourse-cdn.com/v4/letter/g/ecd19e/32.png) [@Guto](https://forum.midnight.network/u/Guto)\
**Post date:** [October 5, 2026, 11:48am UTC](https://forum.midnight.network/t/100-days-of-midnight/1316/23 "2026-10-05T11:48:20Z")

</div>

**Day 36/100 — BrowseMe’s first view of live chain state**

Real milestone today: BrowseMe rendered live chain state in the UI for the first time.

**Listed businesses page** : I import the contract’s struct through the contract API and render it straight into the frontend. Registered businesses now show up with sector, location, track, tier, and status. Track A businesses are assigned Tier 2 and listed as Open. Track B businesses stay unlisted until an attestation is provided, the privacy-tiered design from earlier days is now actually visible, not just enforced under the hood.

**Connect button bug** : clicking the button fired a network request, but the UI gave no sign anything was happening, so people clicked again and hit retry errors. The cause: my wallet had cached the dApp’s session and connected automatically. The wallet was already working while the UI looked idle. Fixed by adding a “Connecting… check your wallet” state.  
**Lesson** : wallet connection is asynchronous and can be silent, worse, it can take wildly different amounts of time depending on whether the wallet has to prompt the user to approve (a fresh handshake) or just confirm an already-cached session. Checking Midnight’s own reference wallet connector example, it has the same gap, no pending state shown between click and resolution. Always reflect the pending state in the UI regardless, and don’t assume a cached session means the same thing, timing-wise, as a fresh one.

**A few loose ends, caught reviewing the screenshots** :

- “lagos” renders lowercase while sector values are title-cased, needs a small display formatter
- There’s an empty gap above the “Listed businesses” heading, looks like leftover layout space or a missing page header
- The listing doesn’t yet show how Track B businesses appear once attested, good candidate for a Day 37 feature: the attestation flow that moves them from unlisted to listed

 ![image](https://canada1.discourse-cdn.com/flex010/uploads/midnightnetwork/original/1X/3d7813e85f97fa40d991017ae127432c3f04b958.png)

 ![image](https://canada1.discourse-cdn.com/flex010/uploads/midnightnetwork/original/1X/d7bc90c147b46767cb2788822f91e219c6e18389.jpeg)

---

<div class="post-metadata">

**Author:** ![Guto](https://avatars.discourse-cdn.com/v4/letter/g/ecd19e/32.png) [@Guto](https://forum.midnight.network/u/Guto)\
**Post date:** [October 7, 2026, 2:28pm UTC](https://forum.midnight.network/t/100-days-of-midnight/1316/24 "2026-10-07T14:28:21Z")

</div>

**Day 37/100 — New nav bar, a details page, and the handshake flow comes online**

Real frontend progress on BrowseMe today.

**New nav bar** : replaced the old one.

**Browse page** : renamed the Listed Businesses page to Browse, where investors can actually look through listed businesses.

**Details page** : built a page for businesses that have been handshook by an investor, so there’s now somewhere to actually see that relationship once it exists.

**Handshake flow** : initiated a handshake, once started, the business appears in Deals, and the investor confirms the handshake from their wallet.

 ![image](https://canada1.discourse-cdn.com/flex010/uploads/midnightnetwork/original/1X/927e836ad95505a46f20277ebe905750a456bab7.png)

 ![image](https://canada1.discourse-cdn.com/flex010/uploads/midnightnetwork/original/1X/52645ad8688905db257850b0a4662958d591fa7d.png)

---

<div class="post-metadata">

**Author:** ![Guto](https://avatars.discourse-cdn.com/v4/letter/g/ecd19e/32.png) [@Guto](https://forum.midnight.network/u/Guto)\
**Post date:** [October 9, 2026, 8:09am UTC](https://forum.midnight.network/t/100-days-of-midnight/1316/25 "2026-10-09T08:09:47Z")

</div>

Day 38/100 — README catches up with the frontend

Quiet day on features, but an important one for the repo.

Status: rewrote it to match the current build. Wallet connect, registration, Browse, handshakes, Deals, shake back and unshake are all listed as working. The Track B attestation flow and the page for viewing private details after a handshake are listed as not built yet.

Handshakes: documented that they work both ways. An investor can shake a business, and a business can shake back.

Privacy Model: added rows for track, tier, status and handshake state. Anything the frontend reads through the indexer is public ledger state, so the README should say that plainly.

Project Structure: updated the file tree to match the repo, including the nav bar, the pages and the Deals hook.

Intro: it now says commitments are computed in-circuit. Proving claims about the hidden data is still on the roadmap.

It’s easy for a README to drift from the project, so I update it as soon as I push changes. That way anyone who lands on the repo gets current information, not stale.

Next up: the page where private details can be seen after a handshake.

 ![image](https://canada1.discourse-cdn.com/flex010/uploads/midnightnetwork/original/1X/62854922b20bdbe52267ac25dee2f7916ce93fd1.png)

---

<div class="post-metadata">

**Author:** ![Guto](https://avatars.discourse-cdn.com/v4/letter/g/ecd19e/32.png) [@Guto](https://forum.midnight.network/u/Guto)\
**Post date:** [October 13, 2026, 1:39pm UTC](https://forum.midnight.network/t/100-days-of-midnight/1316/26 "2026-10-13T13:39:28Z")

</div>

**Day 39/100: Details sharing after a handshake, and a private state bug**

BrowseMe v0.4 adds details sharing. Once a handshake is sealed, each side can choose to share its private details with the other.

**How it works.** Each wallet generates an encryption keypair in its own browser. The public key goes on chain in the handshake: the investor’s when initiating, the owner’s when shaking. Sharing encrypts your registered form, plus the randomness behind its commitment, to the other side’s public key using a NaCl box. The encrypted package is stored on the ledger through `deliverInvestorDetails` or `deliverBusinessDetails`. The receiver decrypts in their browser, recomputes the commitment with `pureCircuits`, and compares it to the one registered on chain. The page shows “Verified” or a warning. `unshake` removes both packages from current ledger state, though they stay in chain history. Anything written on chain is permanent, so removal from current state is not deletion.

**The bug.** The console showed “Contract address not set” on connect. The private state provider scopes stored state per contract address, and `setContractAddress` has to be called before any `get`, `set`, or `remove`. Midnight.js does this automatically inside `deployContract`, `findDeployedContract`, and call transactions, so you only hit the error when you touch private state before one of those runs, which is what my new `join()` did. The fix is one line before the first read: `providers.privateStateProvider.setContractAddress(contractAddress)`. The bulletin board tutorial uses the same pattern.

**Verification.** I tested with two browser profiles. Both showed “Verified against their on-chain commitment” and decrypted each other’s fields correctly. `unshake` worked too: both sides showed ENDED, with a notice that the packages remain in chain history. Verified means the details match the commitment registered on chain. It does not mean the claims inside them are true.

**Cleanup.** I removed the dead initial state builder from `WalletContext.tsx`, so `connect()` now calls `ContractAPI.join(providers, CONTRACT_ADDRESS, { callerAddress })`. `RegisterInvestorPage.tsx` now uses `encodeInvestorForm` from `codec.ts`, so over long values throw instead of being silently cut to 32 bytes. The README now lists details sharing as working, rewords the investor limitation, and has a troubleshooting entry for the “Contract address not set” error.

 ![image](https://canada1.discourse-cdn.com/flex010/uploads/midnightnetwork/original/1X/3821878a93d16d31607b0b105fd19b28338e5355.png)

 ![image](https://canada1.discourse-cdn.com/flex010/uploads/midnightnetwork/original/1X/1e8d397224ef766e904fc24d7d57ed323ac5b47d.png)

---

<div class="post-metadata">

**Author:** ![Guto](https://avatars.discourse-cdn.com/v4/letter/g/ecd19e/32.png) [@Guto](https://forum.midnight.network/u/Guto)\
**Post date:** [October 15, 2026, 9:25am UTC](https://forum.midnight.network/t/100-days-of-midnight/1316/27 "2026-10-15T09:25:58Z")

</div>

**Day 40/100: Attester UI wired in, and how Track B tiers work**

Wired the attester UI into BrowseMe today. The attester form lives inside the Track B business page, so attesting happens from the business being vouched for. I tested the data flow end to end and it works.

**How tiers work now.** After a union attestation plus one other attestation, a Track B business gets an initial Tier 3. After all 4 attestations, it moves to Tier 1. Track A businesses, which register with formal documentation, are Tier 2 and Open from the start.

**Why this mattered.** On Day 36 the Browse page showed Track B businesses as unlisted until an attestation was provided, but nothing in the UI let anyone provide one. The contract could already handle attestations. Now the whole path from an unattested Track B business to a tiered one can be exercised from the frontend.

 ![image](https://canada1.discourse-cdn.com/flex010/uploads/midnightnetwork/original/1X/5f32738e04833a89fea51d227bca4f9eb81224f1.png)

 ![image](https://canada1.discourse-cdn.com/flex010/uploads/midnightnetwork/original/1X/8423c7254b4a1c1894c2166f533852c916db5e9d.png)

[Previous page](https://forum.midnight.network/t/100-days-of-midnight/1316.md?page=1)
