Metadata-Version: 2.5
Name: flop-sdk
Version: 0.3.0
Summary: FLOP Network SDK for Python - HTLC workflows, PoUI proofs, and account management
Project-URL: Bug Tracker, https://github.com/flop-labs/network/issues/new/choose
Project-URL: Homepage, https://github.com/flop-labs/flop-core
Project-URL: Documentation, https://github.com/flop-labs/flop-core/docs
Project-URL: Repository, https://github.com/flop-labs/flop-core
Author-email: FLOP Network <dev@flop.network>
License: MIT OR Apache-2.0
License-File: LICENSE
Keywords: ai,blockchain,flop,htlc,inference,substrate,tee
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.10
Requires-Dist: aiohttp>=3.9.0
Requires-Dist: langfuse<3,>=2.0.0
Requires-Dist: pydantic>=2.0.0
Requires-Dist: substrate-interface>=1.0.0
Requires-Dist: typing-extensions>=4.0.0
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.1.0; extra == 'dev'
Requires-Dist: pytest>=7.4.0; extra == 'dev'
Requires-Dist: ruff>=0.1.0; extra == 'dev'
Requires-Dist: ty==0.0.85; extra == 'dev'
Description-Content-Type: text/markdown

# flop-sdk

Ordinary HTLC creation requires a registered EconomicCritical appraisal profile.
Supply `tee_requirements` / `teeRequirements` as `{profile: {profile_id, version}, model_hash, measurement_hash}` (32-byte hex hashes), or its canonical 100-byte SCALE hex.
The runtime checks that the registered profile and immutable commitments match its policy; there is no simulator default.
For the examples, set `FLOP_HTLC_TEE_REQUIREMENTS` to that canonical hex from your network's registered profile.

FLOP Network SDK for Python — HTLC workflows, PoI proofs, and account management.

