É sabido que muitos blockchains têm problemas de escalabilidade e congestionamento. Esses problemas têm efeitos abrangentes, desde tempos de transação lentos até taxas de transação aumentadas e experiência do usuário degradada.
Uma solução é que web3 seja multi-cadeia usando cadeias L2 (camada dois). Ethereum L2s, como Optimism , Arbitrum e Polygon , são construídos sobre a rede Ethereum, mas são mais rápidos e mais baratos que o Ethereum.
Como compensação, no entanto, eles geralmente são menos seguros que o Ethereum. É por isso que os L2s lidam com as atividades diárias do usuário enquanto ainda contam com o Ethereum L1 como uma base nos bastidores para uma camada segura e descentralizada de liquidação e disponibilidade de dados.
Esta é uma ótima solução - no entanto, existem muitos L2s apenas no Ethereum; cada um uma rede autônoma com suas próprias nuances e experiências.
Construir e usar dapps que interoperam e se movem entre essas redes e o Ethereum L1 pode ser tedioso, difícil e uma experiência ruim para usuários e desenvolvedores.
O que precisamos é que a web3 se torne uma experiência multi-chain , onde os consumidores não precisam saber qual chain estão usando (e francamente, não se importam) e onde os desenvolvedores podem confiar em qualquer rede que melhor suporte as necessidades de seus dapps .
Ao migrar para essa internet multicadeia de blockchains , o web3 se torna uma experiência melhor para todos os envolvidos.
Infelizmente, permitir que os dapps se movam entre as cadeias é um desafio técnico difícil. Neste artigo, veremos uma solução — usando endpoints Infura RPC e Truffle Boxes para construir e conectar essas redes perfeitamente.
Especificamente, usaremos o Optimism Bridge Truffle Box para criar um projeto na rede de testes Ethereum Goerli e uma ponte para o Optimism Goerli.
Como o núcleo de nossa solução de exemplo, contaremos com Truffle Boxes — clichês de “atalho” (como contratos, bibliotecas, módulos e até mesmo dapps totalmente funcionais) da ConsenSys que você pode usar para criar seu dapp.
Para soluções multichain, eles constroem sobre nós Infura RPC para muitas das redes L2.
Como mencionado acima, contaremos especificamente com a caixa de trufas Optimism Bridge . Esta caixa possui todos os contratos necessários para interagir com a ponte Otimismo de L1 e L2 e um conjunto de migrações para implantação, chamada de funções e passagem de mensagens/valores entre as camadas.
Ele ainda tem um script auxiliar que faz tudo o que precisamos para ver tudo isso em ação. Nós simplesmente precisamos descompactá-lo para obter tudo o que precisamos! De acordo com Trufflesuite.com, a caixa inclui:
Nota: uma ponte é uma ferramenta que permite que blockchains independentes se comuniquem, enviem tokens, NFTs, etc.
Antes de começar, precisamos dos seguintes pré-requisitos:
node -v && npm -v
Depois de atender aos pré-requisitos, visite o site da Infura para fazer login (ou inscreva-se para uma nova conta).
Depois de se inscrever com sucesso, a página redireciona para o painel do Infura, onde podemos criar uma nova chave de API, conforme mostrado abaixo.
Clique no botão “Criar uma nova chave” e preencha as informações necessárias.
Depois de criar sua chave de API, o ID do seu projeto ficará visível em seu painel na seção API KEY, conforme mostrado abaixo. Copie e guarde em algum lugar; você precisará dele mais tarde neste tutorial.
A seguir, vamos montar uma Caixa de Ponte de Otimismo de Trufas . Podemos executar o comando unbox em qualquer diretório de sua escolha usando o seguinte comando.
npx truffle unbox optimism-bridge <DIRECTORY_NAME>
Substitua <DIRECTORY_NAME> pelo nome do diretório de sua escolha. Como alternativa, você pode instalar o Truffle globalmente e executar o comando unbox.
npm install -g truffle truffle unbox optimism-bridge <DIRECTORY_NAME>
O comando deve baixar e executar npm install como parte do processo de unboxing.
Agora, execute o seguinte comando para alterar o diretório para o novo que acabamos de criar.
cd truffle-bridge-demo
Nota: truffle-bridge-demo é o nome do nosso diretório que foi criado.
Devemos ter algo semelhante ao que aparece abaixo.
O . O pacote dotenv
npm foi instalado, mas precisaremos adicionar algumas informações ao arquivo .env criado após o unboxing.
O arquivo truffle-config.ovm.js
espera que exista um valor GOERLI_MNEMONIC no arquivo .env para executar comandos nas redes de teste Ethereum Goerli e Optimism Goerli e uma INFURA_KEY para conectar-se à rede.
GOERLI_MNEMONIC="<your-wallet-mnemonic>" INFURA_KEY="<your-infura-key>"
Substitua <your-infura-key> pelas informações que obtivemos anteriormente em nosso painel do Infura. ( Observação : nunca compartilhe suas chaves privadas (mnemônico) com ninguém e mantenha-as seguras). E substitua <your-wallet-mnemonic> pelo seu mnemônico conforme abaixo:
Para recuperar o mnemônico do Metamask, clique no ícone mostrado abaixo em seu Metamask.
Em seguida, clique no botão Export Private Key para copiar o mnemônico.
O Git ignora o arquivo .env neste projeto para ajudar a proteger seus dados privados. É uma boa prática de segurança evitar divulgar suas chaves privadas para o GitHub.
Quando desempacotamos o projeto, todos os contratos e scripts necessários para o projeto foram criados para nós. Nesta próxima etapa, vamos percorrer os contratos individuais e as migrações para entender como as pontes e as interações acontecem entre as redes.
O contrato contract/ethereum/GreeterL1.sol
mostra como enviar uma mensagem pela ponte Optimism de L1 para L2.
//SPDX-License-Identifier: Unlicense // This contract runs on L1, and controls a Greeter on L2. pragma solidity ^0.8.0; import { ICrossDomainMessenger } from "@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol"; contract GreeterL1 { address crossDomainMessengerAddr = 0x5086d1eEF304eb5284A0f6720f79403b4e9bE294; address greeterL2Addr = 0xC0836cCc8FBa87637e782Dde6e6572aD624fb984; function setGreeting(string calldata _greeting) public { bytes memory message; message = abi.encodeWithSignature("setGreeting(string)", _greeting); ICrossDomainMessenger(crossDomainMessengerAddr).sendMessage( greeterL2Addr, message, 1000000 // within the free gas limit amount ); } // function setGreeting } // contract GreeterL1
A migração migrations/3_set_L2_greeting.js
usa o contrato acima para enviar uma mensagem do Ethereum para o Optimism.
var Greeter = artifacts.require("GreeterL1"); /** * Set L2 Greeting * Run this migration on L1 to update the L1 greeting. */ module.exports = async function (deployer) { console.log("Updating the L2 Greetings contract from L1! 👋👋"); const instance = await Greeter.deployed(); const tx = await instance.setGreeting("👋 Greetings from Truffle!"); console.log(`🙌 Greeter txn confirmed on L1! ${tx.receipt.transactionHash}`); console.log(`🛣️ Bridging message to L2 Greeter contract...`); console.log( `🕐 In about 1 minute, check the Greeter contract "read" function: https://goerli-optimism.etherscan.io/address/0xC0836cCc8FBa87637e782Dde6e6572aD624fb984#readContract` ); };
Em seguida, o contracts/optimism/GreeterL2.sol
envia uma mensagem na outra direção (L2->L1) pela ponte Optimism.
//SPDX-License-Identifier: Unlicense // This contract runs on L2, and controls a Greeter on L1. pragma solidity ^0.8.0; import { ICrossDomainMessenger } from "@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol"; contract GreeterL2 { address crossDomainMessengerAddr = 0x4200000000000000000000000000000000000007; address greeterL1Addr = 0x7fA4D972bB15B71358da2D937E4A830A9084cf2e; function setGreeting(string calldata _greeting) public { bytes memory message; message = abi.encodeWithSignature("setGreeting(string)", _greeting); ICrossDomainMessenger(crossDomainMessengerAddr).sendMessage( greeterL1Addr, message, 1000000 // irrelevant here ); } // function setGreeting } // contract GreeterL2
A migração migrations/4_set_L1_greeting.js
usa o contrato acima para enviar uma mensagem do Optimism para o Ethereum.
require("dotenv").config(); const sdk = require("@eth-optimism/sdk"); const ethers = require("ethers"); const Greeter = artifacts.require("GreeterL2"); const goerliMnemonic = process.env["GOERLI_MNEMONIC"]; const infuraKey = process.env["INFURA_KEY"]; const sleep = (milliseconds) => { return new Promise((resolve) => setTimeout(resolve, milliseconds)); }; /** * Set L1 Greeting * Run this migration on L1 to update the L1 greeting. */ module.exports = async function (deployer) { const newGreeting = "👋 Greetings from Truffle!"; //<---- CHANGE THIS VALUE TO YOUR NAME!!! const instance = await Greeter.deployed(); console.log("Updating the L1 Greetings contract from L2! 👋"); const tx = await instance.setGreeting(newGreeting); const txHash = tx.receipt.transactionHash; console.log(`🙌🙌 Greeter txn confirmed on L2! ${txHash}`); console.log( `🛣️ Bridging message to L1 Greeter contract.\n 🕐 This will take at least 1-5 min...` ); // Set providers for Optimism sdk const l1Provider = new ethers.providers.JsonRpcProvider( "https://goerli.infura.io/v3/" + infuraKey ); const l2Provider = new ethers.providers.JsonRpcProvider( "https://optimism-goerli.infura.io/v3/" + infuraKey ); // Connect an L1 signer const wallet = ethers.Wallet.fromMnemonic(goerliMnemonic); const l1Signer = wallet.connect(l1Provider); // Initialize sdk messenger const crossChainMessenger = new sdk.CrossChainMessenger({ l1ChainId: 5, l2ChainId: 420, l1SignerOrProvider: l1Signer, l2SignerOrProvider: l2Provider, }); let statusReady = false; // Sleep for 1 min during L2 -> L1 bridging await sleep(60000); // 60 seconds // Poll the L1 msg status while (!statusReady) { let status = null; status = await crossChainMessenger.getMessageStatus(txHash); statusReady = status == sdk.MessageStatus.READY_FOR_RELAY; if (!statusReady) { console.log( "Message not yet received on L1.\n 🕐 Retrying in 10 seconds..." ); await sleep(10000); // 10 seconds } } console.log("📬 Message received! Finalizing..."); // Open the message on L1 finalize = await crossChainMessenger.finalizeMessage(txHash); console.log( `🎉 Message finalized. Check the L1 Greeter contract "read" function: https://goerli.etherscan.io/address/0x7fA4D972bB15B71358da2D937E4A830A9084cf2e#readContract` ); };
No diretório de scripts também temos goerli_bridge_message.mjs
e goerli_bridge_value.js
para automatizar o processo de compilação de contratos, execução de migrações e envio de mensagens.
Em seguida, vamos implantar nosso contrato em Goerli. O script auxiliar facilita a compilação, migração e ponte de mensagens entre Ethereum Goerli e Optimism Goerli.
Nessas redes, precisaremos do testnet ETH para usá-lo. Para receber alguns, use uma torneira . Também precisaremos adicionar o complemento Optimism à sua conta Infura.
Em seguida, executaremos o seguinte comando para iniciar o projeto.
npm run deploy
Abaixo está uma URL para confirmar (através de Etherscan) a mensagem em ponte após a migração completa.
Um link para confirmar a mensagem em ponte via Etherscan será fornecido após a conclusão da 4ª migração.
Configuramos, instalamos, construímos, implantamos e percorremos com sucesso o projeto que abrimos anteriormente. Em seguida, verificaremos o projeto na rede de teste Goerli Ethereum.
Vá para o explorador de blocos Goerli Etherscan e cole o endereço txn 0xbcc1746a9ebbfcfb71665225c1a353a8c8dc9a1aa528a3babcb5b046d615a353 que foi exibido em nossa CLI durante a implantação.
Um mundo web3 com várias cadeias é crucial se quisermos que a experiência do usuário e do desenvolvedor continue a melhorar. E para conseguir isso, precisamos de maneiras para que os dapps se comuniquem entre as cadeias de maneira rápida e contínua.
Esperançosamente, o exemplo que percorremos usando o Optimism Bridge Truffle Box mostrou a você uma maneira relativamente fácil e rápida de começar. Para saber mais, confira a documentação oficial .
Tenha um ótimo dia!