Skip to main content

AssetRegistry

AssetRegistry.sol is the on-chain ledger for Real-World Asset certificates. Registry partners submit verified certificates here; governance signers approve them; the oracle assigns quality scores. Once approved, a certificate can back a MultiSigGovernance mint proposal.

All contracts are UUPS upgradeable proxies. Source: contracts/core/AssetRegistry.sol.


Roles

Rolekeccak256 constantWho holds itWhat it allows
DEFAULT_ADMIN_ROLE(OZ default)Deployer / admin multisigGrant/revoke all roles
ADMIN_ROLEkeccak256("ADMIN_ROLE")Oracle service accountsetQualityScore, allocateVolume, retireCertificate, setExternalId, upgrades
REGISTRY_ROLEkeccak256("REGISTRY_ROLE")Verified registry walletssubmitCertificate, approveCertificate
ROLE_MANAGERkeccak256("ROLE_MANAGER")AdminGrant/revoke REGISTRY_ROLE

REGISTRY_ROLE is administered by ROLE_MANAGER, not by DEFAULT_ADMIN_ROLE. This lets the admin grant registry access without touching the root role.


Certificate Struct

struct Certificate {
string serialNumber; // Unique registry identifier (e.g. "VCS-2024-001-001")
string projectId; // Project identifier from the registry
uint8 assetType; // Asset type constant (0–9, 255)
string assetMetadata; // IPFS CID of the metadata JSON
uint256 vintage; // Year the environmental benefit was generated
uint256 volume; // Total units (e.g. tCO2e for carbon)
uint256 volumeAvailable; // Units not yet tokenized
string unitOfMeasurement; // "tCO2e", "kg", "acres", "kWh", etc.
address registry; // Submitting wallet address
uint256 submittedAt; // Unix timestamp of submission
uint256 approvedAt; // Unix timestamp of final approval (0 until approved)
bool isApproved; // True once 3-of-5 approvals received
bool isRetired; // True once permanently retired
string externalId; // External DB reference for duplicate prevention
uint8 qualityScore; // 0–100 score assigned by oracle after approval
string ipfsHash; // IPFS CID of supporting documents
}

Asset Type IDs

IDConstantDescription
0CARBON_CREDITCarbon offsets (tCO₂e)
1PLASTIC_CREDITPlastic waste credits
2NITROGEN_CREDITNitrogen reduction credits
3PHOSPHORUS_CREDITPhosphorus reduction credits
4AGRICULTURAL_LANDAgricultural land rights
5MINING_RIGHTSMining rights
6WATER_RIGHTSWater rights
7RENEWABLE_ENERGYRECs / renewable energy certificates
8FORESTRYForestry credits
9BIODIVERSITY_CREDITBiodiversity net gain units
255OTHEROther/custom asset type

Key Functions

submitCertificate

function submitCertificate(
string memory _serialNumber,
string memory _projectId,
uint8 _assetType,
string memory _assetMetadata, // IPFS CID
uint256 _vintage,
uint256 _volume,
string memory _unitOfMeasurement,
string memory _ipfsHash
) external onlyRole(REGISTRY_ROLE) onlyActiveAccount nonReentrant

Submits a new certificate. Requirements:

  • Caller must hold REGISTRY_ROLE and be active in AccountManager.
  • _serialNumber must not already exist.
  • _volume > 0, vintage between 2000 and current year + 1.
  • Valid asset type (0–9 or 255).

On success, the certificate is stored with isApproved = false and approvalCount = 0. Emits CertificateSubmitted.


approveCertificate

function approveCertificate(string memory _serialNumber)
external onlyRole(REGISTRY_ROLE) onlyActiveAccount nonReentrant

Casts one approval vote. Any wallet with REGISTRY_ROLE and active status may approve. Each wallet can only vote once per certificate. When approvalCount >= REQUIRED_APPROVALS (3), the certificate is marked isApproved = true and approvedAt is set. Emits CertificateApproved and (if finalized) CertificateFinalized.

Required approvals: 3-of-5 (REQUIRED_APPROVALS = 3)


setQualityScore

function setQualityScore(string memory _serialNumber, uint8 _qualityScore)
external onlyRole(ADMIN_ROLE)

Called by the oracle after running quality assessment. Certificate must be approved. Score must be 0–100. Emits QualityScoreUpdated.


allocateVolume

function allocateVolume(string memory _serialNumber, uint256 _volume)
external onlyRole(ADMIN_ROLE) nonReentrant returns (uint256)

Deducts _volume from volumeAvailable. Called by the oracle when a mint proposal is executed, to track how many units have been tokenized. Reverts if insufficient volume remains. Emits VolumeAllocated.


retireCertificate

function retireCertificate(string memory _serialNumber)
external onlyRole(ADMIN_ROLE)

Permanently marks a certificate as retired (isRetired = true). Retired certificates are excluded from the registry explorer and cannot have further volume allocated. Emits CertificateRetired.


getCertificate

function getCertificate(string memory _serialNumber)
external view returns (Certificate memory)

Returns the full Certificate struct for a serial number. Reverts if not found.


getCertificatesByRegistry

function getCertificatesByRegistry(address _registry)
external view returns (string[] memory)

Returns all serial numbers submitted by a registry address. Note: includes retired and unapproved certificates — filter on isRetired / isApproved when consuming.


getCertificatesByAssetType

function getCertificatesByAssetType(uint8 _assetType)
external view returns (string[] memory)

Returns all serial numbers for a given asset type ID.


updateAssetMetadata / updateIPFSHash

function updateAssetMetadata(string memory _serialNumber, string memory _assetMetadata) external nonReentrant
function updateIPFSHash(string memory _serialNumber, string memory _ipfsHash) external nonReentrant

Can be called by the submitting registry wallet or ADMIN_ROLE. Used to correct metadata or supporting documents after submission.


Events

EventWhen emitted
CertificateSubmitted(serialNumber, projectId, assetType, registry, volume, vintage)submitCertificate succeeds
CertificateApproved(serialNumber, approver, currentApprovals)Each approval vote
CertificateFinalized(serialNumber, approvedAt)3rd approval received
CertificateRetired(serialNumber, volume)retireCertificate
VolumeAllocated(serialNumber, volume, volumeRemaining)allocateVolume
QualityScoreUpdated(serialNumber, qualityScore)setQualityScore
AssetMetadataUpdated(serialNumber, assetMetadata)updateAssetMetadata
IPFSHashSet(serialNumber, ipfsHash)updateIPFSHash
AccountManagerSet(accountManager)setAccountManager

AccountManager integration

When an AccountManager address is set, every call to submitCertificate and approveCertificate checks that the caller is ACTIVE and not SUSPENDED. When accountManager == address(0) (open mode), the check is skipped — used during testnet setup before accounts are registered.


Certificate Approval Flow

Registry wallet                AssetRegistry              Oracle service
│ │ │
│── submitCertificate() ──────>│ │
│ │ CertificateSubmitted │
│ │ │
│── approveCertificate() ─────>│ (repeat ×3) │
│ │ CertificateFinalized │
│ │ │
│ │<── assessQuality() ─────│ (off-chain → QualityAssessment)
│ │<── setQualityScore() ───│
│ │ │
│ │<── createProposal() ────│ (MultiSigGovernance)
│ │<── allocateVolume() ────│ (after proposal execution)

UUPS Upgrade

_authorizeUpgrade requires ADMIN_ROLE. All upgrades must be performed through the UUPS proxy pattern via upgradeToAndCall.