`SUPPORTED_SPEC_VERSIONS` admits exactly `1013000`, `1014000` through `1014005`, and `1014007`
through `1014014` in this unreleased source. Published `0.2.0` stops at `1014011`.
`SUPPORTED_SPEC_VERSION_RANGE` retains its exported shape as the envelope
`1013000..1014014`; versions inside it that are not listed, `1014006` among them, are not
admitted. Qualification covers
runtime `1013000` at `44a5fedc88614b9a6e8c97605c2ec943faf47d9d`, the
registrar runtime `1014000` at `e4f01cc849fa6c768d5c0f9c111dffb450ea4fa9`
(PR #2726), runtime `1014001` at `de4e2779dbf6f8d25348953ce0992ef8e89756bd`
(PR #2803), runtime `1014002`, the #2637 devnet hybrid-verifier fast path, and runtime
`1014003` at `9035450361681a69c6c02c9c53e47351999ef6f8` (PR #3096). Candidate runtime
`1014004` (1.14.4, PR #3006) has source compatibility coverage for uploader-funded
qualification. Candidate runtime `1014005` (1.14.5) has source compatibility coverage for the
preactivation FCU name replacement. Candidate runtimes `1014007` (1.14.7, integer accounting,
transaction version 2) through `1014011` (funding-time FCU economic snapshots) have source
compatibility coverage for the preactivation FCU accounting, resale and activation changes.
Source coverage does not qualify physical latency or deployment.
Other versions require separate qualification.
`FlopClient` checks on connect and before each HTTP RPC because HTTP has no
runtime-upgrade subscription. `SubstrateClient` checks on connect, before metadata
refresh/signing, and again before submission, including for cached signed extrinsics.
An unsupported runtime raises `FLOPError` with code `RUNTIME_INCOMPATIBLE` and the
qualified versions. Upgrade with `uv pip install --upgrade flop-sdk` to a release
that supports the chain's runtime; allowlist changes require compatibility validation.

## Installation

```bash
pip install flop-sdk
```

### Development Dependencies

```bash
pip install flop-sdk[dev]
```

## Quick Start

```python
import asyncio
import os
from flop_sdk import FlopClient, SubstrateClient, generate_htlc_secrets


async def main():
    # Connect to FLOP node
    async with FlopClient() as client:
        # Check node health
        health = await client.health()
        print(f"Node healthy: {not health.is_syncing}")

        # Generate HTLC secrets
        pre_image, hash_lock = generate_htlc_secrets()

        signer = SubstrateClient()
        htlc_id, tx_hash = signer.create_htlc(
            agent="my-agent",
            task={
                "model": "llama-3-8b",
                "prompt": "Hello",
                "tee_requirements": os.environ["FLOP_HTLC_TEE_REQUIREMENTS"],
            },
            hash_lock=hash_lock,
            reward_amount=5.0,
            timeout_blocks=60,
        )
        signer.close()
        print(f"HTLC submitted: {htlc_id}, tx: {tx_hash}")

        # Query the submitted HTLC
        status = await client.check_htlc_status(hash_lock)
        print(f"HTLC status: {status.status if status else 'not found'}")

        # Wait for settlement after a signed submission
        status = await client.wait_for_settlement(hash_lock, timeout_seconds=30)

        if status:
            print(f"Settled by: {status.miner}")
            print(f"G_n used: {status.gn_used}")
        else:
            print("Timeout - funds refunded")


asyncio.run(main())
```

## Substrate Client (Signed Transactions)

For on-chain operations requiring signed transactions, use `SubstrateClient`. It signs locally and submits through `author_submitExtrinsic`; the HTTP `FlopClient` only queries HTLC state.

```python
import os
from flop_sdk import SubstrateClient, SubstrateOptions, create_agent_wallet, generate_htlc_secrets

# Initialize with account seed
client = SubstrateClient(SubstrateOptions(rpc_url="http://127.0.0.1:16111", seed="alice"))

print(f"Account: {client.address}")
print(f"Balance: {client.get_balance()} FLOP")

# Create HTLC on-chain
pre_image, hash_lock = generate_htlc_secrets()
htlc_id, tx_hash = client.create_htlc(
    agent="my-agent",
    task={
        "model": "llama-3-8b",
        "prompt": "Hello",
        "tee_requirements": os.environ["FLOP_HTLC_TEE_REQUIREMENTS"],
    },
    hash_lock=hash_lock,
    reward_amount=5.0,
    timeout_blocks=60,
)

print(f"HTLC: {htlc_id}, TX: {tx_hash}")

# Redeem HTLC (miner side)
tee_quote = {"version": "1.0", "gn_weight": 1450, "attestation": "deadbeef"}
tx_hash = client.redeem_htlc(htlc_id, pre_image, tee_quote)
print(f"Redeemed: {tx_hash}")

client.close()
```

## Agent Wallet & Session Keys

The unpublished 0.3.0 release candidate targets the runtime's `FlopSessionKeys`
pallet. Both `create_session` and `create_session_onchain` require explicit
keyword-only `per_tx_limit` and `daily_cap` in addition to the lifetime
`spending_cap`. This is a breaking correction; the published 0.2.1 helpers do
not provide this corrected contract. No financial limits are invented for old
calls. Creation returns a transaction hash, and duration is measured in blocks.

Use existing owner and delegate `SubstrateClient` instances on the same approved
network. The delegate signs execution; the wrapper reads its live session nonce
and propagates query, dispatch and circuit-breaker failures. A failed query is
not an absent session and must not trigger replacement credentials or retry.
Reading a nonce does not reserve it or serialize concurrent submissions; a stale
nonce fails at dispatch and the helper propagates that failure without retry.
Decoded session fields require a real boolean and bounded integer wire values.

```python
from flop_sdk import create_session, execute_via_session

# owner_client and delegate_client are existing authenticated SubstrateClient instances.
session_tx = create_session(
    owner_client,
    delegate_client.address,
    spending_cap=10.0,
    per_tx_limit=2.0,
    daily_cap=5.0,
    duration_blocks=3600,
    allowed_pallets=["Balances"],
)
inner_call = delegate_client.substrate.compose_call(
    call_module="Balances",
    call_function="transfer_keep_alive",
    call_params={"dest": recipient_address, "value": 10**18},
)
tx_hash = execute_via_session(delegate_client, owner_client.address, inner_call, 1.0)
```

## API Reference

### FlopClient (Async HTTP)

High-level async HTTP client for RPC queries.

```python
async with FlopClient(
    options=FlopClientOptions(
        rpc_url="http://127.0.0.1:16111/rpc",
    )
) as client:
    # Health check
    health = await client.health()

    # Get balance
    balance = await client.get_balance("flop1qyq...")

    # Check HTLC status
    status = await client.check_htlc_status(hash_lock)

    # Wait for settlement
    settled = await client.wait_for_settlement(hash_lock, timeout_seconds=30)

    # Get account info
    info = await client.get_account_info("flop1qyq...")

    # HTLC writes require SubstrateClient (below)
```

### SubstrateClient (Signed Transactions)

Low-level Substrate client for on-chain operations.

```python
client = SubstrateClient(
    rpc_url="http://127.0.0.1:16111",
    seed="alice",  # development alias; also accepts a mnemonic, 32-byte hex, or //Alice
)

# Account info
print(f"Address: {client.address}")
print(f"Balance: {client.get_balance()} FLOP")

# HTLC operations
htlc_id, tx_hash = client.create_htlc(...)
tx_hash = client.redeem_htlc(htlc_id, pre_image, tee_quote)
status = client.check_htlc_status(hash_lock)

client.close()
```

### Wallet Functions

```python
# Create agent wallet
wallet = create_agent_wallet(client, agent_id, daily_limit=100.0)

# Fund wallet
fund_agent_wallet(client, wallet.address, amount)

# Transfer between wallets
agent_transfer(client, from_wallet, to_address, amount)

# Withdraw to owner
owner_withdraw(client, wallet.address, amount)

# Session management
session_tx = create_session(
    owner_client, delegate_client.address, 10.0, per_tx_limit=2.0, daily_cap=5.0
)
revoke_session(owner_client, delegate_client.address)
execute_via_session(delegate_client, owner_client.address, inner_call, 1.0)
```

### Utilities

```python
from flop_sdk import (
    generate_htlc_secrets,
    sign_message,
    format_flop,
    flop_to_raw,
    raw_to_flop,
    format_address,
    validate_address,
    generate_agent_id,
)

# Generate HTLC secrets
pre_image, hash_lock = generate_htlc_secrets()

# Format amounts
print(format_flop(5.0))  # "5.00 FLOP"
print(flop_to_raw(5.0))  # 5000000000000000000
print(raw_to_flop(5000000000000000000))  # 5.0

# Address utilities
print(format_address("flop1qyq...z9a"))  # "flop1qyq...z9a"
print(validate_address("flop1qyq..."))  # True

# Generate agent ID
agent_id = generate_agent_id("trader")  # "trader_1234567890_abcd1234"
```

## Types

```python
from flop_sdk import (
    HtlcStatus,
    ComputeTask,
    HtlcInfo,
    CreateHtlcResult,
    HealthResponse,
    AccountInfo,
    WalletInfo,
    SessionInfo,
)

# HTLC status enum
status = HtlcStatus.CREATED  # or SETTLED, REFUNDED

# Compute task
task = ComputeTask(
    model="llama-3-8b",
    prompt="Hello, world!",
    max_tokens=100,
    temperature=0.7,
)

# HTLC info
htlc = HtlcInfo(
    htlc_id="htlc_abc123",
    hash_lock="0x...",
    status=HtlcStatus.SETTLED,
    agent="my-agent",
    reward_amount=5.0,
    timeout_block=160,
    miner="flop1qyq...",
    gn_used=1450.75,
)
```

## Error Handling

```python
import os
from flop_sdk import SubstrateClient, generate_htlc_secrets

client = SubstrateClient()
_, hash_lock = generate_htlc_secrets()
try:
    htlc_id, tx_hash = client.create_htlc(
        agent="my-agent",
        task={
            "model": "llama-3-8b",
            "prompt": "Hello",
            "tee_requirements": os.environ["FLOP_HTLC_TEE_REQUIREMENTS"],
        },
        hash_lock=hash_lock,
        reward_amount=5.0,
    )
except Exception as e:
    print(f"Signed extrinsic submission failed: {e}")
finally:
    client.close()
```

## Complete Example

```python
import asyncio
from flop_sdk import (
    FlopClient,
    SubstrateClient,
    create_agent_wallet,
    fund_agent_wallet,
    generate_htlc_secrets,
)


async def main():
    # Async client for queries
    async with FlopClient() as rpc_client:
        # Check node health
        health = await rpc_client.health()
        print(f"✓ Node synced: {not health.is_syncing}")

    # Substrate client for transactions
    client = SubstrateClient(rpc_url="http://127.0.0.1:16111", seed="alice")

    print(f"✓ Connected: {client.address}")
    print(f"✓ Balance: {client.get_balance()} FLOP")

    # Create agent wallet
    wallet = create_agent_wallet(
        client,
        agent_id="trading-agent-01",
        daily_limit=100.0,
    )
    print(f"✓ Wallet created: {wallet.address}")

    # Fund wallet
    fund_agent_wallet(client, wallet.address, 50.0)
    print(f"✓ Wallet funded")

    # Generate HTLC secrets
    pre_image, hash_lock = generate_htlc_secrets()

    # Create HTLC on-chain
    htlc_id, tx_hash = client.create_htlc(
        agent="trading-agent-01",
        task={"model": "llama-3-8b", "prompt": "Analyze BTC trend"},
        hash_lock=hash_lock,
        reward_amount=5.0,
        timeout_blocks=60,
    )
    print(f"✓ HTLC created: {htlc_id}")
    print(f"✓ Transaction: {tx_hash}")

    # Check status
    status = client.check_htlc_status(hash_lock)
    print(f"✓ Status: {status['status']}")

    client.close()


if __name__ == "__main__":
    asyncio.run(main())
```

## Development

```bash
# Install development dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Run tests with coverage
pytest --cov=src/

# Format code
black src/ tests/
ruff check --fix src/ tests/

# Type checking
mypy src/

# Run all checks
ruff format --check . && ruff check . && ty check src examples && pytest
```

## Requirements

- Python 3.10+
- aiohttp>=3.9.0 (async HTTP)
- substrate-interface>=1.0.0 (Substrate RPC)
- pydantic>=2.0.0 (data validation)

## NVIDIA GPU Operators

For miners operating NVIDIA GPUs to earn rewards, see the complete guide:

- **[NVIDIA GPU Operator SDK Guide](../../docs/NVIDIA_GPU_OPERATOR_SDK.md)** - Complete SDK guide for NVIDIA H100/H200/Blackwell with TEE attestation
- [Miner Guide](../../docs/MINER_GUIDE.md) - General mining setup and workflows

Quick example for GPU operators:

```python
from flop_sdk import SubstrateClient
from flop_sdk.tee import NvidiaTeeBridge, generate_tee_quote

# Initialize miner client
client = SubstrateClient(rpc_url="http://127.0.0.1:16111", seed="//Miner")
tee_bridge = NvidiaTeeBridge(simulator_mode=True)  # Set False for production

# Monitor for HTLCs
htlc = client.check_htlc_status(hash_lock)
if htlc and htlc.status == "CREATED":
    # Execute inference on NVIDIA GPU
    result = execute_on_gpu(htlc.task)  # Your GPU execution logic
    
    # Generate TEE quote
    tee_quote = generate_tee_quote(
        miner_address=client.address,
        htlc_hash_lock=htlc.hash_lock,
        model_hash=htlc.task["model"],
        gn_weight=result.gn_weight,
        tee_type="NVIDIA_HOPPER_CC",  # or "NVIDIA_RUBIN_CC", "CPU_WRAPPED_TEE"
    )
    
    # Redeem HTLC with TEE quote
    tx_hash = client.redeem_htlc(
        htlc_id=htlc.htlc_id,
        pre_image=pre_image,
        tee_quote=tee_quote,
    )
    print(f"✓ HTLC redeemed: {tx_hash}")
    
    # Submit PoUI proof batch (optional, for additional rewards)
    proofs = generate_stark_proofs(result)
    task_hash = generate_task_hash(htlc)
    tx_hash = client.submit_poui(proofs, result.gn_weight, task_hash)
    print(f"✓ PoUI proof submitted: {tx_hash}")
```

### TEE Quote Format

```python
tee_quote = {
    "version": "1.0",
    "miner_address": "flop1...",
    "task_reference": {
        "htlc_hash_lock": "0x...",
        "model_hash": "sha256:...",
        "task_timestamp": 1234567890,
    },
    "compute_output": {
        "gn_weight": 1450.0,  # G_n weight (BFLOPs)
        "execution_time_ms": 435,
        "encrypted_result": "0x...",
    },
    "attestation": {
        "tee_type": "NVIDIA_HOPPER_CC",
        "hardware_pubkey": "0x...",
        "quote_hex": "0x...",  # Raw TEE quote
        "signature": "0x...",  # Miner signature
    },
}
```

### Supported TEE Types

| TEE Type | Hardware | Production Ready |
|----------|----------|------------------|
| `NVIDIA_HOPPER_CC` | H100, H200 | ✅ Yes |
| `NVIDIA_RUBIN_CC` | B100, B200 | ✅ Yes |
| `CPU_WRAPPED_TEE` | RTX 4090+ + AMD SEV/Intel TDX | ⚠️ Testnet only |

### TEE Verification

The `NvidiaTeeBridge` validates TEE quotes with:

- **Timestamp freshness:** Quotes must be < 60 seconds old
- **Signature verification:** Validates miner signature
- **Replay protection:** Tracks task hashes to prevent double-spending
- **Hardware verification:** Checks hardware keys against registry (production only)

```python
from flop_sdk.tee import NvidiaTeeBridge, PouiPayload

bridge = NvidiaTeeBridge(simulator_mode=False)

# Register known hardware keys (production)
bridge.register_hardware_key("0x...")

# Verify TEE quote
payload: PouiPayload = parse_tee_quote(quote_json)
result = bridge.verify(payload)

if result.valid:
    print(f"✓ TEE verified: {result.gn_weight} G_n")
else:
    print(f"✗ Verification failed: {result.error}")
```

For complete setup instructions, hardware requirements, and production deployment guide:

- **[NVIDIA GPU Operator SDK Guide](../../docs/NVIDIA_GPU_OPERATOR_SDK.md)** - Complete API reference, dstack integration, production workflows
- **[NVIDIA GPU Operator Guide](../../docs/tutorials/NVIDIA_GPU_OPERATOR_GUIDE.md)** - Hardware setup, TEE configuration, monitoring

## License

Apache-2.0 © FLOP Network

## Links

- [FLOP Network Documentation](https://github.com/flop-labs/flop-core)
- [RPC API Reference](../../docs/RPC_API.md)
- [TypeScript SDK](../typescript/README.md)

## Signing accounts

`SubstrateOptions.seed` accepts a valid mnemonic, a 32-byte hexadecimal seed (with
or without `0x`), an explicit development URI such as `//Alice` or `//Miner`,
or one of the development aliases `alice`, `bob`, `charlie`, `dave`, `eve`,
and `ferdie`. Development accounts are publicly known and must not hold real funds.
Invalid inputs are rejected before connecting. Upgrading from an older SDK can
change the address produced for a mnemonic or hex seed; verify the intended address
before signing and reconcile any account previously derived from the wrong input.

## Reporting issues

Report SDK bugs through the [public issue forms](https://github.com/flop-labs/network/issues/new/choose). Never include seeds or private keys.
