Skip to main content
This guide walks through deploying the Arcana x402 smart contracts to Base Sepolia using the automated deployment script.

Prerequisites

1

Install Dependencies

Install Node.js dependencies including ethers.js and solc:
cd backend
npm install
2

Configure Environment Variables

Create a backend/.env file with the required configuration:
# Required: Deployer wallet private key
PRIVATE_KEY=your_private_key_here

# Required: Agent wallet address for PolicyVault
AGENT_ADDRESS=0x...

# Optional: Base Sepolia RPC URL (defaults to public endpoint)
CHAIN_RPC_URL=https://sepolia.base.org

# Optional: Chain ID (defaults to 84532)
CHAIN_ID=84532

# Optional: USDC token address on Base Sepolia
USDC_ADDRESS=0x036CbD53842c5426634e7929541eC2318f3dCF7e

# Optional: Daily spending limit in ETH (defaults to 50)
DAILY_LIMIT=50
3

Fund Deployer Wallet

Ensure your deployer wallet has sufficient ETH on Base Sepolia for gas fees. Get testnet ETH from:

Environment Variables Reference

PRIVATE_KEY
string
required
Private key of the deployer wallet (with 0x prefix)
Never commit private keys to version control. Use environment variables or secure key management.
AGENT_ADDRESS
address
required
Ethereum address of the agent that will control the PolicyVaultThis address can call withdraw() to spend funds within policy limits.
CHAIN_RPC_URL
string
default:"https://sepolia.base.org"
RPC endpoint for Base Sepolia networkYou can use a public endpoint or your own Alchemy/Infura URL.
CHAIN_ID
number
default:"84532"
Chain ID for Base Sepolia testnet
USDC_ADDRESS
address
default:"0x036CbD53842c5426634e7929541eC2318f3dCF7e"
USDC token contract address on Base SepoliaUsed by the Escrow contract for payments.
DAILY_LIMIT
string
default:"50"
Daily spending limit for PolicyVault in ETH
  • Can be specified as a whole number (e.g., 50) or decimal (e.g., 10.5)
  • Values are parsed to 18 decimals internally
  • Example: 50 = 50 ETH daily limit

Deployment Process

Run the deployment script:
node backend/scripts/deploy-base-sepolia-contracts.mjs

What Happens During Deployment

1

Network Verification

Script connects to Base Sepolia RPC and verifies chain ID matches 84532
2

Compile Contracts

Contracts are compiled using solc compiler:
  • PolicyVault.sol
  • Escrow.sol
  • AgentRegistry.sol
3

Deploy Contracts

Contracts are deployed in sequence with nonce management:
  1. PolicyVault - Initialized with AGENT_ADDRESS and DAILY_LIMIT
  2. Escrow - Initialized with USDC_ADDRESS
  3. AgentRegistry - No constructor arguments
4

Link Contracts

Cross-contract connections are established:
  • PolicyVault: Add Escrow to allowlist
  • AgentRegistry: Set Escrow contract address
  • Escrow: Set AgentRegistry address
5

Output Deployment Info

Deployment addresses are logged to console:
{
  "chainId": "84532",
  "deployer": "0x...",
  "policyVault": "0x...",
  "escrow": "0x...",
  "agentRegistry": "0x..."
}

Deployment Script Details

The deployment script (backend/scripts/deploy-base-sepolia-contracts.mjs) performs several key functions:

Compiler Configuration

settings: {
  optimizer: {
    enabled: false,
    runs: 200,
  },
  outputSelection: {
    '*': {
      '*': ['abi', 'evm.bytecode.object'],
    },
  },
}

Constructor Arguments

await deployContract('PolicyVault', compiled.PolicyVault, signer, [
  AGENT_ADDRESS,  // Agent wallet address
  DAILY_LIMIT,    // Daily spending limit (18 decimals)
], nextNonce);

Contract Linking

After deployment, contracts are linked together:
// Allow Escrow to receive funds from PolicyVault
await policyVault.setAllowlist(await escrow.getAddress(), true);

// Connect AgentRegistry to Escrow for reputation tracking
await agentRegistry.setEscrowContract(await escrow.getAddress());

// Connect Escrow to AgentRegistry for task completion recording
await escrow.setAgentRegistry(await agentRegistry.getAddress());

Verification

After deployment, verify the contracts on BaseScan:
# Install Foundry (if not already installed)
curl -L https://foundry.paradigm.xyz | bash
foundryup

# Verify on BaseScan
forge verify-contract <CONTRACT_ADDRESS> src/PolicyVault.sol:PolicyVault \
  --chain-id 84532 \
  --etherscan-api-key <BASESCAN_API_KEY> \
  --constructor-args $(cast abi-encode "constructor(address,uint256)" <AGENT_ADDRESS> <DAILY_LIMIT>)
Repeat the verification command for each contract (Escrow, AgentRegistry) with appropriate constructor arguments.

Troubleshooting

Insufficient Funds

Error: insufficient funds for gas
Solution: Fund your deployer wallet with Base Sepolia ETH from a faucet.

Invalid Agent Address

Error: Missing or invalid AGENT_ADDRESS in backend/.env
Solution: Ensure AGENT_ADDRESS is a valid Ethereum address with 0x prefix.

Wrong Network

Warning: Expected chain ID 84532, got 1
Solution: Verify your RPC URL points to Base Sepolia, not Ethereum mainnet.

Next Steps

AgentRegistry

Register your agent service

Escrow

Create trustless payments

Build docs developers (and LLMs) love