Repository navigation
Development and Testing
- Introduction
- Project Structure
- Core Components
- Architecture Overview
- Detailed Component Analysis
- Dependency Analysis
- Performance Considerations
- Troubleshooting Guide
- Conclusion
- Appendices
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.
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/(includingscripts/fetch-deps.sh, which fetches the Solidity dependencies, andscripts/check-docs.mjs) and worked examples underexamples/ - Documentation under
docs/and site assets undersite/ - 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)"]
Diagram sources
Section sources
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
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
Diagram sources
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"]
Diagram sources
Section sources
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 testandFOUNDRY_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 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
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%
Diagram sources
Section sources
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 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"]
Diagram sources
Section sources
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
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
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"]
Diagram sources
Section sources
- 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 -vvvfor verbose output and trace execution paths during failures. - Oracle performance: Ensure efficient chain reads and caching strategies; monitor metrics and logs in production.
Common issues and resolutions:
- RPC endpoint misconfiguration: Verify Arc testnet/mainnet URLs in Foundry config.
- Fee estimation errors: Retry
forge scriptwith--legacyif 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.warpto 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
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.
- 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.
- 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-testand Slither, which fails the build on High findings only.check-bytecode.mjsreports 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.
- 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
- 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
- Agent Registration and Lifecycle
- Contract Overview and Architecture
- Economic Security Model and Incentives
- Evidence Verification and Merkle Proofs
- Key Management and Rotation
- Maturity Mechanism and Score Release
- Proposal Workflow and Challenge System
- Score Storage and Data Model
- SigvaraIdentity Contract
- SigvaraOracleBond Contract
- SigvaraReputation Contract
- SigvaraStaking Contract
- Slashing Lifecycle and Dispute Resolution
- Stake Management Functions
- Status Management and Control
- Token and Fee Contracts
- Unbonding Period and Withdrawal Security
- Anti-Manipulation and Security Measures
- Community Flag Processing
- Evidence Sources and Verification
- External Trust Integration
- Merkle Proof System
- Oracle Score Computation
- Payment-Backed Attestations
- Scoring Model and Formulas
- Agent Creation and Key Management
- Agent Operations
- Agent Registration Workflow
- Challenge-Response Authentication
- Gate Access Control
- Integration Patterns and Examples
- SDK Overview and Setup
- Verifier Functions