Skip to content

Latest commit

 

History

History
303 lines (236 loc) · 7.97 KB

File metadata and controls

303 lines (236 loc) · 7.97 KB

Batch Executor - Gas Optimized Batch Relay dApp

Setup & Deployment Guide

Prerequisites

  1. Node.js (v18+)
  2. Foundry — Install from book.getfoundry.sh:
    curl -L https://foundry.paradigm.xyz | bash
    foundryup
  3. MetaMask — Browser wallet extension
  4. Sepolia ETH — Get testnet ETH from a faucet (e.g., sepoliafaucet.com, Alchemy, or Infura faucets)

Installation

npm install

Foundry dependencies (forge-std, openzeppelin-contracts) are already in lib/. If missing, run:

forge install OpenZeppelin/openzeppelin-contracts --no-git
forge install foundry-rs/forge-std --no-git

Environment Setup

Copy the example and fill in your keys:

cp .env.example .env
# Sepolia testnet RPC
SEPOLIA_RPC_URL=https://rpc.sepolia.org

# Private keys (must have Sepolia ETH)
DEPLOYER_PRIVATE_KEY=0xYOUR_PRIVATE_KEY
RELAYER_PRIVATE_KEY=0xYOUR_PRIVATE_KEY

# Auto-populated after deployment
BATCH_EXECUTOR_ADDRESS=
SAMPLE_TOKEN_ADDRESS=
GAS_SPONSOR_ADDRESS=
RELAYER_ADDRESS=

Step 1: Get Sepolia ETH

  1. Go to a Sepolia faucet and request testnet ETH
  2. You need ETH in the deployer wallet to pay for contract deployment gas

Step 2: Compile Contracts

forge build

This will:

  • Compile all contracts in contracts/ with Solidity 0.8.24
  • Use optimizer with 1000 runs + viaIR for maximum gas savings
  • Target cancun EVM version (enables transient storage)
  • Generate artifacts in out/

Step 3: Deploy Contracts to Sepolia

npm run deploy:sepolia

Or manually:

forge script script/Deploy.s.sol:DeployScript \
  --rpc-url $SEPOLIA_RPC_URL \
  --private-key $DEPLOYER_PRIVATE_KEY \
  --broadcast --verify

node script/post-deploy.js

Note: The --verify flag requires an ETHERSCAN_API_KEY environment variable. Set it in your .env file or omit --verify if not needed.

The deployment will:

  1. Deploy BatchExecutor contract (minBatchSize = 1)
  2. Deploy SampleToken with BatchExecutor as the trusted forwarder
  3. Deploy GasSponsor with Sepolia-appropriate limits
  4. Whitelist the deployer as relayer in GasSponsor
  5. Write deployment.json with all contract addresses
  6. Update .env with deployed contract addresses (via post-deploy.js)

Step 4: Fund GasSponsor Pool (Optional)

Send ETH to the GasSponsor contract address for gas reimbursement:

cast send $GAS_SPONSOR_ADDRESS --value 0.05ether \
  --rpc-url $SEPOLIA_RPC_URL \
  --private-key $DEPLOYER_PRIVATE_KEY

Step 5: Start the Server

npm start

The server runs on http://localhost:3000

