Skip to main content

aether-chain-client

pip install aether-chain-client

Python client for the Aether chain: ML-DSA-44 keys, sending and receiving AETH, buying from and selling paid APIs (x402 aether-memo, aether-prepaid and aether-pull) and the on-chain service directory. It talks to a node's CometBFT RPC (port 26657) only.

import os
from aether_client import AetherClient, Key, fetch_paid, find_services, rate_service, withdraw_prepaid

client = AetherClient("http://localhost:26657", "aether-testnet-1")
key = Key.from_mnemonic(os.environ["AETHER_MNEMONIC"])  # same address as `aetherd keys add` / `agentmcp`

sent = client.send(key, "aether1...", "0.5 AETH", memo="invoice-42")
done = client.wait_for_transaction(sent.hash)            # confirmed | failed | pending (timeout)
# Retrying after an error: client.rebroadcast(sent.signed) -- never a second send().

res = fetch_paid(client, key, "https://api.example.com/forecast", max_amount="0.05 AETH", prepay="1 AETH")
# Or, where offered, pay from your own account under a capped, 7-day allowance the seller collects from later:
res2 = fetch_paid(client, key, "https://api.example.com/forecast", max_amount="0.05 AETH", pull_allowance="1 AETH")
services = find_services(client, query="weather", max_price="0.1 AETH", trusted=[owner_address])
# services[i].reputation: payments, payers, ratings (can be faked), trusted_ratings (can't)
# res.receipt: the seller's signed receipt and whether it matches exactly what was sent and received
rate_service(client, key, "https://api.example.com", 5)  # only raters who paid a service count
back = withdraw_prepaid(client, key, "https://api.example.com", withdrawal_id="w1")  # unspent prepaid balance

Standard x402

aether_client.x402.ExactAetherScheme pays the standard x402 v2 exact scheme with the x402 package's clients (x402ClientSync, x402_requests); the setup is in docs/X402.md. It signs a send of exactly what the 402 asks, and the server's facilitator broadcasts it.

AI agent frameworks

AetherToolkit gives an agent seven tools: check a balance, check a transaction, find paid APIs in the on-chain directory, quote an AETH to OSMO swap on Osmosis testnet, send a payment, call a paid API (paying it), and ask the testnet faucet for funds. Each framework gets them in its own form:

pip install "aether-chain-client[langchain]"      # or [openai-agents], [crewai], [llamaindex]
import os
from aether_client import AetherClient, Key
from aether_client.agent_tools import AetherToolkit

client = AetherClient("https://rpc.157-245-252-221.sslip.io", "aether-testnet-1")
kit = AetherToolkit(client, Key.from_mnemonic(os.environ["AETHER_MNEMONIC"]),
                    max_per_payment="0.1 AETH", daily_budget="1 AETH")

tools = kit.langchain()        # LangChain / LangGraph: create_react_agent(model, tools)
tools = kit.openai_agents()    # OpenAI Agents SDK: Agent(name=..., tools=tools)
tools = kit.crewai()           # CrewAI: Agent(..., tools=tools)
tools = kit.llamaindex()       # LlamaIndex: FunctionAgent(tools=tools, llm=...)
specs = kit.tool_specs()       # anything else: OpenAI-style function specs ("anthropic" for Messages API tools)
result = kit.call(name, arguments)   # ... and the answer to the model's tool call
  • Limits hold in code, not just the prompt. A payment over max_per_payment, or past daily_budget in a rolling 24 hours, is refused before anything is signed. kit.spending_status() shows what's left. Paid API calls count what they paid.
  • No double payments. send_payment takes an idempotency_key; the same key returns the first result instead of paying again.
  • Read-only without a key. AetherToolkit(client) offers only the balance, transaction, directory, swap-quote and inflow-cap tools.
  • Swap quotes. aether_quote_swap reads Osmosis's own estimate for the AETH/OSMO pool (1370) and gives the OSMO out, the cost in fees and price impact, and a minOutput for a slippage. It is on for aether-testnet-1; osmosis_rest=[...] names other Osmosis REST endpoints and osmosis_rest=[] turns it off. It only quotes: the swap itself is agentmcp's swap_aeth (see docs/OSMOSIS-POOL.md).
  • Inflow caps. aether_get_inflow_caps (AetherClient.inflow_caps()) lists the tokens other chains may send onto Aether and the room each has left. A transfer of anything else, or over the room, is refused and refunded on the sending chain, so check before asking anyone to send USDC (see docs/IBC-INFLOW-CAP.md). On a chain without the cap yet it answers active: false.
  • Errors are results. A failed call returns {"error": {"code", "message"}}, so the model sees what went wrong instead of the run stopping.
  • Untrusted text stays data. Memos, service names and descriptions and API response bodies are set by other people; the tool descriptions tell the model so.

