Esta tecnología que revolucionará Ethereum está próxima a lanzar
Tags: blockchain, layer2, ethereum
Published: 2022-06-08 17:18:45

---
title: Esta tecnología que revolucionará Ethereum está próxima a lanzar
published: true
description: 
tags: blockchain, layer2, ethereum
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eszl11t9oc42i008yrdy.png
---

zkSync 2.0 es un ZK Rollup full compatible con la Ethereum Virtual Machine. Esto no solo nos permitirá ahorrar gas de la manera mas segura, sino que también podremos lanzar smart contracts escritos en solidity haciéndolo un buen lugar para acoger a DeFi, NFTs y todo lo demás que hoy está ocurriendo en Layer 1. zkSync 2.0 el primer proyecto en lograr esto ya está disponible en un alpha testnet. En este video veremos cómo usar el testnet y lanzaremos un Smart Contract con su respectiva UI. Personalmente estoy muy emocionado por este proyecto que nos permitirá ahorrar gas confiando enteramente en pruebas matemáticas. Esto es algo que especulabamos que iba a ser posible hasta dentro de varios años pero ya está a la vuelta de la esquina.

https://www.youtube.com/watch?v=t8dSW47sqhg

## Antes de iniciar

Asegurate de instalar [Metamask](https://metamask.io/), conectar tu wallet al testnet de zkSync:

* Network Name: `zkSync alpha testnet`
* New RPC URL: `https://zksync2-testnet.zksync.dev`
* Chain ID: `280`

y también asegúrate conseguir ether de prueba en L2 desde ya sea el bridge o el faucet que puedes encontrar en el [Portal de zkSync](https://portal.zksync.io/). Para usar el bridge ocuparás Ether de Goreli que puedes conseguir en [este faucet](https://faucet.goerli.mudit.blog).

## 1. Preparativos

Necesitaremos npm para este tutorial. Les muestro cómo lo hice en Ubuntu 22.04.

```bash
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
nvm install 14
nvm use 14
```

También necesitaremos Docker, a continuación muestro cómo lo instalé.
```bash
sudo apt-get update
sudo apt-get install \
    ca-certificates \
    curl \
    gnupg \
    lsb-release
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
wget https://desktop.docker.com/linux/main/amd64/docker-desktop-4.8.2-amd64.deb
sudo apt install ./docker-desktop-4.8.2-amd64.deb
systemctl --user start docker-desktop
sudo usermod -aG docker $USER
```

Una vez instalado Docker, procedemos a crear un nuevo proyecto de Hardhat.

```bash
mkdir MyL2Project
cd MyL2Project
npm install --save-dev hardhat
npx hardhat
```

Luego de completar el diálogo de Hardhat en la terminal, finalizamos instalando un par de librerías extra.

```bash
# si estás en ubuntu necesitarás esto: sudo apt install build-essential
npm install --save-dev typescript ts-node ethers zksync-web3 @matterlabs/hardhat-zksync-solc@0.3 @matterlabs/hardhat-zksync-deploy@0.2 dotenv
```

## 2. Lanzar un contrato

Primero borramos el contrato que viene por defecto `contracts/Greeter.sol` y escribimos uno nuestro en la carpeta `contracts/`.

`contracts/Hello.sol`
```solidity
// SPDX-License-Identifier: MIT
pragma solidity 0.8.12;

contract Hello {
    string public hello;

    constructor()
    {
        hello = "Hola mundo!";
    }

    function setHello(string memory _hello) public {
        hello = _hello;
    }
}
```

Hardhat también es compatible con Typescript que es lo que usaremos en este video. Así que renombramos `hardhat.config.js` a `hardhat.config.ts` y haremos los cambios necesarios.

`hardhat.config.ts`
```ts
require("@nomiclabs/hardhat-waffle");
require("@matterlabs/hardhat-zksync-deploy");
require("@matterlabs/hardhat-zksync-solc");

module.exports = {
  zksolc: {
    version: "0.1.0",
    compilerSource: "docker",
    settings: {
      optimizer: {
        enabled: true,
      },
      experimental: {
        dockerImage: "matterlabs/zksolc",
      },
    },
  },
  zkSyncDeploy: {
    zkSyncNetwork: "https://zksync2-testnet.zksync.dev",
    ethNetwork: "goerli", // Can also be the RPC URL of the network (e.g. `https://goerli.infura.io/v3/<API_KEY>`)
  },
  networks: {
    // To compile with zksolc, this must be the default network.
    hardhat: {
      zksync: true,
    },
  },
  solidity: {
    version: "0.8.12",
  },
};

