AI agents can't hold ETH for gas. They shouldn't have to. Here's how to build a payment system where agents sign typed data and never touch gas or funds.
The problem
Your AI agent needs to pay for an API, buy data, or settle a trade. Traditional approach: give it a wallet with ETH + USDC. But then you're managing gas balances, handling failed transactions, and praying the agent doesn't get drained.
The solution: EIP-712 payment intents
Instead of executing transactions, agents sign intents - structured messages that say "I want to pay X to Y." A relayer picks up the intent, validates it against spending policies, and submits the on-chain transaction.
The agent never needs ETH. Never submits a transaction. Never holds funds.
Step 1: Define the intent structure
struct PaymentIntent {
address bot; // The agent's address
address to; // Payment recipient
address token; // ERC-20 token (e.g. USDC)
uint256 amount; // Amount in token decimals
uint256 deadline; // Expiry timestamp
bytes32 ref; // Reference hash (memo, invoice ID, etc.)
}
Step 2: Agent signs the intent
import { AxonClient } from '@axonfi/sdk';
const axon = new AxonClient({
relayerUrl: 'https://relay.axonfi.xyz',
botPrivateKey: process.env.BOT_PRIVATE_KEY,
vaultAddress: '0xYourVault',
chainId: 8453,
});
// Signs EIP-712 typed data + sends to relayer
const { txHash } = await axon.pay({
to: recipientAddress,
amount: '10.00', // 10 USDC
memo: 'Monthly API subscription',
});
The SDK handles:
- EIP-712 domain separator (chain-aware, vault-specific)
- Deadline calculation (15 min default)
- Reference hashing (SHA-256 of memo)
- Signature generation
- HTTP submission to the relayer
Step 3: Relayer validates and executes
The relayer checks:
- Is the bot registered on this vault?
- Is the signature valid for this intent?
- Is the amount within the bot's per-tx cap?
- Has the bot exceeded daily/weekly limits?
- Is the destination whitelisted (if whitelist is set)?
- Is the destination blacklisted?
- If amount > AI threshold, run 3-agent verification
Only after all checks pass does it call the vault contract.
Step 4: Vault enforces on-chain
function executePayment(
PaymentIntent calldata intent,
bytes calldata signature
) external onlyRelayer {
require(bots[intent.bot].isActive, "Bot not active");
require(block.timestamp <= intent.deadline, "Expired");
require(intent.amount <= bots[intent.bot].maxPerTxAmount, "Over limit");
// Verify EIP-712 signature
bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(...)));
require(ECDSA.recover(digest, signature) == intent.bot, "Bad sig");
// Transfer
IERC20(intent.token).transfer(intent.to, intent.amount);
}
The on-chain maxPerTxAmount is the hard ceiling. Even if the relayer is compromised, the contract enforces per-bot limits.
Python version
from axonfi import AxonClient
axon = AxonClient(
relayer_url="https://relay.axonfi.xyz",
bot_private_key="0x...",
vault_address="0x...",
chain_id=8453,
)
result = axon.pay(
to="0xrecipient",
amount="5.00",
memo="Data purchase",
)
print(result["txHash"])
LangChain integration
from langchain_axon import AxonToolkit
toolkit = AxonToolkit(
relayer_url="https://relay.axonfi.xyz",
bot_private_key="0x...",
vault_address="0x...",
chain_id=8453,
)
tools = toolkit.get_tools()
# Gives your agent: pay, swap, execute_protocol, get_balance, get_vault_value
Why this matters for agent builders
- No gas management - your agent loop doesn't need to check ETH balances or handle gas estimation
- No fund management - one vault per fleet, not one wallet per agent
- Instant revocation - pause a bot in one click, funds stay safe
- Audit trail - every payment is a signed intent with a memo, queryable on-chain
- Works on any EVM chain - same code on Base, Arbitrum, or any L2
Get started
npm install @axonfi/sdk
# or
pip install axonfi
Source: github.com/axonfi
The contracts are deployed on Base and Arbitrum. Testnet faucets and addresses are in TESTNET.md.
Top comments (0)