Code follows this file. Change the rules here first. Status: SAFE clauses cited below against the three YC post-money SAFE documents (see "SAFE source mapping"). Not legal advice.
N = issued shares + granted options + unissued pool (before the round). SAFE shares and the round's pool top-up are NOT in N.
p_i = A_i / C_i. Sum(p_i) must be < 1, else reject.
Cap_pre = N / (1 - sum p_i) (includes SAFE shares, excludes pool top-up)
SAFE_i shares = floor(p_i * Cap_pre); conversion price = C_i / Cap_pre.
GV-1: N = 8,750,000; sum p = 0.125; Cap_pre = 10,000,000; SAFE1 = 1,000,000 @ $0.50; SAFE2 = 250,000 @ $1.00.
Converts at min(cap price, round price * (1 - d_i)). Round price depends on SAFE shares, so solve by exact-rational fixed-point iteration until no SAFE changes regime and share counts are stable; fail loudly after 1,000 iterations. Cross-check cap-only case against R3 closed form.
Each converted SAFE becomes its own preferred class with original issue price = conversion price, 1x non-participating. Preference = purchase amount (up to rounding).
Inputs: pre-money V, new money I (per investor I_k), pool target t (share of post-round fully diluted). V' = V + I.
X = issued + granted options + SAFE shares (unissued pool excluded).
Pool after = t * FD_post, FD_post = V'/P, so with pool top-up T and pool before B: P = V / (X + B + T), T = (t*V'/P) - B.
Derivation: X + B + T = V/P (top-up in pre-money) and B + T = t*V'/P, so X = (V - t*V')/P and P = (V - t*V')/X, then T = floor(t*V'/P) - B. If T < 0: T = 0 and P = V / (X + B).
New investor k gets floor(I_k / P) shares. FD_post differs from V'/P only within rounding; the engine reports the difference.
GV-1: V=21M, I=9M, X=9,000,000, B=1,000,000, T=500,000, P=$2.00, Fund = 4,500,000.
Default 48 months, 12-month cliff: 25% at cliff, remainder monthly (linear per month, floor). Exercise cost = strike * shares. Termination: unvested return to pool; vested options exercisable for 90 days (default).
Sort preferred classes by preference per as-converted share ascending. For k = 0..n: lowest k convert, others take preference (pro rata in rank order if proceeds are insufficient; pari passu by default), remainder split among common + converted pro rata. Choose the unique consistent k: every converter gets >= its preference per share, every non-converter would get less by converting. Options exercise only if per-share payout > strike; cash exercise adds strike to proceeds. Unissued pool receives nothing.
sha256 of RFC 8785 canonical JSON of the plan, all amounts as strings. A round plan carries its money terms as well as its shares: kind (Founder, Safe or Priced), raise (a list of [investor account, micro-dollars]) and deadline_ns (a string). The contract refuses a proposal whose kind, raise or deadline_ns arguments differ from the ones inside the hashed plan, and in a Safe round each investor's raise must equal the purchase amounts of the SAFEs issued to them. So the hash the board approves fixes who pays how much for which shares, not only the shares.
A pot of money paid to the holders of shares, pro rata by shares held whatever the class (preference and conversion do not apply: this is a distribution, not an exit). The unissued option pool is not a holder and receives nothing. Each holder gets floor(pot × shares / eligible shares) micro-dollars, holders are listed in account-id order and zero amounts are left out, so the payouts never exceed the pot and the rounding remainder (less than one micro-dollar per holder) is reported and not paid. The plan has the exit plan's shape (payouts: a list of [account, micro-dollars]), so the same approve-by-hash and pay-once machinery that runs an exit runs a shared payout.
A SAFT (or a token warrant) is money paid now for the right to tokens at the token generation event (TGE). At the TGE, tokens = floor(amount / price) where price is the lower of the cap price (fully diluted valuation cap / total token supply) and the discounted launch price (launch price × (1 − discount)); the cap wins a tie. A warrant that follows only the cap is a SAFT with no discount. Prices are exact rationals in micro-dollars per whole token; the purchase money not covered by whole tokens is reported (less than one token's price). Together the SAFTs cannot convert to more tokens than the total supply. Unlocking follows R7 (nothing before the cliff, then linear). Unlike a post-money SAFE (R3) nothing here is circular, because the launch price and the supply come from outside. Tokens are counted in base units (decimals base units make one whole token); the cap price is per base unit (cap / supply in base units) and the discount price is per whole token (launch price × (1 − discount)), so tokens = max(floor(amount × supply / cap), floor(amount × 10^decimals × 10000 / (launch price × (10000 − discount)))). The contract computes exactly this (saft_tokens) when the board converts SAFTs and refuses a plan whose token counts differ; it also refuses conversions that exceed the supply or the funded token reserve. This models numbers only; whether a SAFT is a security is a legal question Rounds does not answer.
A round may keep its cap table private. Slots: a depth-6 Poseidon Merkle tree, 64 slots. Leaf = Poseidon(Poseidon(holder_secret), class_id, shares, salt); an unused slot is the leaf of four zeros; node = Poseidon(left, right). Every holder entry has its own fresh secret, so a holder with several classes holds several receipts. A Groth16 proof (circuit cap_table_commit) shows that every share amount is below 2^64, that the amounts add up to the public total_shares, and that the leaves hash to the public root, bound to the public round_id. A payout of pot micro-dollars over total_shares is claimed per leaf with a second proof (circuit private_claim): membership in the committed tree, nullifier = Poseidon(holder_secret, exit_id), and payout = floor(shares * pot / total_shares) exactly, bound to recipient_hash = sha256(recipient account id) mod r so the proof cannot be redirected. The contract verifies both proofs with NEAR's alt_bn128 functions, rejects any public input at or above the BN254 scalar modulus, and records the nullifier before it pays (restoring it if the transfer fails). The paid amount is public; only the link from holder to payout is hidden. Not covered by the proofs: that the committed table is the one the board intended (the board must check the root against the table it is given privately), and that every receipt reaches its holder.
vectors/gv-1.json, vectors/gv-2.json (hand-checked against R3, R6, R8 on 2026-11-06). TODO: add five more (discount-only SAFE; cap+discount each winning; no top-up; down round below caps; exit with out-of-the-money option).
Cap_pre depends on which SAFEs convert at cap vs discount; A_i/C_i of the pre-round capitalization holds only when every SAFE is in the cap regime. GV-3 (discount-only, $2.1612 price, 578,382 SAFE shares) is in test/gv-discount.test.ts.
Read from the three files in ref/ (YC "Postmoney Safe": Valuation Cap Only, Discount Only, MFN Only; all FINAL versions as downloaded 2026-11-07). Section numbers are those of the forms. This maps each Rounds rule to the clause it follows; it does not claim legal validity.
| Rounds rule | YC clause | Status |
|---|---|---|
| R3 conversion price = cap / capitalization (cap-only) | Valuation Cap form s.1(a)(2) and s.2 "Safe Price" = Post-Money Valuation Cap / Company Capitalization | follows |
| R2 capitalization before the round: issued shares, granted options, unissued pool, and all converting SAFEs (so Cap_pre = N / (1 - sum p_i)) | s.2 "Company Capitalization" and "Converting Securities" (includes this Safe and other Safes) | follows |
| Pool top-up excluded from the SAFE's capitalization (R2, R6) | s.2 "Company Capitalization", last bullet: an increase to the Unissued Option Pool in connection with the Equity Financing is included only to the extent Promised Options exceed the pre-increase pool | follows; Promised Options are not modelled (no input for them), so the "only to the extent" exception never applies |
| Cap-only SAFE converts at the lower of cap price and round price | Valuation Cap form s.1(a): the greater of (1) Purchase Amount / lowest Standard Preferred price and (2) Purchase Amount / Safe Price. Greater share count = lower price. GV-7 (round priced below the cap) exercises this | follows |
| R4 discount-only SAFE converts at round price x (1 - discount) | Discount form s.1(a) and s.2 "Discount Price" = lowest Standard Preferred price x Discount Rate (Discount Rate = 100 minus the discount, in percent) | follows; Rounds floors the price to a multiple of 100 micro-dollars (R1) |
| R4 SAFE with both a cap and a discount: lower of the two prices | Not in the YC forms provided. The Cap form has no discount and the Discount form has no cap. This is Rounds' own extension (GV-5) | extension, not sourced |
| R5 converted SAFE becomes its own preferred class, 1x non-participating, original issue price = conversion price | s.2 "Safe Preferred Stock": identical to Standard Preferred except price-based preferences are based on the Safe Price (or Discount Price in the Discount form); s.1(d) intended to operate like non-participating Preferred | follows |
| R8 exit waterfall: cash-out amount senior to common, pro rata with other Safes and Preferred; conversion on par with common | s.1(b) and s.1(d)(ii)-(iii) | follows for converted SAFEs (see next row) |
| Exit before a priced round (Safe still outstanding): greater of Purchase Amount or Purchase Amount / Liquidity Price | s.1(b), s.2 "Liquidity Price" and "Liquidity Capitalization" (excludes the Unissued Option Pool) | not modelled. Rounds only runs exits after a SAFE has converted; s.1(e) terminates the Safe on conversion |
| Dissolution Event (Cash-Out Amount only) | s.1(c) | not modelled |
| Dividend Amount, tax-free reorganization cash reduction, convertible notes as Converting Securities | s.2 "Dividend Amount", s.1(b) second paragraph, s.2 "Converting Securities" | not modelled |
| MFN SAFE | MFN form | not modelled (out of scope) |
Source files are third-party documents kept in ref/ for checking only; they are not part of the Rounds code or license.