### Uma introdução técnica à Scroll zkEVM para desenvolvedores de blockchain
Escrevi este artigo como uma introdução técnica à Scroll zkEVM para desenvolvedores de contratos inteligentes que desejam experimentar a rede.
Neste artigo, abordaremos o seguinte:
Aprender sobre a Scroll zkEVM e como começar com Alpha testnet.
Configurar um ambiente de desenvolvimento com o Foundry e escrever um contrato inteligente que distribui ETH na Alpha testnet com base em uma função de geração de números pseudoaleatórios.
Ajustar o contrato inteligente para se adequar às especificações exatas necessárias para a Alpha testnet.
Implantar nosso contrato inteligente com a ajuda de um script Solidity.
Verificar nosso contrato inteligente na Alpha testnet diretamente a partir da linha de comando do Foundry.
Ao final deste artigo, você aprenderá como implantar seus contratos inteligentes na Alpha testnet da Scroll com o Foundry.
O que é a Scroll zkEVM?
A Scroll zkEVM é uma solução de blockchain de camada 2 recém lançada, projetada especificamente para aumentar a escalabilidade do Ethereum.
A característica distintiva da Scroll e de plataformas semelhantes, como a Polygon zkEVM, é o uso de provas de conhecimento zero (ZK proofs) que funcionam agrupando grandes grupos de transações e as gravando na Ethereum de uma só vez, reduzindo significativamente as taxas de transação em comparação com o processamento de cada transação individualmente na Ethereum.
A melhor coisa sobre as zkEVMs, como a Scroll, é que um desenvolvedor de contratos inteligentes não precisa entender a tecnologia subjacente de ZK para implantar contratos inteligentes compatíveis com a EVM em uma solução muito mais barata e escalável.
Pré-requisitos
Certifique-se de ter algum ETH da rede Goerli em sua carteira. Sim, eu sei que a Goerli está descontinuada, mas você precisará dela por enquanto.
Um conhecimento básico de blockchains e alguma experiência com Solidity.
Se você nunca trabalhou com o Foundry antes, recomendo que verifique o README deste repositório no GitHub, que criei para um workshop há algum tempo.
Não é necessário assistir ao vídeo inteiro; basta dar uma olhada rápida no arquivo README se você nunca trabalhou com o Foundry antes.
Primeiras coisas primeiro: a Ponte!
Sem entrar em muitos detalhes específicos de ZK, saiba que o ETH na rede Scroll espelha o ETH na rede principal da Ethereum. O espelhamento significa que a equipe da Scroll implantou contratos inteligentes de ponte na rede Scroll (Alpha testnet por enquanto) e na rede ETH correspondente (Goerli testnet por enquanto).
Portanto, para obter ETH para pagar pelas taxas de gás na Alpha testnet, você precisa depositar algum ETH Goerli no contrato de ponte na Goerli.
O espelhamento também funciona no sentido oposto.
Para começar:
Acesse a interface de usuário (UI) da Scroll que permite interagir com o contrato da ponte.
Conecte sua carteira Metamask à página da web.
Certifique-se de estar enviando ETH para a rede Scroll, não o contrário. Siga a UI (é realmente intuitiva) e confirme a ponte.
Após a confirmação, talvez seja necessário aguardar de 30 a 45 minutos antes de receber ETH na Alpha testnet. Portanto, você precisa ter paciência por um tempo.
Você está pronto para começar assim que tiver algum ETH na Alpha testnet!
Inicializando um Projeto Foundry
O Foundry é um dos frameworks de desenvolvimento de contratos inteligentes mais recentes a entrar no cenário e está se tornando cada vez mais popular.
Para instalar o Foundry, siga os comandos abaixo ou consulte o Foundry-book.
Execute este comando para baixar o foundryup
curl -L https://foundry.paradigm.xyz | bash
Em seguida, reinicie seu terminal e, em seguida, instale o Foundry executando:
foundryup
Após ter instalado tudo, abra um novo terminal em um novo diretório. Você pode inicializar um novo projeto Foundry usando o seguinte comando:
forge init
Algumas observações:
Todos os contratos inteligentes são criados dentro do diretório
src
por padrão.O comando
forge install
pode instalar novos pacotes como submódulos Git dentro do diretóriolib
.Por padrão, todos os contratos de teste são definidos no diretório de
test
e geralmente têm a extensão.t.sol
, o que significa que um arquivo de contrato chamadohello.sol
terá um arquivo chamadohello.t.sol
, conforme a convenção usual. Você pode executar todos os arquivos de teste com o comandoforge test
.Você pode controlar o comportamento do Foundry configurando o arquivo
foundry.toml
. Esta página no Github fornece uma referência completa para o arquivotoml
. Também compilei um gist que contém uma lista de valores padrão.O diretório de
scripts
contém todos os scripts de implantação e execução para o seu projeto Foundry.
Sempre que você fizer alterações no código, pode compilar todos os contratos inteligentes usando:
forge build
Opcodes e Bytecode: Um Curso Rápido
Antes de escrever o contrato inteligente em si, vamos examinar alguns conceitos que serão úteis para entender o panorama.
Portanto, para aqueles que não sabem, a EVM não executa o Solidity nem qualquer outra linguagem de desenvolvimento de contratos inteligentes. A EVM nem mesmo tem conhecimento da existência dessas linguagens, nem se importa. Isso se aplica à Scroll zkEVM também.
O que acontece é que qualquer código de contrato inteligente é decomposto em um conjunto de instruções executáveis pela EVM conhecido como Bytecode, que é o que a EVM realmente executa.
Ok, mas o que são opcodes, e por que nos importamos? Lembra-se de quando eu disse que o bytecode é um 'conjunto de instruções'?
Bem, cada opcode é uma instrução que, combinada com outros opcodes, compõe o bytecode de qualquer contrato inteligente. Os opcodes são o nível mais baixo de computação que você precisa lidar como desenvolvedor de blockchain. Uma linguagem de contrato inteligente é uma abstração construída sobre esses opcodes.
Por exemplo, se você já usou block.number
em Solidity, você invoca o opcode NUMBER
. Uma referência completa para todos os opcodes suportados pela EVM (para não ser confundido com a zkEVM da Scroll) pode ser encontrada no site da Ethereum Foundation.
Permita-me enfatizar o significado disso com um exemplo claro.
Dê uma olhada neste contrato inteligente simples:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Adder {
function add(uint256 a, uint256 b) public pure returns (uint256) {
uint256 sum = a + b;
return sum;
}
}
Nada mais do que uma função que retorna a soma de dois números. Como se parecerão as instruções de opcode equivalentes? Basta dar uma olhada neste Gist que eu fiz. Você também pode verificar este contrato no Etherscan para verificar o Bytecode e os opcodes por conta própria.
Esta seção pode parecer um desvio indesejado, mas acredite em mim, fará muito mais sentido nas seções seguintes.
Escrevendo o Contrato Inteligente
Finalmente, vamos concluir isso.
Vá para o diretório src
e crie um novo arquivo chamado ScrollTutorial.sol
.
Cole o código a seguir nele:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
contract Dispenser {
// Mapeamento para rastrear os endereços que já fizeram saques
mapping(address => bool) public hasWithdrawn;
function withdraw() public {
require(
!hasWithdrawn[msg.sender],
"Você já fez um saque, desculpe!. Tente novamente de um endereço diferente!"
);
require(
address(this).balance > 0.5 ether,
"Não há fundos suficientes no contrato no momento"
);
uint256 randomNumber = uint256(
keccak256(
abi.encodePacked(
blockhash(block.number - 100),
block.prevrandao,
block.coinbase
)
)
) % 2;
// Verifique se o número aleatório é par
require(
randomNumber == 0,
"Desculpe, mas o hash gerado foi um número ímpar. Tente novamente de um endereço diferente!"
);
// Defina a sinalização hasWithdrawn como verdadeira para este endereço
hasWithdrawn[msg.sender] = true;
// Transfira 0,5 ether para o endereço
payable(msg.sender).transfer(0,5 ether);
}
function deposit() public payable {}
}
Este é um contrato inteligente direto. Vamos entender o código rapidamente:
Queremos que cada endereço possa sacar apenas 0,5 ETH uma vez; o mapeamento
hasWithdrawn
rastreia todos os endereços que sacaram ETH com sucesso.A função
deposit
é uma função simples que aceita pagamentos e permite que nosso contrato receba ETH.A função
withdraw
é onde toda a mágica acontece.
Vamos examinar a função withdraw
em mais detalhes.
As duas primeiras declarações require no início da função garantem que cada endereço possa sacar apenas uma vez e que haja ETH suficiente no contrato para a transação.
A variável
randomNumber
é um número pseudoaleatório que geramos usando alguns valores em tempo real. Vamos examiná-los com mais detalhes em breve.A função
abi.encodePacked
pega todos os argumentos que ela recebe e os concatena em uma única sequência de bytes.A função
keccak256
gera o hash Keccak-256 de qualquer entrada que ela recebe. Fazemos o módulo do valor que esta função gera com 2 para verificar se o hash gerado é par ou não.Em seguida, pagamos o ETH se o hash for par e atualizamos o mapeamento.
Para compilar o contrato inteligente, execute o seguinte comando no seu terminal:
forge build
Dica #1:
PREVRENDAO
é um opcode relativamente novo que substitui o opcode DIFFICULTY e é suportado apenas pelas versões do Solidity 0.8.18 e superiores. Certifique-se de configurar a versão do Solidity de acordo.
Problemas com Nosso Código
Nossa, há muito o que explorar aqui!
Este código está longe de ser adequado para produção, mas vamos discutir um problema mais fundamental primeiro.
Lembre-se que eu linquei uma lista de opcodes que a EVM suporta.
Infelizmente, até o momento, a zkEVM da Scroll NÃO suporta todos esses opcodes.
Ela suporta a maioria deles, mas se você está desenvolvendo um contrato inteligente para uma zkEVM (qualquer zkEVM), você deve entender as diferenças no suporte a opcodes entre a rede e a EVM.
Reveja o código e veja os valores que usamos para gerar nosso número aleatório. Vamos dar uma olhada no que não funcionará em nosso contrato inteligente:
Opcode | Equivalente em Solidity | Diferença comportamental |
BLOCKHASH | blockHash(BlockNum) | Usamos o hash de um bloco 100 atrás do mais recente como parte do hash do nosso número aleatório. No entanto, a Scroll zkEVM NÃO oferece suporte para buscar o hash de um bloco tão antigo. Se o número do bloco exceder a faixa suportada, um 0 será retornado. Suporte da ethereum: [LATEST-1] - [LATEST-256] Suporte da Scroll zkEVM: [LATEST-1]
|
PREVRANDAO | block.prevrendao | Pense no PREVRENDAO como um número de origem pseudo-aleatório, você pode ler mais sobre isso aqui.Comportamento do Ethereum: Retorna um número pseudoaleatório<br><br>Comportamento do zkEVM Scroll: Retorna 0, sem aleatoriedade<br><br>
|
COINBASE | block.coinbase |
Comportamento da EVM: Retorna o endereço do validador do bloco. . Este número é pseudo-aleatório, uma vez que os validadores de ETH são escolhidos aleatoriamente.Comportamento do Scroll: Retorna apenas um único endereço por enquanto, sem aleatoriedade.
|
Então, essencialmente, todos os três valores que concatenamos para obter nosso randomNumber
têm um comportamento pseudoaleatório na EVM. No entanto, eles falham em funcionar ou retornam um valor constante, o que os torna inúteis para nossos fins.
Mas honestamente, mesmo que a Scroll suportasse todos esses opcodes, este contrato ainda não seria digno de produção. Nenhum contrato inteligente sério depende da combinação de valores de bloco para gerar um número aleatório. Para implantar um contrato inteligente que faça uso de aleatoriedade, considere o serviço VRF da Chainlink.
Ajustando o Contrato Inteligente
Já que a Chainlink não é compatível com a Scroll, recorreremos à pseudoaleatoriedade.
Desta vez, faremos uma pequena alteração na função withdraw
de duas maneiras:
Agora permitimos que o usuário passe um argumento ao chamar a função de saque. Usaremos esse argumento como parte do hash do
randomNumber
, para que o usuário tenha algum controle sobre o hash gerado.Substituímos os outros dois valores pelo hash do bloco anterior e o carimbo de data/hora do bloco atual. Não é uma boa fonte de aleatoriedade, mas por enquanto, esta é a melhor solução que conheço.
Sinta-se à vontade para me esclarecer se tiver uma solução melhor.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
contract Dispenser {
// Mapeamento para rastrear os endereços que já fizeram saques
mapping(address => bool) public hasWithdrawn;
function withdraw(uint seedValue) public {
require(
!hasWithdrawn[msg.sender],
"Você já fez um saque, desculpe!. Tente novamente de um endereço diferente!"
);
require(
address(this).balance > 0.5 ether,
"Não há fundos suficientes no contrato no momento"
);
uint256 randomNumber = uint256(
keccak256(
abi.encodePacked(
blockhash(block.number - 1),
block.timestamp,
seedValue
)
)
) % 2;
// Verifique se o número aleatório é par
require(
randomNumber == 0,
"Desculpe, mas o hash gerado foi um número ímpar."
);
// Defina a sinalização hasWithdrawn como verdadeira para este endereço
hasWithdrawn[msg.sender] = true;
// Transfira 0,5 ether para o endereço
payable(msg.sender).transfer(0.5 ether);
}
function deposit() public payable {}
}
Implantação e Verificação do Nosso Contrato Inteligente
Precisaremos passar alguns valores para o Foundry a fim de implantar nosso contrato inteligente. Poderíamos fazer isso diretamente na linha de comando durante a implantação do contrato, mas é mais conveniente fazê-lo em um arquivo dotenv. Crie um novo arquivo .env
no diretório em que você tem seu projeto.
Precisamos adicionar dois valores ao arquivo .env:
RPC_URL: O Foundry precisará de um URL RPC para se conectar à rede de teste Alpha. Podemos obter um URL RPC público para o teste Alpha na documentação da Scroll.
PRIVATE_KEY: Precisaremos da chave privada de uma carteira com ETH na rede de teste Alpha para assinar transações. Seu arquivo env deve ficar assim:
RPC_URL=https://alpha-rpc.scroll.io/l2
PRIVATE_KEY=1dh12j1XXXXXXXXXXXXXh1pqdfjnma91k
Salve o arquivo env. Execute este comando para carregar essas variáveis no seu terminal:
source .env
Agora que configuramos com segurança todas as informações sensíveis, vamos escrever um script para implantar nosso contrato. Você também pode usar o comando forge create
para implantar diretamente a partir da linha de comando, mas considero que usar um script seja mais elegante.
Crie um arquivo ScrollTutorial.s.sol
dentro do diretório de scripts. No arquivo, cole o seguinte código:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import "forge-std/Script.sol";
import {Dispenser} from "../src/ScrollTutorial.sol";
contract MyScript is Script {
function run() external {
uint256 PrivateKey = vm.envUint("PRIVATE_KEY");
vm.startBroadcast(PrivateKey);
Dispenser dispenser = new Dispenser();
vm.stopBroadcast();
}
}
Vamos passar pelo que está acontecendo aqui:
Nas duas primeiras linhas, importamos as utilidades de script da biblioteca padrão do forge e nosso contrato inteligente.
A biblioteca forge-std nos fornece a interface
vm.sol
para usar "códigos de trapaça" valiosos. A funçãoenvUint
pode ser usada para acessar nossas chaves privadas no arquivo .env.Qualquer transação entre
startBroadcast
estopBroadcast
pode ser enviada na cadeia. No nosso caso, precisamos criar uma nova instância do nosso contrato inteligente.
Salve o arquivo de script. Agora estamos prontos para implantar. No seu terminal, execute o seguinte comando:
forge script script/ScrollTutorial.s.sol:MyScript --rpc-url $RPC_URL --broadcast --legacy -vvvv
Dica #2: O Foundry nos permite configurar a verbosidade da linha de comando usando a bandeira '-v'. Eu prefiro usar a máxima verbosidade na maioria das vezes. Você pode ler mais sobre isso aqui.
Dica #3: Para zkEVMs como a Scroll e a zkSync, pode ser necessário passar a flag '--legacy' para as implantações de contratos pelo Foundry, pois geralmente eles não suportam o EIP-1559._
A documentação da Scroll nos fornece um URL da API para o explorador Blockscout, que nos permite verificar nossos contratos. Execute este comando no terminal para verificar seu contrato:
forge verify-contract <CONTRACT_ADDRESS> src/ScrollTutorial.sol:Dispenser --chain-id 534353 --verifier-url https://blockscout.scroll.io/api/ --verifier blockscout
Observação: A API do Blockscout parece estar inativa, e seu comportamento foi reconhecido como inconsistente pela documentação da Scroll. Não consegui verificar meu contrato na linha de comando, e você também pode enfrentar o mesmo problema. No entanto, você pode verificá-lo na interface do Blockscout.
Depois que seu contrato for verificado, você poderá interagir com ele na interface do Blockscout.
Conclusão
Neste artigo, falamos sobre a Scroll zkEVM e como você pode implantar um contrato inteligente nesta rede com uma configuração mínima como desenvolvedor de contratos inteligentes. O lançamento da rede principal da Scroll está prestes a acontecer; este é o melhor momento para começar com essa incrível nova tecnologia.
Este artigo foi escrito por Priyank Gupta e traduzido por Adriano P. de Araujo. O original em inglês pode ser encontrado aqui.
Latest comments (0)