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
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 unittest discover -s tests (checked against ../testdata/vectors.json, generated by the Go code).
Metadata
Release files for aether-chain-client 0.2.9
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| aether_chain_client-0.2.9.tar.gz | 57.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| aether_chain_client-0.2.9-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 108.0 kB
Release files / aether_chain_client-0.2.9.tar.gz
| Download URL | aether_chain_client-0.2.9.tar.gz |
|---|---|
| Size | 57.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d3c026f493bc0ce895aaf2a53ae8a663cd94ed86302b6c8360c00ec90fbf39ad
|
|
BLAKE2b-256 checksum How to use checksums |
ef10e3538848faefc675e8ace38cebe7591b761dc0cf3422e5c340ed207c5f72
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Oct 8, 2026.
Transparency logRelease files / aether_chain_client-0.2.9-py3-none-any.whl
| Download URL | aether_chain_client-0.2.9-py3-none-any.whl |
|---|---|
| Size | 50.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
29d37600f7940be5a9e6d2eb7c6cb3514993e4117cdcce725157d1009a2f547b
|
|
BLAKE2b-256 checksum How to use checksums |
abb272f1a0dc75e7f1f85b5895006e7a2683b8907dab0267f2580a5828992ab5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Oct 8, 2026.
Transparency log