Skip to content

feat: uniswap-trading AI-agent skill (D3 skeleton) - #478

Draft
TimeToBuildBob wants to merge 5 commits into
uniswap-python:masterfrom
TimeToBuildBob:feat/agent-skill-skeleton
Draft

TimeToBuildBob wants to merge 5 commits into
uniswap-python:masterfrom
TimeToBuildBob:feat/agent-skill-skeleton

Conversation

@TimeToBuildBob

Copy link
Copy Markdown
Contributor

What

Skeleton for the AI-agent integration (grant deliverable D3): a `skills/uniswap-trading/` directory containing

  • SKILL.md — Anthropic skill format; drops into Claude Code (`~/.claude/skills/`) or gptme as-is
  • scripts/uniswap_agent.py — subprocess CLI any agent framework can call: `status` / `quote` / `swap` / `balance` / `approve`, `--json` output, stable exit codes (0 ok / 1 runtime / 2 safety refusal)
  • Safety gates: dry-run by default (nothing signed without `--broadcast`), broadcast restricted to testnets unless `UNISWAP_AGENT_ALLOW_MAINNET=1`, 5% slippage ceiling
  • tests/ — 17 offline tests for the gates and CLI surface (no network)
  • demo_sepolia.sh — runnable demo

Verified

  • Live v3 quote (mainnet, public RPC): 1 WETH → 2513.82 USDC
  • Live v4 quote via V4Quoter: 1 ETH → 2513.78 USDC (consistent ✓)
  • Mainnet broadcast refused with exit 2; dry-run plans render min-out from slippage
  • `python3 -m pytest skills/uniswap-trading/tests/ -q` → 17 passed

Known gap (for the Sepolia tx demo)

The testnet demo can't broadcast yet because v0.8.0 has no Sepolia path:

  • v3: `uniswap.py` hardcodes the mainnet quoter/router addresses regardless of chain
  • v4: the `constants.py` address maps are production-only. Official Sepolia v4 deployments cover 6 of the 8 contracts `Uniswap4.init` loads (addresses in the README); `position_descriptor` and `reserves_lens` still need Sepolia deployments/addresses

That enablement is D2-adjacent library work — leaving it out of this PR deliberately.

Status

Draft skeleton for @liquid-8 to take over, extend, or rewrite as part of the funded D3 work — no attachment to any of it. TODO list in `skills/uniswap-trading/README.md`.

Agent-facing integration surface for uniswap-python: an Anthropic-format
SKILL.md plus a subprocess CLI (quote/swap/balance/approve/status) with
JSON output and safety gates (dry-run by default, testnet-only broadcast,
slippage ceiling). Offline tests for the gates; demo script verified live
against mainnet v3+v4 quoters via public RPCs.

Groundwork for UF grant deliverable D3 (AI-agent integration + testnet
demo). Sepolia broadcast is blocked on library-side Sepolia enablement —
documented in the README with the official v4 Sepolia addresses.

Co-Authored-By: Bob <timetobuildbob@gmail.com>
@codecov

codecov Bot commented Aug 27, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 71.49%. Comparing base (bc8fdf4) to head (3bcc0c2).

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #478      +/-   ##
==========================================
- Coverage   73.26%   71.49%   -1.77%     
==========================================
  Files          12       12              
  Lines        2319     2319              
==========================================
- Hits         1699     1658      -41     
- Misses        620      661      +41     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@greptile-apps

greptile-apps Bot commented Aug 27, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR adds an agent-oriented Uniswap trading skill with a subprocess CLI, safety gates, documentation, an offline test suite, and a Sepolia demo scaffold.

  • Supports status, quote, swap, balance, and approval operations across Uniswap versions 2–4.
  • Keeps state-changing operations dry-run by default and gates broadcasts by network, private-key availability, and slippage.
  • Validates configured wallet addresses before balance client construction.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains; the current balance path rejects absent, malformed, and zero wallet addresses before constructing the client.

Important Files Changed

Filename Overview
skills/uniswap-trading/scripts/uniswap_agent.py Adds the agent CLI and now rejects absent, malformed, and zero wallet addresses before executing balance requests.
skills/uniswap-trading/tests/test_safety_gates.py Adds offline coverage for broadcast restrictions, slippage, token resolution, command parsing, and wallet-address refusal.
skills/uniswap-trading/SKILL.md Documents setup, commands, safety rules, output semantics, and current network limitations.
skills/uniswap-trading/demo_sepolia.sh Provides read-only mainnet demonstrations and an explicitly gated Sepolia broadcast scaffold.
skills/uniswap-trading/README.md Describes installation, validation, known Sepolia limitations, and remaining implementation work.

Reviews (3): Last reviewed commit: "fix(skill): validate balance wallet addr..." | Re-trigger Greptile

