The Deed track
The Deed track is the part of the Clear Protocol for real-world assets. A T-Deed is an ERC-721
token from DeedNFT (name DeedNFT, symbol DEED) that stands for one asset: land, a vehicle, an
estate or a piece of commercial equipment. Its description lives on-chain as traits. A validator
contract checks it against criteria for its asset type and records the result on the token. A
validated land or estate deed can be split into ERC-1155 units, and a deed can be locked against an
ERC-20 share token.
The Deed track stands on its own. No contract outside it reads DeedNFT, and the only piece it
shares with the rest of the protocol is the optional TokenRegistry lookup for payment tokens
(token-registry.md). In the app's language the Clear Deed is, on the
chain, a T-Deed (glossary). No service mints T-Deeds yet.
Deployed addresses are in the root README.md (Deployed
addresses). Each contract's functions, roles and events are in
smart-contracts.md.
DeedNFT.solValidator.solValidatorRegistry.solVALIDATOR_ROLE on DeedNFTFundManager.solMetadataRenderer.soltokenURI for a deed from its traits plus stored features, condition, legal details, documents and gallerySubdivide.solFractionalize.solFractionToken.solFractionTokenFactory.solFractionToken for each fraction. Only Fractionalize may call itValidatorFactory.solcreateValidator always revertsHow the contracts connect
DeedNFT is the hub; everything else either checks it or writes to it through a role.
The T-Deed. One token for each asset
- Minting asks the validator and the registry.
DeedNFT.mintAssetrequiresValidatorRegistry.isValidatorActive, then asks the chosenValidatorforsupportsAssetType,defaultOperatingAgreementand, if aFundManageris set,getServiceFee. - The registry hands out the validator role.
ValidatorRegistry.updateValidatorStatusandremoveValidatorcallDeedNFT.addValidator/removeValidatorso that the active validators holdVALIDATOR_ROLEthere and inactive ones do not. They also callFundManager.updateValidatorRoles, which gives each active validatorFEE_MANAGER_ROLEon theFundManager. - Validation is written back by the validator.
Validator.validateDeedreads the deed's traits withgetTraitValueand records the result withDeedNFT.updateValidationStatus. - Fees route through the
FundManager.mintAssetcallsFundManager.processPayment, which only accepts calls from aDeedNFTon its compatible list. - Metadata follows the traits.
DeedNFT.tokenURIasksMetadataRenderer.tokenURIfirst, and every trait write callsMetadataRenderer.syncTraitUpdate.setMetadataRenderergives the rendererVALIDATOR_ROLEonDeedNFTso it can write thecustomMetadatatrait back. - The extensions read the deed and act for its owner.
SubdividechecksDeedNFT.ownerOf,getValidationStatusandgetTraitValue.Fractionalizemoves the deed into its own custody, andFractionTokenFactoryclones the share token for it.
The asset lifecycle
flowchart LR
M["Minter"] -->|"mintAsset"| D["T-Deed<br/>isValidated = false"]
V["Validator.validateDeed"] -->|"updateValidationStatus"| D
D -->|"createSubdivision, mintUnit<br/>(Land or Estate only)"| S["Subdivide<br/>ERC-1155 units"]
D -->|"createFraction"| F["Fractionalize<br/>holds the deed"]
F -->|"mintShares"| T["FractionToken<br/>ERC-20 shares"]
F -->|"unlockAsset"| O["Holder of every share"]1. Mint
Only a MINTER_ROLE holder can mint, and it names the owner.
mintAsset(owner, assetType, uri, definition, configuration, validatorAddress, token, salt):
- 1.The validator is
validatorAddress, or theDeedNFT's default validator if that is zero. It must be active in the registry, implementIValidator, support the asset type and have a default operating agreement. - 2.If a
FundManageris set, the caller — not the owner — pays the validator's service fee intokenthroughprocessPayment. If none is set,tokenmust be the zero address. - 3.With a non-zero
saltthe id isgenerateUniqueTokenId(owner, assetType, definition, salt), a hash reduced to nine digits. Withsaltzero it is the next sequential id, from 1. - 4.The deed gets seven traits:
assetType,isValidated(false),operatingAgreement(the validator's default agreement URI with the token id appended),definition,configuration,validatorandbeneficiary(the owner).DeedNFTMintedis emitted.
Asset types are the DeedNFT.AssetType enum: Land (0), Vehicle (1), Estate (2),
CommercialEquipment (3). What a validator looks for in each is under
land, vehicles,
estates and commercial equipment.
2. Validate
A validator checks the deed's traits against the criteria for its asset type.
Validator.validateDeed(tokenId) needs VALIDATOR_ROLE on that Validator, and reads the deed from
the validator's primaryDeedNFT. It fails — emitting ValidationError and writing nothing — if the
asset type is not supported, or if a required operating agreement or definition is missing or not
recognised. Otherwise it checks that every required trait is present and non-empty, then calls
DeedNFT.updateValidationStatus with the result.
- If an asset type has no criteria,
validateDeedmarks the deed valid.setupValidationCriterialoads the built-in presets;setValidationCriteriasets custom ones. validateDeeddoes not check which validator the deed names. Any active validator can validate any deed in its primaryDeedNFT, and thevalidatortrait becomes that validator.updateMetadataby the owner setsisValidatedback to false and clearsvalidator.isValidated,validatorandbeneficiaryare reserved:setTraitandremoveTraitrefuse them for every caller, and onlyVALIDATOR_ROLEcan setassetType. See Reserved traits.
The full rules are in validation-system.md.
3. Subdivide
A validated land or estate deed can be split into numbered units. The deed's owner calls
Subdivide.createSubdivision and becomes the collection admin. The deed stays with its owner:
subdivision does not take custody. Whoever owns the deed at the time mints units with mintUnit or
batchMintUnits. Each unit is its own ERC-1155 id, (deedId << 128) | unitId, with a supply of one,
and it inherits the deed's asset type, operating agreement, definition, configuration and validator.
Units are validated one by one with Validator.validateSubdivisionUnit. See
subdivision.md.
4. Fractionalize
createFraction moves the deed into Fractionalize and issues an ERC-20 against it. It does not
check that the deed is validated. The caller becomes the collection admin and is the only one who can
mint shares, up to totalShares. The deed comes back out through unlockAsset: before any shares
are minted, to wherever the admin sends it; after, only for someone holding every minted share, whose
shares are burned, which needs the fraction to be burnable. createFraction also accepts a
subdivision unit, but that path always reverts; see
smart-contracts.md. More in
fractionalization.md.
5. Transfer and royalties
T-Deeds move like any ERC-721, but only an approved marketplace can move one for its owner.
Royalty enforcement is on from initialize. With it on, approve and setApprovalForAll revert
("!mkt") for an operator that is not on the setApprovedMarketplace list, and so does a transfer
sent by anyone other than the owner or an approved marketplace. Each transfer rewrites the
beneficiary trait to the new owner. royaltyInfo names the deed's validator contract as the
receiver, at that validator's royaltyFeePercentage — 5% by default, and never more.
Pausing DeedNFT stops minting, burning and updateMetadata, not transfers. An owner can burn a
deed with burnAsset or burnBatchAssets.
asset-workflows.md lists the calls for each step, in order.
Roles
Every contract starts with its deployer holding all of its roles. Who holds them now is in Governance.
DEFAULT_ADMIN_ROLEDeedNFT, FundManager, Subdivide, FractionalizeDeedNFT, every setting: registry, default validator, renderer, FundManager, minters, marketplaces, royalty enforcement, pauseOwnable)Validator, ValidatorRegistry, MetadataRenderer, FractionTokenFactoryMINTER_ROLEDeedNFTmintAssetVALIDATOR_ROLEDeedNFT, SubdivideDeedNFT, granted to active validators by the registry; on Subdivide, by addValidatorVALIDATOR_ROLEValidatorvalidateDeed and validateSubdivisionUnitCRITERIA_MANAGER_ROLE, METADATA_ROLE, FEE_MANAGER_ROLEValidatorADMIN_ROLE, FEE_MANAGER_ROLEFundManagerDeedNFTs; withdrawing validator feesADMIN_ROLESubdivide, FractionalizeSubdivide the marketplace list and granting VALIDATOR_ROLENetworks
The Deed track is deployed on Base Sepolia only. deployments/base-sepolia/ records DeedNFT,
Validator, ValidatorRegistry, FundManager, MetadataRenderer, Subdivide, Fractionalize
and FractionTokenFactory. FractionTokens are clones made per fraction. ValidatorFactory has no
deploy script and is not deployed. Nothing on Base mainnet or Ethereum Sepolia belongs to the Deed
track.
How the contracts are deployed and wired, and what the scripts leave for an admin to do afterwards,
is in smart-contracts.md and
Operators.
Known limitations
DeedNFThas nogetAssetType.Subdividecalls it, so setting a unit'sassetTypetrait reverts. Seesubdivision.md.- A subdivision unit cannot be fractionalized.
Fractionalizehas noonERC1155Received, so receiving a unit reverts. - The
checkApprovalsunlock path never passes.adminApprovalsis never set. - A non-burnable fraction cannot be unlocked once shares are minted. Unlocking burns the shares. See
fractionalization.md. ValidatorFactory.createValidatorreverts.Validatordisables initializers in its constructor, so the factory cannot initialize the validator it deploys.- No tests cover
Subdivide,FractionalizeorValidatorFactory.DeedNFT,Validator,ValidatorRegistry,FundManagerandMetadataRendererhave tests intest/core/.