Skip to main content

EVM Validator Contract

Source on GitHub: github.com/DobprotocolDOBVALIDATOR/distribution-contracts/contracts/DOBValidator.sol

DOBValidator.sol is the on-chain component of the DobValidator platform. It stores submission hashes and TRUFA scores on EVM chains, providing a permanent, tamper-proof record of asset verification results that anyone can query.

Contract Overview

PropertyValue
ContractDOBValidator.sol
Solidity^0.8.20
Access ControlOpenZeppelin AccessControl
Key RoleVALIDATOR_ROLE = keccak256("VALIDATOR_ROLE")
NetworksSepolia, Polygon Amoy, Base Sepolia, Base Mainnet

Access Control

bytes32 public constant VALIDATOR_ROLE = keccak256("VALIDATOR_ROLE");
RolePermissions
DEFAULT_ADMIN_ROLEGrant / revoke roles.
VALIDATOR_ROLEaddProject, setProjectApproved.

The constructor grants both roles to the admin address passed in.

TrufaScores Struct

struct TrufaScores {
uint32 technicalFeasibility;
uint32 regulatoryCompliance;
uint32 financialViability;
uint32 environmentImpact; // note: environmentImpact, not environmental
uint32 overallTrufaScore;
}

Each field is uint32, validated to be <= 100 on-chain. The five fields pack into a single 32-byte storage slot.

Project Struct

struct Project {
bool exists;
bool approved;
address addedBy; // VALIDATOR_ROLE that called addProject
address approvedBy; // VALIDATOR_ROLE that called setProjectApproved
TrufaScores scores;
uint256 addedAt; // block.timestamp on addProject
uint256 approvedAt; // block.timestamp on setProjectApproved (0 until approved)
}

mapping(bytes32 => Project) public projects;

Core Functions

addProject

function addProject(bytes32 projectHash) external onlyRole(VALIDATOR_ROLE);

Registers projectHash as a Pending project. Reverts if the hash already exists. Emits:

event ProjectAdded(bytes32 indexed projectHash, address indexed addedBy, uint256 timestamp);

setProjectApproved

function setProjectApproved(bytes32 projectHash, TrufaScores calldata scores) external onlyRole(VALIDATOR_ROLE);

Approves a previously added project and writes its TRUFA scores. Reverts if any score is > 100, the project does not exist, or it is already approved. Emits:

event ProjectApproved(
bytes32 indexed projectHash,
address indexed approvedBy,
uint32 technicalFeasibility,
uint32 regulatoryCompliance,
uint32 financialViability,
uint32 environmentImpact,
uint32 overallTrufaScore,
uint256 timestamp
);

getProject / isProjectApproved

function getProject(bytes32 projectHash) external view returns (Project memory);
function isProjectApproved(bytes32 projectHash) external view returns (bool);

getProject reverts if the project hash has never been added.

Two-Step Attestation

The deliberate split lets the validator timestamp a submission as soon as it enters review, then publish scores once the review is complete.

Validator: addProject(0xa635...)
--> Project { exists: true, approved: false, addedBy: msg.sender, addedAt: now }

Validator: setProjectApproved(0xa635..., {95, 92, 85, 88, 90})
--> Project { ..., approved: true, approvedBy: msg.sender, scores: {...}, approvedAt: now }

On-Chain Verification (JS)

import { ethers } from 'ethers';

const contract = new ethers.Contract(validatorAddress, abi, provider);
const project = await contract.getProject(certificateHash);

if (project.exists && project.approved) {
const s = project.scores;
console.log('Technical feasibility:', s.technicalFeasibility);
console.log('Regulatory compliance:', s.regulatoryCompliance);
console.log('Financial viability:', s.financialViability);
console.log('Environment impact:', s.environmentImpact);
console.log('Overall TRUFA:', s.overallTrufaScore);
}

Gas Costs

FunctionApproximate gas
addProject~50k (one new storage slot)
setProjectApproved~60k (overwrites the packed scores slot)
getProjectview, free off-chain

Deployed Addresses

TODO: verify and fill in. Addresses are deployed via DOBVALIDATOR/distribution-contracts/scripts/deploy.ts per network.

NetworkChain IDAddress
Ethereum Sepolia11155111TODO
Polygon Amoy80002TODO
Base Sepolia84532TODO
Base Mainnet8453TODO