This guide will walk you through deploying an ERC20 token on the XRPL EVM sidechain testnet using Foundry.
If you don't have Foundry installed yet:
- Visit https://getfoundry.sh
- Run the installation command:
curl -L https://foundry.paradigm.xyz | bash
- Restart your terminal and run:
foundryup
- Verify installation:
forge --version
- An account with XRP for gas fees
- Basic knowledge of Solidity and command line
If you want to use this existing project instead of starting from scratch:
# Clone the repository
git clone <repo-url>
cd xrpl-evm-quickstart
# Install dependencies
forge install
forge install OpenZeppelin/openzeppelin-contracts
# Edit .env with your configuration
nano .env # or use your preferred editor
# Build the project
forge build
# Run tests
forge test
# Deploy to XRPL EVM Sidechain Testnet
forge script script/Deploy.s.sol \
--rpc-url $RPC_URL \
--broadcast \
--legacy
forge init xrpl-evm-quickstart
cd xrpl-evm-quickstart
forge install OpenZeppelin/openzeppelin-contracts
Replace your foundry.toml
with:
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
fs_permissions = [{ access = "read", path = "./"}]
remappings = ["@openzeppelin/=lib/openzeppelin-contracts/"]
solc = "0.8.20"
[rpc_endpoints]
xrpl-evm-testnet = "https://rpc.testnet.xrplevm.org"
Create a .env
file in your project root:
# XRPL EVM Sidechain TESTNET RPC URL
RPC_URL=https://rpc.testnet.xrplevm.org
# Your private key (DO NOT COMMIT THIS TO VERSION CONTROL)
# Use the same format as your working script: 0x prefix for bytes32
PRIVATE_KEY=1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
.env
file or private keys to version control. Add .env
to your .gitignore
file.
source .env
# Check that variables are loaded
echo $RPC_URL
echo $PRIVATE_KEY # Should show your private key (be careful in shared terminals!)
The SimpleERC20.sol
contract is a basic ERC20 token with minting functionality, inheriting from OpenZeppelin's battle-tested contracts.
Key Features:
- Standard ERC20 functionality (transfer, approve, etc.)
- Owner-only minting capability
- Initial supply minted to deployer
The Deploy.s.sol
script follows the proven pattern used for XRPL EVM sidechain deployments:
forge build
Method 1: Using environment variables (recommended)
# Make sure .env is loaded first
source .env
# Deploy using environment variables from the script
forge script script/Deploy.s.sol \
--rpc-url $RPC_URL \
--broadcast \
--legacy \
Method 2: Explicit private key parameter
# Load environment variables
source .env
# Deploy with explicit private key parameter
forge script script/Deploy.s.sol \
--rpc-url $RPC_URL \
--private-key $PRIVATE_KEY \
--broadcast \
--legacy \
--resume
After successful deployment, you'll see:
- Contract address
- Total supply
- Deployer's token balance
- Transaction hash
Check token balance:
cast call <CONTRACT_ADDRESS> "balanceOf(address)" <WALLET_ADDRESS> --rpc-url $RPC_URL
Check total supply:
cast call <CONTRACT_ADDRESS> "totalSupply()" --rpc-url $RPC_URL
Transfer tokens:
cast send <CONTRACT_ADDRESS> "transfer(address,uint256)" <RECIPIENT_ADDRESS> <AMOUNT> --private-key $PRIVATE_KEY --rpc-url $RPC_URL
Mint new tokens (owner only):
cast send <CONTRACT_ADDRESS> "mint(address,uint256)" <RECIPIENT_ADDRESS> <AMOUNT> --private-key $PRIVATE_KEY --rpc-url $RPC_URL
Create test/SimpleERC20.t.sol
:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "forge-std/Test.sol";
import "../src/SimpleERC20.sol";
contract SimpleERC20Test is Test {
SimpleERC20 public token;
address public owner = address(1);
address public user = address(2);
function setUp() public {
vm.prank(owner);
token = new SimpleERC20("Test Token", "TEST", 1000);
}
function testInitialSupply() public {
assertEq(token.totalSupply(), 1000 * 10**18);
assertEq(token.balanceOf(owner), 1000 * 10**18);
}
function testMinting() public {
vm.prank(owner);
token.mint(user, 100 * 10**18);
assertEq(token.balanceOf(user), 100 * 10**18);
assertEq(token.totalSupply(), 1100 * 10**18);
}
function testTransfer() public {
vm.prank(owner);
token.transfer(user, 50 * 10**18);
assertEq(token.balanceOf(user), 50 * 10**18);
assertEq(token.balanceOf(owner), 950 * 10**18);
}
}
forge test
forge test -vv
- Ensure you have sufficient XRP for gas fees
- Gas prices may vary; monitor network congestion
- Verify the RPC URL is correct and accessible
- Check your internet connection
- Ensure your private key is correctly formatted (with or without 0x prefix)
- Verify the associated address has sufficient funds
- Check Solidity version compatibility
- Ensure all dependencies are properly installed
- Never expose private keys: Use hardware wallets or secure key management for production
- Test thoroughly: Always test on testnets before mainnet deployment
- Audit contracts: Consider professional audits for production contracts
- Use established libraries: Leverage OpenZeppelin for standard functionality
- Monitor deployments: Keep track of your deployed contracts and their interactions
Before deploying, you need XRP in your wallet to pay for gas fees. Here's how to get them:
- Visit the XRP Faucet - XRPL EVM Sidechain Testnet
- Enter your wallet address to receive free testnet XRP
- Wait for the transaction to confirm
- Alternatively you can use the Squid router bridge to bridge some test XRP from XRPL to the XRPL EVM Sidechain.
# Check your wallet balance on testnet
cast balance <YOUR_WALLET_ADDRESS> --rpc-url https://rpc.testnet.xrplevm.org
If cast call
returns 0x
, the contract deployment likely failed. Debug with:
# 1. Check if contract exists
cast code <CONTRACT_ADDRESS> --rpc-url $RPC_URL
# 2. Verify your wallet balance
cast balance $(cast wallet address --private-key $PRIVATE_KEY) --rpc-url $RPC_URL
# 3. Check broadcast logs for transaction details
cat broadcast/Deploy.s.sol/1440002/run-latest.json
# 4. Redeploy with maximum verbosity
forge script script/Deploy.s.sol:Deploy --rpc-url xrpl-evm-sidechain --broadcast --skip-simulation -vvvv
Happy deploying! 🚀