Skip to content

Testing methodology

fact

ItemValue
FrameworkFoundry (forge 1.8.x)
CompilerSolidity 0.8.28, optimizer on (200 runs), via_ir = false, EVM cancun
DependenciesOpenZeppelin Contracts v5.1.0
Formatting and lintforge fmt (120 columns), forge lint with a documented exclusion list
Default profilefuzz 2,048 runs; invariant 512 runs × depth 64, fail_on_revert = false
CI profilefuzz 50,000 runs; invariant 5,000 runs × depth 64
Lite profilefuzz 64; invariant 16 × 16, for fast local iteration
Coverage target≥ 95% line and branch on src/ excluding mocks and interfaces
LayerLocationPurposeStatus
Unittest/unit/core, test/unit/tokenEvery external function, every revert path, every event, with exact expected valuespresent
Lifecycletest/unit/core/NoteCore.Lifecycle.t.solEnd-to-end series scenarios: autocall, hold to maturity, breach with physical settlement, cancellation, deferral, refunds, transfers mid-lifepresent
Calendartest/unit/core/MarketCalendar.t.solDST boundaries 2026 to 2030, holidays, early closes, isOfficialClose for every weekday close of a yearpresent
Oracletest/unit/core/OracleAdapter.t.solRound walk-back, window bounds, backup deviation, deferral, force and cancel pathspresent
Fuzztest/fuzz/core (CalendarMath, Matching, Oracle, Settlement), test/fuzz/token (ExpMath, RevenueRouter)Property tests over prices, notionals, decimals, timestamps and rounding; 40 testFuzz_* functionspresent
Invarianttest/invariant/core, test/invariant/token, test/invariant/governanceHandler-based stateful fuzzing: 8 core (+1 reachability), 19 token and 13 governance invariant functions; the core handler includes a lazyCrank actionpresent
Automationtest/unit/automation, test/unit/core/NoteCore.LazyCrank.t.sol, test/fuzz/automationRollPolicy (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.

  • Tests use the mocks in src/mocks: MockUSDG (6 decimals), MockStockToken (18 decimals, uiMultiplier and balanceOfUI exposed, raw balances unchanged), MockAggregatorV3 (8 decimals, arbitrary round history, negative and stale answers), MockFeeSink.
  • Time is advanced with vm.warp to 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 getSeries and accounting views.
  • Events are asserted with vm.expectEmit including indexed parameters.

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 ≤ cap for all refBps, S, D.
  • Matching: N ≤ min(D, S, notionalCap, prefundCapacity) and stockMatched × s0 / 1e8 ≥ N (rounded up).
  • Physical settlement: redeem(units) delivers units × 1e12 × 1e8 / s0 wei within one wei, and the sum over all holders never exceeds stockMatched.
  • Coupon index: sum of accrued over all holders never exceeds couponPool.
  • Oracle: observe never returns a round with updatedAt > closeTs + closeGrace or < 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)) == true for every trading day; DST transitions match the pinned dates.
  • ExpMath: halfLifeDecayWad(t, h) within 1e-9 relative error of a reference for t/h ∈ [0, 64]; equals 0.5e18 at t = h.
  • Treasury: previewRedeem monotone in noteAmount; floor non-decreasing after any redemption.
  • sNOTE: share price non-decreasing across any sequence of deposit, notify, warp, request, redeem.

forge coverage --report lcov in CI; threshold enforced at 95% for src/core, src/oracle, src/token, src/libraries. Mocks and interfaces are excluded.

See Static analysis.

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.