```

Ahora escribimos el script de deploy que debe estar en una nueva carpeta llamada `deploy/`.

`deploy/deploy.ts`
```ts
import { utils, Wallet } from "zksync-web3";
import { HardhatRuntimeEnvironment } from "hardhat/types";
import { Deployer } from "@matterlabs/hardhat-zksync-deploy";
import dotenv from "dotenv"

// An example of a deploy script that will deploy and call a simple contract.
export default async function (hre: HardhatRuntimeEnvironment) {
  dotenv.config()
  console.log(`Running deploy script for the Hello contract`);

  // Initialize the wallet.
  const wallet = new Wallet("" + process.env.PRIVATE_KEY);

  // Create deployer object and load the artifact of the contract we want to deploy.
  const deployer = new Deployer(hre, wallet);
  const artifact = await deployer.loadArtifact("Hello");

  // Deploy this contract. The returned object will be of a `Contract` type, similarly to ones in `ethers`.
  const helloContract = await deployer.deploy(artifact, []);

  // Show the contract info.
  const contractAddress = helloContract.address;
  console.log(`${artifact.contractName} was deployed to ${contractAddress}`);

  // Call the deployed contract.
  const helloFromContract = await helloContract.hello();
  console.log(`Contract says hello to us with ${helloFromContract}!`);
}
```

Crea un archivo llamado `.env` y coloca tu llave privada adentro siguiendo el siguiente formato:

`.env`
```bash
PRIVATE_KEY=TULLAVEAQUÍ
```

Ahora compilamos el contrato.

```bash
npx hardhat compile
```

Y lo lanzamos.

```bash
npx hardhat deploy-zksync
```

## 3. El Frontend

Hacer un frontend para un contrato en zkSync 2.0 Testnet es igual que en cualquier blockchain compatible con la EVM. Solo asegúrate de establecer el netwrok id `280`.

Comenzamos creando un archivos de HTML.

`index.html`
```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
</head>
<body>
  <input id="connect_button" type="button" value="Connect" onclick="connectWallet()" style="display: none"></input>
  <p id="account_address" style="display: none"></p>
  <p id="web3_message"></p>
  <p id="contract_state"></p>
  <input type="input"  value="" id="_hello"></input>
  <input type="button" value="Set Hello" onclick="_setHello()"></input>
  <br>
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/web3/1.3.5/web3.min.js"></script>
  <script type="text/javascript" src="blockchain_stuff.js"></script>
</body>
</html>

<script>
  function _setHello()
  {
    _hello = document.getElementById("_hello").value
    setHello(_hello)
  }
</script>
```

Luego el javascript necesario. Asegúrate de establecer la variable `MY_CONTRACT_ADDRESS` con el address de tu contrato.

`blockchain_stuff.js`
```js
const NETWORK_ID = 280

const MY_CONTRACT_ADDRESS = "0x0000000000000000000000000000000000000000"
const MY_CONTRACT_ABI_PATH = "./json_abi/MyContract.json"
var my_contract

var accounts
var web3

function metamaskReloadCallback() {
  window.ethereum.on('accountsChanged', (accounts) => {
    document.getElementById("web3_message").textContent="Se cambió el account, refrescando...";
    window.location.reload()
  })
  window.ethereum.on('networkChanged', (accounts) => {
    document.getElementById("web3_message").textContent="Se el network, refrescando...";
    window.location.reload()
  })
}

const getWeb3 = async () => {
  return new Promise((resolve, reject) => {
    if(document.readyState=="complete")
    {
      if (window.ethereum) {
        const web3 = new Web3(window.ethereum)
        window.location.reload()
        resolve(web3)
      } else {
        reject("must install MetaMask")
        document.getElementById("web3_message").textContent="Error: Porfavor conéctate a Metamask";
      }
    }else
    {
      window.addEventListener("load", async () => {
        if (window.ethereum) {
          const web3 = new Web3(window.ethereum)
          resolve(web3)
        } else {
          reject("must install MetaMask")
          document.getElementById("web3_message").textContent="Error: Please install Metamask";
        }
      });
    }
  });
};

