SatRank SDK for autonomous agents on Bitcoin Lightning. Discover, pay, self-list, and proxy-fulfill (deposit + hold modes) Lightning-native HTTP services.
Project description
satrank — Python SDK
Python client for SatRank. One verb — fulfill() —
that discovers, pays, and reports a Lightning-native HTTP service in a single
call with a hard budget guarantee.
Install
pip install satrank # core
pip install "satrank[nwc]" # + Nostr Wallet Connect driver
Python 3.10+.
Quickstart
import asyncio
from satrank import SatRank
from satrank.wallet import LndWallet
async def main() -> None:
async with SatRank(
api_base="https://satrank.dev",
wallet=LndWallet(
rest_endpoint="https://127.0.0.1:8080",
macaroon_hex="...", # admin macaroon (hex)
),
caller="my-agent",
) as sr:
result = await sr.fulfill(
intent={"category": "data/weather", "keywords": ["paris"]},
budget_sats=50,
)
print(result["response_body"] if result["success"] else result["error"])
asyncio.run(main())
Discovery only (no wallet)
async with SatRank(api_base="https://satrank.dev", caller="explorer") as sr:
cats = await sr.list_categories()
res = await sr.resolve_intent(category="data/weather", limit=10)
for c in res["candidates"]:
print(c["rank"], c.get("price_sats"), c.get("service_name"))
Wallet drivers
LndWallet— LND REST, macaroon auth.NwcWallet— NIP-47 Nostr Wallet Connect (needssatrank[nwc]).LnurlWallet— LNbits-style HTTP wallets.
See docs/sdk/wallet-drivers.md in the repo.
Documentation
AEPS §10 disputes (SDK 1.6.0+)
AEPS is the open standard SatRank implements. SDK 1.6.0 adds typed methods + zero-dep canonical-byte helpers so agents drive disputes without re-deriving wire formats.
import asyncio
import json
import hashlib
from coincurve import PrivateKey # any BIP-340 lib works
from satrank import (
SatRank,
AepsDisputeNotFoundError,
build_outcome_message_hash,
build_nip98_event_template,
encode_nip98_auth_header,
)
async def main():
async with SatRank(api_base="https://satrank.dev") as sr:
# 1. Open a dispute (NIP-98 auth = disputant pubkey)
body_dict = {
"respondent_pubkey": "<operator-pubkey-hex>",
"dispute_type": "content_correctness",
"receipt_id": 42,
"oracle_pubkeys": [oracle1_pk, oracle2_pk, oracle3_pk],
"oracle_threshold": 2,
}
body = json.dumps(body_dict, separators=(",", ":"))
tmpl = build_nip98_event_template(
url=sr.dispute_endpoint(),
method="POST",
body=body,
)
signed = sign_nip98_event(tmpl, agent_sk) # agent's signer
auth = encode_nip98_auth_header(signed)
dispute = await sr.open_dispute(**body_dict, authorization=auth)
# 2. Each oracle signs the canonical outcome message hash
hash_bytes = build_outcome_message_hash(
dispute["dispute_id"], "disputant_wins"
)["hash_bytes"]
sig = oracle_pk.sign_schnorr(hash_bytes).hex()
# 3. Submit attestation (NIP-98 auth = oracle pubkey)
attest_body = json.dumps(
{"outcome": "disputant_wins", "signature_hex": sig},
separators=(",", ":"),
)
attest_tmpl = build_nip98_event_template(
url=sr.attestation_endpoint(dispute["dispute_id"]),
method="POST",
body=attest_body,
)
attest_auth = encode_nip98_auth_header(
sign_nip98_event(attest_tmpl, oracle_sk)
)
try:
r = await sr.submit_attestation(
dispute_id=dispute["dispute_id"],
outcome="disputant_wins",
signature_hex=sig,
authorization=attest_auth,
)
if r["dispute_state"] == "resolved_disputant":
print("Slashing claim opens against operator bond")
except AepsDisputeNotFoundError:
...
# 4. Public read of dispute state (no auth)
view = await sr.get_dispute(dispute["dispute_id"])
print(view["attestation_counts"], view["state"])
asyncio.run(main())
Typed errors : AepsDisputeNotFoundError (404), AepsDisputeNotOpenError
(409), AepsOracleNotInSetError (403), AepsSignatureInvalidError (400).
The SDK depends only on httpx. BIP-340 Schnorr signing + Nostr event
finalization are the agent's responsibility — pick coincurve,
secp256k1, or any conformant lib.
License
MIT.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file satrank-1.6.0.tar.gz.
File metadata
- Download URL: satrank-1.6.0.tar.gz
- Upload date:
- Size: 49.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1f2a5af9b4b68fe76b143b0583c336abbcfee2f4dc4baae9e2daaf2e852509d2
|
|
| MD5 |
52760085c60d3892506479042409fe43
|
|
| BLAKE2b-256 |
5ff79fee491d21fa93d0b32ee349db2d9bb4e5feabb4ebb613fe1f892c33d711
|
File details
Details for the file satrank-1.6.0-py3-none-any.whl.
File metadata
- Download URL: satrank-1.6.0-py3-none-any.whl
- Upload date:
- Size: 43.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4877af1f1a12713bb57439a7efca6abdac706831b6cbaefe789519b656d33061
|
|
| MD5 |
221d6784748cd8c9d72fccbdd088c768
|
|
| BLAKE2b-256 |
397959f20de9106508be187c27a37453fa3d58451c2f35b8831bba858ea18015
|