Metadata-Version: 2.5
Name: decoded-shredstream
Version: 0.1.0
Summary: Official Python client for Decoded ShredStream by ShredStream.com — pre-execution Solana transactions decoded from shreds, over UDP push or gRPC.
Project-URL: Homepage, https://shredstream.com
Project-URL: Documentation, https://shredstream.com/docs
Project-URL: Repository, https://github.com/shredstream/decoded-shredstream-python
Author-email: "ShredStream.com" <dev@shredstream.com>
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: grpc,low-latency,market-data,shreds,solana,trading,transactions,udp
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Office/Business :: Financial :: Investment
Classifier: Topic :: System :: Networking
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: base58>=2.1
Requires-Dist: grpcio>=1.62
Requires-Dist: protobuf>=4.25
Provides-Extra: fast
Requires-Dist: based58>=0.1.3; extra == 'fast'
Provides-Extra: solana
Requires-Dist: solders>=0.21; extra == 'solana'
Description-Content-Type: text/markdown

# Decoded ShredStream — Python client

Python client for the Decoded ShredStream of ShredStream.com: pre-execution
Solana transactions, decoded from shreds — the serialized
`VersionedTransaction`, its signatures and its slot, delivered over gRPC or
UDP push the moment they propagate.

> **Before execution** — transactions carry no status, logs, balance changes
> or inner instructions, and some will fail on-chain. Use a post-execution
> source to confirm.

The client is synchronous and blocking: iterating it returns one transaction
at a time on the calling thread.

```sh
pip install decoded-shredstream
```

```python
from decoded_shredstream import Client, Filter, GrpcConfig

with Client.grpc(GrpcConfig(endpoint=endpoint, token=token,
                            filters={"all": Filter()})) as client:
    for update in client:
        print(update.slot, update.signature)
```

> **Requirements** — Python 3.10 or later, and a Decoded ShredStream
> subscription on ShredStream.com. Extras: `solana` for `parse()`, `fast` for
> a Rust base58.

With the extras:

```sh
pip install "decoded-shredstream[solana,fast]"
```

## 🔑 Access

Decoded ShredStream is a subscription product, available from ShredStream.com.
One subscription covers both transports, and you can move from one to the
other whenever you need to.

- **gRPC** — you receive an endpoint and an access token. Use the endpoint
  exactly as issued.
- **UDP** — you register your server's IP and port; datagrams are pushed to it.

### Choosing a transport

Both carry the same data; they differ on what the protocol guarantees.

| | gRPC | UDP |
|---|---|---|
| Latency | higher | **lowest** |
| Delivery | ordered, retransmitted | best-effort, no retransmission |
| Server-side filters | **yes** | no — you receive the full stream |

## ⚡ Quickstart — gRPC

```python
from decoded_shredstream import Client, Filter, GrpcConfig

with Client.grpc(
    GrpcConfig(
        endpoint="your-endpoint.shredstream.com:PORT",
        token="YOUR_TOKEN",
        filters={"all": Filter()},
    )
) as client:
    for update in client:
        print(update.slot, len(update.data), list(update.filters))
```

`Client.grpc` connects and subscribes before returning.

## 📡 Quickstart — UDP

```python
from decoded_shredstream import Client, UdpConfig

with Client.udp(UdpConfig(port=8002)) as client:
    print("listening on", client.local_addr)
    for update in client:
        print(update.slot, len(update.data), update.signature.hex())
```

`8002` is only an example: bind whichever port you registered in your account.

## 🔍 Transaction parsing

Every transaction exposes `update.data`, in the standard Solana wire format,
and its signatures without any decoding:

```python
import base58

update.signature                              # first signature, raw 64 bytes
update.signatures                             # every signature
base58.b58encode(update.signature).decode()   # to display one
```

Everything else is available through `parse()`, which returns a
`solders.transaction.VersionedTransaction` and requires the `solana` extra:

```python
for update in client:
    message = update.parse().message
    keys = message.account_keys
    programs = {str(keys[ix.program_id_index]) for ix in message.instructions}
    print(update.slot, keys[0], len(message.instructions), sorted(programs))
```

Without the `solana` extra, `parse()` raises `ImportError`.

## 🎯 Filters

Filters exist on the gRPC transport only. They are evaluated by the server;
the client never filters locally. UDP delivers the full stream.

A subscription carries a **map of named filters**. Each response is tagged
with the names that matched it, exposed as `update.filters`.

```python
from decoded_shredstream import Client, Filter, GrpcConfig

client = Client.grpc(
    GrpcConfig(
        endpoint=endpoint,
        token=token,
        filters={
            "watched": Filter(include=[account]),
            "everything": Filter(),
        },
    )
)
```

### Semantics

A `Filter` holds three lists of base58 account keys, matched against the
accounts a transaction touches. The three conditions are ANDed, and an empty
list adds no constraint — `Filter()` matches every transaction.

| List | Matches when the transaction |
|---|---|
| `include` | touches **at least one** of the accounts |
| `exclude` | touches **none** of the accounts |
| `required` | touches **all** of the accounts |

Matching uses the account keys carried in the transaction, signers included.
Addresses resolved through an Address Lookup Table cannot be filtered on. A
transaction matching several filters is delivered once.

### Replacing filters mid-stream

`update_filters` replaces the whole map atomically. The server applies it
without a reconnect and without a gap in the data, and the new map is the one
any later reconnection re-sends.

```python
client.update_filters({"watched": Filter(include=[account])})
```

## 🔄 Errors & reconnection

Recoverable interruptions never reach you: the client reconnects on its own and
re-sends the current filter map. Only a refused token, a session closed by the
server and a rejected filter map end the stream, raised once by the iteration:

```python
from decoded_shredstream import StreamError

try:
    for update in client:
        ...
except StreamError as e:
    print("stream ended:", e)
```

Every exception, the backoff policy and the telemetry notices are in
[docs/errors.md](docs/errors.md).

## 📖 Documentation

This README is what you need to receive transactions. The rest lives beside it:

| Document | Contents |
|---|---|
| [docs/api.md](docs/api.md) | Every type and method: clients, configuration, filters, updates, UDP codec, performance notes and counters |
| [docs/errors.md](docs/errors.md) | Error types, reconnection policy, telemetry notices |

## 💡 Examples

The `examples/` directory contains runnable programs; each reads its
configuration from the environment.

| File | Shows |
|---|---|
| `udp_quickstart.py` | binding the registered port and printing transactions |
| `grpc_quickstart.py` | connecting, subscribing to everything, printing transactions |
| `grpc_filters.py` | named filters and replacing the map mid-stream |
| `parse_transaction.py` | full parsing with `solders` |
| `raw_bytes_pipeline.py` | forwarding `update.data` without parsing |
| `low_latency.py` | the shape of a minimal consumption loop |

```sh
DECODED_SHREDSTREAM_UDP_PORT=8002 python examples/udp_quickstart.py
DECODED_SHREDSTREAM_ENDPOINT=your-endpoint.shredstream.com:PORT DECODED_SHREDSTREAM_TOKEN=... python examples/grpc_quickstart.py
DECODED_SHREDSTREAM_ENDPOINT=your-endpoint.shredstream.com:PORT DECODED_SHREDSTREAM_TOKEN=... ACCOUNT=<base58> python examples/grpc_filters.py
```

## ⚖️ License

Apache-2.0. See `LICENSE`.
