# Operaciones de blockchain de la scene

Una escena de Decentraland puede interactuar con la blockchain de Ethereum. Esto puede servir para obtener datos sobre la wallet del usuario y los tokens que contiene, o para iniciar transacciones que podrían involucrar cualquier token de Ethereum, fungible o no fungible. Esto puede usarse de muchas maneras, por ejemplo para vender tokens, recompensar tokens como parte de una mecánica de juego, cambiar cómo un jugador interactúa con una escena si posee ciertos tokens, etc.

Ten en cuenta que todas las transacciones en la mainnet de Ethereum que sean iniciadas por una escena requerirán que el jugador apruebe y pague una tarifa de gas.

Todas las operaciones con la blockchain también deben llevarse a cabo como [funciones asíncronas](https://docs.decentraland.org/creator/content-creator-es/scenes-sdk7/patrones-de-programacion/async-functions), ya que el tiempo depende de eventos externos.

## Obtener la cuenta de ethereum de un jugador

Para obtener la cuenta de Ethereum de un jugador, usa `getPlayer()` función.

```ts
import { getPlayer } from '@dcl/sdk/src/players'

export function main() {
	let userData = getPlayer()
	if (!userData.isGuest) {
		console.log(userData.userId)
	} else {
		log('El jugador no está conectado con Web3')
	}
}
```

Ten en cuenta que si un jugador ha entrado a Decentraland como invitado, no tendrá una wallet de ethereum conectada. Si han entrado como invitados, el `isGuest` campo en la respuesta de `getPlayer()` será verdadero. Si `hasConnectedWeb3` es verdadero, entonces puedes obtener la dirección del jugador desde el campo `publicKey`. Aprende más sobre los datos que puedes obtener de un jugador en [obtener datos del jugador](https://docs.decentraland.org/creator/content-creator-es/interactividad/user-data#get-player-data)

Deberías envolver la función en una `async()` función, aprende más sobre esto en [funciones async](https://docs.decentraland.org/creator/content-creator-es/scenes-sdk7/patrones-de-programacion/async-functions)

{% hint style="warning" %}
**📔 Nota**: Aunque la dirección de eth puede contener caracteres en mayúscula, algunos navegadores convierten la cadena devuelta a minúsculas automáticamente. Si deseas comparar valores de direcciones y que funcione en todos los navegadores, usa el `.toLowerCase()` método para convertir el valor a minúsculas.
{% endhint %}

## Comprobar el precio del gas

Después de importar la librería `eth-connect` debes instanciar un proveedor web3 y un request manager, lo que te permitirá conectarte vía web3 a Metamask en el navegador del jugador.

La función abajo obtiene el precio de gas actual en la red principal de Ethereum y lo muestra.

```ts
import { RequestManager } from 'eth-connect'
import { createEthereumProvider } from '@dcl/sdk/ethereum-provider'

executeTask(async function () {
	// crea una instancia del proveedor web3 para interactuar con Metamask
	const provider = createEthereumProvider()
	// Crea el objeto que manejará el envío y recepción de mensajes RPC
	const requestManager = new RequestManager(provider)
	// Comprueba el precio de gas actual en la red de Ethereum
	const gasPrice = await requestManager.eth_gasPrice()
	// registrar respuesta
	console.log({ gasPrice })
})
```

{% hint style="info" %}
**💡 Tip**: Ten en cuenta que las funciones manejadas por el `requestManager` deben llamarse usando `await`, ya que dependen de la obtención de datos externos y pueden tardar algún tiempo en completarse.
{% endhint %}

## Importar un ABI de contrato

Un ABI (Application Binary Interface) describe cómo interactuar con un contrato de Ethereum, determinando qué funciones están disponibles, qué entradas requieren y qué devuelven. Cada contrato de Ethereum tiene su propio ABI; debes importar los ABIs de todos los contratos que desees usar en tu proyecto.

Por ejemplo, aquí hay un ejemplo de una función en el ABI de MANA:

```ts
{
  anonymous: false,
  inputs: [
    {
      indexed: true,
      name: 'burner',
      type: 'address'
    },
    {
      indexed: false,
      name: 'value',
      type: 'uint256'
    }
  ],
  name: 'Burn',
  type: 'event'
}
```

Las definiciones de ABI pueden ser bastante largas, ya que a menudo incluyen muchas funciones, por lo que recomendamos pegar el contenido JSON de un archivo ABI en un `.ts` archivo separado e importarlo desde allí en otros archivos de escena. También recomendamos guardar todos los archivos ABI en una carpeta separada de tu escena, llamada `/contracts`.

```ts
import { abi } from '../contracts/mana'
```

Aquí hay enlaces a diferentes contratos de Decentraland. Obtén el ABI de cada contrato haciendo clic en *Export ABI* y eligiendo *JSON Format*.

* [MANA Token ABI](https://etherscan.io/address/0x0f5d2fb29fb7d3cfee444a200298f468908cc942#code)
* [Decentraland Marketplace](https://etherscan.io/address/0x19a8ed4860007a66805782ed7e0bed4e44fc6717#code)
* [LAND ABI](https://etherscan.io/address/0xf87e31492faf9a91b02ee0deaad50d51d56d5d4d#code)
* [Estate ABI](https://etherscan.io/address/0x959e104e1a4db6317fa58f8295f586e1a978c297#code)
* [AvatarNameRegistry ABI](https://etherscan.io/address/0x894b883905bfEe2CC448880F1b59f4A762E67566)
* [Catalyst ABI](https://etherscan.io/address/0xcc054fab08127c19f621ab83ade5962cd10584ec)

Estos son los contratos de las distintas colecciones de wearables: (cada colección fue emitida como un contrato separado)

* [ExclusiveMasksCollection ABI](https://etherscan.io/address/0xc04528c14c8ffd84c7c1fb6719b4a89853035cdd)
* [Halloween2019Collection ABI](https://etherscan.io/address/0xc1f4b0eea2bd6690930e6c66efd3e197d620b9c2)
* [Halloween2019CollectionFactory ABI](https://etherscan.io/address/0x07ccfd0fbada4ac3c22ecd38037ca5e5c0ad8cfa)
* [Xmas2019Collection ABI](https://etherscan.io/address/0xc3af02c0fd486c8e9da5788b915d6fff3f049866)
* [MCHCollection ABI](https://etherscan.io/address/0xf64dc33a192e056bb5f0e5049356a0498b502d50)
* [CommunityContestCollection ABI](https://etherscan.io/address/0x32b7495895264ac9d0b12d32afd435453458b1c6)
* [DCLLaunchCollection ABI](https://etherscan.io/address/0xd35147be6401dcb20811f2104c33de8e97ed6818)
* [DCGCollection ABI](https://etherscan.io/address/0x3163d2cfee3183f9874e2869942cc62649eeb004)

{% hint style="info" %}
**💡 Tip**: Para ver claramente las funciones expuestas por un contrato, ábrelo en [abitopic.io](https://abitopic.io). Simplemente pega la dirección del contrato allí y abre la *functions* pestaña para ver la lista completa de funciones soportadas y sus argumentos. Incluso puedes probar a llamar a las funciones con diferentes parámetros a través de la página web.
{% endhint %}

Configurar TypeScript para poder importar desde un archivo JSON tiene sus dificultades. La solución alternativa más sencilla recomendada es cambiar la `ABI.JSON` extensión del archivo a `.ts` y modificarlo ligeramente para que su contenido comience con `export default`.

Por ejemplo, si el contenido del archivo ABI comienza con `[{"constant":true,"inputs":[{"internalType":"bytes4" ...etc`, modifícalo para que comience con `export default [{"constant":true,"inputs":[{"internalType":"bytes4" ...etc`.

### Instanciar un contrato

Después de importar la librería `eth-connect` biblioteca y el *abi*, debes instanciar varios objetos que te permitirán usar las funciones del contrato y conectar con Metamask en el navegador del jugador.

También debes importar el proveedor web3. Esto se debe a que Metamask en el navegador del jugador usa web3, por lo que necesitamos una forma de interactuar con eso.

```ts
import { RequestManager, ContractFactory } from 'eth-connect'
import { createEthereumProvider } from '@dcl/sdk/ethereum-provider'
import { abi } from '../contracts/mana'

executeTask(async () => {
	// crea una instancia del proveedor web3 para interactuar con Metamask
	const provider = createEthereumProvider()
	// Crea el objeto que manejará el envío y recepción de mensajes RPC
	const requestManager = new RequestManager(provider)
	// Crea un objeto factory basado en el abi
	const factory = new ContractFactory(requestManager, abi)
	// Usa el objeto factory para instanciar un objeto `contract`, referenciando un contrato específico
	const contract = (await factory.at(
		'0x2a8fd99c19271f4f04b1b7b9c4f7cf264b626edb'
	)) as any
})
```

{% hint style="info" %}
**💡 Tip**: Para contratos que siguen un mismo estándar, como ERC20 o ERC721, puedes importar un único ABI genérico para todos. Luego generas un solo `ContractFactory` objeto con ese ABI y usas esa misma factory para instanciar interfaces para cada contrato.
{% endhint %}

### Llamar a los métodos de un contrato

Una vez que hayas creado un `contract` objeto, puedes llamar fácilmente a las funciones que están definidas en su ABI, pasándoles los parámetros de entrada especificados.

```ts
import { getPlayer } from '@dcl/sdk/src/players'
import { createEthereumProvider } from '@dcl/sdk/ethereum-provider'
import { RequestManager, ContractFactory } from 'eth-connect'
import { abi } from '../contracts/mana'

executeTask(async () => {
	try {
		// Pasos de configuración explicados en la sección anterior
		const provider = createEthereumProvider()
		const requestManager = new RequestManager(provider)
		const factory = new ContractFactory(requestManager, abi)
		const contract = (await factory.at(
			'0x2a8fd99c19271f4f04b1b7b9c4f7cf264b626edb'
		)) as any
		let userData = getPlayer()
		if (userData.isGuest) {
			return
		}

		// Ejecuta una función del contrato
		const res = await contract.setBalance(
			'0xaFA48Fad27C7cAB28dC6E970E4BFda7F7c8D60Fb',
			100,
			{
				from: userData.userId,
			}
		)
		// Registrar la respuesta
		console.log(res)
	} catch (error: any) {
		console.log(error.toString())
	}
})
```

El ejemplo anterior usa el abi del contrato MANA en Ropsten y transfiere 100 *MANA falsos* a tu cuenta en la red de pruebas Ropsten.

### Otras funciones

La biblioteca eth-connect incluye una serie de otros ayudantes que puedes usar. Por ejemplo, para:

* Obtener un precio estimado del gas
* Obtener el balance de una dirección determinada
* Obtener el recibo de una transacción
* Obtener el número de transacciones enviadas desde una dirección
* Convertir entre varios formatos incluyendo hexadecimal, binario, utf8, etc.

## Usar la red de pruebas de Ethereum

Mientras pruebas tu escena, para evitar transferir MANA real u otras monedas, puedes usar la *red de pruebas Ethereum Sepolia* y transferir MANA de prueba falso en su lugar.

Para usar la red de pruebas debes configurar tu extensión Metamask en Chrome para usar la *red de pruebas Sepolia* en lugar de *red principal*.

Debes conseguir Ether de Sepolia, que puedes obtener gratis desde varios faucets externos como [este](https://www.alchemy.com/faucets/ethereum-sepolia/).

{% hint style="info" %}
**💡 Tip**: Para ejecutar la transacción de transferir MANA de Sepolia a tu wallet, necesitarás pagar una tarifa de gas en Sepolia Ether.
{% endhint %}

Para previsualizar tu escena usando la red de pruebas, pega la siguiente URL en una pestaña del navegador. Esto abrirá la escena en el cliente de escritorio de Decentraland:

`decentraland://realm=http://127.0.0.1:8000&local-scene=true&debug=true&dclenv=zone&position=0,0`

{% hint style="info" %}
**💡 Tip**: Cambia el parámetro position por las coordenadas de tu escena, para cargar directamente en tu escena.
{% endhint %}

Cualquier transacción que aceptes mientras visualizas la escena en este modo solo ocurrirá en la red de pruebas y no afectará el saldo de MANA en tu wallet real.

Si necesitas probar transacciones en la Testnet de Polygon y necesitas tener MANA en esa testnet, tendrás que cambiar (swap) MANA a esa red después de adquirirlo en Sepolia. Para puentear (bridge) MANA de Sepolia a la Testnet de Polygon, visita tu [página de cuenta de Decentraland en Sepolia](https://account.decentraland.zone/) y haz clic en ‘swap’ en el lado de Ethereum MANA.

Al ejecutar una vista previa en el cliente web heredado, de una escena que usa una de las librerías de ethereum, debes abrir la vista previa en una ventana de navegador separada, tener Metamask abierto en tu navegador e incluir manualmente la cadena `&ENABLE_WEB3`.

## Enviar mensajes RPC personalizados

Usa la función `sendAsync()` para enviar mensajes por [protocolo RPC](https://en.wikipedia.org/wiki/Remote_procedure_call).

```ts
import { sendAsync } from '~system/EthereumController'

// enviar un mensaje
await sendAsync({
	id: 1,
	method: 'myMethod',
	jsonParams: '{ myParam: myValue }',
})
```

## Contratos inteligentes de Decentraland

En el siguiente enlace puedes encontrar una lista de contratos inteligentes de Ethereum relevantes para el ecosistema de Decentraland. La lista incluye los contratos en mainnet así como en otras redes de prueba de Ethereum.

[contracts.decentraland.org](https://contracts.decentraland.org/links)
