{"@attributes":{"version":"2.0"},"channel":{"title":"DEV Community: Axon Finance","description":"The latest articles on DEV Community by Axon Finance (@axonfi).","link":"https:\/\/dev.to\/axonfi","image":{"url":"https:\/\/media2.dev.to\/dynamic\/image\/width=90,height=90,fit=cover,gravity=auto,format=auto\/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3830996%2Fd7d7c178-7306-4ca6-8a49-b28c6d7689ec.png","title":"DEV Community: Axon Finance","link":"https:\/\/dev.to\/axonfi"},"language":"en","item":[{"title":"Gasless Payments for AI Agents with EIP-712 Intents","pubDate":"Wed, 18 Mar 2026 08:50:23 +0000","link":"https:\/\/dev.to\/axonfi\/gasless-payments-for-ai-agents-with-eip-712-intents-3o61","guid":"https:\/\/dev.to\/axonfi\/gasless-payments-for-ai-agents-with-eip-712-intents-3o61","description":"<p>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.<\/p>\n\n<h2>\n  \n  \n  The problem\n<\/h2>\n\n<p>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.<\/p>\n\n<h2>\n  \n  \n  The solution: EIP-712 payment intents\n<\/h2>\n\n<p>Instead of executing transactions, agents sign <em>intents<\/em> - 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.<\/p>\n\n<p>The agent never needs ETH. Never submits a transaction. Never holds funds.<\/p>\n\n<h3>\n  \n  \n  Step 1: Define the intent structure\n<\/h3>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>struct PaymentIntent {\n    address bot;      \/\/ The agent's address\n    address to;       \/\/ Payment recipient\n    address token;    \/\/ ERC-20 token (e.g. USDC)\n    uint256 amount;   \/\/ Amount in token decimals\n    uint256 deadline; \/\/ Expiry timestamp\n    bytes32 ref;      \/\/ Reference hash (memo, invoice ID, etc.)\n}\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h3>\n  \n  \n  Step 2: Agent signs the intent\n<\/h3>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">AxonClient<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">@axonfi\/sdk<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n\n<span class=\"kd\">const<\/span> <span class=\"nx\">axon<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"nc\">AxonClient<\/span><span class=\"p\">({<\/span>\n  <span class=\"na\">relayerUrl<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">https:\/\/relay.axonfi.xyz<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span>\n  <span class=\"na\">botPrivateKey<\/span><span class=\"p\">:<\/span> <span class=\"nx\">process<\/span><span class=\"p\">.<\/span><span class=\"nx\">env<\/span><span class=\"p\">.<\/span><span class=\"nx\">BOT_PRIVATE_KEY<\/span><span class=\"p\">,<\/span>\n  <span class=\"na\">vaultAddress<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">0xYourVault<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span>\n  <span class=\"na\">chainId<\/span><span class=\"p\">:<\/span> <span class=\"mi\">8453<\/span><span class=\"p\">,<\/span>\n<span class=\"p\">});<\/span>\n\n<span class=\"c1\">\/\/ Signs EIP-712 typed data + sends to relayer<\/span>\n<span class=\"kd\">const<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">txHash<\/span> <span class=\"p\">}<\/span> <span class=\"o\">=<\/span> <span class=\"k\">await<\/span> <span class=\"nx\">axon<\/span><span class=\"p\">.<\/span><span class=\"nf\">pay<\/span><span class=\"p\">({<\/span>\n  <span class=\"na\">to<\/span><span class=\"p\">:<\/span> <span class=\"nx\">recipientAddress<\/span><span class=\"p\">,<\/span>\n  <span class=\"na\">amount<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">10.00<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"c1\">\/\/ 10 USDC<\/span>\n  <span class=\"na\">memo<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">Monthly API subscription<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span>\n<span class=\"p\">});<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>The SDK handles:<\/p>\n\n<ul>\n<li>EIP-712 domain separator (chain-aware, vault-specific)<\/li>\n<li>Deadline calculation (15 min default)<\/li>\n<li>Reference hashing (SHA-256 of memo)<\/li>\n<li>Signature generation<\/li>\n<li>HTTP submission to the relayer<\/li>\n<\/ul>\n\n<h3>\n  \n  \n  Step 3: Relayer validates and executes\n<\/h3>\n\n<p>The relayer checks:<\/p>\n\n<ol>\n<li>Is the bot registered on this vault?<\/li>\n<li>Is the signature valid for this intent?<\/li>\n<li>Is the amount within the bot's per-tx cap?<\/li>\n<li>Has the bot exceeded daily\/weekly limits?<\/li>\n<li>Is the destination whitelisted (if whitelist is set)?<\/li>\n<li>Is the destination blacklisted?<\/li>\n<li>If amount &gt; AI threshold, run 3-agent verification<\/li>\n<\/ol>\n\n<p>Only after all checks pass does it call the vault contract.<\/p>\n\n<h3>\n  \n  \n  Step 4: Vault enforces on-chain\n<\/h3>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>function executePayment(\n    PaymentIntent calldata intent,\n    bytes calldata signature\n) external onlyRelayer {\n    require(bots[intent.bot].isActive, \"Bot not active\");\n    require(block.timestamp &lt;= intent.deadline, \"Expired\");\n    require(intent.amount &lt;= bots[intent.bot].maxPerTxAmount, \"Over limit\");\n\n    \/\/ Verify EIP-712 signature\n    bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(...)));\n    require(ECDSA.recover(digest, signature) == intent.bot, \"Bad sig\");\n\n    \/\/ Transfer\n    IERC20(intent.token).transfer(intent.to, intent.amount);\n}\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>The on-chain <code>maxPerTxAmount<\/code> is the hard ceiling. Even if the relayer is compromised, the contract enforces per-bot limits.<\/p>\n\n<h2>\n  \n  \n  Python version\n<\/h2>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">from<\/span> <span class=\"n\">axonfi<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">AxonClient<\/span>\n\n<span class=\"n\">axon<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">AxonClient<\/span><span class=\"p\">(<\/span>\n    <span class=\"n\">relayer_url<\/span><span class=\"o\">=<\/span><span class=\"sh\">\"<\/span><span class=\"s\">https:\/\/relay.axonfi.xyz<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">bot_private_key<\/span><span class=\"o\">=<\/span><span class=\"sh\">\"<\/span><span class=\"s\">0x...<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">vault_address<\/span><span class=\"o\">=<\/span><span class=\"sh\">\"<\/span><span class=\"s\">0x...<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">chain_id<\/span><span class=\"o\">=<\/span><span class=\"mi\">8453<\/span><span class=\"p\">,<\/span>\n<span class=\"p\">)<\/span>\n\n<span class=\"n\">result<\/span> <span class=\"o\">=<\/span> <span class=\"n\">axon<\/span><span class=\"p\">.<\/span><span class=\"nf\">pay<\/span><span class=\"p\">(<\/span>\n    <span class=\"n\">to<\/span><span class=\"o\">=<\/span><span class=\"sh\">\"<\/span><span class=\"s\">0xrecipient<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">amount<\/span><span class=\"o\">=<\/span><span class=\"sh\">\"<\/span><span class=\"s\">5.00<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">memo<\/span><span class=\"o\">=<\/span><span class=\"sh\">\"<\/span><span class=\"s\">Data purchase<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span>\n<span class=\"p\">)<\/span>\n<span class=\"nf\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">result<\/span><span class=\"p\">[<\/span><span class=\"sh\">\"<\/span><span class=\"s\">txHash<\/span><span class=\"sh\">\"<\/span><span class=\"p\">])<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h2>\n  \n  \n  LangChain integration\n<\/h2>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">from<\/span> <span class=\"n\">langchain_axon<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">AxonToolkit<\/span>\n\n<span class=\"n\">toolkit<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">AxonToolkit<\/span><span class=\"p\">(<\/span>\n    <span class=\"n\">relayer_url<\/span><span class=\"o\">=<\/span><span class=\"sh\">\"<\/span><span class=\"s\">https:\/\/relay.axonfi.xyz<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">bot_private_key<\/span><span class=\"o\">=<\/span><span class=\"sh\">\"<\/span><span class=\"s\">0x...<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">vault_address<\/span><span class=\"o\">=<\/span><span class=\"sh\">\"<\/span><span class=\"s\">0x...<\/span><span class=\"sh\">\"<\/span><span class=\"p\">,<\/span>\n    <span class=\"n\">chain_id<\/span><span class=\"o\">=<\/span><span class=\"mi\">8453<\/span><span class=\"p\">,<\/span>\n<span class=\"p\">)<\/span>\n\n<span class=\"n\">tools<\/span> <span class=\"o\">=<\/span> <span class=\"n\">toolkit<\/span><span class=\"p\">.<\/span><span class=\"nf\">get_tools<\/span><span class=\"p\">()<\/span>\n<span class=\"c1\"># Gives your agent: pay, swap, execute_protocol, get_balance, get_vault_value\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<h2>\n  \n  \n  Why this matters for agent builders\n<\/h2>\n\n<ul>\n<li>\n<strong>No gas management<\/strong> - your agent loop doesn't need to check ETH balances or handle gas estimation<\/li>\n<li>\n<strong>No fund management<\/strong> - one vault per fleet, not one wallet per agent<\/li>\n<li>\n<strong>Instant revocation<\/strong> - pause a bot in one click, funds stay safe<\/li>\n<li>\n<strong>Audit trail<\/strong> - every payment is a signed intent with a memo, queryable on-chain<\/li>\n<li>\n<strong>Works on any EVM chain<\/strong> - same code on Base, Arbitrum, or any L2<\/li>\n<\/ul>\n\n<h2>\n  \n  \n  Get started\n<\/h2>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>npm <span class=\"nb\">install<\/span> @axonfi\/sdk\n<span class=\"c\"># or<\/span>\npip <span class=\"nb\">install <\/span>axonfi\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Source: <a href=\"https:\/\/github.com\/axonfi\" rel=\"noopener noreferrer\">github.com\/axonfi<\/a><\/p>\n\n\n\n\n<p><em>The contracts are deployed on Base and Arbitrum. Testnet faucets and addresses are in <a href=\"https:\/\/github.com\/axonfi\/core\/blob\/main\/TESTNET.md\" rel=\"noopener noreferrer\">TESTNET.md<\/a>.<\/em><\/p>\n\n","category":["ai","ethereum","solidity","tutorial"]},{"title":"Your AI Agent Doesn't Need a Wallet - It Needs a Treasury","pubDate":"Wed, 18 Mar 2026 08:50:14 +0000","link":"https:\/\/dev.to\/axonfi\/your-ai-agent-doesnt-need-a-wallet-it-needs-a-treasury-1dg3","guid":"https:\/\/dev.to\/axonfi\/your-ai-agent-doesnt-need-a-wallet-it-needs-a-treasury-1dg3","description":"<p>Most AI agent frameworks tell you to \"give your agent a wallet.\" So you generate a key pair, fund it with ETH for gas and USDC for payments, and hope nothing goes wrong.<\/p>\n\n<p>Now imagine you have 50 agents. That's 50 wallets, 50 private keys, 50 gas balances to monitor. One compromised key and an agent drains everything it holds.<\/p>\n\n<p>This is the wrong model.<\/p>\n\n<h2>\n  \n  \n  Agents should sign, not hold\n<\/h2>\n\n<p>The mental shift: agents don't need wallets. They need <em>permission to request payments<\/em> from a vault they don't control.<\/p>\n\n<p>Here's the pattern:<\/p>\n\n<ol>\n<li>\n<strong>Owner<\/strong> deploys a vault (a smart contract they control)<\/li>\n<li>\n<strong>Owner<\/strong> registers agent public keys with spending limits<\/li>\n<li>\n<strong>Agent<\/strong> signs a payment intent (EIP-712 typed data) when it needs to pay for something<\/li>\n<li>\n<strong>Relayer<\/strong> validates the signature, checks policies, submits on-chain<\/li>\n<li>\n<strong>Vault<\/strong> verifies the agent is authorized and the amount is within limits<\/li>\n<\/ol>\n\n<p>The agent never holds funds. Never pays gas. Never has withdrawal access.<\/p>\n\n<h2>\n  \n  \n  What a payment intent looks like\n<\/h2>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight typescript\"><code><span class=\"c1\">\/\/ Agent-side code<\/span>\n<span class=\"k\">import<\/span> <span class=\"p\">{<\/span> <span class=\"nx\">AxonClient<\/span> <span class=\"p\">}<\/span> <span class=\"k\">from<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">@axonfi\/sdk<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\n\n<span class=\"kd\">const<\/span> <span class=\"nx\">axon<\/span> <span class=\"o\">=<\/span> <span class=\"k\">new<\/span> <span class=\"nc\">AxonClient<\/span><span class=\"p\">({<\/span>\n  <span class=\"na\">relayerUrl<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">https:\/\/relay.axonfi.xyz<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span>\n  <span class=\"na\">botPrivateKey<\/span><span class=\"p\">:<\/span> <span class=\"nx\">process<\/span><span class=\"p\">.<\/span><span class=\"nx\">env<\/span><span class=\"p\">.<\/span><span class=\"nx\">BOT_KEY<\/span><span class=\"p\">,<\/span>\n  <span class=\"na\">vaultAddress<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">0x...<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span>\n  <span class=\"na\">chainId<\/span><span class=\"p\">:<\/span> <span class=\"mi\">8453<\/span><span class=\"p\">,<\/span> <span class=\"c1\">\/\/ Base<\/span>\n<span class=\"p\">});<\/span>\n\n<span class=\"kd\">const<\/span> <span class=\"nx\">result<\/span> <span class=\"o\">=<\/span> <span class=\"k\">await<\/span> <span class=\"nx\">axon<\/span><span class=\"p\">.<\/span><span class=\"nf\">pay<\/span><span class=\"p\">({<\/span>\n  <span class=\"na\">to<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">0xvendor...<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span>\n  <span class=\"na\">token<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"c1\">\/\/ USDC on Base<\/span>\n  <span class=\"na\">amount<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">5.00<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"c1\">\/\/ 5 USDC<\/span>\n  <span class=\"na\">memo<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">API subscription renewal<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span>\n<span class=\"p\">});<\/span>\n\n<span class=\"nx\">console<\/span><span class=\"p\">.<\/span><span class=\"nf\">log<\/span><span class=\"p\">(<\/span><span class=\"nx\">result<\/span><span class=\"p\">.<\/span><span class=\"nx\">txHash<\/span><span class=\"p\">);<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Under the hood, the SDK signs an EIP-712 <code>PaymentIntent<\/code> struct and POSTs it to the relayer. The agent's private key never touches funds - it only proves \"I am authorized to request this payment.\"<\/p>\n\n<h2>\n  \n  \n  Spending policies\n<\/h2>\n\n<p>The vault owner sets per-agent limits:<\/p>\n\n<ul>\n<li>\n<strong>Per-transaction cap<\/strong> - enforced on-chain, can't be bypassed<\/li>\n<li>\n<strong>Daily\/weekly\/monthly limits<\/strong> - enforced by the relayer<\/li>\n<li>\n<strong>Destination whitelist<\/strong> - agent can only pay approved addresses<\/li>\n<li>\n<strong>Destination blacklist<\/strong> - blocked addresses (always wins over whitelist)<\/li>\n<li>\n<strong>AI verification threshold<\/strong> - payments above X trigger a 3-agent AI review<\/li>\n<\/ul>\n\n<p>All configurable from a dashboard. No code changes, no redeployment.<\/p>\n\n<h2>\n  \n  \n  What if an agent key is compromised?\n<\/h2>\n\n<p>Worst case: the attacker can sign payment intents. But:<\/p>\n\n<ul>\n<li>They're capped by <code>maxPerTxAmount<\/code> (on-chain, immutable per bot)<\/li>\n<li>Daily limits stop runaway spending<\/li>\n<li>Whitelist restricts where funds can go<\/li>\n<li>Owner can pause the bot instantly<\/li>\n<li>The attacker can't withdraw, can't change limits, can't add new bots<\/li>\n<\/ul>\n\n<p>Compare this to a compromised wallet: attacker drains everything, no limits, no recourse.<\/p>\n\n<h2>\n  \n  \n  The infrastructure gap\n<\/h2>\n\n<p>Every agent framework (LangChain, CrewAI, AutoGen, ElizaOS) gives you tool calling, memory, and planning. None of them solve the money problem properly.<\/p>\n\n<p>\"Just use an MPC wallet\" still means your agent holds funds. \"Use a multisig\" means your agent can't transact autonomously. \"Use a custodial API\" means trusting a third party with your money.<\/p>\n\n<p>Non-custodial vaults with scoped permissions is the missing piece.<\/p>\n\n<h2>\n  \n  \n  Try it\n<\/h2>\n\n\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>npm <span class=\"nb\">install<\/span> @axonfi\/sdk\n<span class=\"c\"># or<\/span>\npip <span class=\"nb\">install <\/span>axonfi\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Open source: <a href=\"https:\/\/github.com\/axonfi\" rel=\"noopener noreferrer\">github.com\/axonfi<\/a><\/p>\n\n\n\n\n<p><em>Building with AI agents and need payment infrastructure? The <a href=\"https:\/\/github.com\/axonfi\/sdk\" rel=\"noopener noreferrer\">TypeScript SDK<\/a> and <a href=\"https:\/\/github.com\/axonfi\/sdk-python\" rel=\"noopener noreferrer\">Python SDK<\/a> are on npm\/PyPI. <a href=\"https:\/\/github.com\/axonfi\/langchain-python\" rel=\"noopener noreferrer\">LangChain integration<\/a> available.<\/em><\/p>\n\n","category":["ai","web3","typescript","blockchain"]}]}}