Decentraland is a decentralized protocol for ownership of LAND in a decentralized virtual world.
This subgraph can be used for Decentraland on mainnet, and all testnets. In order to run it for a testnet, the subgraph.yaml
file will need to have the contract addresses changed to point to the correct address for each respective network.
The subgraph takes a long time to sync, because Decentraland has produced a lot of data on mainnet. Somewhere between 5-20 hours, depending on your machine.
The Decentraland smart contracts use upgradeability and proxies. These are important to consider when building a subgraph. With upgradeability, it means that we must carefully make sure every instance of a contract does get tracked by the subgraph, and that if any events are added or removed along the way, the subgraph mappings are written to ensure no important data is missing.
Proxies provide a benefit in that the proxy addresses often emit all of the events. For example, the EstateProxy
emits all the important events for Estates, and the EstateRegistry
has been updated multiple times, yet we only have to ingest events from the proxy address. Care does need to be taken, in that we must examine every EstateRegistry
on mainnet, in case an event has been removed or renamed from a previous version that does not show up on the current version.
If reading storage from a proxy contract, the storage is held at the proxy address as well. In order to access this kind of data, Etherscan does not work. MyCrypto can be used, because you can pass any contract abi to any contract address. Etherscan will only let you use the approved ABI with the contract, and in this case, it is just a simple proxy abi, and it doesn't have the interface to interace with storage
- The
Transfer
event for LANDRegistry.sol has been updated. The first instance had 6 fields, the second one had 5, and the current one has 3 (and is the ERC721 standard). All three need to be tracked. Note that the one with 6 fields is currently not in the LANDRegistry as a legacy event. I added it manually, which is why the abi is now calledModifiedLANDRegistry.json
. I brought this up to Decentralands team in their chat, and they plan on adding in the old transfer event to the most current abi to be backwards compatible
NOTE - Currently having 3 events named
Transfer
causes our autogenerated Typescript types to create 3 types of the same name, which will cause Assembly Script compiler errors. We are working on fixing this - see this issue graphprotocol/graph-node#736. In the mean time, you can just go in and manually rename the events toTransfer2
andTransfer3
or something similar.
These contracts were left out, as they don't directly relate to ownership of parcels and land:
MANAToken
TerraformReserve
ReturnVesting
ServiceLocator
MortgageHelper
RCNToken
KyberOracle
LANDAuction
MANABurner
MultiSigWallet
Nobody
Districts
show up in the Decentraland Marketplace App, and are queryable in the REST API. Unfortunately these are not stored on chain, they are stored by Decentraland in their own server. For now, these can't be added to a subgraph, unless they are put on chain, or sourced on IPFS and referenced on chain. This also includes Contributions
to districts, which is queryable in the REST API.
Some other generic data on Genesis City is not on the blockchain, and thus can't be indexed by a Graph Node. Such as tags
, and map
data.
Most events are ingested by the Graph Node, but some are purposely left out since they do not contribute to data sources we are interested in. These are listed for each contract. Other relevant information is included where needed
Events not included:
DeployAuthorized
DeployForbidden
Approval
ApprovalForAll
EstateRegistrySet
Upgrade
(Proxy contract)OwnerUpdate
(Proxy Contract)
Events not included:
ChangedPublicationFee
ChangedOwnerCut
Events not included:
ChangedPublicationFee
ChangedOwnerCutPerMillion
ChangeLegacyNFTAddress
OwnerUpdate
(Proxy Contract)
This contract code come from the Ripio Network. There were three instances of it shown to exist on etherscan from https://github.com/decentraland/contracts :
- 0x59ccfc50bd19dcd4f40a25459f2075084eebc11e - appears to be a typo, as this is not a contract address
- 0xb3d9444f88dc1c30f18c69ebd8ec6f1fa2706376 - Has seven events emitted, mostly setting global variables, and one Mortgage. Seems deprecated, so was left out of analysis
- 0x90263Ea5C57Dc6603CA7202920735A6E31235bB9 - The current live contract. Oddly only has one event emitted. So this whole contract isn't tracked in the subgraph either
This contract code comes from the Ripio Network. There were three instances of it shown to exist on etherscan from https://github.com/decentraland/contracts :
- 0xea06746f1bd82412f9f243f6bee0b8194d67a67d - appears to be a typo, as this is not a contract address
- 0x0bdaf0d7eb72cac0e0c8defcbe83ccc06c66a602 - Only 4 events, appears it has been abandoned, so it isn't tracked in the subgraph
- 0x9abf1295086afa0e49c60e95c437aa400c5333b8 - 100 transactions, with over 25 event logs, so this is tracked
Events not used:
ReadedOracle
SetCreator
SetEngine
UpdatedLandData
- this event is emitted byLandRegistry.sol
, and appears to just emit duplicate information from theMortgageManager.sol
contract, so we leave it out.
It isn't used directly as a source in the manifest, but it does get called by mortgageManager.ts
to get loan data by calling a public getter. No events are tracked here.
Code exists here. This contract was deployed 4 different times, at the following addresses:
0xCE55f653B5B7a112bfe2ef55fa5621ABDab16D39
0x2b6a877fafd33cd3ee98e772acafe7b6cff7c33b
0x399caff06e6419a8a3a6d4d1d2b94cb14ddeda87
0xf886313f213c198458eba7ae9329525e64eb763a
Only the last address is ingested by the subgraph. This is because there is no proxy for this contract, so it is assumed the first three contracts can be considered abandoned
Events not used:
URIUpdated
Transfer
(ERC721)Approval
(ERC721)ApprovalForAll
(ERC721)
Events not used:
SetLANDRegistry
A Graph Node can run multiple subgraphs. The subgraph ingests event data by calling to Infura through http. It can also connect to any geth node or parity node that accepts RPC calls. Fast synced geth nodes work. To use parity, the --no-warp
flag must be used. Setting up a local Ethereum node is more reliable and faster, but Infura is the easiest way to get started.
This subgraph has three types of files which tell the Graph Node to ingest events from specific contracts. They are:
- The subgraph manifest (subgraph.yaml)
- A GraphQL schema (schema.graphql)
- Mapping scripts (estate.ts, land-registry.ts, legacy-marketplace.ts etc.)
This repository has these files created and ready to compile, so a user can start this subgraph on their own. The only thing that needs to be edited is the contract addresses in the subgraph.yaml
file to change between mainnet and testnets.
We have provided a quick guide on how to start up the Decentraland-Subgraph graph node below. If these steps aren't descriptive enough, the getting started guide has in depth details on running a subgraph.
When you first start out, you will likely want to do a lot of local testing, to quickly iterate on mistakes, and the local deployment of a subgraph is the best way to go for this. See the instructions below:
- Install IPFS and run
ipfs init
followed byipfs daemon
- Install PostgreSQL and run
initdb -D .postgres
followed bypg_ctl -D .postgres start
andcreatedb graph-node
- If using Ubuntu, you may need to install additional packages:
sudo apt-get install -y clang libpq-dev libssl-dev pkg-config
- Clone this repository, and run the following:
yarn
yarn codegen
- Clone https://github.com/graphprotocol/graph-node from master and
cargo build
(this might take a while) - a) Now that all the dependencies are running, you can run the following command to connect to Infura Mainnet (it may take a few minutes for Rust to compile). PASSWORD might be optional, it depends on your postrgres setup:
cargo run -p graph-node --release -- \
--postgres-url postgresql://USERNAME:[PASSWORD]@localhost:5432/graph-node \
--ipfs 127.0.0.1:5001 \
--ethereum-rpc mainnet-infura:https://mainnet.infura.io --debug
- b) Or Mainnet with a Local Ethereum node. This is very common if you are working with brand new contracts, and you have deployed them to a testnet environment like ganache (note that ganache commonly uses port 9545 rather than 8545):
cargo run -p graph-node --release -- \
--postgres-url postgresql://USERNAME:[PASSWORD]@localhost:5432/graph-node \
--ipfs 127.0.0.1:5001 \
--ethereum-rpc mainnet-local:http://127.0.0.1:8545
- c) Or Infura Ropsten (NOTE: Infura testnets are not reliable right now, we get inconsistent results returned. If Ropsten data is needed, it is suggested to run your own Ropsten node)
cargo run -p graph-node --release -- \
--postgres-url postgresql://USERNAME:[PASSWORD]@localhost:5432/graph-node \
--ipfs 127.0.0.1:5001 \
--ethereum-rpc ropsten-infura:https://ropsten.infura.io
-
Now create the subgraph locally on The Graph Node with
yarn create-local
. On The Graph Hosted service, creating the subgraph is done in the web broswer. -
Now deploy the Decentraland subgraph to The Graph Node with
yarn deploy --debug
. You should see a lot of blocks being skipped in thegraph-node
terminal, and then it will start ingesting events from the moment the contracts were uploaded to the network.
Now that you have subgraph is running you may open a Graphiql browser at 127.0.0.1:8000
and get started with querying.
This subgraph has already been deploy to the hosted service, and you can see it under on The Graph Explorer. To understand how deploying to the hosted service works, check out the Deploying Instructions in the official documentation. The most important part of deploying to the hosted service is ensuring that the npm script for deploy
is updated to the correct name that you want to deploy with.
Below are a few ways to show how to query the Decentraland Subgraph for data. The queries show most of the information that is queryable, but there are many other filtering options that can be used, just check out the querying api. These queries can be used locally or in The Graph Explorer playground.
{
parcels {
id
x
y
estate {
id
owner
operator
land
metaData
size
sizeArray
tx
}
owner
data {
id
version
name
description
ipns
}
lastTransferredAt
orderOwner
orderPrice
activeOrder{
id
type
txHash
owner
price
status
buyer
contract
blockNumber
expiresAt
blockTimeCreatedAt
blockTimeUpdatedAt
marketplace
nftAddress
}
createdAt
updatedAt
operators
}
}
{
estates {
id
owner
operator
land
metaData
size
sizeArray
tx
}
{
mortgages {
id
txHash
createdAt
startedAt
lastUpdatedAt
status
borrower
rcnEngine
loan_id
landMarket
landID
deposit
tokenConverter
landCost
parcel{
id
}
estate{
id
}
lender
loanAmount
dueTime
}
}
{
invites {
id
inviteBalance
invites
}
}