Documentation Index
Fetch the complete documentation index at: https://docs.plasma.org/llms.txt
Use this file to discover all available pages before exploring further.
Prerequisites
- Node.js 16+
- Familiarity with Ethereum development
- A wallet with testnet tokens (see testnet chain details)
Contract Preparation
The following example contract will be used throughout this guide:
// 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;
}
}
Deploy with Foundry
Foundry is a fast, Rust-based toolkit for Ethereum development.
-
Install Foundry:
curl -L https://foundry.paradigm.xyz | bash
You may have to source your .bashrc or .zshrc file
-
Set up a new Foundry project:
foundryup
forge init my-plasma-project
cd my-plasma-project
-
Update
foundry.toml with Plasma testnet settings:
[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"
-
Create a
.env file in your project root:
PRIVATE_KEY=your_private_key_here
RPC_URL=https://testnet-rpc.plasma.to
-
Load the environment variables:
-
Save the contract code as
src/SimpleStorage.sol, then deploy:
forge create src/SimpleStorage.sol:SimpleStorage \
--rpc-url $RPC_URL \
--private-key $PRIVATE_KEY \
--constructor-args "Hello, Plasma!"
Foundry will output the deployment transaction hash and contract address:
[⠊] 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",
[...]
-
Test your deployed contract using Foundry’s cast tool. First, read the stored data:
cast call 0x742d35Cc6610C7532C8582d4C371Acb1D5f44D7F \
"getData()" \
--rpc-url $RPC_URL
-
Then update the data and read it again:
# 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
This should output something like:
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
Deploy with Hardhat
Hardhat is a full-featured development framework with rich plugin support.
- Make sure you have the following:
- Node.js 20+ (required for modern Hardhat compatibility)
- Familiarity with Ethereum development
- A wallet with testnet tokens (see testnet chain details)
Node.js 18 and below are no longer supported by Hardhat and may cause ES module compatibility issues.
-
Verify Node.js version:
If you’re using Node.js 18 or below, upgrade to 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
-
Initialize a new Hardhat project:
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
If you encounter compatibility issues, check the Hardhat documentation for the latest supported versions.
Choose Create a JavaScript project when prompted.
-
Update
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/"
}
}
]
}
};
-
Create a
.env file in your project root:
PRIVATE_KEY=your_private_key_here
RPC_URL=https://testnet-rpc.plasma.to
ETHERSCAN_API_KEY=your_api_key_for_verification
-
Create scripts directory and deployment script:
-
Create
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);
});
-
Save the contract code as
contracts/SimpleStorage.sol, then deploy:
npx hardhat run scripts/deploy.js --network plasmaTestnet
-
You’re done!
Deploy with Ethers.js
Ethers.js provides a minimal, programmatic deployment flow.
-
Create a new project:
mkdir my-plasma-ethers-project
cd my-plasma-ethers-project
npm init -y
npm install ethers dotenv solc
-
Create a
.env file in your project root:
PRIVATE_KEY=<your_private_key_here>
RPC_URL=https://testnet-rpc.plasma.to
ETHERSCAN_API_KEY=your_api_key_for_verification
-
Create
compile.js to compile your Solidity contract:
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!');
-
Save your contract as
SimpleStorage.sol, then compile:
This should output:
Contract compiled successfully!
-
Create
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);
});
-
Run the deployment script:
This should output something like:
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!
Verify Deployment
After deploying with any of the above methods, verify your contract deployment.
Troubleshooting
ES Module Compatibility Issues
If you encounter errors like Error [ERR_REQUIRE_ESM]: require() of ES Module, this typically means:
-
Node.js version is too old: Upgrade to Node.js 20+ as mentioned in prerequisites
-
Dependency version mismatch: If upgrading Node.js isn’t possible, you can downgrade the problematic dependency:
npm install micro-eth-signer@0.10.0
Node.js Version Warnings
If you see warnings about unsupported Node.js versions:
WARNING: You are currently using Node.js v18.19.1, which is not supported by Hardhat
Upgrade to Node.js 20+ following the steps in the prerequisites section.
Insufficient Funds
Error: insufficient funds for intrinsic transaction cost
Ensure your wallet has enough testnet tokens. Visit a testnet faucet.
Wrong Network Configuration
Error: network with chainId "1" doesn't match the configured chainId "9746"
Verify your network configuration matches the testnet chain details.
Gas Estimation Failure
Error: cannot estimate gas
Set explicit gas limits in your deployment configuration:
// In your deploy script
const simpleStorage = await SimpleStorage.deploy("Hello, Plasma from Hardhat!", {
gasLimit: 500000
});