DEV Community

Cover image for Any Agent or LLM Can Now Own A Wallet and Perform EVM TXs via NLP
Ross Peili
Ross Peili

Posted on

Any Agent or LLM Can Now Own A Wallet and Perform EVM TXs via NLP

Your agent can own a wallet now — natural language to on-chain swaps on Ethereum, Base, and other EVM chains.

Most agent demos stop at reading the chain. You ask about a token, the model summarizes a blog post, everyone claps, and nothing moves on-chain.

The new defi/evm_tx_handler skill in Skillware is aimed at a different loop: your agent holds its own EVM wallet, turns plain-language trade intent into structured JSON, quotes a Uniswap V2 swap, shows a preview, and — only after confirmation — signs and broadcasts. No MetaMask popup. No pasting calldata into a block explorer. The LLM stays in natural language; the skill stays deterministic Python.

This post walks through what that looks like in practice, how Skillware fits in, and how you might chain it with wallet screening before you send funds anywhere sketchy.


Skillware in a nutshell

Skillware is an open-source Python framework for packaging agent skills the way you’d package a small library: one folder, one contract, works across providers.

Each skill is a bundle:

  • skill.py — deterministic logic (execute()), no hallucinated math
  • manifest.yaml — tool schema, env vars, constitution
  • instructions.md — how the model should use the tool (flows, edge cases, safety)
  • test_skill.py — bundle tests that run in CI

You load a skill once, adapt it for Gemini, Claude, OpenAI, or others via SkillLoader, pass instructions.md as system context, and wire tool calls to skill.execute(...). Same pattern everywhere — see the introduction and agent loops guide.

That separation matters for DeFi: the model parses “Buy 10 DEGEN on Base with USDC”; the skill parses nothing in free text. It only accepts structured action + intent and returns JSON the agent can show to a human.


evm_tx_handler: architecture in plain terms

Registry ID: defi/evm_tx_handler

Issuer: @Hendobox · catalog page

The skill is built around a dedicated agent wallet — not your personal MetaMask, not a treasury. You create a fresh key, fund it lightly, and put it in .env as AGENT_WALLET_PRIVATE_KEY. The constitution is explicit: “Never pass keys in tool args, YAML, or logs.”

Under the hood, EvmTxHandlerSkill loads YAML registries from data/:

  • chains.yaml — today Ethereum mainnet and Base (chain IDs, RPC env keys, verified Uni V2 router addresses)
  • tokens.yaml — symbol → contract per chain
  • addressbook.yaml — human labels → addresses for transfers

Long-term defaults (default chain, slippage, confirm_before_send, max_trade_usd) live in config.yaml (copy from config.yaml.example).

Agent vs skill (the split that keeps you sane)

From the skill’s instructions.md:

You (agent) Skill
Parse natural language into partial intent JSON Merge intent with config and YAML registries
Ask for missing fields in plain language Return missing_fields and suggested_defaults
Show preview to the user and obtain approval Build on-chain quotes; sign swaps and transfers when confirmed
Pass confirmed: true after approval Approve (if needed), swap, or transfer; return tx hash + receipt

So the NLP layer is the LLM. The signing layer is Web3.py inside the skill, using the agent wallet key from the environment — not from the chat thread.

Actions you actually call

The manifest defines eight operations: resolve, quote, preview, execute, transfer, balances, wallet_info, update_preferences.

A typical buy flow (from the skill docs):

  1. User: “Buy 10 Degen on Base with USDC.”
  2. Agent calls resolve with intent like:
{
    "side": "buy",
    "chain": "base",
    "target_asset": "degen",
    "amount": 10,
    "amount_kind": "target_out",
}
Enter fullscreen mode Exit fullscreen mode
  1. If spend_asset is missing, the skill returns missing_fields — the agent asks the user, then continues.
  2. quote / preview — live Uni V2 math, optional USD via CoinGecko if you set COINGECKO_API_KEY.
  3. User approves in plain language.
  4. execute with the same intent and confirmed: true.

