1.1.2 • Published 2 years ago

@dcl/crypto-scene-utils v1.1.2

Weekly downloads
124
License
Apache-2.0
Repository
github
Last release
2 years ago

decentraland-crypto-utils

This library includes a number of helpful pre-built tools that help you deal with common requirements that involve and interacting with data on the blockchain.

Using the Crypto library

To use any of the helpers provided by the utils library

  1. Install it as an npm package. Run this command in your scene's project folder:
npm i @dcl/crypto-scene-utils @dcl/ecs-scene-utils eth-connect -B

Note: This command also installs the latest version of the @dcl/ecs-scene-utils and eth-connect libraries, that are dependencies of the crypto utils library

  1. Run dcl start or dcl build so the dependencies are correctly installed.

  2. Import the library into the scene's script. Add this line at the start of your game.ts file, or any other TypeScript files that require it:

import * as crypto from '@dcl/crypto-scene-utils'
  1. In your TypeScript file, write crypto. and let the suggestions of your IDE show the available helpers.

MANA Operations

As MANA is Decentraland's main currency, this library provides tools to make it especially easy to use in a scene.

Send MANA to an address

To make players in your scene send MANA to a specific address, use the send() function. This function requires the following arguments:

  • toAddress: What ethereum address to send the MANA to
  • amount: How many MANA tokens to send
  • waitConfirm: boolean (optional) If true, the function will not be completed till the transaction is mined and added to a block in the blockchain. If false (default value), the function will be completed as soon as the transaction is requested.
crypto.mana.send(`0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee`, 100)

For example, your scene can have a button that requests players to make a MANA payment to the scene cretor's personal wallet. The button opens a door, but only once a transaction is sent to pay the fee.

import * as crypto from '@dcl/crypto-scene-utils'

(...)

let myWallet = `0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee`

button.addComponent(new OnPointerDown(async e => {
	await crypto.mana.send(myWallet, 100, true).then(
		// open door
	)
  }
))

In this scenario, when players click on the button, they are prompted by Metamask to accept the transaction, paying the required MANA sum plus an ETH gas fee dictated by the market at that time.

What's executed after the .send() function ( in the .then() statement in this case ) only gets called when the function is finished. If waitConfirm is false, then the function ends as soon as the transaction is accepted by the player on Metamask. If waitConfirm is true, the function doesn't end until the transaction is mined by the blockchain, which could take a couple of minutes, depending on the gas fee paid.

Having waitConfirm set to false makes the scene respond faster, but the transaction at this point has no confirmations from the blockchain, so the function is vulnerable to a 0 gas fee exploit. If a player sets the gas price of the transaction to 0, or lower than the market fee, the transaction will never be carried out by the workers in the blockchain, but the player will experience things as if having paid the price. Setting waitConfirm to true prevents this risk, but delays the response of the scene.

Get a player's MANA Balance

Look up how much MANA a player has in their wallet. This is useful to know in advance if a player will be able to pay a fee or buy something from the Marketplace.

Check the current player's balance with myBalance(). This function doesn't require any arguments.

import * as crypto from '@dcl/crypto-scene-utils'

executeTask(async () => {
	let balance = await crypto.mana.myBalance()
	log(balance)
})

Check the balance of any other wallet with balance(). This function just requires the wallet address to check, as a string.

import * as crypto from '@dcl/crypto-scene-utils'

let myWallet = `0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee`

executeTask(async () => {
	let balance = await crypto.mana.balance(myWallet)
	log(balance)
})

Other Currencies

Any currency token that adheres to the ERC20 standard can be handled by this library.

Send

To make players in your scene send a currency token to a specific address, use the send() function. This function requires the following arguments:

  • contractAddress: The address of the smart contract for the token to be sent
  • toAddress: What ethereum address to send the tokens to
  • amount: How many tokens to send
  • waitConfirm: boolean (optional) If true, the function will not be completed till the transaction is mined and added to a block in the blockchain. If false (default value), the function will be completed as soon as the transaction is requested.
crypto.currency.send(
  '0x6B175474E89094C44Da98b954EedeAC495271d0F',
  `0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee`,
  100
)

For example, your scene can have a button that requests players to make a DAI payment to the scene cretor's personal wallet. The button opens a door, but only once a transaction is sent to pay the fee.

import * as crypto from '@dcl/crypto-scene-utils'

(...)

let myWallet = `0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee`

