Pré-requisitos
Preparação do Contrato
O contrato de exemplo a seguir será usado ao longo deste guia:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
contract SimpleStorage {
string private storedData;
address public owner;
event DataStored(string data, address indexed by);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor(string memory initialData) {
storedData = initialData;
owner = msg.sender;
emit DataStored(initialData, msg.sender);
}
modifier onlyOwner() {
require(msg.sender == owner, "Only owner can perform this action");
_;
}
function setData(string memory data) public onlyOwner {
storedData = data;
emit DataStored(data, msg.sender);
}
function getData() public view returns (string memory) {
return storedData;
}
function transferOwnership(address newOwner) public onlyOwner {
require(newOwner != address(0), "New owner cannot be zero address");
emit OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
}
Foundry é um toolkit rápido baseado em Rust para desenvolvimento Ethereum.
-
Instale o Foundry:
curl -L https://foundry.paradigm.xyz | bash
Talvez seja necessário fazer source do seu arquivo .bashrc ou .zshrc.
-
Configure um novo projeto Foundry:
foundryup
forge init my-plasma-project
cd my-plasma-project
-
Atualize
foundry.toml com as configurações da Plasma testnet:
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
solc_version = "0.8.28"
optimizer = true
optimizer_runs = 200
[rpc_endpoints]
plasma_testnet = "https://testnet-rpc.plasma.to"
-
Crie um arquivo
.env na raiz do projeto:
PRIVATE_KEY=your_private_key_here
RPC_URL=https://testnet-rpc.plasma.to
-
Carregue as variáveis de ambiente:
-
Salve o código do contrato como
src/SimpleStorage.sol e, em seguida, implante:
forge create src/SimpleStorage.sol:SimpleStorage \
--rpc-url $RPC_URL \
--private-key $PRIVATE_KEY \
--constructor-args "Hello, Plasma!"
O Foundry exibirá o hash da transação de implantação e o endereço do contrato:
[⠊] Compiling...
[⠢] Compiling 1 files with Solc 0.8.28
[⠆] Solc 0.8.28 finished in 124.81ms
Compiler run successful!
Warning: Dry run enabled, not broadcasting transaction
Contract: SimpleStorage
Transaction: {
"from": "0xbd828f7679656f8f830b89611c933017442f2ebf",
"to": null,
"maxFeePerGas": "0xf",
"maxPriorityFeePerGas": "0x1",
"gas": "0x69f18",
[...]
-
Teste seu contrato implantado usando a ferramenta cast do Foundry. Primeiro, leia os dados armazenados:
cast call 0x742d35Cc6610C7532C8582d4C371Acb1D5f44D7F \
"getData()" \
--rpc-url $RPC_URL
-
Em seguida, atualize os dados e leia novamente:
# Update the stored data.
cast send 0x742d35Cc6610C7532C8582d4C371Acb1D5f44D7F \
"setData(string)" "Updated from Foundry" \
--private-key $PRIVATE_KEY \
--rpc-url $RPC_URL
# Read the stored data again.
cast call 0x742d35Cc6610C7532C8582d4C371Acb1D5f44D7F \
"getData()" \
--rpc-url $RPC_URL
Isso deverá gerar uma saída semelhante a:
blockHash 0x68fbd2aaf1de9c577869056ca634f2103fa1695673a94d8c049d0b78d3733aac
blockNumber 1200423
contractAddress
cumulativeGasUsed 21712
effectiveGasPrice 8
from 0xBd828F7679656F8f830b89611C933017442F2EbF
gasUsed 21712
logs []
logsBloom 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
root
status 1 (success)
transactionHash 0xcf5b1fcc8d19f7cf7992f6e6a8b3ade74e07afbd0da0b9fce26bda4c9503a12b
transactionIndex 0
type 2
blobGasPrice
blobGasUsed
to 0x742D35Cc6610c7532C8582D4C371aCb1D5F44D7F
0x
Hardhat é um framework de desenvolvimento completo com rico suporte a plugins.
- Garanta que você tenha o seguinte:
- Node.js 20+ (necessário para compatibilidade com versões modernas do Hardhat)
- Familiaridade com desenvolvimento Ethereum
- Uma wallet com tokens da testnet (consulte detalhes da chain testnet)
Node.js 18 e anteriores não são mais suportados pelo Hardhat e podem causar problemas de compatibilidade com módulos ES.
-
Verifique a versão do Node.js:
Se você estiver usando Node.js 18 ou anterior, atualize para Node.js 20+:
# Using nvm (recommended)
nvm install 20
nvm use 20
# Or using NodeSource repository (Ubuntu/Debian)
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs
-
Inicialize um novo projeto Hardhat:
mkdir my-plasma-hardhat-project
cd my-plasma-hardhat-project
npm init -y
npm install --save-dev hardhat@latest @nomicfoundation/hardhat-toolbox@latest
npm install dotenv@latest ethers@latest
npx hardhat init
Se encontrar problemas de compatibilidade, consulte a documentação do Hardhat para as versões suportadas mais recentes.
Escolha Create a JavaScript project quando solicitado.
-
Atualize
hardhat.config.js:
require("@nomicfoundation/hardhat-toolbox");
require("dotenv").config();
/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
solidity: {
version: "0.8.28",
settings: {
optimizer: {
enabled: true,
runs: 200
}
}
},
networks: {
plasmaTestnet: {
url: process.env.RPC_URL,
chainId: 9746,
accounts: [process.env.PRIVATE_KEY],
gasPrice: 1000000000, // 1 gwei
}
},
etherscan: {
apiKey: {
plasmaTestnet: process.env.ETHERSCAN_API_KEY
},
customChains: [
{
network: "plasmaTestnet",
chainId: 9746,
urls: {
apiURL: "https://testnet.plasmascan.to/api",
browserURL: "https://testnet.plasmascan.to/"
}
}
]
}
};
-
Crie um arquivo
.env na raiz do projeto:
PRIVATE_KEY=your_private_key_here
RPC_URL=https://testnet-rpc.plasma.to
ETHERSCAN_API_KEY=your_api_key_for_verification
-
Crie o diretório scripts e o script de implantação:
-
Crie
scripts/deploy.js:
const { ethers } = require("hardhat");
async function main() {
// Get the contract factory
const SimpleStorage = await ethers.getContractFactory("SimpleStorage");
console.log("Deploying SimpleStorage contract...");
// Deploy the contract with constructor arguments
const simpleStorage = await SimpleStorage.deploy("Hello, Plasma from Hardhat!");
// Wait for deployment to complete
await simpleStorage.waitForDeployment();
const contractAddress = await simpleStorage.getAddress();
console.log("SimpleStorage deployed to:", contractAddress);
console.log("Transaction hash:", simpleStorage.deploymentTransaction().hash);
// Wait a few blocks for the transaction to be included
console.log("Waiting for block confirmations...");
await simpleStorage.deploymentTransaction().wait(5);
console.log("✅ Deployment completed successfully!");
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
-
Salve o código do contrato como
contracts/SimpleStorage.sol e, em seguida, implante:
npx hardhat run scripts/deploy.js --network plasmaTestnet
-
Pronto!
Ethers.js fornece um fluxo de implantação mínimo e programático.
-
Crie um novo projeto:
mkdir my-plasma-ethers-project
cd my-plasma-ethers-project
npm init -y
npm install ethers dotenv solc
-
Crie um arquivo
.env na raiz do projeto:
PRIVATE_KEY=<your_private_key_here>
RPC_URL=https://testnet-rpc.plasma.to
ETHERSCAN_API_KEY=your_api_key_for_verification
-
Crie
compile.js para compilar seu contrato Solidity:
const fs = require('fs');
const solc = require('solc');
require('dotenv').config();
// Read the contract source code.
const contractSource = fs.readFileSync('SimpleStorage.sol', 'utf8');
// Prepare the input for the Solidity compiler.
const input = {
language: 'Solidity',
sources: {
'SimpleStorage.sol': {
content: contractSource,
},
},
settings: {
outputSelection: {
'*': {
'*': ['*'],
},
},
optimizer: {
enabled: true,
runs: 200,
},
},
};
// Compile the contract.
const output = JSON.parse(solc.compile(JSON.stringify(input)));
// Check for compilation errors.
if (output.errors) {
output.errors.forEach((error) => {
console.error(error.formattedMessage);
});
}
// Extract the contract data.
const contract = output.contracts['SimpleStorage.sol']['SimpleStorage'];
const abi = contract.abi;
const bytecode = contract.evm.bytecode.object;
// Save compilation artifacts.
fs.writeFileSync('SimpleStorage.json', JSON.stringify({
abi: abi,
bytecode: bytecode
}, null, 2));
console.log('Contract compiled successfully!');
-
Salve seu contrato como
SimpleStorage.sol e, em seguida, compile:
Isso deverá gerar:
Contract compiled successfully!
-
Crie
deploy.js:
const { ethers } = require('ethers');
const fs = require('fs');
require('dotenv').config();
async function deploy() {
// Set up provider and wallet.
const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);
console.log('Deploying from account:', wallet.address);
// Check account balance.
const balance = await provider.getBalance(wallet.address);
console.log('Account balance:', ethers.formatEther(balance), 'XPL');
// Load compiled contract.
const contractData = JSON.parse(fs.readFileSync('SimpleStorage.json', 'utf8'));
// Create contract factory.
const factory = new ethers.ContractFactory(
contractData.abi,
contractData.bytecode,
wallet
);
// Deploy the contract.
console.log('Deploying contract...');
const contract = await factory.deploy("Hello, Plasma from Ethers.js!", {
gasLimit: 500000, // Set a reasonable gas limit.
gasPrice: ethers.parseUnits('1', 'gwei'), // 1 gwei gas price.
});
// Wait for deployment.
await contract.waitForDeployment();
const contractAddress = await contract.getAddress();
console.log('Contract deployed to:', contractAddress);
console.log('Transaction hash:', contract.deploymentTransaction().hash);
// Save deployment info.
const deploymentInfo = {
contractAddress: contractAddress,
transactionHash: contract.deploymentTransaction().hash,
deployer: wallet.address,
network: 'plasmaTestnet',
timestamp: new Date().toISOString()
};
fs.writeFileSync('deployment.json', JSON.stringify(deploymentInfo, null, 2));
return contract;
}
async function interact(contract) {
console.log('\nInteracting with deployed contract...');
// Read initial data.
const initialData = await contract.getData();
console.log('Initial data:', initialData);
// Update data.
const updateTx = await contract.setData("Updated via Ethers.js");
await updateTx.wait();
console.log('Data updated. Transaction hash:', updateTx.hash);
// Read updated data.
const updatedData = await contract.getData();
console.log('Updated data:', updatedData);
// Get owner.
const owner = await contract.owner();
console.log('Contract owner:', owner);
}
// Main execution.
deploy()
.then(async (contract) => {
await interact(contract);
console.log('\nDeployment and interaction completed successfully!');
})
.catch((error) => {
console.error('Error:', error);
process.exit(1);
});
-
Execute o script de implantação:
Isso deverá gerar uma saída semelhante a:
Deploying from account: 0xBd828F7679656F8f830b89611C933017442F2EbF
Account balance: 98539.897261933991888304 XPL
Deploying contract...
Contract deployed to: 0xf298A2A7BC526F9228B8C422D38f3c2E0D15449F
Transaction hash: 0x3d16cc55b9148bac9ac20981d9748a0fc89861c6beb92a2f869bb09b75f685b2
Interacting with deployed contract...
Initial data: Hello, Plasma from Ethers.js!
Data updated. Transaction hash: 0xe3328862ece5d0ca4ca84d25c4130d6749ec872c24bf76eea23dfa8c50c22505
Updated data: Updated via Ethers.js
Contract owner: 0xBd828F7679656F8f830b89611C933017442F2EbF
Deployment and interaction completed successfully!
Verifique a Implantação
Após implantar com qualquer um dos métodos acima, verifique a implantação do seu contrato.
Solução de Problemas
Se encontrar erros como Error [ERR_REQUIRE_ESM]: require() of ES Module, isso geralmente significa:
-
Versão do Node.js muito antiga: Atualize para Node.js 20+ conforme mencionado nos pré-requisitos
-
Incompatibilidade de versão de dependência: Se atualizar o Node.js não for possível, você pode fazer downgrade da dependência problemática:
npm install micro-eth-signer@0.10.0
Avisos de Versão do Node.js
Se você ver avisos sobre versões não suportadas do Node.js:
WARNING: You are currently using Node.js v18.19.1, which is not supported by Hardhat
Atualize para Node.js 20+ seguindo as etapas na seção de pré-requisitos.
Fundos Insuficientes
Error: insufficient funds for intrinsic transaction cost
Garanta que sua wallet tenha tokens da testnet suficientes. Visite um faucet da testnet.
Configuração de Rede Incorreta
Error: network with chainId "1" doesn't match the configured chainId "9746"
Verifique se a configuração de rede corresponde aos detalhes da chain testnet.
Falha na Estimativa de Gas
Error: cannot estimate gas
Defina limites de gas explícitos em sua configuração de implantação:
// In your deploy script
const simpleStorage = await SimpleStorage.deploy("Hello, Plasma from Hardhat!", {
gasLimit: 500000
});