Metadata-Version: 2.4
Name: prime-sdk-python
Version: 0.5.0
Summary: A self-contained Python SDK for interacting with Dragonchain nodes.
Project-URL: Homepage, https://git.dragonchain.com/dragonchain/prime-sdk-python
Project-URL: Repository, https://git.dragonchain.com/dragonchain/prime-sdk-python
Author: Dragonchain
License: Apache-2.0
License-File: LICENSE
Keywords: blockchain,dragonchain,prime,sdk
Requires-Python: >=3.9
Requires-Dist: pyyaml>=5.4
Requires-Dist: requests>=2.25
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == 'dev'
Description-Content-Type: text/markdown

# Dragonchain Python SDK

A self-contained Python SDK for interacting with Dragonchain (Prime) nodes.

## Installation

```bash
pip install prime-sdk-python
```

Or, from a local checkout:

```bash
pip install -e .
```

Requires Python 3.9+.

## Usage

```python
from prime_sdk import DragonchainSDK, TransactionCreateRequest

# Initialize the SDK
client = DragonchainSDK(
    "your-public-id",
    "your-auth-key-id",
    "your-auth-key",
    "https://your-dragonchain-endpoint.com",
)

# Check system health (raises DragonchainAPIError if unhealthy)
client.system.health()

# Get system status
status = client.system.status()
print(f"Chain ID: {status.id}, Level: {status.level}")

# Create a transaction
resp = client.transaction.create(
    TransactionCreateRequest(
        txn_type="my-transaction-type",
        payload='{"message": "Hello Dragonchain"}',
        tag="example-tag",
    )
)
print(f"Created transaction: {resp.transaction_id}")
```

## Transaction Modes

`create` and `create_bulk` return **immediately** with the assigned transaction
ID(s). They do **not** wait for block inclusion. Blocks are assembled
asynchronously on a ~5-second cycle.

### Fire and Forget

Most use cases only need the transaction ID. No polling required.

```python
resp = client.transaction.create(
    TransactionCreateRequest(
        txn_type="my-transaction-type",
        payload='{"message": "Hello Dragonchain"}',
    )
)
print("Transaction ID:", resp.transaction_id)
# Done — no need to wait for a block.
```

### Wait for Block

If you need the block ID (e.g. for interchain verification or Daria), poll
`get` until `header.block_id` is populated.

```python
import time

resp = client.transaction.create(
    TransactionCreateRequest(
        txn_type="my-transaction-type",
        payload='{"message": "Hello Dragonchain"}',
    )
)

while True:
    txn = client.transaction.get(resp.transaction_id)
    if txn.header.block_id:
        print("Block ID:", txn.header.block_id)
        break
    time.sleep(2)
```

## Loading credentials from a file

The SDK can read chain credentials from a YAML file:

```yaml
default: my-public-id
chains:
  - name: my-chain
    publicId: my-public-id
    authKeyId: my-auth-key-id
    authKey: my-auth-key
    endpoint: https://chains.dragonchain.com
```

```python
from prime_sdk import DragonchainSDK
from prime_sdk.credentials import load_config

cfg = load_config("~/.dragonchain/credentials.yaml")
chain = cfg.get_default_chain()

client = DragonchainSDK(
    chain.public_id, chain.auth_key_id, chain.auth_key, chain.endpoint
)
```

## Available Endpoints

### System
- `system.health()` — Check system health
- `system.status()` — Get system status

### Transaction
- `transaction.create(req)` — Create a new transaction
- `transaction.create_bulk(req)` — Create multiple transactions
- `transaction.get(transaction_id)` — Get transaction by ID
- `transaction.list()` — List all transactions

### Transaction Type
- `transaction_type.create(req)` — Create a new transaction type
- `transaction_type.get(txn_type)` — Get transaction type by name
- `transaction_type.list()` — List all transaction types
- `transaction_type.delete(txn_type)` — Delete a transaction type

### Smart Contract
- `contract.create(req)` — Create a new smart contract
- `contract.get(contract_id)` — Get smart contract by ID
- `contract.list()` — List all smart contracts
- `contract.update(contract_id, req)` — Update a smart contract
- `contract.upload(contract_id, filepath)` — Upload smart contract code
- `contract.delete(contract_id)` — Delete a smart contract

### Block
- `block.get(block_id)` — Get block by ID

### Proof Measure (public, unauthenticated)
- `proof_measure.get_security(network, since=None)` — A network's accumulated security since `since` (unix seconds), as a raw measure + USD valuation. `network` = `"BTC"` or `"ETH"`.
- `proof_measure.report(req)` — Per-transaction "securedBy" report over interchain anchors.
- `proof_measure.health()` — Service liveness.

## Interchain trace

`transaction.get_interchain` / `block.get_interchain` trace a prime block to the
public-chain anchors covering it. By default they return the **first anchor per
chain** (anchor proofs are chained, so the earliest per chain is the meaningful
one):

```python
# Default: first anchor per chain (ETH, BTC, …)
trace = client.block.get_interchain("42")

# Up to 3 anchors per chain
trace = client.block.get_interchain("42", per_chain=3)

# All anchors, only the ETH-mainnet chain ("1"); "0" = BTC
trace = client.block.get_interchain("42", per_chain=0, chains=["1"])
```

## Proof Measure

`proof-measure` is a separate, **public, unauthenticated** Dragonchain service
(the measured-immutability / "securedBy" metric) at
`https://proof-measure.dragonchain.com`. It needs no credentials. Decimal fields
are returned as strings (full precision) and timestamps as int unix seconds.

```python
import time
from prime_sdk import ProofMeasureClient, ReportRequest, ReportAnchorInput

# Via the main SDK (targets the default public endpoint):
sec = client.proof_measure.get_security("BTC", int(time.time()) - 3600)
print(f"BTC secured by {sec.value_usd_formatted} ({sec.raw.value} {sec.raw.unit})")

# Or standalone — no prime credentials needed:
pm = ProofMeasureClient()  # or ProofMeasureClient("http://localhost:9481")

report = pm.report(
    ReportRequest(
        transaction_id="tx-123",
        prime_id="my-prime",
        block_id="42",
        anchors=[
            ReportAnchorInput(tx_hash="0x...", timestamp=anchor_unix, network="BTC"),
            ReportAnchorInput(tx_hash="0x...", timestamp=anchor_unix, network="ETH"),
        ],
    )
)
print(f"Secured by {report.total_value_usd_formatted} across {len(report.anchors)} anchors")

pm.health()
```

## Authentication

The SDK uses HMAC-SHA256 authentication. You need to provide:
- `public_id` — Your Dragonchain public ID
- `auth_key_id` — Your authentication key ID
- `auth_key` — Your authentication key
- `base_url` — The base URL of your Dragonchain node (e.g. "https://chains.dragonchain.com")

## Error handling

Any non-2xx response raises `prime_sdk.DragonchainAPIError`, which exposes
`.status_code` and `.body`:

```python
from prime_sdk import DragonchainAPIError

try:
    client.transaction.get("nonexistent-id")
except DragonchainAPIError as e:
    print(e.status_code, e.body)
```

## License

Apache-2.0