button.addComponent(new OnPointerDown(async e => {
	await crypto.currency.send('0x6B175474E89094C44Da98b954EedeAC495271d0F', myWallet, 1, true).then(
		// open door
	)
  }
))

In this scenario, when players click on the button, they are prompted by Metamask to accept the transaction, paying the required DAI sum plus an ETH gas fee dictated by the market at that time. Once that transaction is accepted on Metamask, the door opens.

What's executed after the .send() function ( in the .then() statement in this case ) only gets called when the function is finished. If waitConfirm is false, then the function ends as soon as the transaction is accepted by the player on Metamask. If waitConfirm is true, the function doesn't end until the transaction is mined by the blockchain, which could take a couple of minutes, depending on the gas fee paid.

Having waitConfirm set to false makes the scene respond faster, but the transaction at this point has no confirmations from the blockchain, so the function is vulnerable to a 0 gas fee exploit. If a player sets the gas price of the transaction to 0, or lower than the market fee, the transaction will never be carried out by the workers in the blockchain, but the player will experience things as if having paid the price. Setting waitConfirm to true prevents this risk, but delays the response of the scene.

Check balance

Look up how much of a coin a player has in their wallet. This is useful to know in advance if a player will be able to pay a fee or buy something in the scene.

Check the balance of any other wallet with balance(). This function requires the following arguments:

  • contractAddress: Addess of the token's smart contract.
  • address: Wallet address that you want to check the balance of.
import * as crypto from '@dcl/crypto-scene-utils'

let myWallet = `0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee`

executeTask(async () => {
	let balance = await crypto.currency.balance('0x6B175474E89094C44Da98b954EedeAC495271d0F', myWallet)
	log(balance)
})

Other functions

Call any functions that are available in a token's contract by instancing a contract object. When doing so, you must pass the token's address as a parameter.

import * as crypto from '@dcl/crypto-scene-utils'
import { mainnet } from '../node_modules/@dcl/crypto-utils/utils/contract'

executeTask(async () => {
  const contract = await crypto.currency.getContract(crypto.contract.mainnet.MANAToken)
  log(contract.contract.totalSupply())
})

The getContract() function also returns the requestManager object, which you can use to have greater control over the handling of the transaction.

const { contract, requestManager } = await crypto.currency.getContract(
  crypto.contract.mainnet.MANAToken
)

NFTs

Any non-fungible token that adheres to the ERC721 standard can be handled by this library. Other tokens that don't adhere to the standard but that share common methods with it can also have those methods accessed through the functions in this library.

Transfer an NFT

To make players in your scene transfer an NFT to a specific address, use the transfer() function. This function requires the following arguments:

  • contractAddress: The address of the smart contract for the token to be sent
  • toAddress: What ethereum address to send the tokens to
  • tokenId: The id of the specific token to send within the smart contract
  • waitConfirm: boolean (optional) If true, the function will not be completed till the transaction is mined and added to a block in the blockchain. If false (default value), the function will be completed as soon as the transaction is requested.
crypto.nft.transfer(
  Mainnet.Halloween2019Collection,
  `0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee`,
  1
)

For example, your scene can have a button that requires sending any wearable item to the scene cretor's personal wallet. The button opens a door, but only once a transaction is sent to transfer the token.

import * as crypto from '@dcl/crypto-scene-utils'

(...)

let myWallet = `0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee`

button.addComponent(new OnPointerDown(async e => {
	await crypto.nft.transfer(crypto.contract.mainnet.Halloween2019Collection, myWallet, 1, true).then(
		// open door
	)
  }
))

In this scenario, when players click on the button, they are prompted by Metamask to accept the transaction, transfering the NFT token plus paying an ETH gas fee dictated by the market at that time. Once that transaction is accepted on Metamask, the door opens.

What's executed after the .send() function ( in the .then() statement in this case ) only gets called when the function is finished. If waitConfirm is false, then the function ends as soon as the transaction is accepted by the player on Metamask. If waitConfirm is true, the function doesn't end until the transaction is mined by the blockchain, which could take a couple of minutes, depending on the gas fee paid.

Having waitConfirm set to false makes the scene respond faster, but the transaction at this point has no confirmations from the blockchain, so the function is vulnerable to a 0 gas fee exploit. If a player sets the gas price of the transaction to 0, or lower than the market fee, the transaction will never be carried out by the workers in the blockchain, but the player will experience things as if having paid the price. Setting waitConfirm to true prevents this risk, but delays the response of the scene.

