📚 Reference📜 Smart Contracts

Smart Contracts

PayNode’s contracts are minimal, immutable, and fully verified on Basescan. The protocol uses CREATE2 for deterministic addresses across all EVM chains.


📍 Contract Addresses

The Treasury Address receiving the 1% protocol fee is 0x598bF63F5449876efafa7b36b77Deb2070621C0E.

🔵 Base Mainnet (Production)

ConfigurationValue
Chain ID8453
Public RPChttps://mainnet.base.org
Block ExplorerBasescan
PayNode Router0x4A73696ccF76E7381b044cB95127B3784369Ed63
USDC0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913

🧪 Base Sepolia (Testnet / Sandbox)

💡 How to get Testnet Gas (ETH)?

  1. Optimism Faucet (Highly Recommended): console.optimism.io/faucet — 0.01 ETH daily.

Note: Faucets frequently go down or change rules. If this link fails, search for ‘Base Sepolia Faucet’ or bridge ETH from Sepolia (L1) to Base (L2) independently.

💰 How to get Testnet USDC?

Use the PayNode CLI: bun run paynode-402 mint --network testnet or manually call mint on the MockUSDC contract.

ConfigurationValue
Chain ID84532
Public RPChttps://sepolia.base.org
Block ExplorerBasescan Sepolia
PayNode Router0x24cD8b68aaC209217ff5a6ef1Bf55a59f2c8Ca6F
Mock USDC0x65c088EfBDB0E03185Dbe8e258Ad0cf4Ab7946b0

🚰 How to get Testnet USDC?

  1. Open the MockUSDC Basescan Page.
  2. Click the “Contract” tab -> “Write Contract” button.
  3. Click “Connect to Web3” and link your wallet.
  4. Expand function 3. mint.
  5. Enter your address and 1000000000 (for 1,000 USDC). Click Write.

📄 Core ABI

pay — Standard Payment

function pay(
    address token,       // ERC20 token (e.g. USDC)
    address merchant,    // Merchant receiving 99%
    uint256 amount,      // Total amount (smallest unit)
    bytes32 orderId      // External tracking ID
) external;

payWithPermit — Single-Tx Payment (EIP-2612)

Allows a third-party relayer (e.g. AI Agent) to pay on behalf of a token holder using an offline signature. No prior approve() needed.

function payWithPermit(
    address payer,       // Token holder who signed the permit
    address token,       // ERC20 token with EIP-2612 support
    address merchant,    // Merchant receiving 99%
    uint256 amount,      // Total amount
    bytes32 orderId,     // External tracking ID
    uint256 deadline,    // Permit expiry timestamp
    uint8 v, bytes32 r, bytes32 s  // ECDSA signature
) external;

PaymentReceived Event

Emitted on every successful payment. SDK Verifiers decode this event for on-chain verification.

event PaymentReceived(
    bytes32 indexed orderId,
    address indexed merchant,
    address indexed payer,
    address token,
    uint256 amount,
    uint256 fee,
    uint256 chainId      // Cross-chain replay protection
);

🛡️ Security Features

FeatureDescription
SafeERC20Handles non-standard ERC20 return values safely
Ownable2StepTwo-step ownership transfer prevents accidental lockout
PausableOwner can emergency-pause all payments
Custom ErrorsInvalidAddress(), AmountTooLow(), UnauthorizedCaller() — saves gas vs string requires
Deterministic DeployCREATE2 ensures same address across all EVM chains
ChainId in EventsPrevents cross-chain replay attacks

🚰 Faucet & Test Tokens (Sandbox)

To test PayNode on Base Sepolia, you need mock USDC. Our test token includes a public mint function for easy onboarding.

Option 1: Manual Mint via Basescan

  1. Visit the MockUSDC Contract on Basescan.
  2. Connect your wallet (MetaMask/Coinbase Wallet).
  3. Go to Write Contract -> mint.
  4. Enter your address and an amount (e.g., 1000000000 for 1,000 USDC — remember it has 6 decimals).
  5. Click Write and confirm the transaction.

Option 2: Programmatic Mint (Python SDK)

Agents can “self-fund” their testing wallets:

from paynode_sdk import PayNodeAgentClient
from web3 import Web3
 
# Initialize with private key
client = PayNodeAgentClient("YOUR_PRIVATE_KEY", ["https://sepolia.base.org"])
 
# Mock USDC ABI (minimal)
usdc_abi = [{"inputs": [{"name": "to", "type": "address"}, {"name": "amount", "type": "uint256"}], "name": "mint", "outputs": [], "stateMutability": "nonpayable", "type": "function"}]
usdc = client.w3.eth.contract(address="0x65c088EfBDB0E03185Dbe8e258Ad0cf4Ab7946b0", abi=usdc_abi)
 
# Mint 1,000 USDC
tx = usdc.functions.mint(client.account.address, 1000 * 10**6).build_transaction({
    'from': client.account.address,
    'nonce': client.w3.eth.get_transaction_count(client.account.address),
    'gas': 100000,
    'gasPrice': int(client.w3.eth.gas_price * 1.2)
})
signed_tx = client.account.sign_transaction(tx)
client.w3.eth.send_raw_transaction(signed_tx.raw_transaction)
print("💰 Test USDC Minted!")

Payment Flow (Manual Integration)

If building without the SDK:

  1. USDC.approve(RouterAddress, amount)
  2. Router.pay(USDC_Address, merchant, amount, orderId)
  3. Router atomically splits: 99% → merchant, 1% → treasury
  4. PaymentReceived event is emitted
  5. Verify the event in your backend to confirm payment

MIT 2026 © Nextra.