Certificates
When a submission is approved and TRUFA scores are assigned, DobValidator issues a certificate -- a cryptographically verifiable attestation that a real-world asset has been reviewed and scored. Certificates are anchored on-chain and can be publicly verified by anyone.
Certificate Structure
Each certificate contains the following data:
| Field | Description | Example |
|---|---|---|
| Certificate Hash | SHA-256 of canonical submission + scores + wallets | 0xa6352db1... |
| Submission ID | Internal reference to the submission record | sub_a8f3c2d1 |
| Owner Wallet | Wallet address of the asset owner | GBDM6KRX... or 0x305DaB... |
| TRUFA Scores | All five dimension scores | {tech: 95, reg: 92, fin: 85, env: 88, overall: 90} |
| Status | Current certificate status | ACTIVE |
| Issued At | Timestamp of certificate issuance | 2026-03-07T14:30:00Z |
| Stellar Tx Hash | Stellar on-chain attestation transaction | null or tx hash |
| EVM Tx Hash | EVM on-chain attestation transaction | 0x5563... |
Hash Computation
The certificate hash is the SHA-256 digest of a canonical JSON object that includes:
- Submission data -- Device info, location, financials (normalized and sorted)
- TRUFA scores -- All five scores as integers
- Wallet addresses -- The owner's wallet address(es)
canonical_json = normalize({
submission: { deviceInfo, location, financials },
scores: { technical, regulatory, financial, environmental, overall },
wallets: { owner: "GBDM6KRX..." }
})
certificate_hash = "0x" + SHA256(canonical_json)
The 0x prefix follows Ethereum convention and is used consistently across both Stellar and EVM attestations.
On-Chain Attestation
Certificate hashes and scores are written to blockchain through a two-step process on the DOBValidator.sol smart contract.
Step 1: Add Project
The validator calls addProject(bytes32 hash) to register the certificate hash on-chain:
function addProject(bytes32 _hash) external onlyRole(VALIDATOR_ROLE) {
// Registers the project hash
// Sets initial state (not yet approved)
}
This creates an on-chain record that the hash exists and has been submitted for validation.
Step 2: Approve with Scores
The validator then calls setProjectApproved(bytes32 hash, TrufaScores scores) to write the TRUFA scores:
function setProjectApproved(
bytes32 _hash,
TrufaScores calldata _scores
) external onlyRole(VALIDATOR_ROLE) {
// Stores TRUFA scores on-chain
// Marks project as approved
}
Once this transaction confirms, the certificate is fully anchored on-chain with its scores.
Supported Networks
| Network | Contract Address | Status |
|---|---|---|
| Ethereum Sepolia | Deployed | Active |
| Polygon Amoy | Deployed | Active |
| Base Sepolia | Deployed | Active |
| Base Mainnet | Deployed | Active |
PDF Generation
Upon approval, a PDF certificate is generated with the following elements:
- Header -- DobProtocol branding and "Certificate of Verification" title
- Asset Summary -- Device name, type, location
- TRUFA Scores -- Visual representation of all four dimensions plus overall
- Certificate Details -- Hash, issuance date, owner wallet
- QR Code -- Links to the public verification URL for instant mobile verification
- Digital Signature -- Cryptographic reference to the on-chain attestation
The QR code encodes the verification URL: https://validator.dobprotocol.com/verify/{certificateHash}
Certificate Statuses
| Status | Description | Transitions From |
|---|---|---|
ACTIVE | Certificate is valid and verifiable | Initial state after approval |
EXPIRED | Certificate has passed its validity period | ACTIVE (automatic) |
REVOKED | Certificate has been explicitly invalidated | ACTIVE (admin action) |
Status Rules
- ACTIVE -- The default state. The certificate is valid, and verification returns a positive result.
- EXPIRED -- Certificates may have a validity period. Once expired, verification still returns the data but indicates the certificate is no longer current.
- REVOKED -- An admin can revoke a certificate if the asset is found to be non-compliant, decommissioned, or fraudulently represented. Revocation is permanent.
Public Verification
Anyone can verify a certificate without authentication through the public verification endpoint:
GET /api/public/certificate/verify/:hash
Response
{
"valid": true,
"certificate": {
"hash": "0xa6352db1...",
"status": "ACTIVE",
"issuedAt": "2026-03-07T14:30:00Z",
"scores": {
"technical": 95,
"regulatory": 92,
"financial": 85,
"environmental": 88,
"overall": 90
},
"asset": {
"deviceName": "AquaPure Water Purifier WP-3000",
"deviceType": "Water Purification System",
"location": "Arica, Chile"
},
"onChain": {
"evmTxHash": "0x5563...",
"stellarTxHash": null,
"network": "Base Mainnet"
}
}
}
Verification Logic
- Look up the certificate by hash in the database
- Check that the status is
ACTIVE - Optionally cross-reference the on-chain record to confirm the hash and scores match
- Return the certificate data with the verification result
Integration with Token Studio
Certificates are linked to distribution pools on Token Studio through the following flow:
- During pool creation -- A
?certificateHash=query parameter pre-fills the certificate selector in the create-pool form. - After pool creation -- Pool creators can link or unlink certificates from the pool dashboard's validation panel.
- API linkage -- The
POST /api/validation/pool/:address/linkendpoint writes the certificate hash and TRUFA score to the pool record.
Pool Fields
| Column | Type | Description |
|---|---|---|
validator_certificate_hash | VARCHAR | The 0x-prefixed certificate hash |
validator_submission_id | VARCHAR | Reference to the submission |
validator_overall_score | INTEGER | TRUFA overall score (0--100) |
validated_at | TIMESTAMP | When the certificate was linked |
validation_status | VARCHAR | 'validated', 'revoked', etc. |
Webhook Notifications
DobValidator can notify Token Studio of certificate status changes via webhook:
POST /api/validation/webhook/status
Headers: x-internal-api-key: <shared secret>
{
"certificateHash": "0xa6352db1...",
"status": "revoked",
"reason": "Asset decommissioned"
}
This allows Token Studio to automatically update pool validation status when a certificate is revoked or expires, without requiring manual intervention.