DSP: 0010 Title: LAND contract Author: Ignacio Mazzara Status: Accepted Type: Standards Created: 2019-03-11
Every parcel in Decentraland's world is represented by a non-fungible token ERC #721 that is indivisible and unique. This registry is powered by a smart contract where it is defined all the information related to each parcel.
Decentraland's most important digital asset is its LAND token. The world is divided into square parcels of LAND that act similarly to a domain name: the owner of a LAND can decide what to show inside the 3D experience, in very much the same way as the owner of "example.com" can decide what webpage to show when a browser connects to that domain.
The LAND token exists within a EVM blockchain (currently Ethereum). Decentraland is one of the first examples of the ERC 721 "NFT" token (the standard explicitly cites Decentraland and CryptoPunks as the first projects to experiment with this idea).
This document describes the structure, and the expected behavior and functionality of interacting components provided by the LAND contract also known as LANDRegistry contract.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 8174 when, and only when, they appear in all capitals, as shown here.
LAND is compliant with the ERC721 Ethereum standard, and implements the ERC721Base interface, as well as the ERC721Enumerable interface.
Its implementation could be find here.
Parcel: the logical unit of land subdivision in the Decentraland's world. Each parcel may contain metadata formerly used to save its content.
LAND: a brand name for parcels.
Coordinates: x, y representation of the parcel.
Asset Id: token id of the parcel generated by encoding the x and y coordinates.
Estate: a group of parcels placed together.
Account: an Ethereum address
The coordinates of a LAND parcel are its X and Y coordinates, using 128 bits to represent the (signed) coordinate.
The following are examples of coordinates:
X | Y | 256-bit Hexadecimal Representation |
---|---|---|
0 | 0 | 0x0000000000000000000000000000000000000000000000000000000000000000 |
-1 | 0 | 0xffffffffffffffffffffffffffffffff00000000000000000000000000000000 |
1 | -1 | 0x00000000000000000000000000000001ffffffffffffffffffffffffffffffff |
-1 | 150 | 0xffffffffffffffffffffffffffffffff00000000000000000000000000000096 |
0 | 90 | 0x000000000000000000000000000000000000000000000000000000000000005a |
150 | 150 | 0x0000000000000000000000000000009600000000000000000000000000000096 |
This contract was created using a proxy pattern which allows upgradability.
The account owner of the LAND proxy contract.
The account owner of the LAND registry contract.
Account allowed to create new parcels.
Account which is the owner of a specific parcel.
Account which plays as a co-owner for all the parcels owned by another account. An account can has multiple ApprovedForAll
Account which plays as a co-owner for a specific parcel. A parcel can has only one Operator.
Account that can update the parcel metadata of all of the parcels owned by another account. An account can has multiple UpdateManager
Account only allowed to update the parcel metadata. A parcel can has only one UpdateOperator.
Every parcel has metadata which is used to represent its content (scene). The metadata has the following structure:
version,name,description,ipns
- Version: number of the metadata version.
- Name: Parcel name.
- Description: Parcel description.
- IPNS: ipns hash link to the parcel scene.
E.g: 0,"My parcel","Description",""
To be defined.
Update
Emitted when the parcel metadata changed.
Update(
uint256 assetId,
address holder,
address operator,
string data
)
UpdateOperator
Emitted when the parcel update operator changed.
UpdateOperator(uint256 assetId, address operator)
DEPRECATED: Transfer
Emitted when the parcel was transfered.
Events from block 4944642 to 5270587 have this topic:
Transfer(
address from,
address to,
uint256 assetId,
address operator,
bytes userData,
bytes operatorData
)
DEPRECATED: Transfer
Emitted when the parcel was transfered.
Events from block 5270587 to 6239536 have this topic:
Transfer(
address from,
address to,
uint256 assetId,
address operator,
bytes userData
)
Transfer
Emitted when the parcel was transfered.
Events from block 6239536 to latest have this topic:
Transfer(address from, address to, uint256 assetId)
ApprovalForAll
Emitted when an account gives approval for all of their tokens to another address.
ApprovalForAll(address operator, address holder, bool authorized)
Approval
Emitted when an account gives approval a specific token to another address.
Approval(address owner, address operator, uint256 assetId)
OwnerUpdate
Emitted when the owner of the contract changed.
OwnerUpdate(address _prevOwner, address _newOwner)
EstateRegistrySet
Emitted when the EstateRegistry changed.
EstateRegistrySet(address registry)
setApprovalForAll
Set or remove an account as ApprovedForAll
setApprovalForAll(address operator, bool authorized)
isApprovedForAll
Get if an account is ApprovedForAll for a specific address
isApprovedForAll(address assetHolder, address operator) return (bool)
Approve
Set an account as Operator.
To clean the Operator, set it to the zero address.
function approve(address operator, uint256 assetId)
getApproved
Get the parcel Operator
getApproved(uint256 assetId) returns (address)
getApprovedAddress
Get the parcel Operator
getApprovedAddress(uint256 assetId) returns (address)
isAuthorized
Get if an account is ApprovedForAll or Operator for a parcel
isAuthorized(address operator, uint256 assetId) returns (bool)
setUpdateOperator
Set an account as UpdateOperator
setUpdateOperator(uint256 assetId, address operator)
updateOperator
Get the parcel UpdateOperator
updateOperator(uint256 assetId) returns (address)
isUpdateAuthorized
Get if an account is ApprovedForAll, Operator or UpdateOperator for a parcel
isUpdateAuthorized(address operator, uint256 assetId)
transferFrom
Transfer a parcel to another address using the parcel's asset id.
transferFrom(address from, address to, uint256 assetId)
transferLand
Transfer a parcel to another address using the parcel's coordinates.
transferLand(int256 x, int256 y, address to)
transferManyLand
Transfer many parcels to another address using the parcels coordinates.
transferManyLand(int256[] x, int256[] y, address to)
safeTransferFrom
Transfer a parcel to another address using the parcel's asset id and checking if the destination account is a contract and implements OnERC721Received
function.
safeTransferFrom(address from, address to, uint256 assetId)
safeTransferFrom
Transfer a parcel to another address using the parcel's asset id and checking if the destination account is a contract and implements OnERC721Received
function with extra data.
safeTransferFrom(
address from,
address to,
uint256 assetId,
bytes userData
)
transferLandToEstate
Add a parcel to an Estate using the parcel's coordinates.
transferLandToEstate(int256 x, int256 y, uint256 estateId)
transferManyLandToEstate
Add a many parcels to an Estate using the parcels coordinates.
transferManyLandToEstate(int256[] x, int256[] y, uint256 estateId)
createEstate
Create an Estate with many parcels using its coordinates.
createEstate(int256[] x, int256[] y, address beneficiary)
createEstateWithMetadata
Create an Estate with many parcels using its coordinates and metadata.
createEstateWithMetadata(
int256[] x,
int256[] y,
address beneficiary,
string metadata
)
updateLandData
Update the parcel metadata using its coordinates.
updateLandData(int256 x, int256 y, string data)
updateManyLandData
Update many parcels metadata using its coordinates.
updateManyLandData( int256[] x, int256[] y, string data)
landData
Get the parcel metadata using its coordinates.
landData(int256 x, int256 y) returns (string data)
tokenMetadata
Get the parcel metadata using its asset id.
tokenMetadata(uint256 assetId) returns (string data)
encodeTokenId
Encode the parcel coordinates to the parcel asset id.
encodeTokenId(int256 x, int256 y) returns (uint256)
decodeTokenId
Decode the parcel asset id to the parcel coordinates.
decodeTokenId(uint256 value) returns (int, int)
tokensOf
Get the parcels asset id owned by an account.
tokensOf(address owner) returns (uint256[])
landOf
Get the parcels coordinates owned by an account.
landOf(address owner) returns (int[], int[])
ownerOfLand
Get the parcel owner using the parcel's coordinates.
ownerOfLand(int256 x, int256 y)
ownerOf
Get the parcel owner using the parcel's asset id.
ownerOf(uint256 assetId) returns (address)
ownerOfLandMany
Get the parcels owners using the parcels coordinates.
ownerOfLandMany(int256[] x, int256[] y) returns (address[])
tokenOfOwnerByIndex
Get the parcel asset id by the owner index.
tokenOfOwnerByIndex(address owner, uint256 index) returns (uint256 assetId)
exists
Get is the parcel has owner using the parcel coordinates.
exists(int256 x, int256 y) returns (bool)
exists
Get is the parcel has owner using the parcel asset id.
exists(uint256 assetId) returns (bool)
supportsInterface
Get if the contract supports an interface.
supportsInterface(bytes4 _interfaceID) returns (bool)
proxyOwner
Get the owner of the proxy contract.
proxyOwner() returns (address)
totalSupply
Get the count of parcels created.
totalSupply()
authorizedDeploy
Get if an account is an AuthorizedDeployer.
authorizedDeploy(adderss operator) returns (bool)
balanceOf
Get the count of parcels owned by an account.
balanceOf(address owner) returns (uint256)
currentContract
Get the current implementation contract address.
currentContract() returns (address)
name
Get the name of the contract.
name() returns (string)
description
Get the description of the contract.
description() returns (string)
decimals
Get the decimals of the contract.
decimals() returns (uint256)
owner
Get the owner of the contract.
owner() returns (address)
symbol
Get the symbol of the contract.
symbol() returns (string)
estateRegistry
Get the current Estate registry contract address.
estateRegistry returns (address)
GET_METADATA
Get the GET_METADATA function selector.
GET_METADATA() returns (bytes4)
ping
Set the latest caller activity to now.
ping(address user)
setLatestToNow
Set the latest account activity to now.
setLatestToNow(address user)
latestPing
Get the latest activity of an account.
latestPing(address) returns (uint256)
assignNewParcel
Create a new parcel by its coordinates.
assignNewParcel(int256 x, int256 y, address beneficiary)
assignMultipleParcels
Create multiple parcels by its coordinates.
assignMultipleParcels(int256[] x, int256[] y, address beneficiary)
authorizeDeploy
Authorize an account to create new parcels.
authorizeDeploy(address beneficiary)
forbidDeploy
Forbid an account to create new parcels.
forbidDeploy(address beneficiary)
transferOwnership
Transfer the ownership of the contract to another account.
transferOwnership(address _newOwner)
setEstateRegistry
Set the Estate Registry contract address.
setEstateRegistry(address registry)
As blocklimit limitation, every transaction which support many
parcels manipulation may run out of gas. It is strongly recommended to divide the transaction in multiple ones to achieve the same.
From the above landOf
and tokensOf
may not work if the account is owner of more than 20 parcels.