payperbyte-sdk 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,167 @@
1
+ Metadata-Version: 2.4
2
+ Name: payperbyte-sdk
3
+ Version: 0.1.0
4
+ Summary: Python SDK for PayPerByte — verified, provenance-first data for AI agents. No token; direct-allowance USDC settlement on Arbitrum.
5
+ Requires-Python: >=3.10
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: web3>=6.0
8
+ Requires-Dist: aiohttp>=3.9
9
+ Provides-Extra: x402
10
+ Requires-Dist: x402[evm,requests]==2.12.0; extra == "x402"
11
+ Requires-Dist: eth-account==0.13.7; extra == "x402"
12
+ Requires-Dist: web3==7.16.0; extra == "x402"
13
+ Requires-Dist: requests==2.34.2; extra == "x402"
14
+ Dynamic: description
15
+ Dynamic: description-content-type
16
+ Dynamic: provides-extra
17
+ Dynamic: requires-dist
18
+ Dynamic: requires-python
19
+ Dynamic: summary
20
+
21
+ # payperbyte-sdk — PayPerByte Python SDK
22
+
23
+ Python SDK for PayPerByte (the BYTE Library data layer) — the verified, provenance-first data layer for AI agents. Discover first-party feeds, subscribe, stream payloads, and verify every payload against its on-chain EIP-712 attestation. No token; direct-allowance USDC settlement on Arbitrum.
24
+
25
+ ## Installation
26
+
27
+ ```bash
28
+ pip install payperbyte-sdk
29
+ ```
30
+
31
+ Keyless x402 pay-per-call support (the `GatewayClient`) needs the optional x402 stack:
32
+
33
+ ```bash
34
+ pip install "payperbyte-sdk[x402]"
35
+ ```
36
+
37
+ ## Quick Start
38
+
39
+ ```python
40
+ from eth_account import Account
41
+ from byte import (
42
+ Publisher,
43
+ Subscriber,
44
+ Mercat,
45
+ GatewayClient,
46
+ verify_payload,
47
+ HashMismatchError,
48
+ ARBITRUM_SEPOLIA,
49
+ )
50
+
51
+ # 1. Discover — browse first-party feeds via the keyless x402 gateway catalog.
52
+ gw = GatewayClient(account=Account.from_key("0x...")) # a wallet, NOT an API key
53
+ catalog = gw.discover() # GET /feeds
54
+ for feed in catalog["feeds"]:
55
+ print(feed["id"], feed["price"], feed["provenance"])
56
+
57
+ # Or discover publishers via the indexer (Mercat).
58
+ mercat = Mercat(ARBITRUM_SEPOLIA.indexer_url)
59
+ publishers = await mercat.search(topic="eth-price")
60
+
61
+ # 2. Subscribe — register in the social registry and approve DataStream to pull
62
+ # per-message fees directly. No escrow, no deposit: your USDC stays in your
63
+ # wallet until a message is actually settled. allowance_usdc is a 6-decimal
64
+ # spend ceiling sized to cover the fees you expect to pay.
65
+ subscriber = Subscriber("0x...private_key...", ARBITRUM_SEPOLIA)
66
+ subscriber.subscribe(publishers[0]["address"], allowance_usdc=10.0)
67
+
68
+ # 3. Stream — receive payload events as the publisher broadcasts.
69
+ async for msg in subscriber.stream():
70
+ payload = fetch_from_my_archive(msg["payload_hash"])
71
+
72
+ # 4. Verify — keccak256(canonical bytes) vs the on-chain attested hash.
73
+ # Throws HashMismatchError if the bytes don't match what was attested.
74
+ try:
75
+ verify_payload(payload, msg["payload_hash"])
76
+ except HashMismatchError:
77
+ continue # do NOT consume mismatched bytes
78
+ consume(payload)
79
+ ```
80
+
81
+ ## Keyless x402 (pay-per-call)
82
+
83
+ The `GatewayClient` mirrors the BYTE x402 gateway. It is **keyless**: a wallet signs the
84
+ payment (EIP-3009 `transferWithAuthorization`, gasless — the facilitator broadcasts and
85
+ pays gas). There is **no API key** anywhere.
86
+
87
+ ```python
88
+ from eth_account import Account
89
+ from byte import GatewayClient
90
+
91
+ gw = GatewayClient(account=Account.from_key("0x...")) # defaults to https://x402.payperbyte.io
92
+ result = gw.fetch_feed("crypto-top100") # GET -> 402 -> sign USDC -> retry -> data
93
+ print(result["data"])
94
+ print(result["settlement"]) # {"success", "payer", "transaction"} (on-chain settle tx) or None
95
+ print(result["disclaimerCategory"])
96
+ ```
97
+
98
+ POST oracle feeds (`fact-oracle`, `evidence-pack`, `usc-statute`) take a JSON body:
99
+
100
+ ```python
101
+ result = gw.fetch_feed("fact-oracle", body={
102
+ "question": "What is the current US federal funds rate?",
103
+ "subscriber_address": "0x...", # REQUIRED — must already be registered on-chain with a DataStream USDC allowance
104
+ })
105
+ ```
106
+
107
+ > **Two distinct USDC flows.** The on-chain settlement leg (Subscriber.subscribe →
108
+ > register in DataRegistry + approve DataStream as a direct USDC spender) is
109
+ > independent of the x402 gateway payment (GatewayClient → EIP-3009 at fetch time).
110
+ > For `fact-oracle`, the subscriber must already be registered with a DataStream
111
+ > allowance *before* the x402 POST succeeds.
112
+
113
+ ## Features
114
+
115
+ - **Feed discovery** — browse the x402 gateway catalog (`GatewayClient.discover`) or search publishers via the indexer (`Mercat`)
116
+ - **Subscription management** — subscribe, unsubscribe, check status (direct-allowance USDC settlement; the SDK approves DataStream as a direct spender)
117
+ - **Data streaming** — publish and receive payloads via DataStream
118
+ - **Payload verification** — every payload carries an EIP-712 PayloadAttestation; verify `keccak256(canonical bytes)` against the on-chain hash before acting on the data
119
+ - **Keyless x402** — pay-per-call feed access with a wallet (EIP-3009), no API key
120
+ - **Provenance** — read publisher status, subscriber/message counts, and revenue from the on-chain registry
121
+
122
+ ## Network Support
123
+
124
+ | Network | Chain ID | Status |
125
+ |---------|----------|--------|
126
+ | Arbitrum Sepolia | 421614 | Live (testnet) |
127
+ | Arbitrum One | 42161 | Planned (mainnet, audit-gated) |
128
+
129
+ ## PayPerByte contracts
130
+
131
+ PayPerByte is a lean 3-contract core. No token; all settlement is in external USDC. Subscriptions are a direct ERC-20 allowance — there is no escrow contract. A subscriber registers in DataRegistry and grants DataStream a USDC allowance; DataStream pulls the exact per-message fee with `transferFrom` at publish time, so funds stay in the subscriber's wallet until a message is settled. Each payload carries an EIP-712 `PayloadAttestation` so subscribers can confirm exactly what they received and from whom.
132
+
133
+ | Contract | Role |
134
+ |----------|------|
135
+ | DataRegistry | Publisher registration; subscriber social registry (`subscribe` / `unsubscribe` / `isSubscribed`) |
136
+ | DataStream | Per-message payload settlement; pulls fees via direct USDC allowance |
137
+ | SchemaRegistry | Feed schema + methodology references |
138
+
139
+ Contract and settlement-USDC addresses are resolved per-network by the SDK (`ARBITRUM_SEPOLIA`, `LOCAL_ANVIL`).
140
+
141
+ ## Canonical payload bytes
142
+
143
+ Publish-side and verify-side hashing both use the same canonical form (`byte.canonical`):
144
+ UTF-8 of JSON with recursively lexicographically-sorted object keys and no insignificant
145
+ whitespace. This guarantees `keccak256` parity across the publish/verify boundary **and**
146
+ between the Python and TypeScript SDKs. Keep payload values to strings, bools, and integers
147
+ that round-trip identically across languages (or pre-stringify floats); full RFC-8785/JCS
148
+ float/large-integer normalization is out of scope.
149
+
150
+ ## Modules
151
+
152
+ - `ByteClient` — low-level client holding the web3 contract instances (used by `Publisher`/`Subscriber`)
153
+ - `Publisher` — register a feed, publish data, sign EIP-712 PayloadAttestations
154
+ - `Subscriber` — subscribe (register in DataRegistry + approve DataStream as a direct USDC spender), receive payloads, stream events
155
+ - `GatewayClient` — keyless x402 pay-per-call client (a wallet, not an API key)
156
+ - `verify_payload` / `verify_event_payload` / `fetch_and_verify` — subscriber-side payload verification against on-chain attestations
157
+ - `Mercat` — feed search and discovery (connects to the indexer API)
158
+
159
+ ## Related
160
+
161
+ - [byte-mcp-server](https://github.com/0rkz/byte-mcp-server) — MCP server for AI agent integration
162
+ - [byte-x402-gateway](https://github.com/0rkz/byte-x402-gateway) — keyless x402 payment gateway (a wallet, not an API key)
163
+ - [byte-discovery-api](https://github.com/0rkz/byte-discovery-api) — agent discovery endpoint
164
+
165
+ ## License
166
+
167
+ MIT
@@ -0,0 +1,147 @@
1
+ # payperbyte-sdk — PayPerByte Python SDK
2
+
3
+ Python SDK for PayPerByte (the BYTE Library data layer) — the verified, provenance-first data layer for AI agents. Discover first-party feeds, subscribe, stream payloads, and verify every payload against its on-chain EIP-712 attestation. No token; direct-allowance USDC settlement on Arbitrum.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install payperbyte-sdk
9
+ ```
10
+
11
+ Keyless x402 pay-per-call support (the `GatewayClient`) needs the optional x402 stack:
12
+
13
+ ```bash
14
+ pip install "payperbyte-sdk[x402]"
15
+ ```
16
+
17
+ ## Quick Start
18
+
19
+ ```python
20
+ from eth_account import Account
21
+ from byte import (
22
+ Publisher,
23
+ Subscriber,
24
+ Mercat,
25
+ GatewayClient,
26
+ verify_payload,
27
+ HashMismatchError,
28
+ ARBITRUM_SEPOLIA,
29
+ )
30
+
31
+ # 1. Discover — browse first-party feeds via the keyless x402 gateway catalog.
32
+ gw = GatewayClient(account=Account.from_key("0x...")) # a wallet, NOT an API key
33
+ catalog = gw.discover() # GET /feeds
34
+ for feed in catalog["feeds"]:
35
+ print(feed["id"], feed["price"], feed["provenance"])
36
+
37
+ # Or discover publishers via the indexer (Mercat).
38
+ mercat = Mercat(ARBITRUM_SEPOLIA.indexer_url)
39
+ publishers = await mercat.search(topic="eth-price")
40
+
41
+ # 2. Subscribe — register in the social registry and approve DataStream to pull
42
+ # per-message fees directly. No escrow, no deposit: your USDC stays in your
43
+ # wallet until a message is actually settled. allowance_usdc is a 6-decimal
44
+ # spend ceiling sized to cover the fees you expect to pay.
45
+ subscriber = Subscriber("0x...private_key...", ARBITRUM_SEPOLIA)
46
+ subscriber.subscribe(publishers[0]["address"], allowance_usdc=10.0)
47
+
48
+ # 3. Stream — receive payload events as the publisher broadcasts.
49
+ async for msg in subscriber.stream():
50
+ payload = fetch_from_my_archive(msg["payload_hash"])
51
+
52
+ # 4. Verify — keccak256(canonical bytes) vs the on-chain attested hash.
53
+ # Throws HashMismatchError if the bytes don't match what was attested.
54
+ try:
55
+ verify_payload(payload, msg["payload_hash"])
56
+ except HashMismatchError:
57
+ continue # do NOT consume mismatched bytes
58
+ consume(payload)
59
+ ```
60
+
61
+ ## Keyless x402 (pay-per-call)
62
+
63
+ The `GatewayClient` mirrors the BYTE x402 gateway. It is **keyless**: a wallet signs the
64
+ payment (EIP-3009 `transferWithAuthorization`, gasless — the facilitator broadcasts and
65
+ pays gas). There is **no API key** anywhere.
66
+
67
+ ```python
68
+ from eth_account import Account
69
+ from byte import GatewayClient
70
+
71
+ gw = GatewayClient(account=Account.from_key("0x...")) # defaults to https://x402.payperbyte.io
72
+ result = gw.fetch_feed("crypto-top100") # GET -> 402 -> sign USDC -> retry -> data
73
+ print(result["data"])
74
+ print(result["settlement"]) # {"success", "payer", "transaction"} (on-chain settle tx) or None
75
+ print(result["disclaimerCategory"])
76
+ ```
77
+
78
+ POST oracle feeds (`fact-oracle`, `evidence-pack`, `usc-statute`) take a JSON body:
79
+
80
+ ```python
81
+ result = gw.fetch_feed("fact-oracle", body={
82
+ "question": "What is the current US federal funds rate?",
83
+ "subscriber_address": "0x...", # REQUIRED — must already be registered on-chain with a DataStream USDC allowance
84
+ })
85
+ ```
86
+
87
+ > **Two distinct USDC flows.** The on-chain settlement leg (Subscriber.subscribe →
88
+ > register in DataRegistry + approve DataStream as a direct USDC spender) is
89
+ > independent of the x402 gateway payment (GatewayClient → EIP-3009 at fetch time).
90
+ > For `fact-oracle`, the subscriber must already be registered with a DataStream
91
+ > allowance *before* the x402 POST succeeds.
92
+
93
+ ## Features
94
+
95
+ - **Feed discovery** — browse the x402 gateway catalog (`GatewayClient.discover`) or search publishers via the indexer (`Mercat`)
96
+ - **Subscription management** — subscribe, unsubscribe, check status (direct-allowance USDC settlement; the SDK approves DataStream as a direct spender)
97
+ - **Data streaming** — publish and receive payloads via DataStream
98
+ - **Payload verification** — every payload carries an EIP-712 PayloadAttestation; verify `keccak256(canonical bytes)` against the on-chain hash before acting on the data
99
+ - **Keyless x402** — pay-per-call feed access with a wallet (EIP-3009), no API key
100
+ - **Provenance** — read publisher status, subscriber/message counts, and revenue from the on-chain registry
101
+
102
+ ## Network Support
103
+
104
+ | Network | Chain ID | Status |
105
+ |---------|----------|--------|
106
+ | Arbitrum Sepolia | 421614 | Live (testnet) |
107
+ | Arbitrum One | 42161 | Planned (mainnet, audit-gated) |
108
+
109
+ ## PayPerByte contracts
110
+
111
+ PayPerByte is a lean 3-contract core. No token; all settlement is in external USDC. Subscriptions are a direct ERC-20 allowance — there is no escrow contract. A subscriber registers in DataRegistry and grants DataStream a USDC allowance; DataStream pulls the exact per-message fee with `transferFrom` at publish time, so funds stay in the subscriber's wallet until a message is settled. Each payload carries an EIP-712 `PayloadAttestation` so subscribers can confirm exactly what they received and from whom.
112
+
113
+ | Contract | Role |
114
+ |----------|------|
115
+ | DataRegistry | Publisher registration; subscriber social registry (`subscribe` / `unsubscribe` / `isSubscribed`) |
116
+ | DataStream | Per-message payload settlement; pulls fees via direct USDC allowance |
117
+ | SchemaRegistry | Feed schema + methodology references |
118
+
119
+ Contract and settlement-USDC addresses are resolved per-network by the SDK (`ARBITRUM_SEPOLIA`, `LOCAL_ANVIL`).
120
+
121
+ ## Canonical payload bytes
122
+
123
+ Publish-side and verify-side hashing both use the same canonical form (`byte.canonical`):
124
+ UTF-8 of JSON with recursively lexicographically-sorted object keys and no insignificant
125
+ whitespace. This guarantees `keccak256` parity across the publish/verify boundary **and**
126
+ between the Python and TypeScript SDKs. Keep payload values to strings, bools, and integers
127
+ that round-trip identically across languages (or pre-stringify floats); full RFC-8785/JCS
128
+ float/large-integer normalization is out of scope.
129
+
130
+ ## Modules
131
+
132
+ - `ByteClient` — low-level client holding the web3 contract instances (used by `Publisher`/`Subscriber`)
133
+ - `Publisher` — register a feed, publish data, sign EIP-712 PayloadAttestations
134
+ - `Subscriber` — subscribe (register in DataRegistry + approve DataStream as a direct USDC spender), receive payloads, stream events
135
+ - `GatewayClient` — keyless x402 pay-per-call client (a wallet, not an API key)
136
+ - `verify_payload` / `verify_event_payload` / `fetch_and_verify` — subscriber-side payload verification against on-chain attestations
137
+ - `Mercat` — feed search and discovery (connects to the indexer API)
138
+
139
+ ## Related
140
+
141
+ - [byte-mcp-server](https://github.com/0rkz/byte-mcp-server) — MCP server for AI agent integration
142
+ - [byte-x402-gateway](https://github.com/0rkz/byte-x402-gateway) — keyless x402 payment gateway (a wallet, not an API key)
143
+ - [byte-discovery-api](https://github.com/0rkz/byte-discovery-api) — agent discovery endpoint
144
+
145
+ ## License
146
+
147
+ MIT
@@ -0,0 +1,53 @@
1
+ """
2
+ payperbyte-sdk — Python SDK for PayPerByte (the BYTE Library data layer).
3
+
4
+ Verified, provenance-first data for AI agents. No token; settlement is in
5
+ external USDC on Arbitrum. Three on-chain contracts: DataRegistry (publisher /
6
+ subscriber social registry), SchemaRegistry (feed schemas), and DataStream
7
+ (per-message settlement). Subscribers approve DataStream as a direct USDC
8
+ spender — there is no escrow contract. Keyless x402 payments (a wallet, not an
9
+ API key) for pay-per-call feed access via the gateway.
10
+
11
+ Usage:
12
+ from byte import (
13
+ Publisher, Subscriber, GatewayClient,
14
+ verify_payload, HashMismatchError, ARBITRUM_SEPOLIA,
15
+ )
16
+
17
+ # Publisher: register a schema + publisher (no token stake), then publish.
18
+ publisher = Publisher(private_key, ARBITRUM_SEPOLIA)
19
+ publisher.register("eth-price", schema)
20
+ publisher.publish(subscriber_addr, {"signal": "short"})
21
+
22
+ # Subscriber: register in the social registry + approve DataStream to pull
23
+ # per-message fees directly (no escrow / no deposit), then stream payloads.
24
+ subscriber = Subscriber(private_key, ARBITRUM_SEPOLIA)
25
+ subscriber.subscribe(publisher_addr, allowance_usdc=10.0)
26
+ async for msg in subscriber.stream():
27
+ payload = fetch_from_archive(msg["payload_hash"])
28
+ try:
29
+ verify_payload(payload, msg["payload_hash"]) # keccak256 vs attested hash
30
+ except HashMismatchError:
31
+ continue # do NOT consume mismatched bytes
32
+ consume(payload)
33
+
34
+ # Gateway: keyless x402 pay-per-call (a wallet signs EIP-3009; no API key).
35
+ from eth_account import Account
36
+ gw = GatewayClient(account=Account.from_key(private_key))
37
+ result = gw.fetch_feed("crypto-top100")
38
+ """
39
+
40
+ from byte.publisher import Publisher
41
+ from byte.subscriber import Subscriber
42
+ from byte.mercat import Mercat
43
+ from byte.client import ByteClient
44
+ from byte.gateway import GatewayClient
45
+ from byte.networks import ARBITRUM_SEPOLIA, ARBITRUM_ONE, LOCAL_ANVIL
46
+ from byte.verify import (
47
+ verify_payload, verify_event_payload, fetch_and_verify, HashMismatchError,
48
+ )
49
+
50
+ __all__ = ["Publisher", "Subscriber", "Mercat", "ByteClient", "GatewayClient",
51
+ "ARBITRUM_SEPOLIA", "ARBITRUM_ONE", "LOCAL_ANVIL",
52
+ "verify_payload", "verify_event_payload", "fetch_and_verify",
53
+ "HashMismatchError"]