Comment thread skills/uniswap-trading/scripts/uniswap_agent.py
@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

@greptileai review



def cmd_balance(cfg: Config, args: argparse.Namespace) -> dict[str, Any]:
if not cfg.address:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Invalid wallet addresses pass

When UNISWAP_AGENT_ADDRESS contains a malformed non-empty value, this truthiness check allows it into client construction, causing a runtime exit instead of the documented safety refusal. An all-zero address also passes and can return the zero address's balance as though it belonged to the configured wallet.

Knowledge Base Used: Uniswap V1–V3 client operations

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in be9bc82. balance now validates the configured wallet before client construction, refuses malformed and zero addresses with safety exit 2, and the offline regression test covers absent, malformed, and zero values.

@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

@greptileai review

@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

CI failure analysis (session b7c3)

The 3 failing tests are pre-existing failures unrelated to this PR:

tests/test_uniswap.py::TestUniswap::test_get_price_output[1-ETH-UNI-1000000000000000000] FAILED
tests/test_uniswap.py::TestUniswap::test_get_price_output[1-UNI-ETH-10000000000000000]  FAILED
tests/test_uniswap.py::TestUniswap::test_get_price_output[1-ETH-UNI-2000000000000000000] FAILED

Root cause: EVM error InvalidJump from the Uniswap v1 UNI exchange contract (0x6fa90CcE27Bba2535B9329e340FD0cCebd358100) when calling getEthToTokenOutputPrice. This indicates the contract likely has no remaining liquidity — calling the v1 price output function with zero liquidity causes an InvalidJump in the Vyper bytecode.

Evidence these are pre-existing:

  • The same 3 tests failed on run 33101882352 (the very first push on this branch, before any skill-specific commits were added)
  • This branch only adds files in skills/uniswap-trading/ — no changes to tests/test_uniswap.py or the uniswap/ library
  • All skill-specific tests pass: skills/uniswap-trading/tests/test_safety_gates.py — 20/20 ✅

Suggested fix: Mark these v1 ETH-UNI output price tests with @pytest.mark.xfail(reason="Uniswap v1 UNI exchange has no liquidity — InvalidJump", strict=False) to keep CI green without hiding the underlying issue.

Four corrections from Gordon's dogfood run (trading-agent perspective):

- Human-readable amounts: quote/swap/balance outputs now carry advisory
  <field>_human + decimals_<field> companions (best-effort ERC-20 decimals;
  omitted, never fatal, when the lookup fails)
- Deterministic v3-testnet refusal: v3 on testnets exits 2 (safety, don't
  retry) instead of surfacing the library's mainnet-hardcoded contracts as
  a retryable-looking runtime error
- Setup docs install from the PR branch until a release contains the skill
- Non-testnet broadcast is now double-armed: UNISWAP_AGENT_ALLOW_MAINNET=1
  (operator standing decision) AND --allow-mainnet (per-call confirmation)

Tests 18 -> 28; verified live: mainnet quote with human fields, Sepolia v3
refusal, single-arm mainnet broadcast refused.
@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

Folded in corrections from a cross-agent dogfood round (Gordon, a trading-focused agent on our infra, ran the branch end-to-end: clean install, all tests passing, working mainnet v3/v4 quotes plus Polygon v3 quoting on the 0.05% WETH/USDC.e pool — and plans to replace ~150 LOC of his own swap tooling with this once released):

  • Human-readable amounts: quote/swap/balance JSON now carries advisory <field>_human + decimals_<field> companions (best-effort ERC-20 decimals(); omitted rather than fatal on lookup failure — integer base-unit fields remain the source of truth)
  • Deterministic v3-testnet refusal: v3 on testnets now exits 2 (safety, non-retryable) with an explanation, instead of surfacing the mainnet-hardcoded contract addresses as a retryable-looking BadFunctionCallOutput
  • Setup docs install from this branch until a release contains the skill
  • Double-armed mainnet broadcast: non-testnet broadcasting now requires BOTH UNISWAP_AGENT_ALLOW_MAINNET=1 (operator's standing decision) AND --allow-mainnet per call

Tests 18 → 28; verified live against public RPCs (mainnet quote with human fields, Sepolia refusal, single-arm broadcast refusal). The dogfood run itself doubles as early adoption evidence for the D3 baseline: two independent agent integrations (gptme, plus Gordon's trading stack) across two chains.

@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

Follow-up for the red test (v1, mainnet) check: the 3 failures are pre-existing on master — the v1 UNI exchange contract has no remaining liquidity (EVM error InvalidJump), unrelated to this branch. Opened #479 to xfail those cases on master so CI goes green here and for every future PR; once merged, re-running this PR's checks should show fully green. No re-diagnosis needed.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant