Requisitos previos
Preparación del contrato
El siguiente contrato de ejemplo se usará a lo largo de esta guía:
// 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;
}
}
Despliega con Foundry
Foundry es un toolkit rápido basado en Rust para desarrollo en Ethereum.
-
Instala Foundry:
curl -L https://foundry.paradigm.xyz | bash
Puede que tengas que ejecutar source a tu archivo .bashrc o .zshrc
-
Configura un nuevo proyecto Foundry:
foundryup
forge init my-plasma-project
cd my-plasma-project
-
Actualiza
foundry.toml con la configuración de la testnet de Plasma:
[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"
-
Crea un archivo
.env en la raíz de tu proyecto:
PRIVATE_KEY=your_private_key_here
RPC_URL=https://testnet-rpc.plasma.to
-
Carga las variables de entorno:
-
Guarda el código del contrato como
src/SimpleStorage.sol y luego despliégalo:
forge create src/SimpleStorage.sol:SimpleStorage \
--rpc-url $RPC_URL \
--private-key $PRIVATE_KEY \
--constructor-args "Hello, Plasma!"
Foundry generará el hash de la transacción de despliegue y la dirección del 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",
[...]
-
Prueba tu contrato desplegado usando la herramienta cast de Foundry. Primero, lee los datos almacenados:
cast call 0x742d35Cc6610C7532C8582d4C371Acb1D5f44D7F \
"getData()" \
--rpc-url $RPC_URL
-
Luego actualiza los datos y léelos nuevamente:
# 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
Esto debería generar algo como:
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
Despliega con Hardhat
Hardhat es un framework de desarrollo completo con amplio soporte de plugins.
- Asegúrate de tener lo siguiente:
- Node.js 20+ (requerido para compatibilidad con Hardhat moderno)
- Familiaridad con el desarrollo en Ethereum
- Una wallet con tokens de testnet (consulta los detalles de la cadena testnet)
Node.js 18 e inferiores ya no son soportados por Hardhat y pueden causar problemas de compatibilidad con módulos ES.
-
Verifica la versión de Node.js:
Si estás usando Node.js 18 o inferior, actualiza a 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
-
Inicializa un nuevo proyecto 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
Si encuentras problemas de compatibilidad, revisa la documentación de Hardhat para las últimas versiones soportadas.
Elige Create a JavaScript project cuando se te solicite.
-
Actualiza
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/"
}
}
]
}
};
-
Crea un archivo
.env en la raíz de tu proyecto:
PRIVATE_KEY=your_private_key_here
RPC_URL=https://testnet-rpc.plasma.to
ETHERSCAN_API_KEY=your_api_key_for_verification
-
Crea el directorio scripts y el script de despliegue:
-
Crea
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);
});
-
Guarda el código del contrato como
contracts/SimpleStorage.sol y luego despliégalo:
npx hardhat run scripts/deploy.js --network plasmaTestnet
-
¡Listo!
Despliega con Ethers.js
Ethers.js provee un flujo de despliegue programático y mínimo.
-
Crea un nuevo proyecto:
mkdir my-plasma-ethers-project
cd my-plasma-ethers-project
npm init -y
npm install ethers dotenv solc
-
Crea un archivo
.env en la raíz de tu proyecto:
PRIVATE_KEY=<your_private_key_here>
RPC_URL=https://testnet-rpc.plasma.to
ETHERSCAN_API_KEY=your_api_key_for_verification
-
Crea
compile.js para compilar tu 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!');
-
Guarda tu contrato como
SimpleStorage.sol y luego compílalo:
Esto debería generar:
Contract compiled successfully!
-
Crea
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);
});
-
Ejecuta el script de despliegue:
Esto debería generar algo como:
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!
Verifica el despliegue
Después de desplegar con cualquiera de los métodos anteriores, verifica el despliegue de tu contrato.
Solución de problemas
Problemas de compatibilidad con módulos ES
Si encuentras errores como Error [ERR_REQUIRE_ESM]: require() of ES Module, esto generalmente significa:
-
La versión de Node.js es demasiado antigua: Actualiza a Node.js 20+ como se menciona en los requisitos previos
-
Desajuste en la versión de la dependencia: Si no es posible actualizar Node.js, puedes degradar la dependencia problemática:
npm install micro-eth-signer@0.10.0
Advertencias de versión de Node.js
Si ves advertencias sobre versiones no soportadas de Node.js:
WARNING: You are currently using Node.js v18.19.1, which is not supported by Hardhat
Actualiza a Node.js 20+ siguiendo los pasos en la sección de requisitos previos.
Fondos insuficientes
Error: insufficient funds for intrinsic transaction cost
Asegúrate de que tu wallet tenga suficientes tokens de testnet. Visita un faucet de testnet.
Configuración de red incorrecta
Error: network with chainId "1" doesn't match the configured chainId "9746"
Verifica que tu configuración de red coincida con los detalles de la cadena testnet.
Falla en la estimación de gas
Error: cannot estimate gas
Establece límites de gas explícitos en tu configuración de despliegue:
// In your deploy script
const simpleStorage = await SimpleStorage.deploy("Hello, Plasma from Hardhat!", {
gasLimit: 500000
});