How it works

How it works

Four actors, one loop: the issuer commits an accredited set, the investor proves membership in the browser, the contract verifies the proof natively, and the pool settles.

Issuercommits rootInvestorproves in browserContractverifies nativelyPoolsettles + mintsprivate inputs stay in the browser · only a 256-byte proof crosses the wire

The loop, step by step

  1. Accredit. The issuer (or the self-serve route) builds a Merkle tree whose leaves are Poseidon3(investor_id, cap, investor_secret), and commits the root on chain with update_accredited_set. That emits RootUpdated with the new root and epoch.
  2. Prove. The investor assembles the circuit input, their private identity plus the Merkle path, and runs snarkjs in a Web Worker. Out comes a 256-byte proof and four public inputs: [merkle_root, amount, nullifier, epoch]. The private inputs never leave the browser.
  3. Verify. The investor calls subscribe. The contract checks the proof against the committed verifying key using the native BN254 host function, checks the root and epoch match current pool state, and rejects a reused nullifier.
  4. Settle. The contract pulls the public amount of Testnet USDC from the investor, mints pool tokens, records the nullifier, and emits Subscribed with the commitment.

What the ledger sees

A passive observer sees the subscribing wallet, the amount, a nullifier, and a commitment. They do not see which leaf was used, the investor’s id, their cap, or their secret, and so cannot link the subscription to a real-world identity or to the same investor across epochs.