Skip to main content

DeedRegistry

UUPS upgradeable contract that registers verified forest deeds on-chain and manages the BCO supply through minting and burning.

PropertyValue
Solidity0.8.28
ProxyUUPS (EIP-1822)
AddressTPw2dKZcVwqCKDNCQbEwRory1xKqj6zSj1
Storage Gap__gap[48] reserved for upgrades

Roles

RoleAssigned ToPurpose
DEFAULT_ADMIN_ROLEMulti-sig 3/5Manage roles, configure limits
REGISTRAR_ROLEMulti-sig 3/5Register and deactivate deeds
PAUSER_ROLEMulti-sig 3/5Emergency pause
UPGRADER_ROLEMulti-sig via timelockAuthorize upgrades

Data Structures

Deed

struct Deed {
bytes32 id; // Unique deed identifier
uint256 areaInSquareMeters;
string geolocation; // GPS coordinates or boundary description
string documentHash; // Off-chain document reference
uint48 registeredAt; // Timestamp of registration
uint48 deactivatedAt; // Timestamp of deactivation (0 if active)
DeedStatus status; // Active or Deactivated
}

DeedStatus

enum DeedStatus {
Active, // Deed is valid, BCO is minted
Deactivated // Deed is invalid, BCO is burned
}

Key Functions

Deed Management

/// @notice Registers a new forest deed and mints BCO to treasury.
/// @dev Only REGISTRAR_ROLE. Subject to rate limits.
function registerDeed(
bytes32 id,
uint256 areaM2,
string calldata geolocation,
string calldata documentHash
) external;

/// @notice Deactivates a deed and burns the equivalent BCO.
/// @dev Only REGISTRAR_ROLE. Company must pre-approve the burn amount.
function deactivateDeed(bytes32 deedId, string calldata reason) external;

/// @notice Updates IPFS documents of an existing active deed.
/// @dev Only REGISTRAR_ROLE.
function updateDocuments(
bytes32 deedId,
string calldata newDocumentHash,
string calldata reason
) external;

View Functions

function getDeed(bytes32 id) external view returns (Deed memory);
function totalDeedCount() external view returns (uint256);
function activeDeedCount() external view returns (uint256);
function totalActiveArea() external view returns (uint256);
function verifyInvariant() external view returns (bool);
function todayRegistrations() external view returns (uint256);
function getDeedIdByIndex(uint256 index) external view returns (bytes32);
function getDeedIds(uint256 offset, uint256 limit) external view returns (bytes32[] memory);

/// @notice Public document verification — anyone can verify a deed's document.
function verifyDocument(
bytes32 deedId,
string calldata documentHash
) external view returns (bool isValid, Deed memory deed);

Configuration

/// @notice Updates rate limits. Admin only.
function setRateLimits(uint256 newMaxDaily, uint256 newMaxArea) external;

/// @notice Sets the timelock controller address.
/// @dev Protected by progressive timelock (dual auth: admin OR timelock).
function setTimelock(address newTimelock) external;

/// @notice Sets the supply threshold for direct upgrades.
/// @dev Protected by progressive timelock (dual auth: admin OR timelock).
function setDirectUpgradeSupplyLimit(uint256 newLimit) external;

Recovery

function recoverNative() external;
function recoverERC20(address token, uint256 amount) external;

Rate Limits

ParameterDefaultConstraints
Max deeds per day10Min 1
Max area per deed10,000,000 m²Min 1
Max string length512 bytesGeolocation and documentHash

Events

event DeedRegistered(bytes32 indexed deedId, uint256 areaInSquareMeters, uint256 timestamp);
event DeedDeactivated(bytes32 indexed deedId, uint256 timestamp);
event RateLimitsUpdated(uint256 maxDaily, uint256 maxArea);
event TimelockUpdated(address indexed oldTimelock, address indexed newTimelock);

Invariant

After every registerDeed() and deactivateDeed():

BCOToken.totalSupply() == DeedRegistry.totalActiveArea() × 10¹⁸

This is enforced by the contract logic and verified by verifyInvariant().