Check player for Tokens

Check if a player holds any specific tokens in their wallet using checkTokens(). You can either check for any token that belogs to a given contract (eg: any cryptokitty), or for particular token IDs within that contract (eg: only for cryptokitty number 500 or 501).

This function requires the following arguments:

  • contractAddress: The address of the smart contract for the token to be checked
  • tokenIds: One or multiple token IDs to check player ownership. This can be a single number, or an array of multiple numbers.

The function returns true or false depending on if the player's wallet owns any of the indicated tokens.

import * as crypto from '@dcl/crypto-scene-utils'


executeTask(async () => {
	let await hasToken = crypto.nft.checkTokens(crypto..contract.mainnet.Halloween2019Collection, [1, 2, 3, 4, 5])
	// only open door to vip area for those that have the tokens
})

Other functions

Call any functions that are available in a token's contract by instancing a contract object. When doing so, you must pass the token's address as a parameter.

import * as crypto from '@dcl/crypto-scene-utils'


executeTask(async () => {
  const contract = await crypto.nft.getContract(crypto..contract.mainnet.Halloween2019Collection)
  log(contract.contract.totalSupply())
})

The getContract() function also returns the requestManager object, which you can use to have greater control over the handling of the transaction.

const { contract, requestManager } = await getContract(crypto.contract.mainnet.MANAToken)

Signing Messages

Request a player to use the private key of their Ethereum wallet to sign a message.

This is a valuable security measure to validate that the player who owns that wallet was truly there, since the signature of a private key can't be forged. Several smart contracts also require passing signed strings as parameters.

import * as crypto from '@dcl/crypto-scene-utils'

executeTask(async () => {
  const message = await crypto.ethereum.signMessage('msg: this is a top secret message')
  log(`MESSAGE: `, message)
})

Note: The string for the message to sign must start be preceded by msg:.

Whenever the signMessage() funcition is called, Metamask will open on the player's browser to request to accept signing the message.

The signMessage() function returns an object that contains:

  • message: The original message that was signed, preceded by the string # DCL Signed message↵msg:
  • signature: The string generated from encrypting the original message through the player's private key

Decentraland contracts

This library includes an enum list of all official Decentraland-released smart contracts, to easily refer to them when using the different functions.

A separate list exists for contracts on mainnet, ropsten, kovan and rinkeby networks.

import { mainnet } from '../node_modules/@dcl/crypto-utils/utils/contract'

log(crypto.contract.mainnet.MANAToken)

The Marketplace

This library exposes several functions that allow players to interact directly with the Decentraland marketplace from inside a scene.

Buy an item from the marketplace

A player can buy an item that's on sale on the Decentraland marketplace without leaving a Decentraland scene, using the executeOrder() function.

This function takes three arguments:

  • nftAddress: string The address of the smart contract for the token being sold. For example if this is a Decentraland wearable, it would be the address of the collection that the wearable belongs to.
  • assetId: number The id of the specific token being traded, within its contract.
  • price: number The price being paid for the item, in MANA. This number is expressed in full MANA units, not in Wei.

TIP: If you navigate the Marketplace to a wearable that's on sale, you'll find both the nftAddress and assetId are part of the URL. For example, in the url https://market.decentraland.org/contracts/0xd35147be6401dcb20811f2104c33de8e97ed6818/tokens/28706, the nftAddress is 0xd35147be6401dcb20811f2104c33de8e97ed6818 and the assetId is 28706. You can obtain all the required data about wearables on sale by querying the Marketplace API.

NOTE: The item needs to be currently published on sale in the Decentraland marketplace.

import * as crypto from '@dcl/crypto-scene-utils'


