Scene blockchain operations

Blockchain Interactions

Index icon See index
Search Icon

Scene blockchain operations

By interacting with the Ethereum blockchain you can, for example, require that a user pays a fee before activating something in your scene. The SDK is currently experimenting with different ways to interface with the Ethereum blockchain. Currently there are three ways you can achieve this:

  • Using the Web3 API
  • Using the ethjs library
  • Using the ethereum controller

IMPORTANT: At the present time, none of these three solutions are fully supported by the SDK, and the way in which they are implemented is very likely to change. For this reason, we advise that you only try these out for proofs of concept, but not to develop final experiences.

Obtain a user’s public key

You can obtain a user’s public Ethereum key by using getUserPublicKey(). You can then use this information to send payments to the user, or as a way to recognize users.

The example below imports the UserIdentity library and runs getUserPublicKey() to get the public key of the user’s Metamask account and log it to console. The user must be logged into their Metamask account on their browser for this to work.

import { createElement, inject, UserIdentity } from "decentraland-api/src"

export default class Scene extends ScriptableScene<any, any> {
  userIdentity: UserIdentity

  state = {
    publicKey: ""

  async sceneDidMount() {
    const publicKey = await this.userIdentity!.getUserPublicKey()
    this.setState({ publicKey })

  render() {
    return <scene />

Web3 API

The SDK includes an interface for the Web3 API. You can use it to call methods of this API from your scene’s code. The interface includes two methods: send and sendAsync, which can be used to call the methods from the API. We have only whitelisted the following methods from the API, all others are currently not supported:

  • eth_sendTransaction
  • eth_getTransactionReceipt
  • eth_estimateGas
  • eth_call
  • eth_getBalance
  • eth_getStorageAt
  • eth_blockNumber
  • eth_gasPrice
  • eth_protocolVersion
  • net_version
  • eth_getTransactionCount
  • eth_getBlockByNumber

To use it, you must first install web3 in your local machine. To do so, run the following:

npm i web3

IMPORTANT: The SDK works with version 0.20.6 of the Web3 library. It doesn’t currently support newer versions.

Below is a sample that uses this API to get the contents of a block in the blockchain.

import { createElement, ScriptableScene } from "decentraland-api"
import Web3 = require("web3")

export default class EthereumProvider extends ScriptableScene {
  async sceneDidMount() {
    const provider = await this.getEthereumProvider()
    const web3 = new Web3(provider)

    web3.eth.getBlock(48, function(error: Error, result: any) {
      console.log("Eth block 48 (from scene)", result)

  async render() {
    return <scene />

For more details and a full reference of what’s possible with this API, see Web3’s documentation

ethjs library

To use it, you must first install ethjs in your local machine. To do so, run the following:

npm install --save ethjs

For more details and a full reference of what’s possible with this library, see ethjs’s documentation

The Ethereum Controller

Another way to perform operations on the Ethereum blockchain is through the ethereum controller. This controller is packaged with the SDK, so you don’t need to run any manual installations. You must first import it into your scene:

  1. Import the EthereumController to the .tsx file:
import {
} from "decentraland-api"
  1. Then inject the ethereum controller as a decorator into your custom scene class:
export default class myScene extends ScriptableScene {
  eth: EthereumController
  // (...)

The examples below show some of the things you can do with this controller.

Require a payment

Once the EthereumController has been imported, you can run the requirePayment function. This function prompts the user to accept a paying a sum to an Ethereum wallet of your choice. Users must always accept payments manually, a payment can never be implied directly from the user’s actions in the scene.

this.eth.requirePayment(receivingAddress, amount, currency)

The function requires that you specify an Ethereum wallet address to receive the payment, an amount for the transaction and a specific currency to use (for example, MANA or ETH).

If accepted by the user, the function returns the hash number of the transaction that has been started.

const myWallet = 0x0123456789...
const enterPrice = 10

// (...)

async sceneDidMount() {
  this.eventSubscriber.on(door_click, async () => {
    await this.eth!.requirePayment(myWallet, entrancePrice, MANA)

    this.setState(isDoorClosed: !this.state.isDoorClosed)

The example above listens for clicks on a door entity. When clicked, the user is prompted to make a payment in MANA to a specific wallet for a given ammount. Once the user accepts this payment, the rest of the function can be executed, in this case the isDoorClosed variable in the scene’s state is changed. If the user doesn’t accept the payment, the rest of the function won’t be executed and the variable’s state won’t change.

Tip: We recommend defining the wallet address and the ammount to pay as global constants at the start of the .tsx file. These are values you might need to change in the future, setting them as constants makes it easier to update the code.

Using the Ethereum test network

While testing your scene, to avoid transferring real MANA currency, you can use the Ethereum Ropsten test network and transfer fake MANA instead.

To use the test network you must set your Metamask Chrome extension to use the Ropsten test network instead of Main network.

You must also own MANA in the Ropsten blockchain. To obtain free Ropsten mana in the test network, go to our MANA faucet.

Tip: To run the transaction of transferring Ropsten MANA to your wallet, you will need to pay a gas fee in Ropsten Ether. If you don’t have Ropsten Ether, you can obtain it for free from various external faucets like this one.

To preview your scene using the test network, add the DEBUG property to the URL you’re using to access the scene preview on your browser. For example, if you’re accessing the scene via, you should set the URL to

Any transactions that you accept while viewing the scene in this mode will only occur in the test network and not affect the MANA balance in your real wallet.

Wait for a transaction

Another thing that the ethereum controller allows you to do is check if a specific transaction has been already mined. This looks for a specific transaction’s hash number and verifies that it has been validated by a miner and added to the blockchain.

await this.eth.waitForMinedTx(currency, tx, receivingAddress)

The function requires that you specify a currency to use (for example, MANA or ETH), a transaction hash number and the Ethereum wallet address that received the payment.

const myWallet = 0x0123456789...

// (...)

async sceneDidMount() {
  this.eventSubscriber.on(door_click, async () => {
    const tx = await this.eth!.requirePayment(myWallet, entrancePrice, MANA)
    const userPaid = await this.eth!.waitForMinedTx(currency,tx, receivingAddress)
    this.setState(isDoorClosed: !this.state.isDoorClosed)

The example above first requires the user to accept a transaction, if the user accepts it, then requirePayment returns a hash that can be used to track the transaction and see if it’s been mined. Once the transaction is mined and accepted as part of the blockchain, the isDoorClosed variable in the scene state is changed.



The latest tutorials sent straight to your inbox.



Share this tutorial with your community.