Skip to content

Development and Testing

RunTimeAdmin edited this page Nov 2, 2026 · 27 revisions

Development & Testing

**Referenced Files in This Document** - [foundry.toml](https://github.com/RunTimeAdmin/Sigvara/blob/main/foundry.toml) - [README.md](https://github.com/RunTimeAdmin/Sigvara/blob/main/README.md) - [Sigvara_Build_Document.md](https://github.com/RunTimeAdmin/Sigvara/blob/main/Sigvara_Build_Document.md) - [test/E2E.t.sol](https://github.com/RunTimeAdmin/Sigvara/blob/main/test/E2E.t.sol) - [test/StakingInvariant.t.sol](https://github.com/RunTimeAdmin/Sigvara/blob/main/test/StakingInvariant.t.sol) - [oracle/package.json](https://github.com/RunTimeAdmin/Sigvara/blob/main/oracle/package.json) - [packages/sdk/package.json](https://github.com/RunTimeAdmin/Sigvara/blob/main/packages/sdk/package.json) - [packages/sdk/vitest.config.ts](https://github.com/RunTimeAdmin/Sigvara/blob/main/packages/sdk/vitest.config.ts)

Table of Contents

  1. Introduction
  2. Project Structure
  3. Core Components
  4. Architecture Overview
  5. Detailed Component Analysis
  6. Dependency Analysis
  7. Performance Considerations
  8. Troubleshooting Guide
  9. Conclusion
  10. Appendices

Introduction

This document provides comprehensive development and testing guidance for Sigvara’s codebase. It covers Foundry setup, project structure, compilation settings, and the full testing infrastructure across Solidity contracts, the oracle service, and the TypeScript SDK. It also explains unit tests, integration tests, fuzzing, invariant testing patterns, test organization with helpers and fixtures, debugging techniques, gas analysis, performance profiling, code style guidelines, pull request workflows, security considerations, and examples of effective testing for smart contracts and oracle services.

Project Structure

The repository is organized into clear layers:

  • On-chain protocol contracts under src/
  • Foundry-based tests under test/, including unit, E2E, upgrade, fork, and invariant suites
  • Oracle service under oracle/ with Node.js modules and tests
  • TypeScript SDK under packages/sdk/ with Vitest tests
  • Deployment scripts under script/
  • Repository checks and tools under scripts/ (including scripts/fetch-deps.sh, which fetches the Solidity dependencies, and scripts/check-docs.mjs) and worked examples under examples/
  • Documentation under docs/ and site assets under site/
  • Archive token-launch contracts under archive/token-launch/
graph TB
A["Repository Root"] --> B["src/ (Solidity contracts)"]
A --> C["test/ (Foundry tests)"]
A --> D["oracle/ (Node.js oracle)"]
A --> E["packages/sdk/ (TypeScript SDK)"]
A --> F["script/ (Deployment scripts)"]
A --> G["docs/ (Protocol documentation)"]
A --> H["site/ (Public site assets)"]
A --> I["archive/token-launch/ (Legacy token contracts)"]
Loading

Diagram sources

Section sources

Core Components

Sigvara’s core on-chain components are:

  • Identity registry managing agent identity, operator control, Ed25519 keys, and status transitions
  • Reputation registry storing computed scores and challenge windows
  • Staking core managing bonds, slashing, unbonding, and slash proceeds distribution
  • Oracle bond contract controlling who can propose reputation updates when enabled

These contracts use UUPS proxies and role-based access control. The README documents their roles and interactions, while the build document provides historical context and interface summaries.

Section sources

Architecture Overview

The system integrates ERC-8004 identity and feedback registries with Sigvara’s computed reputation and staked-slashing layer. The oracle computes normalized scores from payment-backed attestations and community signals, proposes them to the reputation registry, and the slashing committee enforces accountability through staking and slashing.

graph TB
subgraph "Signal Sources"
PY["Payers<br/>signed outcomes (delivered)"]
CA["CounterAudit<br/>seals packets, carries payer outcomes"]
WD["Watchdog scanners<br/>rug / abuse flags"]
end
subgraph "ERC-8004"
EID["Identity Registry"]
EREP["Reputation Registry"]
end
subgraph "Sigvara Protocol"
OR["Reputation Oracle"]
REP["SigvaraReputation"]
ST["SigvaraStaking"]
ID["SigvaraIdentity"]
OB["SigvaraOracleBond"]
end
CONS["SDK Consumers"]
PY --> OR
CA --> OR
WD --> OR
EID --> OR
EREP --> OR
OR --> REP
ST --> REP
ST --> ID
OB --> OR
REP --> CONS
Loading

Diagram sources

Detailed Component Analysis

Foundry Setup and Configuration

Foundry configuration defines source/output directories, library remappings, optimizer settings, solc version, fuzz runs, CI fuzz intensity, filesystem permissions, and RPC endpoints for Arc testnet/mainnet.

Key points:

  • Source directory: src
  • Output directory: out
  • Libraries: lib
  • Remappings include OpenZeppelin contracts and forge-std
  • Optimizer enabled with 200 runs
  • Solidity compiler version 0.8.24
  • EVM version cancun, set explicitly so a Foundry upgrade cannot change what is compiled
  • Fuzz runs: 1000 default, 5000 in CI profile
  • Filesystem read-write permission for deployments directory
  • RPC endpoints for Arc testnet and mainnet
flowchart TD
Start(["Foundry Config"]) --> Src["src = 'src'"]
Start --> Out["out = 'out'"]
Start --> Libs["libs = ['lib']"]
Start --> Remap["Remappings for OpenZeppelin and forge-std"]
Start --> Opt["optimizer = true, runs = 200"]
Start --> Solc["solc_version = '0.8.24'"]
Start --> FS["fs_permissions for './deployments'"]
Start --> Fuzz["fuzz.runs = 1000"]
Start --> CIFuzz["profile.ci fuzz.runs = 5000"]
Start --> RPC["rpc_endpoints arc_testnet / arc_mainnet"]
Loading

Diagram sources

Section sources

Testing Infrastructure Overview

The repository includes three primary test surfaces:

  • Contract tests using Foundry (unit, fuzz, E2E, upgrade, invariants)
  • Oracle tests using Node.js built-in test runner
  • SDK tests using Vitest

Commands:

  • Contracts: forge test and FOUNDRY_PROFILE=ci forge test
  • Oracle: cd oracle && node --test
  • SDK: cd packages/sdk && npx vitest run

The README enumerates these commands and counts, while package manifests define scripts and dependencies. As of 2 November 2026 the contract suite has 724 tests in 32 files (each of the 19 invariants counts once), the oracle suite 852 and the SDK suite 233. Without a fork URL, 712 of the contract tests run and 12 skip, and 8 of the SDK tests, the integration tests, skip without a live deployment. Vitest strips types without checking them, so CI also runs npm run typecheck in packages/sdk, which checks the SDK's tests against its types as well as its sources.

The Solidity dependencies are fetched into lib/ before the first build with sh scripts/fetch-deps.sh. It fetches OpenZeppelin and forge-std each by commit, because lib/ is gitignored and there are no submodules.

Section sources

Unit Tests

Unit tests validate individual contract functions in isolation using Foundry’s in-memory EVM. They do not require external networks or deployed contracts. Two fork suites are the exception: test/SlashDrillFork.t.sol forks Arc testnet on every run, so it needs the arc_testnet endpoint in foundry.toml to answer, and test/SplitAuthorityFork.t.sol skips its twelve tests unless you pass --fork-url https://rpc.testnet.arc.io. Typical usage:

  • Run all contract tests: forge test
  • Increase fuzz density: FOUNDRY_PROFILE=ci forge test

These tests cover identity operations, reputation proposals, staking flows, and edge cases.

Section sources

Integration Tests (E2E)

The E2E suite covers the full agent lifecycle: registration, staking, reputation proposal/finalization, slashing, and zero-reputation enforcement. It deploys mock tokens and proxy implementations, wires roles, and asserts state transitions and distributions.

Key scenarios:

  • Full happy path register → stake → propose/finalize → slash → zero
  • Slash dispute and reinstatement
  • Reputation challenge rejection
  • Unbonding period enforcement
  • Slash sweeping unbonding queue
  • Multiple epochs of score evolution
  • Multiple independent agents
sequenceDiagram
participant Test as "E2EIntegrationTest"
participant Identity as "SigvaraIdentity"
participant Reputation as "SigvaraReputation"
participant Staking as "SigvaraStaking"
participant Token as "MockSVR"
Test->>Token : mint(operator, amount)
Test->>Identity : registerAgent(agentAddress, pubKey, signature)
Test->>Staking : depositStake(didHash, MIN_STAKE)
Test->>Reputation : proposeReputation(didHash, data, evidenceRoot)
Test->>Reputation : finalizeReputation(didHash)
Test->>Staking : initiateSlash(didHash, victim, evidence)
Test->>Staking : executeSlash(didHash)
Staking-->>Token : burn 75%
Staking-->>Victim : credit 25%
Loading

Diagram sources

Section sources

Fuzz Testing

Fuzz testing drives randomized inputs against contract functions to uncover edge cases. The Foundry configuration sets default fuzz runs and a higher CI profile. Use:

  • Default fuzz: forge test
  • CI fuzz intensity: FOUNDRY_PROFILE=ci forge test

The README documents running fuzz at higher intensity.

Section sources

Invariant Testing

Invariant tests assert properties that must hold after any reachable sequence of actions. The suite targets the staking contract with handlers that exercise deposits, withdrawals, slash initiation/dispute/execution, status changes, and time progression.

Important invariants:

  • Custody matches recorded obligations (stake + queued withdrawals + unclaimed proceeds)
  • Token conservation (deposits equal held + claimed + burned + pulled)
  • Slashed agents fully zeroed (no stake, no queue)
  • Burned balance only grows
  • Disputed agents stay bonded
  • Active agents are collateralized (at least minimum stake)

The handler rules on disputes as the admin and also drives expireSlash. A second campaign, OracleBondInvariantTest, covers the operator bond registry with five more invariants: signer mappings stay symmetric, a signer is never also an operator, an address has standing only through a bonded Active operator, nobody is left signing for nobody, and the active count and custody still add up. Run it with forge test --match-contract OracleBondInvariantTest.

Three more suites cover the score store, the fee registry and the identity registry. Each handler keeps a model of what its contract should hold, and fails a campaign both when a call the model says must be refused goes through and when one it says must work is refused, which is how funds or scores get stuck.

  • ReputationInvariantTest (three invariants): the books match the history, so the stored score, its evidence root and its maturity anchor are only what a finalize or a slash left there and a pending proposal is exactly as it was made; no factor is above its cap and a rise is released no faster than the maturity rate allows; and no call broke a rule about who may propose, finalize or reject, and when.
  • EpochFeesInvariantTest (two invariants): custody equals what is owed, each agent's balance equals its history, an agent is charged at most once per epoch, and every distribution splits by its stage.
  • IdentityInvariantTest (three invariants): every identity is what registration and the transitions since left, each operator's list holds exactly the agents that operator holds, a slash is final, nothing returns to PendingBond, and a signature made for another operator, key, chain or registry never registers an agent.

Together the five suites hold 19 invariants. Run them with forge test --match-contract ReputationInvariantTest, EpochFeesInvariantTest and IdentityInvariantTest. scripts/mutation/mutate-invariants.sh breaks the three contracts 113 ways and requires an invariant to fail each time, with the unit tests out of the picture. It caught 109. The four it leaves alive change nothing observable: a bond check backs up two of the checks, and removal falls back to a scan when a recorded position in the operator index is stale.

flowchart TD
Start(["Invariant Suite"]) --> Seed["Seed bonds for agents"]
Seed --> Target["Target handler contract"]
Target --> Actions["Randomized actions:<br/>deposit, withdraw, slash, dispute, resolve, expire, cancel, claim"]
Actions --> Assert["Assert invariants:<br/>custodyMatchesRecordedObligations<br/>tokenConservation<br/>slashedAgentsFullyZeroed<br/>burnedOnlyGrows<br/>disputedAgentsStayBonded<br/>activeAgentsAreCollateralised"]
Loading

Diagram sources

Section sources

Oracle Service Testing

The oracle service is a Node.js application with its own test suite using the built-in test runner. Package scripts define start and test. Dependencies include dotenv and ethers.

Usage:

  • Run oracle tests: cd oracle && node --test

Section sources

SDK Testing

The TypeScript SDK uses Vitest for unit and integration tests. Configuration enables globals and Node environment. Scripts include build, test, and typecheck.

Usage:

  • Run SDK tests: cd packages/sdk && npx vitest run

Section sources

Dependency Analysis

The testing infrastructure depends on:

  • Foundry toolchain for Solidity compilation and testing
  • OpenZeppelin contracts for upgradeable proxies and ERC20 mocks
  • Forge-std for testing utilities
  • Node.js runtime for oracle tests
  • Vitest for SDK tests
graph TB
Foundry["Foundry Toolchain"] --> Contracts["Solidity Contracts"]
Foundry --> Tests["Contract Tests"]
OpenZeppelin["OpenZeppelin Contracts"] --> Contracts
ForgeStd["Forge-Std"] --> Tests
NodeJS["Node.js Runtime"] --> OracleTests["Oracle Tests"]
Vitest["Vitest"] --> SDKTests["SDK Tests"]
Loading

Diagram sources

Section sources

Performance Considerations

  • Compiler optimization: Enabled with 200 runs; adjust based on deployment needs.
  • Fuzz intensity: Default 1000 runs; CI profile increases to 5000 runs for deeper coverage.
  • Gas analysis: Use Foundry’s built-in tools (forge inspect, forge snapshot) to analyze gas usage and regressions.
  • Profiling: Leverage forge test -vvv for verbose output and trace execution paths during failures.
  • Oracle performance: Ensure efficient chain reads and caching strategies; monitor metrics and logs in production.

Troubleshooting Guide

Common issues and resolutions:

  • RPC endpoint misconfiguration: Verify Arc testnet/mainnet URLs in Foundry config.
  • Fee estimation errors: Retry forge script with --legacy if fee estimation behaves unexpectedly.
  • Chain metadata unknown: Avoid adding Etherscan entries for unsupported chain IDs until native support ships.
  • Test failures due to time-sensitive logic: Use vm.warp to advance block timestamps in tests.
  • Role misassignment: Ensure admin grants correct roles to staking core, oracle, and committee addresses. On main the staking-core, committee and slasher roles are administered by UPGRADER_ROLE, which the timelock holds on a real deployment, so the admin alone cannot grant them there.

Section sources

Conclusion

Sigvara’s development and testing infrastructure combines robust Foundry configurations, comprehensive contract tests, fuzzing, invariants, and parallel test suites for the oracle and SDK. Following the documented setup, testing patterns, and security practices ensures reliable development, audit readiness, and safe deployment.

Appendices

Code Style Guidelines

  • Solidity: Follow Foundry conventions, use consistent naming, and keep functions focused.
  • TypeScript: Use strict typing, linting, and Vitest best practices.
  • Node.js: Modularize oracle components, add tests per module, and handle errors gracefully.

Pull Request Processes and Contribution Workflows

  • Branching strategy: Feature branches off main, PRs reviewed before merge.
  • CI checks: Ensure all tests pass (contracts, oracle, SDK, and the simulation plan) along with scripts/check-bytecode.mjs, scripts/check-docs.mjs, scripts/check-authz.mjs, scripts/check-headers.mjs, scripts/check-evidence-fixture.mjs, scripts/check-outcome-vectors.mjs, scripts/check-secrets.mjs, scripts/check-before-renounce.mjs --self-test and Slither, which fails the build on High findings only. check-bytecode.mjs reports a mismatch without failing once main's contract sources have moved past the commit the deployment file records.
  • Documentation: Update relevant docs for protocol changes.
  • Security: Include audit notes and threat model updates where applicable.

Security Considerations

  • Access control: Restrict privileged roles to timelock or multisig on mainnet.
  • Upgradeability: Use UUPS proxies controlled by governance.
  • Reentrancy: Apply guards where necessary.
  • Oracle trust: Validate payment-backed attestations and evidence roots.
  • Slashing fairness: Ensure dispute windows and frozen bonds prevent escape.

Section sources

Audit Preparation Checklist

  • Complete unit, integration, fuzz, and invariant tests.
  • Verify role assignments and upgrade paths.
  • Review oracle validation logic and evidence handling.
  • Confirm slashing distributions and unbonding enforcement.
  • Document known weaknesses and mitigation strategies.

Section sources

Overview

Clone this wiki locally