executeTask(async () => {
	await crypto.marketplace.executeOrder(
        	`0xd35147be6401dcb20811f2104c33de8e97ed6818`,
       		`28706`,
        	30
      	)
}

To buy the item, the player must give the Decentraland Marketplace permissions to operate with MANA on their behalf. If the player doesn't have these permissions set, the executeOrder() will ask for two transactions: one to set these permissions and one to do buy the item.

TIP: You can check to see if your wallet has these permissions set by going to the Marketplace settings page and seeing if this checkbox is checked: Authorize the Marketplace contract to operate MANA on your behalf

Check the player's authorizations

Before a player can buy on the Decentraland Marketplace, they need to give the Marketplace contract permissions to operate with MANA on their behalf. Before a player posts a new order to sell an item, they also need to give the Marketplace permissions to handle items of the contract that items belongs to.

If a player tries to run the executeOrder() function without the necessary permissions, the function will handle adding those permissions first.

To check if a player has the necessary permissions to buy with the Marketplace and has enough MANA in their balance, use isAuthorizedAndHasBalance(). This function requires one field:

  • price: string How much MANA the player should have in their balance. This number is expressed in full MANA units, not in Wei.
import * as crypto from '@dcl/crypto-scene-utils'

executeTask(async () => {
  let permissions = await crypto.marketplace.isAuthorizedAndHasBalance(1000)
  log(permissions)
})

This function returns true only if the player has MANA authorized for the Marketplace, and holds enough MANA currently.

To make the player approve MANA for spending in the Marketplace, you can use the setApproval() function of the currency section of this library, like so:

import * as crypto from '@dcl/crypto-scene-utils'

executeTask(async () => {
  await crypto.currency.setApproval(crypto.contract.mainnet.MANAToken, mainnet.Marketplace)
})

To check if a player has all of the possible permissions set up for the Marketplace, run the isAuthorizedAll() function. This function has one optional parameter

  • address: string (optional) What player address to check for permissions. If no value is provided, it uses the current player running the scene.
import * as crypto from '@dcl/crypto-scene-utils'

executeTask(async () => {
  let permissions = await crypto.marketplace.isAuthorizedAll()
  log(permissions)
})

This function returns an object with three main objects, bidding, buying, and selling. Each of these contains a field for each of the available contracts that might have permissions for that purpose, and for each of these contracts, there's an object containing the address and a boolean for the authorized status of that contract for that purpose.

Below is an extract of part of what the response looks like:

{
	bidding: {
		mana: { address: "0x0f5d2fb29fb7d3cfee444a200298f468908cc942", authorized: true}
	},
	buying: {
		mana: { address: "0x0f5d2fb29fb7d3cfee444a200298f468908cc942", authorized: true}
	}.
	selling: {
		communityContest: { address: "0x32b7495895264ac9d0b12d32afd435453458b1c6", authorized: true},
		(...)
	}
}

If permissions are missing, they can be added with the setApproval() function from the currency or the nftsection of the library, depending on the case.

import * as crypto from '@dcl/crypto-scene-utils'

executeTask(async () => {
  // Give permisions for MANA
  await crypto.currency.setApproval(
    crypto.contract.mainnet.MANAToken,
    crypto.contract.mainnet.Marketplace
  )

  // Give permissions for a specific wearable collection
  await crypto.nft.setApproval(
    crypto.contract.mainnet.Halloween2019Collection,
    crypto.contract.mainnet.Marketplace
  )
})

Sell from a scene

A player can put an item on sale on the Marketplace from within a Decentraland scene using the createOrder() function.

This function takes three arguments:

  • nftAddress: string The address of the smart contract for the token to sell. For example if this is a Decentraland wearable, it would be the address of the collection that the wearable belongs to.
  • assetId: number The id of the specific token being traded, within its contract.
  • price: number The price to set for the order, in MANA. This number is expressed in full MANA units, not in Wei.
  • expireAt: number (optional) When to expire this offer, expressed as milliseconds since January 1, 1970, 00:00:00 UTC. If a value is not set, it defaults to one month from the present time.

TIP: If you navigate the Marketplace to a wearable that's on sale, you'll find both the nftAddress and assetId are part of the URL. For example, in the url https://market.decentraland.org/contracts/0xd35147be6401dcb20811f2104c33de8e97ed6818/tokens/28706, the nftAddress is 0xd35147be6401dcb20811f2104c33de8e97ed6818 and the assetId is 28706. You can obtain all the required data about wearables on sale by querying the Marketplace API.

import * as crypto from '@dcl/crypto-scene-utils'


executeTask(async () => {
	await crypto.marketplace.createOrder(
        	`0xd35147be6401dcb20811f2104c33de8e97ed6818`,
       		`28706`,
        	30
      	)
}

NOTE: The player creating the order needs to own the token being put on sale. The player must also have permissions set to allow the Marketplace contract to operate with this specific token contract. If it's a wearable, the player must have granted permissions for that specific wearable collection.

Cancel the selling of a token

A token that's on sale on the Marketplace can be taken off sale from within a scene, by using the cancelOrder() function.

This function takes two arguments:

  • nftAddress: string The address of the smart contract for the token to sell. For example if this is a Decentraland wearable, it would be the address of the collection that the wearable belongs to.
  • assetId: number The id of the specific token being traded, within its contract.

TIP: If you navigate the Marketplace to a wearable that's on sale, you'll find both the nftAddress and assetId are part of the URL. For example, in the url https://market.decentraland.org/contracts/0xd35147be6401dcb20811f2104c33de8e97ed6818/tokens/28706, the nftAddress is 0xd35147be6401dcb20811f2104c33de8e97ed6818 and the assetId is 28706. You can obtain all the required data about wearables on sale by querying the Marketplace API.

import * as crypto from '@dcl/crypto-scene-utils'


executeTask(async () => {
	await crypto.marketplace.cancelOrder(
        	`0xd35147be6401dcb20811f2104c33de8e97ed6818`,
       		`28706`
      	)
}

NOTE: The player cancelling the order needs to be the creator of the order in the Marketplace and own the token being put on sale. The player must also have permissions set to allow the Marketplace contract to operate with this specific token contract. If it's a wearable, the player must have granted permissions for that specific wearable collection.

Third parties operating tokens

You can check if a given contract is allowed to handle a given token for a player, and otherwise carry out a transaction to allow it to.

Many smart contracts require to be given explicit permission by a wallet owner to operate with the token on their behalf, especially when the contract has the ability to remove tokens from the owner's balance.

Currencies

To check if a contract has permissions to handle a specific currency token for a player, use the isApproved() function. This function takes 3 arguments:

  • contractAddress: string Address of the token smartcontract to check
  • owner: string Address of the player that is currently holding the token
  • spender: string Address of the contract to check for having permissions to spend the token
import * as crypto from '@dcl/crypto-scene-utils'

executeTask(async () => {
  let approval = await crypto.currency.isApproved(
    crypto.contract.mainnet.MANAToken,
    crypto.contract.mainnet.Marketplace
  )
  log(approval)
})

The isApproved() function returns a boolean indicating wether permissions are there or not.

To check how much is the maximum allowance that a contract has to handle a specific currency token for a player, use the allowance() function. This function takes three arguments:

  • contractAddress: string Address of the token smartcontract to check
  • owner: string Address of the player that is currently holding the token
  • spender: string Address of the contract to check for having permissions to spend the token
import * as crypto from '@dcl/crypto-scene-utils'

executeTask(async () => {
  let approval = await crypto.currency.allowance(
    crypto.contract.mainnet.MANAToken,
    crypto.contract.mainnet.Marketplace
  )
  log(approval)
})

The allowance() function returns a string with the number of allowed currency, expressed in wei units.

To grant permissions to a contract to handle a specific currency token for a player, use the setApproval() function. This function takes 4 arguments:

  • contractAddress: string Address of the token smartcontract to check
  • spender: string Address of the contract to check for having permissions to spend the token
  • waitConfirm: boolean (optional) If true, resolve promise when the transaction is mined on the blockchain
  • amount: string (optional) Maximum amount of the currency to allow the spender to spend
import * as crypto from '@dcl/crypto-scene-utils'

executeTask(async () => {
  await crypto.currency.setApproval(
    crypto.contract.mainnet.MANAToken,
    crypto.contract.mainnet.Marketplace,
    true
  )
})

NFTs

To check if a contract has permissions to handle a specific type of NFT for a player, use the isApprovedForAll() function. This function takes 3 arguments:

  • contractAddress: string Address of the token smartcontract to check
  • assetHolder: string Address of the player that is currently holding the token
  • operator: string Address of the contract to check for having permissions to handle the token
import * as crypto from '@dcl/crypto-scene-utils'

executeTask(async () => {
  let approval = await crypto.nft.isApproved(
    crypto.contract.mainnet.Halloween2019Collection,
    crypto.contract.mainnet.Marketplace
  )
  log(approval)
})

The isApproved() function returns a boolean indicating wether permissions are there or not.

To grant permissions to a contract to handle a specific NFT for a player, use the setApprovalForAll() function. This function takes 4 arguments:

  • contractAddress: string Address of the token smartcontract to check
  • operator: string Address of the contract to check for having permissions to spend the token
  • approved: boolean (optional) If true, sets the contract as approved for this NFT, if false, it removes these same approvals. true by default.
import * as crypto from '@dcl/crypto-scene-utils'

executeTask(async () => {
  await crypto.nft.setApprovalForAll(
    crypto.contract.mainnet.Halloween2019Collection,
    crypto.contract.mainnet.Marketplace,
    true
  )
})

Call functions from any contract

Call any functions that are available in any smart contract by instancing a contract object. When doing so, you must pass:

  • contractAdress: The token's Ethereum smart contract address.
  • abi: The ABI definition for the contract, where all of its functions and parameters are listed
executeTask(async () => {
  const contract = await crypto.contract.getContract(
    '0xF87E31492Faf9A91B02Ee0dEAAd50d51d56D5d4d',
    LANDAbi
  )
})

The getContract() function also returns the requestManager object, which you can use to have greater control over the handling of the transaction.

const { contract, requestManager } = await crypto.currency.getContract(
  crypto.contract.mainnet.MANAToken
)

You can obtain the ABI of a contract on etherscan. For example, if you go to the Etherscan page for the LAND contract, you can find the ABI by picking the Contract tab in the bottom section and then scrolling down. You can export the ABI to JSON, and add that as a file in your scene's project, or paste its contents into a .ts file in your scene's project.

Avatar

Get user information

To get information about an user, use the getUserInfo() function.

getUserInfo has one optional argument:

  • address: string which is the ETH address of a user

If an address is not specified, the function will use the address of the current user running the scene.

This example retrieves the data of an address and prints the username in console:

import * as crypto from '@dcl/crypto-scene-utils'

crypto.avatar.getUserInfo('0x521b0fef9cdcf250abaf8e7bc798cbe13fa98692').then((userInfo) => {
  log(userInfo.metadata.avatars[0].name)
})

The getUserData() function returns the following information:

  • content: An array containing four objects, each with the path to a different screenshot of the player: a full body image, and three versions of the face in full and in thumbnail resolution.
  • metdta: An object that includes:
    • avatar: All of the wearables and configurations on the avatar
    • inventory: All of the wearables the player owns
    • ethAddress: (string) The public key of the player's Ethereum wallet. If the player has no linked wallet, this field will be null.
    • name: The player's user name, as others see in-world
    • userId: (string) A UUID string that identifies the player. If the player has a public key, this field will have the same value as the public key. the player's email and bio if present.
  • timestamp: A timestamp for the time this data was fetched.

Note: For any Ethereum transactions with the player, always use the ethAddress field, instead of the userId.

Get a user's snapshot images

Use getPlayerSnapshots() to fetch a set of URLs for snapshots of the player wearing the current wearables they have on. These snapshots are available in different resolutions, and both of the face and full body.

The response contains the following data:

  • face: URL for the full resolution image of the face, with 512x512 pixels
  • face128: URL for the face as a 128x128 pixel image
  • face256: URL for the face as a 256x256 pixel image
  • body: URL for the full resolution image of the face, with 512x1024 pixels

Optionally pass a player id to fetch the snapshots of that player's particular avatar, it will otherwise fetch the snapshots of the player's avatar.

import * as crypto from '@dcl/crypto-scene-utils'

// create an entity to use as canvas
let planeEntity = new Entity()
planeEntity.addComponent(new Transform( {position: new Vector3(8, 1, 8)}))
planeEntity.addComponent(new PlaneShape())
engine.addEntity(planeEntity)

// fetch snapshot data
crypto.avatar.getPlayerSnapshots('0x521b0fef9cdcf250abaf8e7bc798cbe13fa98692').then((snapShots) => {
  log(snapShots)

  // apply snapshot to the plane entity
  if (snapShots) {
    let faceTexture = new Texture(snapShots.face256)
    let faceMaterial = new Material()
    faceMaterial.albedoTexture = faceTexture
    planeEntity.addComponent(faceMaterial)
  }
})

This example fetches the snapshots from a specific player, then sets that as a texture on a plane.

Get user inventory

To fetch the full inventory of wearable items owned by a player, use the getUserInventory() function.

getUserInventory has one optional argument:

  • address: string which is the ETH address of an user

If an address is not specified, the function will use the address of the current user running the scene.

This example retrieves the inventory of an address and print a list of items in the console:

import * as crypto from '@dcl/crypto-scene-utils'

crypto.avatar.getUserInventory('0x521b0fef9cdcf250abaf8e7bc798cbe13fa98692').then((inventory) => {
  log(inventory)
})

This function returns an array with the full names of each wearabe, for example:

["dcl://halloween_2019/zombie_suit_mask", "dcl://community_contest/cw_tuxedo_tshirt_upper_body", "dcl://dcl_launch/mana_hoodie_upper_body"]

Check if a player has an item

To check if an item is in the inventory of a player, use the itemInInventory function.

itemInInventory has one required and one optional argument:

  • wearable: string which is the name of a wearable (e.g.: dcl://dcl_launch/razor_blade_upper_body)

  • equiped: boolean (optional) if true, the player must have the item currently equipped (default: false)

This example checks if the player has the Razor Blade Jacket wearable equiped. If so, the function returns true.

import * as crypto from '@dcl/crypto-scene-utils'

crypto.avatar
  .itemInInventory('dcl://dcl_launch/razor_blade_upper_body', true)
  .then((isItemEquiped) => {
    if (isItemEquiped) log('The Razor Blade jacket is equiped')
    else log('This item is not equiped')
  })

Tip: You can find out the full name of a wearable by using getListOfWearables() to get a full list of all wearables supported by Decentraland, with all their information.

Check if a player has one of several items

To check if at least one of several items are in the inventory of a player, use the itemsInInventory function.

itemsInInventory has one required and one optional argument:

  • wearables: string[] An array with the string names of the wearables to look for (e.g.: ["dcl://dcl_launch/razor_blade_upper_body", "dcl://community_contest/cw_tuxedo_tshirt_upper_body"]).

  • equiped: boolean (optional) if true, the player must have one of the items currently equipped (default: false).

This example checks if the player has the Razor Blade Jacket equiped or the Tuxedo Shirt. If so, the function returns true.

import * as crypto from '@dcl/crypto-scene-utils'

crypto.avatar
  .itemsInInventory(
    [
      'dcl://dcl_launch/razor_blade_upper_body',
      'dcl://community_contest/cw_tuxedo_tshirt_upper_body',
    ],
    true
  )
  .then((isItemEquiped) => {
    if (isItemEquiped) log('One of the items is equiped')
    else log('None of the items are equiped')
  })

Tip: You can find out the full name of a wearable by using getListOfWearables() to get a full list of all wearables supported by Decentraland, with all their information.

Get the rarity of the player's rarest item

Use the rarestItem() function to find out what's the rarest item that the player owns.

It returns the rarity category as a value from the rarityLevel enum.

rarestItem() has one optional argument:

  • equiped: boolean (optional) if true, only the items currently equipped are considered.

This example checks what's the rarest item owned and logs the category name.

import * as crypto from '@dcl/crypto-scene-utils'

crypto.avatar
  .rarestItem(
    true
  )
  .then((item) => {
   log('rarest item equipped: ', rarityLevel[item] )
  })

Tip: To see the name of the rarity category, rather than the index, reference the rarityLevel enum, for example rarityLevel[response].

Get data of all wearables

To fetch a list of wearables supported by Decentraland, including their full names, categories, contracts, etc, call the getListOfWearables(). This function supports the following filters:

{
  collectionIds: string[]
  wearableIds: string[]
  textSearch: string
}
import * as crypto from '@dcl/crypto-scene-utils'

executeTask(async () => {
  const someWearables = await crypto.wearable.getListOfWearables({ collectionIds: ['urn:decentraland:ethereum:collections-v1:mf_sammichgamer'] })
  log(someWearables)
})

This function returns an array of wearables.


Contribute

In order to test changes made to this repository in active scenes, do the following:

  1. Run npm run link on this repository
  2. On the scene directory, after you installed the dependency, run npm link @dcl/crypto-scene-utils

CI/CD

This repository uses semantic-release to atumatically release new versions of the package to NPM.

Use the following convention for commit names:

feat: something: Minor release, every time you add a feature or enhancement that doesn’t break the api.

fix: something: Bug fixing / patch

chore: something: Anything that doesn't require a release to npm, like changing the readme. Updating a dependency is not a chore if it fixes a bug or a vulnerability, that's a fix.

If you break the API of the library, you need to do a major release, and that's done a different way. You need to add a second comment that starts with BREAKING CHANGE, like:

commit -m "feat: changed the signature of a method" -m "BREAKING CHANGE: this commit breaks the API, changing foo(arg1) to foo(arg1, arg2)"