Testing methodology
Toolchain
Section titled “Toolchain”fact
| Item | Value |
|---|---|
| Framework | Foundry (forge 1.8.x) |
| Compiler | Solidity 0.8.28, optimizer on (200 runs), via_ir = false, EVM cancun |
| Dependencies | OpenZeppelin Contracts v5.1.0 |
| Formatting and lint | forge fmt (120 columns), forge lint with a documented exclusion list |
| Default profile | fuzz 2,048 runs; invariant 512 runs × depth 64, fail_on_revert = false |
| CI profile | fuzz 50,000 runs; invariant 5,000 runs × depth 64 |
| Lite profile | fuzz 64; invariant 16 × 16, for fast local iteration |
| Coverage target | ≥ 95% line and branch on src/ excluding mocks and interfaces |
Test layers
Section titled “Test layers”| Layer | Location | Purpose | Status |
|---|---|---|---|
| Unit | test/unit/core, test/unit/token | Every external function, every revert path, every event, with exact expected values | present |
| Lifecycle | test/unit/core/NoteCore.Lifecycle.t.sol | End-to-end series scenarios: autocall, hold to maturity, breach with physical settlement, cancellation, deferral, refunds, transfers mid-life | present |
| Calendar | test/unit/core/MarketCalendar.t.sol | DST boundaries 2026 to 2030, holidays, early closes, isOfficialClose for every weekday close of a year | present |
| Oracle | test/unit/core/OracleAdapter.t.sol | Round walk-back, window bounds, backup deviation, deferral, force and cancel paths | present |
| Fuzz | test/fuzz/core (CalendarMath, Matching, Oracle, Settlement), test/fuzz/token (ExpMath, RevenueRouter) | Property tests over prices, notionals, decimals, timestamps and rounding; 40 testFuzz_* functions | present |
| Invariant | test/invariant/core, test/invariant/token, test/invariant/governance | Handler-based stateful fuzzing: 8 core (+1 reachability), 19 token and 13 governance invariant functions; the core handler includes a lazyCrank action | present |
| Automation | test/unit/automation, test/unit/core/NoteCore.LazyCrank.t.sol, test/fuzz/automation | RollPolicy (22), NoteAutomation (20), lazy crank / seriesCreator / dueWork (27) and roll-date fuzz (2) | present |
Status reflects the repository at the time these pages were written and is updated as suites land.
Unit conventions
Section titled “Unit conventions”- Tests use the mocks in
src/mocks:MockUSDG(6 decimals),MockStockToken(18 decimals,uiMultiplierandbalanceOfUIexposed, raw balances unchanged),MockAggregatorV3(8 decimals, arbitrary round history, negative and stale answers),MockFeeSink. - Time is advanced with
vm.warpto exact official close timestamps; no test relies on “now”. - Every test that moves value asserts balances of all parties before and after, and asserts the escrow identity via
getSeriesandaccountingviews. - Events are asserted with
vm.expectEmitincluding indexed parameters.
Fuzz properties
Section titled “Fuzz properties”fact Present in test/fuzz: matching and requiredPrefund bounds, coupon index conservation across transfers, physical settlement within one wei and quoteToStock sum bound, civil-date round trips, day-of-week sequencing, DST rule, official-close and holiday/early-close logic, mulDivUp, bps bounds, WAD round trips, clamp, deviation symmetry, oracle walk-back, walk limit, answer validation, backup deviation and fallback, force timing, ExpMath decay bounds and monotonicity, router floor and current price bounds, previewSell rounding, sell accounting and sync split.
specified Target property list:
- Coupon discovery:
floor ≤ couponBps ≤ capfor allrefBps,S,D. - Matching:
N ≤ min(D, S, notionalCap, prefundCapacity)andstockMatched × s0 / 1e8 ≥ N(rounded up). - Physical settlement:
redeem(units)deliversunits × 1e12 × 1e8 / s0wei within one wei, and the sum over all holders never exceedsstockMatched. - Coupon index: sum of
accruedover all holders never exceedscouponPool. - Oracle:
observenever returns a round withupdatedAt > closeTs + closeGraceor< closeTs − maxPreCloseLag, and returns the same round whenever it is called after the grace (reference model in the fuzz suite; 10,000 differential vectors against the Python model). - Calendar:
isOfficialClose(officialCloseOf(d)) == truefor every trading day; DST transitions match the pinned dates. - ExpMath:
halfLifeDecayWad(t, h)within 1e-9 relative error of a reference fort/h ∈ [0, 64]; equals0.5e18att = h. - Treasury:
previewRedeemmonotone innoteAmount; floor non-decreasing after any redemption. - sNOTE: share price non-decreasing across any sequence of deposit, notify, warp, request, redeem.
Coverage
Section titled “Coverage”forge coverage --report lcov in CI; threshold enforced at 95% for src/core, src/oracle, src/token, src/libraries. Mocks and interfaces are excluded.
Static analysis
Section titled “Static analysis”See Static analysis.
Reviews and audits
Section titled “Reviews and audits”Internal security review completed by the build team (reports under audit/ in the repository; full test run at the reviewed commit: 77 suites, 900 passed, 0 failed, 1 skipped). No external audit yet; an independent engagement is planned after the raise. See Audits.