Important nuance (easy to miss): execute re-quotes on-chain at broadcast time. Preview amounts can drift. The skill warns you to call quote or preview immediately before confirmation — not five minutes earlier.

For ERC20 spends, you may get a two-step flow: approve tx, then swap. If the response includes approve_tx_hash, tell the user both hashes landed.


Copy-paste: load the skill and run a Gemini loop

Install Skillware and deps (web3>=6), set RPC URLs and the agent wallet key, then:

import os
import google.genai as genai
from google.genai import types
from skillware.core.env import load_env_file
from skillware.core.loader import SkillLoader

load_env_file()
bundle = SkillLoader.load_skill("defi/evm_tx_handler")
skill = bundle["module"].EvmTxHandlerSkill()
client = genai.Client()
tool = SkillLoader.to_gemini_tool(bundle)

intent = {
    "side": "buy",
    "chain": "base",
    "target_asset": "degen",
    "spend_asset": "usdc",
    "amount": 10,
    "amount_kind": "target_out",
}

response = client.models.generate_content(
    model="gemini-2.5-flash",
    contents="Resolve and quote a buy of 10 DEGEN on Base with USDC.",
    config=types.GenerateContentConfig(
        tools=[tool],
        system_instruction=bundle["instructions"],
    ),
)
# On function_call: skill.execute({"action": ..., "intent": ...})
# After preview + user approval:
# skill.execute({"action": "execute", "intent": intent, "confirmed": True})
Enter fullscreen mode Exit fullscreen mode

No keys in the prompt. No MetaMask. The model never sees your private key — only the skill reads AGENT_WALLET_PRIVATE_KEY from the environment.

Want to try the flow without mainnet? The repo ships runnable examples:

EVM_TX_HANDLER_EXAMPLE_DEMO=1 python examples/gemini_evm_tx_handler.py
Enter fullscreen mode Exit fullscreen mode

See examples/gemini_evm_tx_handler.py and examples/claude_evm_tx_handler.py in the examples index.


Safety rails (built into the skill, not bolted on later)

A few things the skill enforces so agents don’t YOLO on-chain:

  • confirm_before_sendexecute / transfer blocked until confirmed: true
  • Balance pre-checks — insufficient funds return status: insufficient_balance before broadcast
  • max_trade_usd — fail closed if USD price unavailable when a cap is set
  • Constitution — dedicated wallet only, not financial advice, fail closed on missing RPC or registry entries

The skill itself recommends pairing with finance/wallet_screening before large sends to unknown addresses — screening runs locally in one execute() call (sanctions, malicious interaction counts, PnL context). That’s a natural chain: screen a recipient or counterparty wallet first; only if the report looks acceptable, call transfer or execute on the tx handler.

Same agent loop, two tools, one conversation:

  1. User: “Send 0.5 ETH to 0xABC… but check if it’s safe first.”
  2. Agent calls wallet_screening with the address.
  3. Agent summarizes summary.sanctioned_entity_match, summary.malicious_interaction_count, etc.
  4. If clean (and user still wants to proceed), agent calls evm_tx_handlertransfer with preview → user confirms → confirmed: true.

Both skills load through the same SkillLoader pattern; you’re composing capabilities, not rewriting provider-specific tool JSON from scratch.


Limits (honest ones)

Today this skill is Uniswap V2 only, on Ethereum + Base (see data/chains.yaml). No bridges, no aggregators, no Polygon router in the registry yet — adding chains is a YAML + verification exercise, not magic NLP.

Natural language can still be mis-parsed. Preview drift is real. Market risk is real. The skill gives you structure, signing, and guardrails; it doesn’t replace human judgment on whether a trade makes sense.


Where to go next

If you’ve been wiring one-off Web3 tools per provider, this is the other path: one skill bundle, any agent, one wallet the agent actually controls — with previews, confirmations, and screening chained in when you need them.

Top comments (0)