Skip to main content

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 (needs satrank[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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

satrank-1.6.0.tar.gz (49.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

satrank-1.6.0-py3-none-any.whl (43.4 kB view details)

Uploaded Python 3

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

Hashes for satrank-1.6.0.tar.gz
Algorithm Hash digest
SHA256 1f2a5af9b4b68fe76b143b0583c336abbcfee2f4dc4baae9e2daaf2e852509d2
MD5 52760085c60d3892506479042409fe43
BLAKE2b-256 5ff79fee491d21fa93d0b32ee349db2d9bb4e5feabb4ebb613fe1f892c33d711

See more details on using hashes here.

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

Hashes for satrank-1.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4877af1f1a12713bb57439a7efca6abdac706831b6cbaefe789519b656d33061
MD5 221d6784748cd8c9d72fccbdd088c768
BLAKE2b-256 397959f20de9106508be187c27a37453fa3d58451c2f35b8831bba858ea18015

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page