Description
The streaming_invariant_tests.rs (10KB) and stream_balance_property_tests.rs (25KB) test streaming invariants, but there are no invariant tests for the broader contract state. Critical invariants like "total token balance in contract should equal sum of all meter balances + dust accumulator + gas buffers + insurance pool + protocol fees" are not tested. The buffer_tests.rs (14KB) tests gas buffer operations but doesn't verify the global token accounting invariant.
Invariant gaps:
- No total supply invariant test (tokens in contract == user funds + protocol funds + dust)
- No streaming invariant (sum of all stream rates == total outflow rate)
- No admin action invariant (admin can never increase their own balance directly)
- No oracle invariant (oracle prices must always be positive and bounded)
- No insurance pool invariant (pool outflows cannot exceed pool inflows + initial capital)
- No debt invariant (total debt across all users <= total collateral locked)
Technical Context & Impact
- Affected Components/Files:
contracts/utility_contracts/src/streaming_invariant_tests.rs, contracts/utility_contracts/src/stream_balance_property_tests.rs, contracts/utility_contracts/src/buffer_tests.rs
- Impact: Protocol Soundness, Financial Safety, Bug Detection
Step-by-Step Implementation Guide
- Create
tests/invariant_tests.rs with InvariantChecker struct that holds a snapshot of the contract state
- Implement global accounting invariant:
check_total_token_accounting(env) -> Result:
- Read token balance via
token::Client::balance
- Iterate all meters and sum their balances
- Add dust accumulator value
- Add gas buffer total
- Add insurance pool value
- Add protocol fee accumulator
- Assert:
token_balance == sum(meter_balances) + dust + gas + insurance + fees
- Implement streaming invariant:
check_streaming_invariant(env) -> Result:
- Sum all active stream rates
- Compare with actual token outflow rate from contract (delta balance / delta time)
- Assert divergence < rounding tolerance
- Add invariant test to every test function: Call
check_invariants(env, before_state, after_state) after each state mutation
- Write fuzz harness with invariant checking: Random operations sequence, check invariants after each operation
- Implement admin privilege invariant: Verify admin cannot directly transfer contract tokens to themselves or bypass fee logic
- Add CI invariant job: Run invariant tests with optimized build for faster execution
Verification & Testing Steps
- Run invariant tests on clean state (should pass)
- Intentionally introduce accounting bug -> invariant test should fail, proving it works
- Run with random fuzz sequences for 1000 iterations, checking invariants after each
- Verify invariants hold after all existing test scenarios
- Measure performance overhead of invariant checking (<2x test execution time)
- Run full test suite with invariants enabled:
cargo test --package utility_contracts -- --include-ignored
Description
The
streaming_invariant_tests.rs(10KB) andstream_balance_property_tests.rs(25KB) test streaming invariants, but there are no invariant tests for the broader contract state. Critical invariants like "total token balance in contract should equal sum of all meter balances + dust accumulator + gas buffers + insurance pool + protocol fees" are not tested. Thebuffer_tests.rs(14KB) tests gas buffer operations but doesn't verify the global token accounting invariant.Invariant gaps:
Technical Context & Impact
contracts/utility_contracts/src/streaming_invariant_tests.rs,contracts/utility_contracts/src/stream_balance_property_tests.rs,contracts/utility_contracts/src/buffer_tests.rsStep-by-Step Implementation Guide
tests/invariant_tests.rswithInvariantCheckerstruct that holds a snapshot of the contract statecheck_total_token_accounting(env) -> Result:token::Client::balancetoken_balance == sum(meter_balances) + dust + gas + insurance + feescheck_streaming_invariant(env) -> Result:check_invariants(env, before_state, after_state)after each state mutationVerification & Testing Steps
cargo test --package utility_contracts -- --include-ignored