Subdivision
Subdivide splits a validated Land or Estate T-Deed into numbered units. Each unit is its own
ERC-1155 token with a supply of one, so a unit behaves like a non-fungible token inside one
collection per deed. The deed itself stays with its owner.
On this page
Source: Subdivide.sol. Every function, role and
event is in smart-contracts.md.
flowchart LR
O["Deed owner"] -->|"createSubdivision"| S["Subdivision<br/>(per deed)"]
O -->|"mintUnit, batchMintUnits"| U["Units<br/>ERC-1155, supply 1 each"]
V["Validator.validateSubdivisionUnit"] -->|"updateUnitValidationStatus"| U
A["Collection admin"] -->|"traits, metadata,<br/>burnable, validator"| UUnit token ids
A unit's token id packs the deed id and the unit id into one number.
tokenId = (deedId << 128) | unitIdThe high 128 bits are the deed id; the low 128 bits are the unit id, from 0 to totalUnits - 1.
uri and royaltyInfo take this combined id. Most other functions take deedId and unitId
separately.
Creating a subdivision
function createSubdivision(
uint256 deedId,
string memory name,
string memory description,
string memory symbol,
string memory collectionUri,
uint256 totalUnits,
bool burnable
) externalThe caller must own the deed, and the deed must:
- be validated (
DeedNFT.getValidationStatus), and - have asset type Land (0) or Estate (2). Vehicles and commercial equipment cannot be subdivided;
supportsSubdivision(assetType)reports this.
totalUnits must be above zero, symbol and collectionUri must not be empty, and the deed must
not already have an active subdivision. The caller becomes the collection admin. Event:
SubdivisionCreated.
Subdivision does not take custody of the deed. Its owner can still transfer or burn it. Minting units and deactivating the subdivision follow whoever owns the deed at the time; the collection admin stays whoever created the subdivision until the role is handed on.
Minting units
function mintUnit(uint256 deedId, uint256 unitId, address to) external
function batchMintUnits(uint256 deedId, uint256[] calldata unitIds, address[] calldata recipients) external- Only the deed's current owner can mint. The subdivision must be active and the contract not paused.
- Each unit id must be below
totalUnitsand not already minted. A zero recipient means the deed's owner. - Minting does not check the deed's validation status again.
Each new unit gets these traits:
isValidatedfalseparentDeedunitType"Subdivision Unit"beneficiaryassetType, operatingAgreement, definition, configurationvalidatorvalidator traitEvent: UnitMinted, one per unit.
Holding, transferring and burning units
- Transfers use the standard ERC-1155
safeTransferFromandsafeBatchTransferFrom, one unit at a time (amountmust be 1). Each transfer rewrites the unit'sbeneficiarytrait to the new holder.ownerOf(tokenId)returns the current holder. - Burning:
burnUnit(deedId, unitId)by the unit's holder, only while the subdivision isburnable. Event:UnitBurned. - Deactivating:
deactivateSubdivision(deedId)by the deed's current owner, once every minted unit has been burned. A deactivated subdivision's views revert, and the deed can be subdivided again. Event:SubdivisionDeactivated.
The collection admin
The collection admin manages a subdivision's units after they are minted.
setUnitMetadata(deedId, unitId, metadata)uri in place of the collection URIsetBurnable(deedId, burnable)setSubdivisionValidator(deedId, validator)ValidatorRegistry; zero clears itsetUnitTrait(deedId, unitId, traitKey, traitValue)bytes32 key and raw bytessetUnitTraitFlexible(deedId, unitId, traitKey, traitValue, valueType)DeedNFT.setTrait: a 32-byte key is used as is, anything else is hashed and recorded as the trait's name. valueType 0 raw bytes, 1 string, 2 number, 3 booleanremoveUnitTrait(deedId, unitId, traitName)transferCollectionAdmin(deedId, newAdmin)setUnitTraitName (by ADMIN_ROLE) names a trait key for every unit.
Validating units
Units are validated one at a time, against their own traits. A validator holding
VALIDATOR_ROLE on its Validator contract calls:
function validateSubdivisionUnit(address subdivideContract, uint256 deedId, uint256 unitId) externalThe check is the same as for a deed (validation-system.md), applied to
the unit's traits. Three things must be in place:
Subdivideis on theValidator's compatible list (addCompatibleDeedNFT).- The
ValidatorholdsVALIDATOR_ROLEonSubdivide(addValidator, byADMIN_ROLE) and is active in theValidatorRegistry. The registry does not grant this role onSubdivide; only onDeedNFT. - Every trait the criteria require is set on the unit itself. A unit copies only
assetType,operatingAgreement,definitionandconfigurationfrom its deed, so traits such ascountryorparcelNumberhave to be set on each unit by the collection admin.
The result is written by Subdivide.updateUnitValidationStatus, which sets the unit's
isValidated and validator traits. Event: UnitValidated.
Metadata and royalties
uri(tokenId)returns the unit's own metadata URI if the collection admin set one, otherwisecollectionUri/unitId.royaltyInfo(tokenId, salePrice)names the unit'svalidatorcontract as the receiver, at that validator's royalty rate. A unit with no validator falls back to the parent deed'sroyaltyInfo.- ERC-7496 reads:
getUnitTraitValue,getUnitTraitValues,getUnitTraitKeys,getUnitTraitName,getUnitTraitMetadataURI. - Status reads:
getUnitValidationStatus,isUnitValidated,getUnitAssetType,getSubdivisionValidator,subdivisionExists,unitExists,getUnitMetadata.
Subdivide stores an approved-marketplace list, a royalty-enforcement flag and a transfer validator
(setApprovedMarketplace, setRoyaltyEnforcement, setToDefaultSecurityPolicy,
setTransferValidator, all ADMIN_ROLE). No approval or transfer reads them, so unit transfers
are not restricted to approved marketplaces.
Roles and pausing
- Deed owner: creates the subdivision, mints units, deactivates it.
- Collection admin: the table above.
VALIDATOR_ROLEonSubdivide:updateUnitValidationStatus. Granted withaddValidator.ADMIN_ROLE: pause,addValidatorandremoveValidator, trait names, the marketplace settings.DEFAULT_ADMIN_ROLE: upgrades.
pause stops createSubdivision, mintUnit and batchMintUnits. Transfers, burning and the
collection admin's functions keep working.
Known limitations
DeedNFThas nogetAssetType.Subdividecalls it throughIDeedNFT, sosetUnitTraitandsetUnitTraitFlexiblerevert on theassetTypekey, andgetUnitAssetTypereverts for a unit without its ownassetTypetrait. Units minted normally copyassetTypefrom the deed, sogetUnitAssetTypeworks for them.- A unit cannot be fractionalized.
Fractionalizecannot receive ERC-1155 tokens; seefractionalization.md. - The deed is not locked. If its owner transfers it, the new owner controls minting and deactivation. If it is burned, no more units can be minted, the subdivision can never be deactivated, and
royaltyInfofor a unit without a validator reverts. - A unit's validation does not follow the deed's. Units start unvalidated, and a later change to the deed's status does not reach them.
- No tests cover
Subdivide.