const getContract = async (web3, address, abi_path) => {
  const response = await fetch(abi_path);
  const data = await response.json();
  
  const netId = await web3.eth.net.getId();
  contract = new web3.eth.Contract(
    data,
    address
    );
  return contract
}

async function loadDapp() {
  metamaskReloadCallback()
  document.getElementById("web3_message").textContent="Please connect to Metamask"
  var awaitWeb3 = async function () {
    web3 = await getWeb3()
    web3.eth.net.getId((err, netId) => {
      if (netId == NETWORK_ID) {
        var awaitContract = async function () {
          my_contract = await getContract(web3, MY_CONTRACT_ADDRESS, MY_CONTRACT_ABI_PATH)
          document.getElementById("web3_message").textContent="You are connected to Metamask"
          onContractInitCallback()
          web3.eth.getAccounts(function(err, _accounts){
            accounts = _accounts
            if (err != null)
            {
              console.error("An error occurred: "+err)
            } else if (accounts.length > 0)
            {
              onWalletConnectedCallback()
              document.getElementById("account_address").style.display = "block"
            } else
            {
              document.getElementById("connect_button").style.display = "block"
            }
          });
        };
        awaitContract();
      } else {
        document.getElementById("web3_message").textContent="Please connect to zkSync Testnet";
      }
    });
  };
  awaitWeb3();
}

async function connectWallet() {
  await window.ethereum.request({ method: "eth_requestAccounts" })
  accounts = await web3.eth.getAccounts()
  onWalletConnectedCallback()
}

loadDapp()

const onContractInitCallback = async () => {
  var hello = await my_contract.methods.hello().call()

  var contract_state = "Hello: " + hello
  
  document.getElementById("contract_state").textContent = contract_state;
}

const onWalletConnectedCallback = async () => {
}


//// Functions ////

const setHello = async (_hello) => {
  const result = await my_contract.methods.setHello(_hello)
  .send({ from: accounts[0], gas: 100000, value: 0 })
  .on('transactionHash', function(hash){
    document.getElementById("web3_message").textContent="Waiting confirmation...";
  })
  .on('receipt', function(receipt){
    document.getElementById("web3_message").textContent="Success.";    })
  .catch((revertReason) => {
    console.log("ERROR! Transaction reverted: " + revertReason.receipt.transactionHash)
  });
}
```

Ahora extraemos el JSON ABI que está en el archivo `TUPROYECTO/artifacts-zk/contracts/Hello.sol/Hello.json` bajo el tag `"abi"`. Que debería verse algo así una vez puesto en una nueva carpeta que creamos llamada `json_abi`:

`json_abi/MyContract.json`
```json
[
    {
      "inputs": [],
      "stateMutability": "nonpayable",
      "type": "constructor"
    },
    {
      "inputs": [],
      "name": "hello",
      "outputs": [
        {
          "internalType": "string",
          "name": "",
          "type": "string"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "string",
          "name": "_hello",
          "type": "string"
        }
      ],
      "name": "setHello",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    }
]
```

Ahora estamos listos para interactuar con nuestro contrato instalando un servidor local y luego iniciándolo.

```bash
npm i --global lite-server
lite-server
```

Fuentes oficiales: [Github de NVM](https://github.com/nvm-sh/nvm), [Instalar Docker en Ubuntu](https://docs.docker.com/engine/install/ubuntu/), [Descarga de Docker Desktop](https://docs.docker.com/desktop/release-notes/), [Instalar Docker Desktop en Ubuntu](https://docs.docker.com/desktop/linux/install/ubuntu/), [zkSync Testnet Getting Started](https://v2-docs.zksync.io/api/hardhat/getting-started.html#initializing-the-project)

**Gracias por ver este tutorial!**

Sígannos en dev.to y en [Youtube](https://www.youtube.com/c/FilosofiaCodigo) para todo lo relacionado al desarrollo en Blockchain en Español.