hodlodds 0.2.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.
hodlodds-0.2.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 HodlOdds
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,177 @@
1
+ Metadata-Version: 2.4
2
+ Name: hodlodds
3
+ Version: 0.2.0
4
+ Summary: Python client for HodlOdds: pay-per-answer crash odds for Solana memecoins over x402 (USDC on Solana or Base).
5
+ License: MIT
6
+ Project-URL: Homepage, https://hodlodds.com
7
+ Project-URL: Source, https://github.com/hodlodds/hodlodds-sdk
8
+ Keywords: x402,solana,base,usdc,memecoin,risk,pump.fun
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Requires-Python: >=3.10
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Requires-Dist: httpx<1,>=0.27
16
+ Requires-Dist: x402[evm,svm]==2.25.0
17
+ Dynamic: license-file
18
+
19
+ # hodlodds — Python client
20
+
21
+ Pay-per-answer **crash odds for Solana memecoins**, paid per request with
22
+ [x402](https://www.x402.org) (USDC on Solana or Base). No accounts, no API keys.
23
+
24
+ > **Status: pre-launch.** The API at `https://api.hodlodds.com` is not yet open for
25
+ > payments. Its model is being evaluated against a pre-registered forward test.
26
+ > A limited paid beta opens only if it passes. Until then this client is published
27
+ > so you can read the code and test the payment flow on **Solana devnet** or **Base Sepolia**.
28
+
29
+ ## What it answers
30
+
31
+ > What are the odds that this token's price falls 90% or more within the next 60 minutes?
32
+
33
+ A crash is a completed one-minute close, priced in SOL, at least 90% below the
34
+ reference price within the next 60 minutes. Coverage: SOL-quoted pump.fun
35
+ graduates. Every answer carries a confidence level (high / medium / low) based on
36
+ how well past predictions in that probability range matched reality.
37
+
38
+ | Route | Price (planned) | Notes |
39
+ |---|---|---|
40
+ | `GET /v1/status` | free | Feed state (`live` / `stale` / `down`), age, incidents, uptime |
41
+ | `GET /v1/meta` | free | Definition, prices, payment details, model card |
42
+ | `GET /v1/risk/{mint}` | $0.01 | Fresh odds for one token |
43
+ | `GET /v1/board?limit=N` | $0.005 per coin delivered | Ranked, filtered board of 10–500 covered tokens; pay only for coins returned, empty is free |
44
+ | `GET /v1/risk/{mint}/last` | $0.002 | Last known odds during a feed interruption, at most 30 minutes old, labelled stale, confidence lowered one level |
45
+
46
+ You only pay for fresh, covered answers. "Not covered", "feed interrupted" and
47
+ "too old" answers are free, and this client never signs for them.
48
+
49
+ ## Install
50
+
51
+ ```sh
52
+ pip install "git+https://github.com/hodlodds/hodlodds-sdk"
53
+ ```
54
+
55
+ Python 3.10+. Dependencies: `httpx` and the official `x402[svm,evm]==2.25.0` SDK (pinned).
56
+
57
+ ## Use
58
+
59
+ Command line:
60
+
61
+ ```sh
62
+ hodlodds status
63
+ hodlodds risk <MINT> --keypair ~/.config/hodlodds/wallet.json --pay-to <RECIPIENT> --network devnet
64
+ hodlodds risk <MINT> --keypair ~/.config/hodlodds/base-wallet.json --pay-to <BASE_RECIPIENT> --network base-sepolia
65
+ hodlodds board --limit 100 --sort safest --max-risk 0.05 --min-liquidity 50 --max-price 0.5 \
66
+ --keypair ... --pay-to ... --network devnet
67
+ ```
68
+
69
+ Python:
70
+
71
+ ```python
72
+ from hodlodds import HodlOdds, HodlOddsError
73
+
74
+ with HodlOdds("https://api.hodlodds.com", keypair="~/.config/hodlodds/wallet.json",
75
+ network="devnet", pay_to="<RECIPIENT>", max_price_usdc="0.01") as client:
76
+ print(client.status()["state"])
77
+ try:
78
+ answer = client.risk("<MINT>")
79
+ row = answer.data["row"]
80
+ print(row["p_crash_60m"], row["confidence"]["level"], answer.payment["explorer"])
81
+ except HodlOddsError as e:
82
+ print(e, e.status, e.body) # free refusals land here; e.payment is set if a payment may have happened
83
+ ```
84
+
85
+ `<RECIPIENT>` is the payment address published in `GET /v1/meta` (and in this
86
+ README at launch). Pin it in your code: the client refuses any offer that pays
87
+ someone else.
88
+
89
+ Networks: `devnet` and `solana` (mainnet; `mainnet` is an alias) take a Solana
90
+ JSON key file; `base-sepolia` and `base` take an EVM key file
91
+ (`{"private_key": "0x..."}`, mode 0600). Prices are the same on both chains, and the
92
+ API offers both; the client signs only on the network you chose.
93
+
94
+ ```python
95
+ base = HodlOdds("https://api.hodlodds.com", keypair="~/.config/hodlodds/base-wallet.json",
96
+ network="base", pay_to="<BASE_RECIPIENT>", max_price_usdc="0.01")
97
+ ```
98
+
99
+ Board options: `limit` 10–500 (default 50); `sort` = `safest` (default), `riskiest`,
100
+ `liquidity`, `newest`, `active`; filters `max_risk`, `min_risk`, `min_liquidity_sol`,
101
+ `min_age_min`, `max_age_min`, `min_trades_5`, `min_confidence` (`high`/`medium`/`low`).
102
+ The total price is `0.005 × coins returned`; pass a `max_price` at least that high
103
+ (the client caps a single board payment at 2.5 USDC).
104
+
105
+ ```python
106
+ board = client.board(limit=100, sort="safest", max_risk=0.05, min_liquidity_sol=50, max_price_usdc="0.5")
107
+ for row in board.data["rows"]:
108
+ print(row["mint"], row["p_crash_60m"], row["confidence"]["level"])
109
+ ```
110
+
111
+ ### If an answer is lost after you paid
112
+
113
+ The paid request waits up to 90 seconds (`paid_timeout`, 30–600): verification and
114
+ on-chain settlement usually take one to three seconds. If the connection still ends
115
+ after the payment settled, nothing is lost:
116
+
117
+ - The server keeps that payment redeemable **once** for 24 hours.
118
+ - In Python, the error carries it: `client.redeem(error.payment)` re-sends the same
119
+ authorization with `HodlOdds-Redeem: 1`. It never signs a new payment and never
120
+ settles a second time.
121
+ - The CLI saves it to `~/.config/hodlodds/pending/<id>.json` (mode 0600) and prints
122
+ the path; run `hodlodds redeem <file>` after about two minutes.
123
+ - While the server is still confirming the payment on-chain, a redeem answers
124
+ `409` with `Retry-After`; if the payment never settled, it says so (nothing was
125
+ charged).
126
+
127
+ Environment variables for the CLI: `HODLODDS_BASE_URL`, `HODLODDS_NETWORK`,
128
+ `HODLODDS_KEYPAIR`, `HODLODDS_PAY_TO`, `HODLODDS_MAX_PRICE`.
129
+ Exit status: `0` success, `1` refusal/API/transport failure, `2` invalid usage.
130
+
131
+ ## Safety rules built into the client
132
+
133
+ - A payment is signed only after the 402 offer passes every check: x402 v2, the
134
+ chosen network, exact USDC, authorization flow, the pinned `payTo`, a valid
135
+ facilitator fee payer distinct from you, a bounded timeout, and a price at or
136
+ below your limit (default 0.01 USDC, hard cap 1 USDC; exact atomic arithmetic).
137
+ - Payments are **never retried automatically**. If anything goes wrong after an
138
+ authorization was sent, the error says so and carries the details
139
+ (`HodlOddsError.payment`) so you can reconcile against your wallet history or
140
+ redeem the answer once (see above).
141
+ - The key file must be a regular, non-symlink file with mode 0600. It is read
142
+ locally and never printed or sent; only the SDK-signed USDC transfer
143
+ authorization leaves your machine. Use a dedicated low-balance wallet.
144
+ - HTTPS only (plain HTTP only for a local test server). No redirects, no
145
+ environment proxies, bounded headers and bodies.
146
+ - Mainnets require an explicit `network="solana"` (or `"base"`) and a pinned
147
+ `pay_to`; the CLI requires `--network solana|base --pay-to ...` on the command line.
148
+
149
+ ## Test wallet (devnet / Base Sepolia)
150
+
151
+ ```sh
152
+ hodlodds-wallet new ~/.config/hodlodds/my-devnet.json # prints the public address only
153
+ hodlodds-wallet new --network base-sepolia ~/.config/hodlodds/base-sepolia.json
154
+ ```
155
+
156
+ Fund it with test USDC at https://faucet.circle.com (network: Solana Devnet or Base Sepolia).
157
+ Never put real funds in a test wallet.
158
+
159
+ ## Tests
160
+
161
+ ```sh
162
+ python -m unittest discover -s tests -v
163
+ ```
164
+
165
+ The tests run offline with a fake server and a fake SDK seam; with the pinned SDK
166
+ installed, one more test builds a real signature with all RPC calls mocked.
167
+
168
+ ## Disclaimer
169
+
170
+ Odds, not guarantees. Not financial advice. Low odds do not mean a token is
171
+ safe; collapses can happen without warning. The operator also runs an
172
+ independent trading system that may trade tokens HodlOdds scores; it never
173
+ receives customer requests or purchases, and nobody can pay to change a score.
174
+
175
+ ## License
176
+
177
+ MIT
@@ -0,0 +1,159 @@
1
+ # hodlodds — Python client
2
+
3
+ Pay-per-answer **crash odds for Solana memecoins**, paid per request with
4
+ [x402](https://www.x402.org) (USDC on Solana or Base). No accounts, no API keys.
5
+
6
+ > **Status: pre-launch.** The API at `https://api.hodlodds.com` is not yet open for
7
+ > payments. Its model is being evaluated against a pre-registered forward test.
8
+ > A limited paid beta opens only if it passes. Until then this client is published
9
+ > so you can read the code and test the payment flow on **Solana devnet** or **Base Sepolia**.
10
+
11
+ ## What it answers
12
+
13
+ > What are the odds that this token's price falls 90% or more within the next 60 minutes?
14
+
15
+ A crash is a completed one-minute close, priced in SOL, at least 90% below the
16
+ reference price within the next 60 minutes. Coverage: SOL-quoted pump.fun
17
+ graduates. Every answer carries a confidence level (high / medium / low) based on
18
+ how well past predictions in that probability range matched reality.
19
+
20
+ | Route | Price (planned) | Notes |
21
+ |---|---|---|
22
+ | `GET /v1/status` | free | Feed state (`live` / `stale` / `down`), age, incidents, uptime |
23
+ | `GET /v1/meta` | free | Definition, prices, payment details, model card |
24
+ | `GET /v1/risk/{mint}` | $0.01 | Fresh odds for one token |
25
+ | `GET /v1/board?limit=N` | $0.005 per coin delivered | Ranked, filtered board of 10–500 covered tokens; pay only for coins returned, empty is free |
26
+ | `GET /v1/risk/{mint}/last` | $0.002 | Last known odds during a feed interruption, at most 30 minutes old, labelled stale, confidence lowered one level |
27
+
28
+ You only pay for fresh, covered answers. "Not covered", "feed interrupted" and
29
+ "too old" answers are free, and this client never signs for them.
30
+
31
+ ## Install
32
+
33
+ ```sh
34
+ pip install "git+https://github.com/hodlodds/hodlodds-sdk"
35
+ ```
36
+
37
+ Python 3.10+. Dependencies: `httpx` and the official `x402[svm,evm]==2.25.0` SDK (pinned).
38
+
39
+ ## Use
40
+
41
+ Command line:
42
+
43
+ ```sh
44
+ hodlodds status
45
+ hodlodds risk <MINT> --keypair ~/.config/hodlodds/wallet.json --pay-to <RECIPIENT> --network devnet
46
+ hodlodds risk <MINT> --keypair ~/.config/hodlodds/base-wallet.json --pay-to <BASE_RECIPIENT> --network base-sepolia
47
+ hodlodds board --limit 100 --sort safest --max-risk 0.05 --min-liquidity 50 --max-price 0.5 \
48
+ --keypair ... --pay-to ... --network devnet
49
+ ```
50
+
51
+ Python:
52
+
53
+ ```python
54
+ from hodlodds import HodlOdds, HodlOddsError
55
+
56
+ with HodlOdds("https://api.hodlodds.com", keypair="~/.config/hodlodds/wallet.json",
57
+ network="devnet", pay_to="<RECIPIENT>", max_price_usdc="0.01") as client:
58
+ print(client.status()["state"])
59
+ try:
60
+ answer = client.risk("<MINT>")
61
+ row = answer.data["row"]
62
+ print(row["p_crash_60m"], row["confidence"]["level"], answer.payment["explorer"])
63
+ except HodlOddsError as e:
64
+ print(e, e.status, e.body) # free refusals land here; e.payment is set if a payment may have happened
65
+ ```
66
+
67
+ `<RECIPIENT>` is the payment address published in `GET /v1/meta` (and in this
68
+ README at launch). Pin it in your code: the client refuses any offer that pays
69
+ someone else.
70
+
71
+ Networks: `devnet` and `solana` (mainnet; `mainnet` is an alias) take a Solana
72
+ JSON key file; `base-sepolia` and `base` take an EVM key file
73
+ (`{"private_key": "0x..."}`, mode 0600). Prices are the same on both chains, and the
74
+ API offers both; the client signs only on the network you chose.
75
+
76
+ ```python
77
+ base = HodlOdds("https://api.hodlodds.com", keypair="~/.config/hodlodds/base-wallet.json",
78
+ network="base", pay_to="<BASE_RECIPIENT>", max_price_usdc="0.01")
79
+ ```
80
+
81
+ Board options: `limit` 10–500 (default 50); `sort` = `safest` (default), `riskiest`,
82
+ `liquidity`, `newest`, `active`; filters `max_risk`, `min_risk`, `min_liquidity_sol`,
83
+ `min_age_min`, `max_age_min`, `min_trades_5`, `min_confidence` (`high`/`medium`/`low`).
84
+ The total price is `0.005 × coins returned`; pass a `max_price` at least that high
85
+ (the client caps a single board payment at 2.5 USDC).
86
+
87
+ ```python
88
+ board = client.board(limit=100, sort="safest", max_risk=0.05, min_liquidity_sol=50, max_price_usdc="0.5")
89
+ for row in board.data["rows"]:
90
+ print(row["mint"], row["p_crash_60m"], row["confidence"]["level"])
91
+ ```
92
+
93
+ ### If an answer is lost after you paid
94
+
95
+ The paid request waits up to 90 seconds (`paid_timeout`, 30–600): verification and
96
+ on-chain settlement usually take one to three seconds. If the connection still ends
97
+ after the payment settled, nothing is lost:
98
+
99
+ - The server keeps that payment redeemable **once** for 24 hours.
100
+ - In Python, the error carries it: `client.redeem(error.payment)` re-sends the same
101
+ authorization with `HodlOdds-Redeem: 1`. It never signs a new payment and never
102
+ settles a second time.
103
+ - The CLI saves it to `~/.config/hodlodds/pending/<id>.json` (mode 0600) and prints
104
+ the path; run `hodlodds redeem <file>` after about two minutes.
105
+ - While the server is still confirming the payment on-chain, a redeem answers
106
+ `409` with `Retry-After`; if the payment never settled, it says so (nothing was
107
+ charged).
108
+
109
+ Environment variables for the CLI: `HODLODDS_BASE_URL`, `HODLODDS_NETWORK`,
110
+ `HODLODDS_KEYPAIR`, `HODLODDS_PAY_TO`, `HODLODDS_MAX_PRICE`.
111
+ Exit status: `0` success, `1` refusal/API/transport failure, `2` invalid usage.
112
+
113
+ ## Safety rules built into the client
114
+
115
+ - A payment is signed only after the 402 offer passes every check: x402 v2, the
116
+ chosen network, exact USDC, authorization flow, the pinned `payTo`, a valid
117
+ facilitator fee payer distinct from you, a bounded timeout, and a price at or
118
+ below your limit (default 0.01 USDC, hard cap 1 USDC; exact atomic arithmetic).
119
+ - Payments are **never retried automatically**. If anything goes wrong after an
120
+ authorization was sent, the error says so and carries the details
121
+ (`HodlOddsError.payment`) so you can reconcile against your wallet history or
122
+ redeem the answer once (see above).
123
+ - The key file must be a regular, non-symlink file with mode 0600. It is read
124
+ locally and never printed or sent; only the SDK-signed USDC transfer
125
+ authorization leaves your machine. Use a dedicated low-balance wallet.
126
+ - HTTPS only (plain HTTP only for a local test server). No redirects, no
127
+ environment proxies, bounded headers and bodies.
128
+ - Mainnets require an explicit `network="solana"` (or `"base"`) and a pinned
129
+ `pay_to`; the CLI requires `--network solana|base --pay-to ...` on the command line.
130
+
131
+ ## Test wallet (devnet / Base Sepolia)
132
+
133
+ ```sh
134
+ hodlodds-wallet new ~/.config/hodlodds/my-devnet.json # prints the public address only
135
+ hodlodds-wallet new --network base-sepolia ~/.config/hodlodds/base-sepolia.json
136
+ ```
137
+
138
+ Fund it with test USDC at https://faucet.circle.com (network: Solana Devnet or Base Sepolia).
139
+ Never put real funds in a test wallet.
140
+
141
+ ## Tests
142
+
143
+ ```sh
144
+ python -m unittest discover -s tests -v
145
+ ```
146
+
147
+ The tests run offline with a fake server and a fake SDK seam; with the pinned SDK
148
+ installed, one more test builds a real signature with all RPC calls mocked.
149
+
150
+ ## Disclaimer
151
+
152
+ Odds, not guarantees. Not financial advice. Low odds do not mean a token is
153
+ safe; collapses can happen without warning. The operator also runs an
154
+ independent trading system that may trade tokens HodlOdds scores; it never
155
+ receives customer requests or purchases, and nobody can pay to change a score.
156
+
157
+ ## License
158
+
159
+ MIT
@@ -0,0 +1,5 @@
1
+ """HodlOdds: pay-per-answer crash odds for Solana memecoins over x402 (USDC on Solana or Base)."""
2
+ from .client import NETWORKS, Answer, HodlOdds, HodlOddsError, PendingPayment, load_pending, save_pending
3
+
4
+ __all__ = ["HodlOdds", "HodlOddsError", "Answer", "NETWORKS", "PendingPayment", "save_pending", "load_pending"]
5
+ __version__ = "0.2.0"
@@ -0,0 +1,5 @@
1
+ import sys
2
+
3
+ from .client import main
4
+
5
+ sys.exit(main())