Step 6: Deploy to Render.com

  1. Push your repository to GitHub
  2. On Render.com, create a new Web Service and connect your repo
  3. Render auto-detects render.yaml and configures the build/start commands
  4. Set these environment variables in the Render dashboard:
    • SEPOLIA_RPC_URL — Your Sepolia RPC endpoint
    • DEPLOYER_PRIVATE_KEY — Deployer wallet key (needed for the token faucet)
    • RELAYER_PRIVATE_KEY — Relayer wallet private key
    • BATCH_EXECUTOR_ADDRESS — From deployment.json
    • SAMPLE_TOKEN_ADDRESS — From deployment.json
    • GAS_SPONSOR_ADDRESS — From deployment.json
    • RELAYER_ADDRESS — Relayer wallet address
  5. Set CORS_ORIGIN to your Render URL (e.g., https://gas-optimizer.onrender.com)

File Structure

.
+-- contracts/                 # Solidity contracts
|   +-- BatchExecutor.sol      # Main batch execution contract
|   +-- GasSponsor.sol         # Gas sponsorship pool
|   +-- SampleToken.sol        # ERC-20 token for testing
+-- test/                      # Foundry test suite
|   +-- GasBenchmark.t.sol     # 27 tests across 8 categories
+-- script/                    # Deployment scripts
|   +-- Deploy.s.sol           # Foundry Solidity deploy script
|   +-- post-deploy.js         # Updates .env after deployment
+-- lib/                       # Foundry dependencies
|   +-- forge-std/             # Foundry standard library
|   +-- openzeppelin-contracts/# OpenZeppelin contracts
+-- out/                       # Compiled artifacts (generated by forge)
+-- index.html                 # Frontend dApp interface
+-- server.js                  # Express server
+-- relayer.js                 # Relayer logic
+-- signer.js                  # Offline signer utility
+-- foundry.toml               # Foundry configuration
+-- remappings.txt             # Import remappings
+-- render.yaml                # Render.com deployment config
+-- package.json               # Node.js dependencies
+-- deployment.json            # Deployed contract addresses (auto-generated)
+-- .env.example               # Environment variable template
+-- .env                       # Environment variables (create this)

Contract Addresses

After deployment, check deployment.json for:

  • BatchExecutor address
  • SampleToken address
  • GasSponsor address

The frontend automatically fetches these addresses from the server via GET /api/config, so no manual editing of index.html is needed.

To verify the config endpoint:

curl http://localhost:3000/api/config

Gas Sponsor Configuration

Default limits on Sepolia (set in script/Deploy.s.sol):

  • Max per claim: 0.005 ETH
  • Daily relayer limit: 0.1 ETH
  • Daily user limit: 0.002 ETH per address
  • Global daily limit: 0.5 ETH total

For local development (Anvil), limits are 10x higher.

API Endpoints

GET /

HTML frontend interface

GET /health

Check server and relayer status

{
  "status": "ok",
  "relayer": "initialized|not configured",
  "timestamp": "2026-02-22T..."
}

GET /api/config

Get deployed contract addresses and network config

{
  "batchExecutorAddress": "0x...",
  "sampleTokenAddress": "0x...",
  "gasSponsorAddress": "0x...",
  "rpcUrl": "https://rpc.sepolia.org",
  "chainId": 11155111,
  "chainName": "Sepolia",
  "blockExplorer": "https://sepolia.etherscan.io"
}

GET /api/batch/status

Get current batch queue status

POST /api/batch/flush

Force flush the current queue (admin endpoint)

GET /api/gas-stats

Get gas usage analytics and batch history

GET /api/nonce/:address

Get on-chain nonce for a user address

POST /api/relay

Submit a signed request

{
  "request": {
    "from": "0x...",
    "to": "0x...",
    "value": "0",
    "gas": "100000",
    "nonce": "0",
    "deadline": "0",
    "data": "0x..."
  },
  "signature": "0x..."
}

Testing

Run Foundry Tests

forge test -vv

Gas Report

forge test --gas-report

Manual Testing via Frontend

  1. Open the app (localhost:3000 or your Render URL)
  2. Connect MetaMask to Sepolia
  3. Select recipients and set amount
  4. Sign and submit

Troubleshooting

Compilation fails

# Clear cache and recompile
forge clean
forge build

Deployment fails

  • Verify you have Sepolia ETH in the deployer wallet
  • Check SEPOLIA_RPC_URL is valid and reachable
  • Ensure DEPLOYER_PRIVATE_KEY is correct

Server won't start

# Check if port 3000 is in use
netstat -ano | findstr :3000  # Windows
lsof -i :3000                # macOS/Linux

Relayer not initialized

  • Verify all environment variables in .env are set
  • Check contract addresses match deployed contracts
  • Ensure SEPOLIA_RPC_URL is working

Security Notes

IMPORTANT: Never use mainnet private keys with this project.

  1. Use Sepolia testnet accounts only
  2. Never commit .env to git (it's in .gitignore)
  3. Use environment variables on Render.com (marked as secrets)
  4. The GasSponsor contract owns the sponsorship pool
  5. Owner can pause claims and withdraw funds

Support & Resources