DEV Community

Cover image for Esta tecnología que revolucionará Ethereum está próxima a lanzar
Ahmed Castro
Ahmed Castro

Posted on

Esta tecnología que revolucionará Ethereum está próxima a lanzar

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, 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. Para usar el bridge ocuparás Ether de Goreli que puedes conseguir en este faucet.

1. Preparativos

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

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
nvm install 14
nvm use 14
Enter fullscreen mode Exit fullscreen mode

También necesitaremos Docker, a continuación muestro cómo lo instalé.

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
Enter fullscreen mode Exit fullscreen mode

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

mkdir MyL2Project
cd MyL2Project
npm install --save-dev hardhat
npx hardhat
Enter fullscreen mode Exit fullscreen mode

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

# 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
Enter fullscreen mode Exit fullscreen mode

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

// 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;
    }
}
Enter fullscreen mode Exit fullscreen mode

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

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",
  },
};

Enter fullscreen mode Exit fullscreen mode

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

deploy/deploy.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}!`);
}
Enter fullscreen mode Exit fullscreen mode

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

.env

PRIVATE_KEY=TULLAVEAQUÍ
Enter fullscreen mode Exit fullscreen mode

Ahora compilamos el contrato.

npx hardhat compile
Enter fullscreen mode Exit fullscreen mode

Y lo lanzamos.

npx hardhat deploy-zksync
Enter fullscreen mode Exit fullscreen mode

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

<!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>
Enter fullscreen mode Exit fullscreen mode

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

blockchain_stuff.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)
  });
}
Enter fullscreen mode Exit fullscreen mode

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

[
    {
      "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"
    }
]
Enter fullscreen mode Exit fullscreen mode

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

npm i --global lite-server
lite-server
Enter fullscreen mode Exit fullscreen mode

Fuentes oficiales: Github de NVM, Instalar Docker en Ubuntu, Descarga de Docker Desktop, Instalar Docker Desktop en Ubuntu, zkSync Testnet Getting Started

Gracias por ver este tutorial!

Sígannos en dev.to y en Youtube para todo lo relacionado al desarrollo en Blockchain en Español.

Top comments (0)