Repository navigation
Evidence Sources and Verification
- Introduction
- Project Structure
- Core Components
- Architecture Overview
- Detailed Component Analysis
- Dependency Analysis
- Performance Considerations
- Troubleshooting Guide
- Conclusion
This document explains how Sigvara’s reputation system collects, verifies, and commits evidence for agent reputation. It focuses on:
- Payment-backed attestations and settlement verification
- Payer identity extraction from transfer logs
- Anti-fraud controls such as self-payment detection and per-payer caps
- External trust integration through ERC-8004 feedback
- Community flag processing and governance
- The Merkle tree proof system for evidence commitment and verification
- Counterparty validation, diversity requirements, and manipulation prevention
The system separates computation from storage: the oracle computes scores off-chain, while the on-chain contract stores finalized scores, pending proposals, challenge windows, and Merkle roots over evidence.
Evidence flows from on-chain payment logs and external registries into the oracle, which computes a six-factor score and proposes it to SigvaraReputation. Consumers read the matured score and can verify individual evidence leaves against the committed root.
graph TB
subgraph "On-chain signals"
CH["EVM chain<br/>Transfer logs"]
EREP["ERC-8004 Reputation Registry<br/>raw feedback"]
ID["SigvaraIdentity<br/>agent status + stake view"]
end
subgraph "Oracle"
PAY["payments.js<br/>settlement verification"]
MERKLE["merkle.js<br/>evidence leaves + Merkle root"]
SCORE["scoring.js<br/>six-factor scoring"]
end
subgraph "Contracts"
REP["SigvaraReputation.sol<br/>propose / finalize / verifyEvidence"]
STAKING["SigvaraStaking (external)<br/>slash → zero score"]
end
CH --> PAY
EREP --> SCORE
ID --> SCORE
PAY --> SCORE
SCORE --> REP
REP --> MERKLE
STAKING --> REP
Diagram sources
- payments.js:167-272
- merkle.js:78-204
- scoring.js:130-155
- SigvaraReputation.sol:378-504
- SigvaraIdentity.sol:534-545
Section sources
- Payment verification: Validates settlement transactions, extracts payer from transfer logs, enforces minimum amount and confirmations, and timestamps events by block time.
-
Pulled payments: When
PAYMENT_SCAN_ENABLED=1, each operator scansTransferlogs to registered agent addresses itself and credits what it finds with no outcome (ADR 0003)./atteststays as a hint and as the only carrier of outcomes. - Anti-fraud controls: Rejects self-payments, limits per-payer contribution, decays volume and success evidence, and uses maturity to prevent farm-and-cash-out.
- External trust: Normalizes ERC-8004 feedback into a capped external score. CounterAudit's own tag is not recognised, so its feedback is not counted twice.
-
Community flags: Unresolved flags reduce the community factor; flags are raised by credentialed services through
POST /flag, separate from slashing. - Merkle evidence: Each proposal carries a Merkle root over evidence leaves; verifiers rebuild leaves from chain data, taking the outcome from the oracle, and check them against the contract-stored root.
- Counterparty validation: Per-payer caps scale with counterparty standing; propagation grants points only for counterparties with external trust, gated by maturity.
Section sources
- payment-backed-attestations.md:24-78
- payment-backed-attestations.md:179-197
- reputation-model.md:21-49
- reputation-model.md:132-149
- reputation-model.md:151-173
- reputation-model.md:177-225
- merkle.js:78-204
- SigvaraReputation.sol:761-769
The reputation pipeline is designed so that anyone can independently verify the inputs used to compute a score without trusting the oracle’s internal state file.
sequenceDiagram
participant Client as "Client"
participant Oracle as "Oracle"
participant Chain as "EVM Chain"
participant Contract as "SigvaraReputation"
Client->>Oracle : POST /attest with txHash
Oracle->>Chain : getTransactionReceipt(txHash)
Chain-->>Oracle : receipt + logs
Oracle->>Chain : getBlock(blockNumber)
Chain-->>Oracle : block timestamp
Oracle->>Oracle : extract payer from Transfer log
Oracle->>Oracle : apply decay, caps, self-payment checks
Oracle->>Contract : proposeReputation(didHash, data, evidenceRoot)
Contract-->>Client : ScoreProposed event
Note over Client,Contract : Challenge window opens
Client->>Contract : verifyEvidence(didHash, leaf, proof)
Contract-->>Client : bool
Diagram sources
Attestations now require a real settlement transaction. The oracle:
- Reads the agent address from the identity registry
- Fetches the transaction receipt and scans for accepted asset transfers to the agent
- Enforces the minimum amount on each sender (a zero-value transfer never counts) and the minimum confirmations
- Reads each qualifying sender from the transfer logs as its own payer; the largest contributor names the attestation
- Records the settlement per transaction, agent and sender to prevent replay
- Stamps evidence with the block timestamp, not submission time
- Computes fee activity from accumulated, decayed volume
- Records an outcome only when the caller holds an oracle token; otherwise it credits the payment with none
flowchart TD
Start(["Attestation request"]) --> ValidateTx["Validate txHash format"]
ValidateTx --> GetReceipt["Fetch receipt"]
GetReceipt --> ReceiptOk{"Receipt exists and succeeded?"}
ReceiptOk --> |No| RpcError["Return RPC error or rejection"]
ReceiptOk --> CheckConfirmations["Check confirmations"]
CheckConfirmations --> Confirmed{"Enough confirmations?"}
Confirmed --> |No| Unconfirmed["Reject unconfirmed"]
Confirmed --> ScanTransfers["Scan Transfer logs for asset credit to agent"]
ScanTransfers --> CreditsFound{"Any credits?"}
CreditsFound --> |No| NoTransfer["Reject no transfer"]
CreditsFound --> GroupBySender["Group credits by sender"]
GroupBySender --> MinAmount{"Any sender above zero and at the minimum amount?"}
MinAmount --> |No| BelowMin["Reject below minimum"]
MinAmount --> BlockTime["Read block timestamp"]
BlockTime --> SelfCheck{"Self-payment?"}
SelfCheck --> |Yes| SelfPay["Reject self_payment"]
SelfCheck --> Dedupe["Deduplicate by (tx, agent, sender)"]
Dedupe --> StoreEvent["Store settlement time in ms, leaf encodes seconds"]
StoreEvent --> End(["Verified payment event"])
Diagram sources
Section sources
- payment-backed-attestations.md:24-78
- payment-backed-attestations.md:94-140
- payments.js:46-104
- payments.js:167-272
- Payer identity: Taken from the transfer logs, not from the caller-supplied attester field. Each qualifying sender is its own payer, and the largest contributor names the attestation.
- Self-payment detection: Refuses payments where the payer equals the operator or agent address.
- Per-payer cap: Limits each counterparty’s contribution to feeScore and attestation weight; trusted counterparties receive a scaled multiplier based on their external standing.
- Decay: Volume and success evidence decay by half-life; stale evidence cannot maintain a score indefinitely.
- Outcome handling: Pulled payments, and payments attested without an oracle token, carry no outcome and are excluded from both sides of the success ratio. An attested outcome goes on the largest leg alone.
flowchart TD
A["Grouped evidence by payer"] --> B["Compute decayed volume and weight"]
B --> C["Apply per-payer cap"]
C --> D["Scale successes proportionally when capped"]
D --> E["Exclude pulled payments from success ratio"]
E --> F["Aggregate diversified volume and attestations"]
Diagram sources
Section sources
- ERC-8004 provides canonical identity and raw signed feedback.
- The oracle reads linked agent feedback, normalizes recognized rating dimensions, and scales the mean to a capped external score.
- CounterAudit publishes under its own
counteraudittag, which the normalizer does not recognise, so its feedback is not counted twice: outcomes already feed the success factor directly. - Propagation grants up to 5 points based on counterparties’ external standing, pro-rated and capped, using matured totals to damp reflexivity.
graph LR
LINK["Operator links Sigvara agent to ERC-8004 identity"] --> READ["Oracle reads ERC-8004 feedback"]
READ --> NORMALIZE["Normalize recognized tags"]
NORMALIZE --> SCALE["Scale to externalScore cap"]
SCALE --> SCORE["Include in computeScore"]
CA["CounterAudit outcomes"] --> EXCLUDE["Own tag, not recognised by the normalizer"]
EXCLUDE --> SCORE
Diagram sources
Section sources
- Community factor starts at 5 points and decreases with unresolved flags.
- Flags are raised by credentialed services through
POST /flag, separate from slashing, and cleared withPOST /flag/resolve. - Decay makes flag penalties gradual; flooring ensures integer scores.
flowchart TD
Flags["Unresolved flags"] --> Penalty["Penalty = flags × 2"]
Penalty --> Cap["Cap penalty at 5"]
Cap --> Community["communityScore = max(0, floor(5 - penalty))"]
Diagram sources
Section sources
Each proposal includes a Merkle root over evidence leaves. Verifiers:
- Rebuild leaves from chain data (txHash, payer, amount, settledAt in seconds) and the outcome code the oracle reports
- Verify the leaf against the contract-stored root using OpenZeppelin’s MerkleProof
- Use sorted-pair hashing and promote odd nodes to prevent malleability
classDiagram
class Merkle {
+leafFor(event) bytes32
+buildTree(events) object
+rootFor(events) bytes32
+proofFor(tree, index) bytes32[]
+verifyProof(leaf, proof, root) bool
+hashPair(a, b) bytes32
+settledSeconds(event) number
+outcomeCode(success) uint8
}
class SigvaraReputation {
+evidenceRoots[didHash] bytes32
+verifyEvidence(didHash, leaf, proof) bool
}
Merkle --> SigvaraReputation : "verifies leaves against root"
Diagram sources
Section sources
- Self-payment refusal: Prevents trivial wash attempts using operator or agent addresses.
- Per-payer cap: Limits contribution to feeScore and attestation weight; trusted counterparties gain a multiplier based on external standing.
- Diversity requirement: Reaching the feeScore cap requires multiple distinct payers; at the default of 4 points per payer it takes five payers with no standing of their own, and fewer when the payers are trusted (down to three at full standing); the exact number depends on configuration.
- Propagation gating: Only counterparties with external trust contribute to propagation; unknown parties count as zero. A counterparty the node could not get an answer for (throttled, timed out or dropped) is retried, and if the read still fails the agent is skipped for that epoch.
flowchart TD
P["Payer evidence"] --> S["Self-payment check"]
S --> |Pass| C["Apply per-payer cap"]
C --> T["Scale cap by trusted counterparty standing"]
T --> D["Count distinct counterparties"]
D --> G["Gate propagation on external trust"]
Diagram sources
Section sources
The oracle depends on chain data and external registries; the contract depends on identity and optional operator bonding.
graph TB
PAY["payments.js"] --> CH["EVM provider"]
PAY --> CFG["Environment config"]
MERKLE["merkle.js"] --> ETH["ethers"]
SCORE["scoring.js"] --> PAY
SCORE --> EXT["ERC-8004 feedback"]
REP["SigvaraReputation.sol"] --> ID["SigvaraIdentity.sol"]
REP --> OP["IOperatorSet (optional)"]
Diagram sources
- payments.js:28-104
- merkle.js:18
- scoring.js:130-155
- SigvaraReputation.sol:12
- SigvaraReputation.sol:180-197
Section sources
- payments.js:28-104
- merkle.js:18
- scoring.js:130-155
- SigvaraReputation.sol:12
- SigvaraReputation.sol:180-197
- Decay arithmetic: Uses scaled integers to preserve precision with BigInt amounts and avoid float drift.
- Event pruning: Leaves with negligible weight are pruned once per epoch to prevent unbounded state growth.
-
Scanning cost: Pulling payment evidence increases RPC load; backoff and chunking mitigate rate limits. The scan also spaces its
getLogscalls (PAYMENT_SCAN_PACE_MS, 500 ms by default) and, when it credits nothing, re-runs its filter against a settlement it already holds. A failed canary holds the checkpoint, so the range is scanned again at the next epoch. - Maturity: Read-time extrapolation avoids reliance on oracle liveness for score accrual.
Common issues and resolutions:
- RPC failures: Treat as transient errors; do not interpret as rejected attestations.
- Unconfirmed transactions: Require configured confirmation depth before acceptance.
-
Missing asset configuration: In required mode, a missing
PAYMENT_ASSET, or aPAYMENT_MIN_AMOUNTof 0, stops startup. - Outcome mismatch: Ensure settledAt is in seconds and outcome uses the three-state code to avoid root mismatches.
- Duplicate settlement: Deduplication key includes transaction, agent, and sender to handle batch transfers.
Section sources
- payment-backed-attestations.md:125-140
- payments.js:167-272
- merkle.js:20-40
- merkle.js:72-76
- 0003-evidence-intake.md:156-180
Sigvara’s evidence system ties reputation to verifiable on-chain payments, external trust, and community flags. Payment verification anchors attestations to real economic activity, anti-fraud controls limit manipulation, and the Merkle proof system makes the oracle’s inputs auditable. External trust integration and propagation ensure that reputation reflects broader ecosystem standing while resisting reflexivity and Sybil amplification. Together, these mechanisms make reputation costly to fake, perishable over time, and transparently verifiable.
- 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