Tested with langchain-core 1.6, openai-agents 0.23, crewai 1.6 and llama-index-core 0.14.

Selling

Charge per request from a Python service -- all three payment schemes, the /.well-known/x402 manifest for the service directory, and withdrawals of unspent prepaid balances. Compatible with the Go paywall and every Aether buyer.

import os
from fastapi import FastAPI, Request
from aether_client import AetherClient, Key, Paywall

client = AetherClient("http://localhost:26657", "aether-testnet-1")
pw = Paywall(client, "aether1...", "0.01 AETH", name="Weather", description="Forecasts by city",
             prepaid_ledger="ledger.json",           # customers' balances: back it up
             min_deposit="0.1 AETH",
             payout_key=Key.from_mnemonic(os.environ["PAYOUT_MNEMONIC"]),  # pays withdrawals; keep a small float in it
             receipt_key=payee_key,  # sign a receipt for every paid response (or a delegated key + receipt_delegation)
             pull_collector_key=Key.from_mnemonic(os.environ["COLLECTOR_MNEMONIC"]), pull_credit="1 AETH")  # aether-pull: needs no funds
pw.start_collecting()  # collects what aether-pull buyers owe, in batches
api = FastAPI()

@api.get("/forecast")
async def forecast(request: Request):
    return {"paid_by": request.scope["aether"].payer}

app = pw.asgi(api, free=["/health"])   # Flask/Django: app.wsgi_app = pw.wsgi(app.wsgi_app); who paid: environ["aether.payment"]

The ledger is one JSON file (the Go paywall's format) for one process. Chain lookups block, so the ASGI adapter runs them in a thread.

Amounts always carry a unit ("1.5 AETH", "1500000uaeth").

USDC. AetherClient(rpc, chain_id, usdc_channel="channel-N") (Aether's end of its channel to Noble) also knows USDC: Noble's uusdc over exactly that channel, never a lookalike that arrived another way. For USDC that arrives another route, give its denom trace and its denom on the issuing chain instead: usdc_path="transfer/channel-2", usdc_base_denom="erc20:0x0C382e685bbeeFE5d3d9C29e29E341fEE8E84C5d", usdc_issuer="Injective" (usdc_base_denom defaults to uusdc). Then send(key, to, "5 USDC") sends USDC, balances(address) lists each asset, wait_for_payment matches in the asset of min_amount, and fetch_paid pays services priced in USDC with max_amount (and prepay / pull_allowance) in USDC; an amount in another asset than the service charges is refused with ASSET_MISMATCH before anything is paid. Results carry asset, amount, balance, owed and allowance in that asset's base units; the *_uaeth fields are set only for AETH. Without the channel, "5 USDC" is an unknown unit. The seller kit charges USDC too: Paywall(client, pay_to, "0.05 USDC", usdc_channel="channel-N") charges Noble USDC for everything (payments, deposits and balances, pull allowances and collections, withdrawals), min_deposit and pull_credit must then be in USDC, and 402s, the manifest and receipts carry the asset exactly as cmd/paywall's do.

Tests: python -m pytest tests (checked against ../testdata/vectors.json, generated by the Go code).

Metadata

Release files for aether-chain-client 0.2.17

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for aether-chain-client 0.2.17
File Size Uploaded Provenance Actions
aether_chain_client-0.2.17.tar.gz 85.6 kB With provenance Details for aether_chain_client-0.2.17.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for aether-chain-client 0.2.17
File Interpreter ABI Platform Actions
aether_chain_client-0.2.17-py3-none-any.whl Python 3 none any Details for aether_chain_client-0.2.17-py3-none-any.whl

Total release size: 156.5 kB

Release files / aether_chain_client-0.2.17.tar.gz

Download URL aether_chain_client-0.2.17.tar.gz
Size 85.6 kB
Tags Source
SHA-256 checksum
How to use checksums
f900b37150030173975a16e6cae256734e138da47c3de4c6bba08fc6b4c79231
BLAKE2b-256 checksum
How to use checksums
8899e32a23f9eadf82868f225b67912d0af8434ba3ba2ddbacf154a2126dbe77
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 1, 2026.

Transparency log

Release files / aether_chain_client-0.2.17-py3-none-any.whl

Download URL aether_chain_client-0.2.17-py3-none-any.whl
Size 70.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d75eeea8c7a8d9869e01f34f107455aa5439661bd91c33be173b6bf38b316fc8
BLAKE2b-256 checksum
How to use checksums
fda4a74605a869b87fc43f50c8e0b8c43d0d200afae6ef79495b3d8d79addb21
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 1, 2026.

Transparency log

Security for aether-chain-client 0.2.17

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for aether_chain_client-0.2.17.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 1, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page