Repository navigation
Custom Scoring Factors
- Introduction
- Project Structure
- Core Components
- Architecture Overview
- Detailed Component Analysis
- Dependency Analysis
- Performance Considerations
- Troubleshooting Guide
- Conclusion
- Appendices
This document explains how to extend Sigvara’s reputation scoring system with custom factors. It covers the current six-factor architecture, where computation happens off-chain in the oracle and only finalized scores are stored on-chain, and how to add new scoring algorithms by modifying the oracle’s scoring module. It also documents evidence source integration patterns for connecting external data sources and validating incoming attestations, the mathematical foundations of score computation, weight distribution strategies, decay mechanisms, practical examples of custom factors such as social graph analysis or transaction pattern recognition, testing strategies, and performance considerations for real-time computation.
The key design principle is that the oracle computes a deterministic score from verifiable evidence, while the smart contract stores and enforces caps, challenge windows, maturity, and slashing behavior. New factors should be pure functions where possible, consume deterministic inputs, and integrate cleanly into the existing factor pipeline.
Sigvara separates scoring logic from storage:
- The oracle implements evidence intake, normalization, decay, and factor computation.
- The
SigvaraReputationcontract stores proposed and finalized scores, enforces per-factor caps, and exposes matured scores to consumers. - Documentation describes the model, signal topology, and governance around proposals and challenges.
graph TB
subgraph "Oracle"
SC["scoring.js<br/>factor functions"]
EX["external.js<br/>ERC-8004 feedback"]
JO["jobs.js<br/>ERC-8183 jobs"]
ST["store.js<br/>attestations, flags, payments"]
EP["epoch-policy.js<br/>action decisions"]
IN["index.js<br/>epoch orchestration"]
end
subgraph "On-chain"
REP["SigvaraReputation.sol<br/>proposal, finalize, maturity"]
end
SC --> IN
EX --> IN
JO --> IN
ST --> IN
EP --> IN
IN --> REP
Diagram sources
- scoring.js
- external.js
- jobs.js:1-388
- store.js
- epoch-policy.js
- index.js:937-944
- SigvaraReputation.sol
Section sources
The current scoring system has six factors:
- Fee Activity: measures verified payment volume, capped at 20 points.
- Success Rate: measures outcomes signed by the payer or recorded by a credentialed service against total outcome-bearing attestations, capped at 15 points.
- Tenure: measures span of verified paid activity faded by recency, capped at 30 points.
- External Trust: normalizes ERC-8004 feedback, capped at 25 points.
- Community: penalizes unresolved flags, capped at 5 points.
- Propagation: inherits trust from counterparties’ external standing, capped at 5 points.
These factors are computed off-chain and summed to a maximum of 100. The contract validates each factor against its cap before accepting a proposal.
The oracle keeps the six caps in one frozen table, oracle/score-caps.js, which scoring.js, payments.js and external.js all read. score-caps.test.js compares each cap with the matching MAX_*_SCORE constant in SigvaraReputation.sol, so a reweight is one edit there, plus a failing test if the contract was not changed with it.
Section sources
The scoring flow is:
- Evidence collection: attestations, flags, payment events, ERC-8004 feedback, and optional ERC-8183 job verdicts.
- Normalization and decay: convert raw signals into weighted values using shared decay functions.
- Factor computation: compute each factor as a pure function.
- Aggregation: sum factors and clamp totals.
- Proposal: the oracle proposes a score plus an evidence root to the contract.
- Challenge window: the community or committee can reject a bad proposal.
- Finalization: after the window, anyone can finalize; the score becomes spendable over time via maturity.
sequenceDiagram
participant Source as "Evidence Sources"
participant Oracle as "Oracle index.js"
participant Store as "store.js"
participant Scoring as "scoring.js"
participant Contract as "SigvaraReputation.sol"
Source->>Store : Attestations, flags, payments
Oracle->>Store : Load state and scan chain
Oracle->>Scoring : Compute factors
Scoring-->>Oracle : {feeScore, successScore, ageScore, externalScore, communityScore, propagationScore}
Oracle->>Contract : proposeReputation(data, evidenceRoot)
Contract-->>Oracle : PendingScore opened
Note over Contract : Challenge window opens
Oracle->>Contract : finalizeReputation(didHash)
Contract-->>Oracle : ReputationUpdated(totalScore)
Diagram sources
The scoring module defines pure functions for each factor and a central aggregator. This makes factors testable in isolation and ensures determinism across operators.
Key implementation patterns:
- Each factor returns a bounded integer score.
- Time-dependent factors accept explicit clocks to avoid host drift.
- Decay is applied upstream so factor functions receive already-weighted inputs.
- The aggregator sums factors and clamps external and propagation scores to their caps.
flowchart TD
Start(["computeScore"]) --> Fee["Compute feeScore"]
Start --> Success["Compute successScore"]
Start --> Age["Compute ageScore"]
Start --> External["Clamp externalScore"]
Start --> Community["Compute communityScore"]
Start --> Propagation["Clamp propagationScore"]
Fee --> Sum["Sum factors"]
Success --> Sum
Age --> Sum
External --> Sum
Community --> Sum
Propagation --> Sum
Sum --> Return(["Return {factors, total}"])
Diagram sources
Section sources
External trust is normalized from recognized tags in the ERC-8004 registry, counted only from reviewers that pass reviewers.js:3-51: bonded Sigvara agents registered for 30 days, with a matured score of at least 40, that paid the agent, one vote per cluster of reviewers sharing an operator or a funder. The module verifies ownership of the linked identity. CounterAudit feedback uses its own tag, which is not recognised, so it is not counted twice.
Integration steps:
- Configure external RPC and contracts.
- Verify NFT ownership matches expected operator wallet.
- Read clients, last indices, and feedback rows.
- Normalize recognized tags to a rating from 0 to 1, rate each qualifying reviewer by its mean, and weight independent reviewers by how recently each paid.
- Scale mean to the external score cap.
flowchart TD
Init["init(cfg)"] --> Enabled{"Enabled?"}
Enabled --> |No| Zero["externalScore = 0"]
Enabled --> |Yes| Verify["verifyOwnership(agentId, owner)"]
Verify --> Valid{"Owner matches?"}
Valid --> |No| Zero
Valid --> |Yes| Read["readFeedbackRows(agentId)"]
Read --> Normalize["normalize recognized tags"]
Normalize --> Mean["reviewers.scoreFeedback: qualifying reviewers, weighted mean, at most MAX_EXTERNAL_SCORE"]
Mean --> Result["externalScoreFor returns score"]
Diagram sources
Section sources
Job verdicts provide on-chain success/failure signals without self-reporting. The module decodes events, assembles job lifecycles, filters invalid cases, and converts jobs into evidence compatible with the existing merkle leaf format.
Integration steps:
- Enable via registry address and RPC.
- Scan logs for job events.
- Decode and assemble jobs.
- Filter out self-paid, self-evaluated, non-terminal, or missing-settlement jobs.
- Convert to evidence shape with payer, amount, settledAt, and success.
flowchart TD
Scan["scanLogs(registry, blocks)"] --> Decode["decodeLog(log)"]
Decode --> Assemble["assembleJobs(decoded, blockTimes)"]
Assemble --> Filter["rejectionReason(job)"]
Filter --> Keep{"Valid evidence?"}
Keep --> |Yes| ToEvidence["toEvidence(jobs, provider)"]
Keep --> |No| Drop["record dropped reason"]
ToEvidence --> Output["evidence array"]
Diagram sources
Section sources
The store persists attestation outcomes, flags with timestamps, links, cooldowns, and payment events. It provides decayed flag counts, deduplication of settlement transactions, and pruning of old events.
Integration steps:
- Validate and record attestations with cooldowns.
- Record flags with timestamps and decay weights.
- Credit payment events with txHash, amount, payer, and outcome. An outcome is recorded only for a caller holding an oracle token or from the payer's own signed outcome; a stranger's attestation, like a payment found by the chain scan, credits the payment with no outcome, and either can add one later, once.
- Prune old events and flags based on half-life thresholds.
flowchart TD
Input["Attestation / Flag / Payment"] --> Validate["Validate fields"]
Validate --> Dedupe{"Already credited?"}
Dedupe --> |Yes| Reject["Reject duplicate"]
Dedupe --> |No| Persist["Persist to store"]
Persist --> Decay["Apply decay weights"]
Decay --> ScoreInput["Provide decayed inputs to scoring"]
Diagram sources
Section sources
Success rate uses pseudo-observations in the denominator to prevent scale invariance and single-observation dominance. The formula approaches but never reaches the cap, ensuring evidence accumulation matters.
Formula characteristics:
- Denominator includes a prior constant.
- Score increases with both success ratio and total observations.
- Decayed weights reduce both numerator and denominator, causing silence to cost points.
Section sources
Tenure measures the span between first and last verified payment, not calendar age since registration. It applies a logarithmic curve and multiplies by recency to fade abandoned agents.
Curve characteristics:
- Logarithmic growth over days.
- Capped amplitude.
- Recency clamped to 0–1.
- With payment verification off there is no activity data, and it falls back to calendar age for legacy deployments. With verification on, an agent with no payments gets an empty window and scores 0.
Section sources
Weights are distributed to resist wash trading and Sybil attacks:
- Fee and success were reduced to limit easily manufactured activity.
- Tenure and external trust increased because they cannot be shortcut.
- Community and propagation remain small but meaningful.
Caps ensure the total does not exceed 100 and each factor is validated on-chain.
Section sources
Decay is applied uniformly across signals:
- Payments decay by half-life.
- Flags decay faster than payments.
- Decayed weights feed into volume, success ratio, tenure recency, and community penalties.
Shared decay functions ensure consistency across components.
Section sources
To add a custom factor:
- Define a pure function that takes deterministic inputs and returns a bounded score.
- Integrate evidence collection if needed (e.g., external API, chain logs).
- Normalize and validate inputs.
- Apply decay if appropriate.
- Add the factor to the aggregation step in
computeScore. - Update the contract’s
ReputationDatastruct and caps if adding a new slot, and the matching entry inoracle/score-caps.js. - Add tests covering edge cases, bounds, and determinism.
classDiagram
class CustomFactor {
+compute(input) number
+validate(input) bool
+decay(value, timestamp) number
}
class ScoringModule {
+computeScore(options) object
+feeScore()
+successScore()
+ageScore()
+communityScore()
+customFactor()
}
class EvidenceSource {
+fetchData() array
+normalize(rows) array
+verifyOwnership() bool
}
CustomFactor --> EvidenceSource : "consumes"
ScoringModule --> CustomFactor : "calls"
Diagram sources
Section sources
A social graph factor could measure how many distinct counterparties have interacted with an agent, weighted by their own external standing. Inputs include counterparty addresses, their ERC-8004 external scores, and interaction frequency.
Implementation notes:
- Use unique counterparty count rather than volume to avoid amplification.
- Cap contribution per counterparty.
- Apply decay to older interactions.
- Ensure no reflexivity: do not inherit from the agent itself.
A pattern recognition factor could detect consistent behavior such as regular settlement intervals, diverse asset usage, or low volatility in trade sizes. Inputs include payment timestamps, amounts, assets, and counterparties.
Implementation notes:
- Use statistical measures like variance, autocorrelation, or entropy.
- Normalize to 0–1 range.
- Apply decay to recent anomalies differently than long-term trends.
- Guard against gaming by requiring minimum observation windows.
Domain-specific signals might include compliance checks, regulatory status, or industry certifications. Inputs come from external registries or attestations.
Implementation notes:
- Treat signals as binary or graded trust indicators.
- Require verification of source authenticity.
- Exclude self-reported signals unless cryptographically backed.
- Clamp scores to avoid dominating other factors.
Section sources
Each factor should have unit tests covering:
- Boundary conditions (zero, negative, overflow).
- Monotonicity (inputs increase → score does not decrease).
- Caps and floors.
- Decay behavior.
- Determinism with explicit clocks.
Existing tests demonstrate these patterns for fee, success, age, community, and aggregation.
Section sources
Test external feedback normalization, ownership verification, and error handling. Test job decoding, assembly, filtering, and conversion to evidence.
Section sources
Verify that proposals with out-of-range factors revert, challenge windows work, finalization updates matured scores, and slashing zeroes everything.
Section sources
- Prefer pure functions for factors to enable caching and parallel evaluation.
- Chunk external reads and job scans to respect RPC limits.
- Use shared decay functions to avoid duplication.
- Prune old events and flags to keep state size bounded.
- Thread chain timestamps through scoring to avoid host clock drift.
- Use deterministic inputs for all time-dependent calculations.
- Maintain divergence tolerance for float drift while aiming for fixed-point arithmetic in the future.
Section sources
graph LR
Index["index.js"] --> Scoring["scoring.js"]
Index --> Store["store.js"]
Index --> External["external.js"]
Index --> Jobs["jobs.js"]
Index --> EpochPolicy["epoch-policy.js"]
External --> Index
Jobs --> Index
Store --> Index
EpochPolicy --> Index
Index --> Contract["SigvaraReputation.sol"]
Diagram sources
- index.js:937-944
- scoring.js
- store.js
- external.js
- jobs.js:1-388
- epoch-policy.js
- SigvaraReputation.sol
Section sources
- Keep factor functions pure and side-effect-free.
- Cache normalized external feedback when safe.
- Use chunked I/O for chain scans.
- Prune old state to prevent unbounded growth.
- Measure latency of external RPC calls and set timeouts.
- Avoid heavy computations inside hot paths; precompute where possible.
Common issues and resolutions:
- External feed unreachable: check RPC configuration and chain ID resolution.
- Ownership mismatch: verify NFT owner matches expected operator wallet.
- Duplicate attestations: ensure settlement hashes are deduplicated per recipient.
- Divergence between operators: inspect per-factor deltas and evidence roots.
- State persistence failures: monitor health endpoint and file system permissions.
Section sources
Extending Sigvara’s reputation scoring system requires careful integration of evidence sources, pure factor functions, and robust testing. The current architecture supports adding custom factors while maintaining determinism, decay, and on-chain validation. By following the extension patterns and considering performance and security implications, you can implement domain-specific trust signals, social graph analysis, or transaction pattern recognition without compromising the integrity of the scoring pipeline.
| Factor | Max Points | Source | Formula Notes |
|---|---|---|---|
| Fee Activity | 20 | Verified payment volume | Decayed volume per payer, capped |
| Success Rate | 15 | Outcomes signed by the payer or reported by a credentialed service | Ratio with pseudo-observations |
| Tenure | 30 | Span of verified activity | Logarithmic curve × recency |
| External Trust | 25 | ERC-8004 feedback | Normalized tag mean scaled to cap |
| Community | 5 | Unresolved flags | Linear penalty with decay |
| Propagation | 5 | Counterparty external standing | Pro-rated by counterparty external standing |
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