orblivion 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.
Files changed (36) hide show
  1. orblivion-0.1.0/LICENSE +21 -0
  2. orblivion-0.1.0/MANIFEST.in +4 -0
  3. orblivion-0.1.0/PKG-INFO +235 -0
  4. orblivion-0.1.0/README.md +217 -0
  5. orblivion-0.1.0/orblivion.egg-info/PKG-INFO +235 -0
  6. orblivion-0.1.0/orblivion.egg-info/SOURCES.txt +34 -0
  7. orblivion-0.1.0/orblivion.egg-info/dependency_links.txt +1 -0
  8. orblivion-0.1.0/orblivion.egg-info/requires.txt +2 -0
  9. orblivion-0.1.0/orblivion.egg-info/top_level.txt +1 -0
  10. orblivion-0.1.0/pit_sdk/__init__.py +70 -0
  11. orblivion-0.1.0/pit_sdk/_util.py +100 -0
  12. orblivion-0.1.0/pit_sdk/account.py +428 -0
  13. orblivion-0.1.0/pit_sdk/auth.py +70 -0
  14. orblivion-0.1.0/pit_sdk/client.py +2322 -0
  15. orblivion-0.1.0/pit_sdk/constants.py +257 -0
  16. orblivion-0.1.0/pit_sdk/curve_session.py +517 -0
  17. orblivion-0.1.0/pit_sdk/delegation.py +239 -0
  18. orblivion-0.1.0/pit_sdk/eip712.py +129 -0
  19. orblivion-0.1.0/pit_sdk/errors.py +139 -0
  20. orblivion-0.1.0/pit_sdk/execution.py +172 -0
  21. orblivion-0.1.0/pit_sdk/fast.py +1204 -0
  22. orblivion-0.1.0/pit_sdk/hosted.py +410 -0
  23. orblivion-0.1.0/pit_sdk/http.py +360 -0
  24. orblivion-0.1.0/pit_sdk/league.py +588 -0
  25. orblivion-0.1.0/pit_sdk/money.py +109 -0
  26. orblivion-0.1.0/pit_sdk/onchain.py +326 -0
  27. orblivion-0.1.0/pit_sdk/plans.py +455 -0
  28. orblivion-0.1.0/pit_sdk/pricing.py +260 -0
  29. orblivion-0.1.0/pit_sdk/risks.py +332 -0
  30. orblivion-0.1.0/pit_sdk/router.py +454 -0
  31. orblivion-0.1.0/pit_sdk/rpc.py +217 -0
  32. orblivion-0.1.0/pit_sdk/signer.py +179 -0
  33. orblivion-0.1.0/pit_sdk/tokens.py +235 -0
  34. orblivion-0.1.0/pit_sdk/verify.py +1849 -0
  35. orblivion-0.1.0/pyproject.toml +33 -0
  36. orblivion-0.1.0/setup.cfg +4 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Orblivion
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,4 @@
1
+ # The sdist carries the package source, README.md, LICENSE and pyproject.toml: no tests, fixtures or examples.
2
+ prune tests
3
+ prune examples
4
+ global-exclude *.py[cod]
@@ -0,0 +1,235 @@
1
+ Metadata-Version: 2.4
2
+ Name: orblivion
3
+ Version: 0.1.0
4
+ Summary: Trade on Robinhood Chain through Orblivion from an Orbio agent: every transaction is decoded and checked locally before the agent's key signs it.
5
+ License-Expression: MIT
6
+ Project-URL: Documentation, https://orblivion.com/docs/
7
+ Keywords: orblivion,orbio,robinhood-chain,trading,agents,uniswap,sdk
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Operating System :: OS Independent
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Topic :: Office/Business :: Financial :: Investment
12
+ Requires-Python: >=3.10
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Requires-Dist: eth-account>=0.13.6
16
+ Requires-Dist: eth-abi>=5
17
+ Dynamic: license-file
18
+
19
+ # orblivion
20
+
21
+ Trade on Robinhood Chain (chain 4663) through Orblivion, the trading layer for Orbio agents, from Python. Orblivion
22
+ finds the route, builds the transaction and simulates it. Your agent's own key signs it, and Orblivion's relay sends it.
23
+
24
+ **Nothing the server returns is signed until this SDK has decoded and checked it locally**, and every mined transaction
25
+ is checked again against what was signed. The decoder and the checks are this package's own: the same rules, rule names
26
+ and error codes as the TypeScript SDK (`@orblivion/sdk`), proven against the same recorded answers.
27
+
28
+ Python 3.10 or later. Depends on `eth-account` and `eth-abi` only; HTTP uses the standard library.
29
+
30
+ ## Install
31
+
32
+ ```sh
33
+ pip install orblivion
34
+ ```
35
+
36
+ ## Quickstart
37
+
38
+ ```python
39
+ import os
40
+ from eth_account import Account
41
+ from orblivion import OrblivionClient
42
+
43
+ client = OrblivionClient(account=Account.from_key(os.environ["AGENT_KEY"]),
44
+ max_notional_usd=25) # the client refuses anything bigger, whatever the server says
45
+
46
+ client.sign_in() # optional: the first call signs in for you
47
+ quote = client.quote(sell="ETH", buy="USDG", amount_usd=10)
48
+ plan = client.plan(sell="ETH", buy="USDG", amount_usd=10) # every check, nothing signed
49
+ dry = client.trade(sell="ETH", buy="USDG", amount_usd=10, dry_run=True)
50
+ sent = client.trade(sell="ETH", buy="USDG", amount_usd=10) # checked, signed, sent, checked again
51
+ print(sent.tx_hash, sent.amount_out, sent.min_out, sent.fee)
52
+ ```
53
+
54
+ The client talks to `https://api.orblivion.com` unless told otherwise: pass another server first, or leave it out
55
+ (`OrblivionClient(account=...)`) and set `ORBLIVION_API_URL`. Plain `http` is accepted only for `127.0.0.1`,
56
+ `localhost` and `::1`; anything else must be `https`.
57
+
58
+ `headers={...}` adds headers to every request to the Orblivion API (never to the RPC or the sequencer); their values
59
+ are never shown in an error or a repr.
60
+
61
+ ## Signing in
62
+
63
+ `sign_in()` asks the server for an EIP-4361 (Sign-In with Ethereum) message, checks it names this server's host, chain
64
+ 4663, this wallet and a short expiry, signs it, and receives an API key bound to that wallet, kept in memory only.
65
+ Pass `api_key=` to reuse one; the client checks it is bound to its wallet first.
66
+
67
+ ## Quote, plan, trade
68
+
69
+ | Call | What it does |
70
+ |---|---|
71
+ | `quote(sell=, buy=, amount_usd= \| amount_in=, slippage_bps=None, shield=False)` | The server's best route and what it discloses. Read-only; the server's word. |
72
+ | `plan(sell=, buy=, amount_usd= \| amount_in=, ...)` | The trade's plan, checked exactly as `trade` checks it, with **nothing signed**. A sale of an ERC-20 token whose swap is built only around a Permit2 signature stops after the permit's checks (`complete=False`). |
73
+ | `trade(sell=, buy=, amount_usd= \| amount_in=, slippage_bps=None, approval="budget", dry_run=False, accept_risks=None, shield=False, policies=None)` | Prepare, check, sign, send through the relay, wait for the receipt, check what was mined. With `dry_run=True` it stops after signing and sends nothing. |
74
+ | `search_tokens(q, tier=None, kind=None, limit=20, shield=False)` | Search the token registry. Symbols are copied by impersonators: pick a token by its address. |
75
+ | `inspect_token(token, shield=False)` | One token as a trade would see it, checked against the SDK's own reads of the chain, refusing nothing. |
76
+ | `wallet.balances(tokens=None, who=None)` | ETH and token balances, read from the chain. |
77
+ | `approvals.status()`, `approvals.revoke()` | The wallet's Permit2 approvals; take them back. |
78
+
79
+ Core tokens are named by symbol (`ETH`, `WETH`, `USDG`, `cbBTC`, `ORBIO`, `NVDA`, `SPY`); every other token by its
80
+ contract address. Amounts are `int` in the token's smallest unit (`parse_token("1.5", "USDG")`), or `amount_usd`.
81
+
82
+ ## Fast mode
83
+
84
+ For an agent that holds its own key and trades a major pair, `fast()` cuts the path from decision to relay to one call:
85
+
86
+ ```python
87
+ fast = client.fast().start() # keeps its Chainlink marks, nonce, base fee, allowances and fee tier warm
88
+ r = fast.trade("ETH", "USDG", amount_usd=10) # or client.fast_trade(...)
89
+ print(r.path, r.tx_hash, r.timings["decision_to_accepted_ms"])
90
+ ```
91
+
92
+ The SDK builds the transaction itself on a pinned route (`FAST_ROUTES`: ETH, WETH, USDG, NVDA and SPY; never cbBTC,
93
+ which takes the normal path before anything is signed), with `min_out` from its own quote of that route (kept warm; the
94
+ tolerance at most the server's pair default), your fee tier in ETH, WETH or USDG by the fee currency rule, and the
95
+ output to your wallet; checks it with `verify_fast` (the server's own rules), signs it and sends it to
96
+ `POST /api/v1/live/fast`, which rebuilds the calldata and relays only an exact match.
97
+
98
+ - Anything stale, an ineligible pair (ORBIO, launchpad and long-tail tokens, a stock token after hours), a token you
99
+ haven't approved to Permit2 yet, a pool further under the Chainlink marks than its fee and the pair's band (75 bps
100
+ against USDG, 125 for a cross pair), or marks from your RPC more than 3% from the server's falls back to `trade()`
101
+ before anything is signed (`r.path == "fallback"`, `r.fallback_reason`); `fallback=False` raises instead.
102
+ - One `trade()` never lets two transactions land. After a refusal the server answers before relaying, the SDK asks your
103
+ own RPC about the signed transaction first: on chain, it is the result (`r.note`); its nonce taken by another
104
+ transaction, the next one takes a fresh nonce; otherwise the retry or the fallback signs at the same nonce. A refusal
105
+ that may follow a relay (`NONCE` without that proof, `IN_FLIGHT`, `SUBMIT_REJECTED`, `SEQUENCER_UNREACHABLE`, no
106
+ answer) raises with the hash. `trade(nonce=n)` signs the normal path's first transaction at `n` (and refuses when the
107
+ wallet's pending nonce isn't `n`).
108
+ - `tolerance_bps` tightens the minimum (it can't exceed the server's cap); `min_out` sets your own when it is higher.
109
+ The slippage table is pinned in the SDK (`FAST_TOLERANCES`); the server's published one can only tighten it.
110
+ - `simulate=False` skips the server's simulation of the exact signed transaction (one round trip to the node); a
111
+ transaction that would revert then costs its gas. `dry_run=True` has the server check and simulate it, and relay
112
+ nothing.
113
+ - Run the agent in US East, near the chain's sequencer: from far away its round trip dominates every trade.
114
+
115
+ ## Risks and Dossier Shield
116
+
117
+ Any token with a route trades; the server discloses what it found in `risks` (`[{code, severity, detail}]`).
118
+
119
+ - **Severe risks trade only when you accept them by name** in `accept_risks`: `HONEYPOT`, `TRANSFER_TAX`, `LOOKALIKE`,
120
+ `AMOUNT_HOOK`, `HIGH_PRICE_IMPACT`, `UNSCREENED`, `IMPERSONATOR`. The SDK never accepts a risk for you, and accepting
121
+ one loosens none of its price or minimum-output checks.
122
+ - **Dossier Shield** (`shield=True`): 10 bps on top of the trade's fee, Dossier's verdict on the token, and `policies`
123
+ (`block_impersonators`, on by default, `verified_only`, `block_risks`).
124
+
125
+ ```python
126
+ r = client.trade(sell="ETH", buy="0x…", amount_usd=5, accept_risks=["TRANSFER_TAX"])
127
+ s = client.trade(sell="ETH", buy="0x…", amount_usd=5, shield=True, policies={"verified_only": True})
128
+ s.dossier # {"verdict": "verified", "url": "…"}
129
+ s.fee_bps, s.fee_class, s.fee_tier # 60, "other", 50
130
+ ```
131
+
132
+ ## Fees
133
+
134
+ Orblivion's fee depends on the two tokens a trade swaps (fee schedule 2, pinned in `constants`):
135
+
136
+ - **Major trades**: both tokens are majors (`ETH`, `WETH`, `USDG`, `cbBTC`, `ORBIO`, or a Robinhood stock token). They
137
+ pay the wallet's volume tier: 25 bps, or 15 or 10 after enough 30-day volume.
138
+ - **Every other trade** pays exactly 50 bps.
139
+ - **Dossier Shield** adds 10 bps to either.
140
+
141
+ The SDK works out the class itself, from its own pinned majors and, for a token named by address, its own read of the
142
+ chain (the stock tokens' beacon). It never takes the server's word for the class. A plan whose `fee_class` differs is
143
+ refused (`FEE_CLASS`). The plan's `fee_bps` must be one the class and Shield mode allow, `fee_tier` must be that fee
144
+ without Shield's 10, and the calldata must pay exactly `fee_bps` (`FEE_BPS`). The SDK can't know the wallet's volume, so
145
+ it accepts any tier up to the posted 25 for a major trade. `max_fee_bps=` on the client sets a hard cap on top (`None`, the
146
+ default, leaves the schedule to bound the fee). Every quote, plan and trade result carries `fee_bps`, `fee_class` and
147
+ `fee_tier`.
148
+
149
+ The default slippage covers the trade's posted fee (40 bps plus the fee, within the pair's tolerance plus the fee).
150
+
151
+ ## Sessions and hosted agents
152
+
153
+ ```python
154
+ owner = OrblivionClient(url, wallet_account)
155
+ executor = OrblivionClient(url, hot_account)
156
+ grant = owner.sessions.grant(executor=executor.address, max_trade_usd=20, max_day_usd=60, max_trades=10, hours=12,
157
+ allow_7702=True)
158
+ executor.sessions.trade(grant.session_id, sell="ETH", buy="USDG", amount_usd=5, session=grant)
159
+ owner.sessions.revoke(grant.session_id)
160
+ ```
161
+
162
+ The owner's signed root delegation carries caveats the chain enforces (the router only, ETH per trade and per day, the
163
+ expiry, the number of trades, the executor as the only redeemer), and its salt binds the limits, the accepted risks,
164
+ Shield and the fees, so neither the server nor the executor can widen them. Every new grant is binding version 4, with
165
+ `fees` exactly the schedule's for its Shield mode (`verify.fee_terms`); the owner's SDK refuses any other version or
166
+ fees (`GRANT_LIMITS`). A session trade pays what the binding allows for the trade's own class, which the executor's SDK
167
+ and Orblivion's co-signer each read themselves. Sessions granted before version 4 keep their one fee. An executor trading without
168
+ the `Grant` can state the session's Shield mode with `session_shield=`. Otherwise its SDK holds the trade to the
169
+ schedule without Shield. `client.hosted` runs an agent's loop on the Orblivion server; a live hosted agent's executor
170
+ must carry the co-signer's attestation, which the SDK verifies before the owner signs anything.
171
+
172
+ An AI agent (`brain="orbio_llm"`) decides each tick with a model on Orbio's gateway from the owner's own strategy prompt:
173
+ `client.hosted.create(brain="orbio_llm", params=ai_params("Follow the trend; keep half in USDG.",
174
+ "anthropic/claude-haiku-5.5"), interval_s=900, pairs=["ETH-USDG"], limits=...)`: Orblivion's own Orbio credits pay
175
+ first (a fair daily share per owner wallet, cheap models, 15-minute ticks), then the owner's own Orbio balance.
176
+ `hosted.ai_options()` lists the templates, models and prices, the pool and this wallet's share; `hosted.spend(id)` its
177
+ model calls and cost. The owner's Orbio balance needs Sign in with Orbio: `hosted.ai_connect()` returns Orbio's consent
178
+ page, refused (`AI_AUTHORIZE_URL`) unless it is `https://www.orbio.so/oauth/authorize` with PKCE S256 asking for exactly
179
+ Orblivion's grant: its client id (pass `client_id=` to pin it; until Orbio registers the app, the one the server's AI
180
+ options name, which its answer must repeat), the server's own `/orbio-callback.html` as the redirect, and the scope
181
+ `openid inference`, each named once. Orblivion's redirect page finishes it. No answer carries an Orbio credential.
182
+ Sign in with Orbio isn't open on the public API yet.
183
+
184
+ ## Your account
185
+
186
+ ```python
187
+ page = client.me.trades(limit=25) # newest first; refused=True adds refused calls and unmined trades
188
+ for t in page.trades:
189
+ print(t.time, t.path, t.token_in.token, t.amount_in, t.token_out.token, t.amount_out, t.amount_out_kind, t.status)
190
+ older = client.me.trades(limit=25, before=page.next_before) if page.next_before else None
191
+
192
+ p = client.me.portfolio() # balances at independent marks; p.total_usd counts priced ones only
193
+ print(p.total_usd, p.fee_tier.tier_bps, p.fee_tier.volume_to_next_usd)
194
+ s = client.me.sessions() # active sessions and hosted agents in summary
195
+ ```
196
+
197
+ The signed-in wallet's own trades through Orblivion (agent, session, hosted or fast; `amount_out` is what the wallet
198
+ received once mined, `amount_out_kind` `"actual"`, else the plan's minimum, `"minimum"`), its balances read from the
199
+ chain and valued at the independent marks Orblivion's volume tier uses (a token without one is listed with its amount,
200
+ `priced=False`), its fee tier and the volume to the next, and its active sessions and hosted agents. Read-only: these
201
+ calls sign nothing and change nothing. The server answers for the key's own wallet only, and the SDK still checks every
202
+ answer: its shape (`ACCOUNT_SHAPE`) and that it is this client's wallet's (`ACCOUNT_WALLET`). Information only: nothing
203
+ in these answers feeds a signing decision, which always rests on the SDK's own reads. No fee figure is returned.
204
+ Token symbols and names are their deployer's word: show them as text.
205
+
206
+ ## What the SDK verifies
207
+
208
+ The same rules as the TypeScript SDK, by the same names: the router, chain, sender and transaction type; every Universal
209
+ Router command decoded and re-encoded byte for byte; the value and what is pulled; the tokens and hops; every recipient
210
+ (output only to the wallet, one fee payment only); the fee (its class, count, size, token, recipient); the minimum output against
211
+ the quote, the simulation and Chainlink prices the SDK reads itself, or its own quote of the exact route for tokens
212
+ without a feed; the size, the deadline and the gas; Permit2 permits and approvals; token records against the chain
213
+ (lookalikes of core assets refused unless accepted); and, after mining, that what was mined is what was signed.
214
+
215
+ ## Pinned values
216
+
217
+ The chain, the contracts, the core tokens, the fee schedule and the session co-signer (`constants.COSIGNER`) are pinned;
218
+ the server's config must agree (`ConfigMismatchError`). Its `fee` must publish schedule 2 exactly: `schedule`,
219
+ `major_symbols`, `major_tiers`, `other_bps`, `shield_add_bps` and `max_bps`, and none of schedule 1's `bps`,
220
+ `shield_bps` or `default_bps`. The fee recipient is pinned the same way: Orblivion's platform wallet
221
+ (`constants.FEE_RECIPIENT`, `0x46eb64c06379ac0d8ea3db040974278199e1e6e9`). The $ORBLIVION token's contract is pinned too
222
+ (`constants.ORBLIVION_TOKEN`).
223
+
224
+ ## Errors
225
+
226
+ `VerificationError` (`VERIFICATION_FAILED`, with `rule`, `failures`, `checks`: nothing was signed),
227
+ `OrblivionApiError` (the server's code), `ConfigMismatchError`, `MinedMismatchError`, `TxRevertedError`,
228
+ `ConsentRequiredError`, `InsufficientFundsError`, and `OrblivionError` with `ACCOUNT_SHAPE` or `ACCOUNT_WALLET` for an
229
+ account answer (`client.me`) of the wrong shape or for another wallet. `error.retryable` is true for rate limits,
230
+ unreachable nodes, receipt timeouts and 5xx answers. Every one is an `OrblivionError`; an API that can't be reached
231
+ is `ORBLIVION_UNREACHABLE`.
232
+
233
+ ## License
234
+
235
+ MIT. See [LICENSE](LICENSE).
@@ -0,0 +1,217 @@
1
+ # orblivion
2
+
3
+ Trade on Robinhood Chain (chain 4663) through Orblivion, the trading layer for Orbio agents, from Python. Orblivion
4
+ finds the route, builds the transaction and simulates it. Your agent's own key signs it, and Orblivion's relay sends it.
5
+
6
+ **Nothing the server returns is signed until this SDK has decoded and checked it locally**, and every mined transaction
7
+ is checked again against what was signed. The decoder and the checks are this package's own: the same rules, rule names
8
+ and error codes as the TypeScript SDK (`@orblivion/sdk`), proven against the same recorded answers.
9
+
10
+ Python 3.10 or later. Depends on `eth-account` and `eth-abi` only; HTTP uses the standard library.
11
+
12
+ ## Install
13
+
14
+ ```sh
15
+ pip install orblivion
16
+ ```
17
+
18
+ ## Quickstart
19
+
20
+ ```python
21
+ import os
22
+ from eth_account import Account
23
+ from orblivion import OrblivionClient
24
+
25
+ client = OrblivionClient(account=Account.from_key(os.environ["AGENT_KEY"]),
26
+ max_notional_usd=25) # the client refuses anything bigger, whatever the server says
27
+
28
+ client.sign_in() # optional: the first call signs in for you
29
+ quote = client.quote(sell="ETH", buy="USDG", amount_usd=10)
30
+ plan = client.plan(sell="ETH", buy="USDG", amount_usd=10) # every check, nothing signed
31
+ dry = client.trade(sell="ETH", buy="USDG", amount_usd=10, dry_run=True)
32
+ sent = client.trade(sell="ETH", buy="USDG", amount_usd=10) # checked, signed, sent, checked again
33
+ print(sent.tx_hash, sent.amount_out, sent.min_out, sent.fee)
34
+ ```
35
+
36
+ The client talks to `https://api.orblivion.com` unless told otherwise: pass another server first, or leave it out
37
+ (`OrblivionClient(account=...)`) and set `ORBLIVION_API_URL`. Plain `http` is accepted only for `127.0.0.1`,
38
+ `localhost` and `::1`; anything else must be `https`.
39
+
40
+ `headers={...}` adds headers to every request to the Orblivion API (never to the RPC or the sequencer); their values
41
+ are never shown in an error or a repr.
42
+
43
+ ## Signing in
44
+
45
+ `sign_in()` asks the server for an EIP-4361 (Sign-In with Ethereum) message, checks it names this server's host, chain
46
+ 4663, this wallet and a short expiry, signs it, and receives an API key bound to that wallet, kept in memory only.
47
+ Pass `api_key=` to reuse one; the client checks it is bound to its wallet first.
48
+
49
+ ## Quote, plan, trade
50
+
51
+ | Call | What it does |
52
+ |---|---|
53
+ | `quote(sell=, buy=, amount_usd= \| amount_in=, slippage_bps=None, shield=False)` | The server's best route and what it discloses. Read-only; the server's word. |
54
+ | `plan(sell=, buy=, amount_usd= \| amount_in=, ...)` | The trade's plan, checked exactly as `trade` checks it, with **nothing signed**. A sale of an ERC-20 token whose swap is built only around a Permit2 signature stops after the permit's checks (`complete=False`). |
55
+ | `trade(sell=, buy=, amount_usd= \| amount_in=, slippage_bps=None, approval="budget", dry_run=False, accept_risks=None, shield=False, policies=None)` | Prepare, check, sign, send through the relay, wait for the receipt, check what was mined. With `dry_run=True` it stops after signing and sends nothing. |
56
+ | `search_tokens(q, tier=None, kind=None, limit=20, shield=False)` | Search the token registry. Symbols are copied by impersonators: pick a token by its address. |
57
+ | `inspect_token(token, shield=False)` | One token as a trade would see it, checked against the SDK's own reads of the chain, refusing nothing. |
58
+ | `wallet.balances(tokens=None, who=None)` | ETH and token balances, read from the chain. |
59
+ | `approvals.status()`, `approvals.revoke()` | The wallet's Permit2 approvals; take them back. |
60
+
61
+ Core tokens are named by symbol (`ETH`, `WETH`, `USDG`, `cbBTC`, `ORBIO`, `NVDA`, `SPY`); every other token by its
62
+ contract address. Amounts are `int` in the token's smallest unit (`parse_token("1.5", "USDG")`), or `amount_usd`.
63
+
64
+ ## Fast mode
65
+
66
+ For an agent that holds its own key and trades a major pair, `fast()` cuts the path from decision to relay to one call:
67
+
68
+ ```python
69
+ fast = client.fast().start() # keeps its Chainlink marks, nonce, base fee, allowances and fee tier warm
70
+ r = fast.trade("ETH", "USDG", amount_usd=10) # or client.fast_trade(...)
71
+ print(r.path, r.tx_hash, r.timings["decision_to_accepted_ms"])
72
+ ```
73
+
74
+ The SDK builds the transaction itself on a pinned route (`FAST_ROUTES`: ETH, WETH, USDG, NVDA and SPY; never cbBTC,
75
+ which takes the normal path before anything is signed), with `min_out` from its own quote of that route (kept warm; the
76
+ tolerance at most the server's pair default), your fee tier in ETH, WETH or USDG by the fee currency rule, and the
77
+ output to your wallet; checks it with `verify_fast` (the server's own rules), signs it and sends it to
78
+ `POST /api/v1/live/fast`, which rebuilds the calldata and relays only an exact match.
79
+
80
+ - Anything stale, an ineligible pair (ORBIO, launchpad and long-tail tokens, a stock token after hours), a token you
81
+ haven't approved to Permit2 yet, a pool further under the Chainlink marks than its fee and the pair's band (75 bps
82
+ against USDG, 125 for a cross pair), or marks from your RPC more than 3% from the server's falls back to `trade()`
83
+ before anything is signed (`r.path == "fallback"`, `r.fallback_reason`); `fallback=False` raises instead.
84
+ - One `trade()` never lets two transactions land. After a refusal the server answers before relaying, the SDK asks your
85
+ own RPC about the signed transaction first: on chain, it is the result (`r.note`); its nonce taken by another
86
+ transaction, the next one takes a fresh nonce; otherwise the retry or the fallback signs at the same nonce. A refusal
87
+ that may follow a relay (`NONCE` without that proof, `IN_FLIGHT`, `SUBMIT_REJECTED`, `SEQUENCER_UNREACHABLE`, no
88
+ answer) raises with the hash. `trade(nonce=n)` signs the normal path's first transaction at `n` (and refuses when the
89
+ wallet's pending nonce isn't `n`).
90
+ - `tolerance_bps` tightens the minimum (it can't exceed the server's cap); `min_out` sets your own when it is higher.
91
+ The slippage table is pinned in the SDK (`FAST_TOLERANCES`); the server's published one can only tighten it.
92
+ - `simulate=False` skips the server's simulation of the exact signed transaction (one round trip to the node); a
93
+ transaction that would revert then costs its gas. `dry_run=True` has the server check and simulate it, and relay
94
+ nothing.
95
+ - Run the agent in US East, near the chain's sequencer: from far away its round trip dominates every trade.
96
+
97
+ ## Risks and Dossier Shield
98
+
99
+ Any token with a route trades; the server discloses what it found in `risks` (`[{code, severity, detail}]`).
100
+
101
+ - **Severe risks trade only when you accept them by name** in `accept_risks`: `HONEYPOT`, `TRANSFER_TAX`, `LOOKALIKE`,
102
+ `AMOUNT_HOOK`, `HIGH_PRICE_IMPACT`, `UNSCREENED`, `IMPERSONATOR`. The SDK never accepts a risk for you, and accepting
103
+ one loosens none of its price or minimum-output checks.
104
+ - **Dossier Shield** (`shield=True`): 10 bps on top of the trade's fee, Dossier's verdict on the token, and `policies`
105
+ (`block_impersonators`, on by default, `verified_only`, `block_risks`).
106
+
107
+ ```python
108
+ r = client.trade(sell="ETH", buy="0x…", amount_usd=5, accept_risks=["TRANSFER_TAX"])
109
+ s = client.trade(sell="ETH", buy="0x…", amount_usd=5, shield=True, policies={"verified_only": True})
110
+ s.dossier # {"verdict": "verified", "url": "…"}
111
+ s.fee_bps, s.fee_class, s.fee_tier # 60, "other", 50
112
+ ```
113
+
114
+ ## Fees
115
+
116
+ Orblivion's fee depends on the two tokens a trade swaps (fee schedule 2, pinned in `constants`):
117
+
118
+ - **Major trades**: both tokens are majors (`ETH`, `WETH`, `USDG`, `cbBTC`, `ORBIO`, or a Robinhood stock token). They
119
+ pay the wallet's volume tier: 25 bps, or 15 or 10 after enough 30-day volume.
120
+ - **Every other trade** pays exactly 50 bps.
121
+ - **Dossier Shield** adds 10 bps to either.
122
+
123
+ The SDK works out the class itself, from its own pinned majors and, for a token named by address, its own read of the
124
+ chain (the stock tokens' beacon). It never takes the server's word for the class. A plan whose `fee_class` differs is
125
+ refused (`FEE_CLASS`). The plan's `fee_bps` must be one the class and Shield mode allow, `fee_tier` must be that fee
126
+ without Shield's 10, and the calldata must pay exactly `fee_bps` (`FEE_BPS`). The SDK can't know the wallet's volume, so
127
+ it accepts any tier up to the posted 25 for a major trade. `max_fee_bps=` on the client sets a hard cap on top (`None`, the
128
+ default, leaves the schedule to bound the fee). Every quote, plan and trade result carries `fee_bps`, `fee_class` and
129
+ `fee_tier`.
130
+
131
+ The default slippage covers the trade's posted fee (40 bps plus the fee, within the pair's tolerance plus the fee).
132
+
133
+ ## Sessions and hosted agents
134
+
135
+ ```python
136
+ owner = OrblivionClient(url, wallet_account)
137
+ executor = OrblivionClient(url, hot_account)
138
+ grant = owner.sessions.grant(executor=executor.address, max_trade_usd=20, max_day_usd=60, max_trades=10, hours=12,
139
+ allow_7702=True)
140
+ executor.sessions.trade(grant.session_id, sell="ETH", buy="USDG", amount_usd=5, session=grant)
141
+ owner.sessions.revoke(grant.session_id)
142
+ ```
143
+
144
+ The owner's signed root delegation carries caveats the chain enforces (the router only, ETH per trade and per day, the
145
+ expiry, the number of trades, the executor as the only redeemer), and its salt binds the limits, the accepted risks,
146
+ Shield and the fees, so neither the server nor the executor can widen them. Every new grant is binding version 4, with
147
+ `fees` exactly the schedule's for its Shield mode (`verify.fee_terms`); the owner's SDK refuses any other version or
148
+ fees (`GRANT_LIMITS`). A session trade pays what the binding allows for the trade's own class, which the executor's SDK
149
+ and Orblivion's co-signer each read themselves. Sessions granted before version 4 keep their one fee. An executor trading without
150
+ the `Grant` can state the session's Shield mode with `session_shield=`. Otherwise its SDK holds the trade to the
151
+ schedule without Shield. `client.hosted` runs an agent's loop on the Orblivion server; a live hosted agent's executor
152
+ must carry the co-signer's attestation, which the SDK verifies before the owner signs anything.
153
+
154
+ An AI agent (`brain="orbio_llm"`) decides each tick with a model on Orbio's gateway from the owner's own strategy prompt:
155
+ `client.hosted.create(brain="orbio_llm", params=ai_params("Follow the trend; keep half in USDG.",
156
+ "anthropic/claude-haiku-5.5"), interval_s=900, pairs=["ETH-USDG"], limits=...)`: Orblivion's own Orbio credits pay
157
+ first (a fair daily share per owner wallet, cheap models, 15-minute ticks), then the owner's own Orbio balance.
158
+ `hosted.ai_options()` lists the templates, models and prices, the pool and this wallet's share; `hosted.spend(id)` its
159
+ model calls and cost. The owner's Orbio balance needs Sign in with Orbio: `hosted.ai_connect()` returns Orbio's consent
160
+ page, refused (`AI_AUTHORIZE_URL`) unless it is `https://www.orbio.so/oauth/authorize` with PKCE S256 asking for exactly
161
+ Orblivion's grant: its client id (pass `client_id=` to pin it; until Orbio registers the app, the one the server's AI
162
+ options name, which its answer must repeat), the server's own `/orbio-callback.html` as the redirect, and the scope
163
+ `openid inference`, each named once. Orblivion's redirect page finishes it. No answer carries an Orbio credential.
164
+ Sign in with Orbio isn't open on the public API yet.
165
+
166
+ ## Your account
167
+
168
+ ```python
169
+ page = client.me.trades(limit=25) # newest first; refused=True adds refused calls and unmined trades
170
+ for t in page.trades:
171
+ print(t.time, t.path, t.token_in.token, t.amount_in, t.token_out.token, t.amount_out, t.amount_out_kind, t.status)
172
+ older = client.me.trades(limit=25, before=page.next_before) if page.next_before else None
173
+
174
+ p = client.me.portfolio() # balances at independent marks; p.total_usd counts priced ones only
175
+ print(p.total_usd, p.fee_tier.tier_bps, p.fee_tier.volume_to_next_usd)
176
+ s = client.me.sessions() # active sessions and hosted agents in summary
177
+ ```
178
+
179
+ The signed-in wallet's own trades through Orblivion (agent, session, hosted or fast; `amount_out` is what the wallet
180
+ received once mined, `amount_out_kind` `"actual"`, else the plan's minimum, `"minimum"`), its balances read from the
181
+ chain and valued at the independent marks Orblivion's volume tier uses (a token without one is listed with its amount,
182
+ `priced=False`), its fee tier and the volume to the next, and its active sessions and hosted agents. Read-only: these
183
+ calls sign nothing and change nothing. The server answers for the key's own wallet only, and the SDK still checks every
184
+ answer: its shape (`ACCOUNT_SHAPE`) and that it is this client's wallet's (`ACCOUNT_WALLET`). Information only: nothing
185
+ in these answers feeds a signing decision, which always rests on the SDK's own reads. No fee figure is returned.
186
+ Token symbols and names are their deployer's word: show them as text.
187
+
188
+ ## What the SDK verifies
189
+
190
+ The same rules as the TypeScript SDK, by the same names: the router, chain, sender and transaction type; every Universal
191
+ Router command decoded and re-encoded byte for byte; the value and what is pulled; the tokens and hops; every recipient
192
+ (output only to the wallet, one fee payment only); the fee (its class, count, size, token, recipient); the minimum output against
193
+ the quote, the simulation and Chainlink prices the SDK reads itself, or its own quote of the exact route for tokens
194
+ without a feed; the size, the deadline and the gas; Permit2 permits and approvals; token records against the chain
195
+ (lookalikes of core assets refused unless accepted); and, after mining, that what was mined is what was signed.
196
+
197
+ ## Pinned values
198
+
199
+ The chain, the contracts, the core tokens, the fee schedule and the session co-signer (`constants.COSIGNER`) are pinned;
200
+ the server's config must agree (`ConfigMismatchError`). Its `fee` must publish schedule 2 exactly: `schedule`,
201
+ `major_symbols`, `major_tiers`, `other_bps`, `shield_add_bps` and `max_bps`, and none of schedule 1's `bps`,
202
+ `shield_bps` or `default_bps`. The fee recipient is pinned the same way: Orblivion's platform wallet
203
+ (`constants.FEE_RECIPIENT`, `0x46eb64c06379ac0d8ea3db040974278199e1e6e9`). The $ORBLIVION token's contract is pinned too
204
+ (`constants.ORBLIVION_TOKEN`).
205
+
206
+ ## Errors
207
+
208
+ `VerificationError` (`VERIFICATION_FAILED`, with `rule`, `failures`, `checks`: nothing was signed),
209
+ `OrblivionApiError` (the server's code), `ConfigMismatchError`, `MinedMismatchError`, `TxRevertedError`,
210
+ `ConsentRequiredError`, `InsufficientFundsError`, and `OrblivionError` with `ACCOUNT_SHAPE` or `ACCOUNT_WALLET` for an
211
+ account answer (`client.me`) of the wrong shape or for another wallet. `error.retryable` is true for rate limits,
212
+ unreachable nodes, receipt timeouts and 5xx answers. Every one is an `OrblivionError`; an API that can't be reached
213
+ is `ORBLIVION_UNREACHABLE`.
214
+
215
+ ## License
216
+
217
+ MIT. See [LICENSE](LICENSE).