@blazephoenix/sdk 0.4.0 → 1.0.0

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.
package/README.md CHANGED
@@ -1,184 +1,185 @@
1
1
  # @blazephoenix/sdk
2
2
 
3
3
  Official TypeScript SDK for **[BlazePhoenix](https://blazephoenix.xyz)** — the on-chain
4
- DEX aggregator on **Base · Ethereum · Optimism · Arbitrum**.
4
+ DEX aggregator on **Base · Ethereum · Optimism · Arbitrum · Robinhood Chain**.
5
5
 
6
- Every number the API serves is computed **on-chain** by the Quoter contract
7
- (`previewPlan`) — your bot, your frontend and the site itself all read the same truth.
8
- **No API key. No signup. Open CORS.**
9
-
10
- > Live docs & playground: **https://blazephoenix.xyz/?tab=api**
6
+ **1.x runs 100% on YOUR RPC.** Every quote is an `eth_call` from your process to your
7
+ node, against the Quoter contract that settles the swap. There is no BlazePhoenix API
8
+ in the read path, no key, and the package ships no RPC endpoints (a test enforces it).
9
+ We don't pay for your reads, and you don't depend on our servers being up.
11
10
 
12
11
  ```bash
13
- npm i github:blazephoenixxyz-crypto/SDK # builds on install — no registry needed
14
- # (or, once published to npm:) npm i @blazephoenix/sdk
15
- # optional (only for the on-chain module: quoteOnChain / watchFills / getFills):
16
- npm i viem
12
+ npm i @blazephoenix/sdk viem
13
+ # or straight from GitHub (builds on install): npm i github:blazephoenixxyz-crypto/SDK viem
17
14
  ```
18
15
 
19
- ## Quote → approve → send (the whole loop)
16
+ ## Quote → build → execute
20
17
 
21
18
  ```ts
22
- import { BlazePhoenix, buildSwapTx, buildApproveTx, toBaseUnits } from '@blazephoenix/sdk';
23
-
24
- const blaze = new BlazePhoenix();
25
- const amountIn = toBaseUnits('1.5', 18); // "1.5" WETH → 1500000000000000000n
26
-
27
- const q = await blaze.quote({
28
- chain: 'base', // 8453 | 'base' | 1 | 'eth' | 10 | 42161 …
29
- tokenIn: 'WETH', // 0x-address, ETH/WETH/USDC/BZPX — or ANY traded
30
- // symbol ('TOSHI', 'DEGEN'…): resolved to the
31
- // deepest-liquidity token, echoed in q.resolved
32
- tokenOut: 'USDC',
33
- amountIn,
34
- recipient: '0xYOU', // ← makes the API return ready-to-send calldata
35
- slippageBps: 50,
19
+ import { BlazePhoenix } from '@blazephoenix/sdk';
20
+
21
+ const blaze = new BlazePhoenix({
22
+ rpc: { base: process.env.BASE_RPC_URL }, // YOUR node — any provider's free tier is enough
36
23
  });
37
24
 
38
- // once per token: allow the Router to pull tokenIn (exact amount — or MAX_UINT256)
39
- await wallet.sendTransaction(buildApproveTx({ chain: 'base', token: q.tokenIn, amount: amountIn }));
40
- // then execute exactly what was quoted:
41
- await wallet.sendTransaction(buildSwapTx(q)); // { to, data, value }
25
+ // 1) the Quoter's preview, read on your node ("amount" is human units)
26
+ const q = await blaze.quote({ chain: 'base', tokenIn: 'WETH', tokenOut: 'USDC', amount: '1.5' });
27
+ q.amountOut; // net output after the 0.28% fee (bigint, base units)
28
+ q.checks.verdict; // Phoenix Check: ok | caution | danger | blocked (fails closed)
29
+ q.version; // protocol version that answered ('1.0.0' today, '2.0.0' once deployed)
30
+
31
+ // 2) the swap transaction(s): verified calldata + the approval step if needed
32
+ const plan = await blaze.buildSwap({
33
+ chain: 'base', tokenIn: 'WETH', tokenOut: 'USDC', amount: '1.5',
34
+ recipient: me, from: me, // `from` enables the allowance check
35
+ slippageBps: 50, // default 50; never below the on-chain floor
36
+ });
37
+ plan.steps; // [approve?, swap] — { chainId, to, data, value }
38
+ plan.minOut; // the minimum the Router will enforce for you
39
+ plan.encodedBy; // 'quoter' on 2.x (the Quoter's own bytes, verified) · 'sdk' on 1.x
40
+
41
+ // 3) optional: dry-run on your node, then execute with YOUR wallet
42
+ await blaze.simulate(plan, me); // { ok, amountOut } or the decoded revert
43
+ const res = await blaze.execute({ wallet, plan }); // approve → simulate → swap → receipt
44
+ res.amountOut; // realised, from the Router's Swap event
42
45
  ```
43
46
 
44
- ## Batch quotes (screeners / arb loops)
47
+ `execute` takes a viem `WalletClient`. The SDK never asks for, stores or touches a key.
48
+
49
+ ## Your RPC, your way
45
50
 
46
51
  ```ts
47
- const { results } = await blaze.quoteBatch([
48
- { chain: 'base', tokenIn: 'WETH', tokenOut: 'USDC', amountIn: 10n ** 18n },
49
- { chain: 'base', tokenIn: 'WETH', tokenOut: 'BZPX', amountIn: 10n ** 18n },
50
- { chain: 'arbitrum', tokenIn: 'WETH', tokenOut: 'USDC', amountIn: 10n ** 18n },
51
- ]); // one round-trip (max 10), per-item errors inline
52
+ new BlazePhoenix({ rpc: 'https://your-base-node.example/KEY' }); // one node — its own chain
53
+ new BlazePhoenix({ rpc: ['https://node-a.example', 'https://node-b.example'] }); // your fallback order
54
+ new BlazePhoenix({ rpc: window.ethereum }); // the user's wallet (EIP-1193)
55
+ new BlazePhoenix({ rpc: http('https://…', { batch: true }) }); // any viem Transport
56
+ new BlazePhoenix({ rpc: { base: '…', eth: ['…', '…'], arbitrum: provider } }); // per chain
57
+ new BlazePhoenix(); // reads BLAZEPHOENIX_RPC_BASE / _ETHEREUM / _OPTIMISM / _ARBITRUM / _ROBINHOOD
58
+ // (comma-separated for fallback) or BLAZEPHOENIX_RPC_URL
52
59
  ```
53
60
 
54
- ## Deep links (bot buttons / referral posts)
61
+ - Each node is asked for `eth_chainId` once. Quoting Base contracts on an Ethereum node
62
+ throws `rpc_chain_mismatch` instead of returning garbage.
63
+ - With a single node, `chain` may be omitted: the node's own chain is used.
64
+ - A chain without a configured node throws `rpc_required` — nothing silently falls back
65
+ to someone else's infrastructure.
66
+ - `https://` and `wss://` only (`http://` allowed for `localhost` — your anvil/geth).
67
+ URLs are redacted in every error message, because keys live in them.
55
68
 
56
- ```ts
57
- import { deepLink } from '@blazephoenix/sdk';
69
+ ## Versions — pick yours
58
70
 
59
- deepLink({ chain: 'base', tokenIn: 'ETH', tokenOut: 'BZPX', amount: '0.5' });
60
- // → https://blazephoenix.xyz/?tab=swap&chain=8453&in=ETH&out=BZPX&amt=0.5
61
- ```
71
+ Protocol versions are deployments, not SDK versions:
62
72
 
63
- ## On-chain module (optional `viem` peer)
64
-
65
- Zero middlemen — same numbers, straight from the chain. **RPC optional since
66
- v0.4.0**: omit `rpcUrl` and the SDK falls back across public keyless endpoints
67
- (bring your own node for production throughput). Still zero providers and zero
68
- keys shipped — enforced by tests.
73
+ | version | status | what it is |
74
+ |---|---|---|
75
+ | `1.0.0` | **live** on all five chains | the generation deployed at launch |
76
+ | `2.0.0` | pending | the final Core / Hub / Solver / Quoter / Router from [BlazePhoenix-Dex](https://github.com/blazephoenixxyz-crypto/Blaze-Phoenix-Dex) (`VERSION()` = `"2.0.0"`) |
69
77
 
70
78
  ```ts
71
- import { quoteOnChain, watchFills, getFills } from '@blazephoenix/sdk';
79
+ new BlazePhoenix({ rpc, version: 'latest' }); // default: newest version deployed on each chain
80
+ new BlazePhoenix({ rpc, version: '1' }); // stay on 1.x
81
+ await blaze.quote({ ...req, version: '2.0.0' }); // per call
82
+ ```
72
83
 
73
- const { preview } = await quoteOnChain({
74
- chain: 'base', rpcUrl: RPC,
75
- tokenIn: '0x4200000000000000000000000000000000000006',
76
- tokenOut: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
77
- amountIn: 10n ** 18n,
78
- });
84
+ The SDK adapts to what each version can do (`featuresOf(version)`):
85
+
86
+ | capability | 1.x | 2.x |
87
+ |---|---|---|
88
+ | preview + Router calldata in ONE call (`previewAndEncode`) | — (encoded by the SDK) | ✅ verified field by field |
89
+ | native ETH in, no pre-wrap (`swapExactInNative`) | wrap first: `buildWrapTx` | ✅ |
90
+ | solve + execute in the same tx (`mode: 'best'` → `swapBestExactIn`) | — | ✅ |
91
+ | on-chain `batchQuote` | parallel previews | ✅ chunked |
92
+ | `ExecutionProof` on every fill (quoted vs realised vs floor) | — | ✅ |
93
+
94
+ ### New deployments reach you without a new SDK release
95
+
96
+ The registry has three layers:
97
+
98
+ 1. **Embedded** — shipped in the package. Non-zero addresses are **pins**: nothing fetched
99
+ at runtime can move them.
100
+ 2. **Remote** — `GET https://blazephoenix.xyz/api/deployments` (static JSON, refreshed every
101
+ 10 min in the background; the first lookup waits at most 3 s). It can only fill what the
102
+ snapshot doesn't know — e.g. the 2.0.0 addresses the day they are deployed — and only for
103
+ versions that can be verified on-chain (2.x+). Every remote-sourced set is **verified on
104
+ your RPC before first use**:
105
+ code at every address, `VERSION()` matches, and the Quoter, Router and Solver all point at
106
+ the same Hub and Solver. Anything else fails closed (`deployment_unverified`).
107
+ 3. **Your overrides** — always win:
79
108
 
80
- const unwatch = await watchFills({
81
- chain: 'base', rpcUrl: RPC,
82
- onFill: (f) => console.log(f.txHash, f.amountIn, '→', f.amountOut),
109
+ ```ts
110
+ new BlazePhoenix({
111
+ rpc,
112
+ contracts: { base: { router: '0x…', quoter: '0x…', version: '2.0.0' } }, // your fork / audit target
113
+ registry: { mode: 'embedded' }, // never touch the network for addresses
83
114
  });
115
+ await blaze.deployments(); // the chains × versions table this client sees
116
+ await blaze.verifyDeployment({ chain: 'base' }); // run the on-chain checks yourself
84
117
  ```
85
118
 
86
- `getFills({ chain, rpcUrl, fromBlock, toBlock })` gives you the raw fill history —
87
- the input for the **quoted-vs-executed verification pattern** documented on the
88
- API page: re-run each fill's quote at its block and compare with the executed
89
- amount the event recorded. Verify us, don't trust us.
90
-
91
- ## Resilient by default (v0.3.0)
119
+ ## Why the calldata can be trusted
92
120
 
93
- Every call ships the same meta-patterns the BlazePhoenix edge runs — no config:
121
+ On 2.x, `Quoter.previewAndEncode` returns the preview **and** the exact `swapExactIn` bytes that
122
+ execute it. The Quoter's own source says what that is worth — *"a compromised Quoter fools the
123
+ interface"* — so the SDK never forwards those bytes blind. It decodes them with the Router ABI
124
+ and refuses (`calldata_mismatch`) unless the amount, recipient, deadline, the route
125
+ (identical to the previewed one, connecting tokenIn → tokenOut) and a minimum at least the
126
+ on-chain floor all match what you asked. Your slippage then only ever **tightens** that minimum.
94
127
 
95
- - identical concurrent calls **coalesce into one request** (singleflight)
96
- - preview quotes ride a **1s micro-cache** (`cacheTtlMs`; never applied to
97
- `recipient`/`exact` requests — execution data stays fresh, always)
98
- - transient failures (network, 429, 502–504) **retry with backoff** and honour
99
- the server's `retry-after` (`retries`, default 2)
128
+ ## More
100
129
 
101
130
  ```ts
102
- // a price loop in one line — overlap-safe, stop() when done:
103
- import { pollQuote } from '@blazephoenix/sdk';
104
- const stop = pollQuote(blaze,
105
- { chain: 'base', tokenIn: 'WETH', tokenOut: 'USDC', amountIn: 10n ** 18n },
106
- (q) => console.log('WETH→USDC', q.amountOut),
107
- { intervalMs: 4000 });
131
+ await blaze.quoteExact(req); // previewPlanExact: every concentrated leg dry-run on the pool
132
+ await blaze.quoteBatch([req1, req2]); // per-item { ok, quote } | { ok:false, error }
133
+ await blaze.getFills({ chain: 'base', lookbackBlocks: 5_000n }); // Swap (+ ExecutionProof on 2.x)
134
+ const stop = await blaze.watchFills({ chain: 'base', onFill: console.log });
135
+ await blaze.tokenInfo('base', '0x…'); // symbol / name / decimals
136
+ await blaze.solvency(); // the staking engine's proof-of-solvency (Base)
137
+ toJSON(quote); // bigint → string, for HTTP / queues / LLMs
108
138
  ```
109
139
 
110
- ## 🔥 Phoenix Bot — zero-custody Telegram bot
140
+ Pure helpers (no RPC): `buildApproveTx`, `buildWrapTx`, `buildUnwrapTx`, `permit2TypedData`,
141
+ `encodeSwapExactInWithPermit2`, `encodeSwapExactIn`, `verifySwapExactIn`, `minOutFor`,
142
+ `decodeBlazeError`, `toBaseUnits`, `fromBaseUnits`, `deepLink`.
111
143
 
112
- [`examples/phoenix-bot.ts`](examples/phoenix-bot.ts) is a complete Telegram bot
113
- with a difference: **it never holds a key**. It quotes on-chain truth, streams
114
- real fills (`/watch`), and executes by deep-linking users into their OWN wallet.
115
- The famous trading bots custody your funds; this one can't lose what it never
116
- touches.
117
-
118
- ```bash
119
- npm i grammy viem
120
- BOT_TOKEN=... RPC_URL=https://your-base-rpc npx tsx examples/phoenix-bot.ts
121
- ```
144
+ Tokens: `0x` addresses, or the universal symbols `ETH` (native), `WETH`, `USDC` (the chain's
145
+ dollar asset — USDG on Robinhood), `BZPX`. Anything else: pass the address. The SDK never
146
+ guesses a token from a ticker.
122
147
 
123
148
  ## Errors
124
149
 
125
- HTTP-level failures throw `BlazeApiError` with a stable `code`:
150
+ Every failure is a `BlazeError` with a stable `code`; protocol reverts carry `revert`
151
+ (`RouterE` / `QuoterE` / `SolverE` / `HubE` + the reason from the contract's own source):
126
152
 
127
153
  | code | meaning |
128
154
  |---|---|
129
- | `bad_*` (400) | invalid parameter — message names the field |
130
- | `no_route` (422) | Quoter reverted: no executable route for this pair/size |
131
- | `rpc_unreachable` (502) | all upstream RPCs failed — retry shortly |
155
+ | `rpc_required` | no node configured for that chain |
156
+ | `rpc_chain_mismatch` | the node serves a different chain |
157
+ | `rpc_error` | your node failed (network, rate limit) |
158
+ | `no_route` | the Solver found no executable path (`SolverE(5)`) or the quote reverted |
159
+ | `not_executable` | the Quoter says the route cannot settle now (`canExecute = false`) |
160
+ | `calldata_mismatch` | Quoter bytes did not match your request — refused |
161
+ | `deployment_unverified` | a registry deployment failed on-chain verification |
162
+ | `unsupported_by_version` | e.g. native ETH input on a 1.x Router |
163
+ | `not_deployed` / `bad_request` / `wallet_chain_mismatch` / `reverted` | as named |
132
164
 
133
- ## Reference
165
+ ## MCP (AI agents)
134
166
 
135
- - REST endpoint: `GET https://blazephoenix.xyz/api/quote`
136
- - Batch: `POST https://blazephoenix.xyz/api/quote/batch`
137
- - Manifest (contracts / token / event topics): `GET https://blazephoenix.xyz/api/manifest`
138
- - Examples: [`examples/`](examples) — plain quote, Telegram bot, fill watcher
139
- - Protocol fee: 0.28% on quoted output; **execution surplus is fee-exempt → user**
167
+ [`@blazephoenix/mcp`](https://github.com/blazephoenixxyz-crypto/blazephoenix-mcp) wraps this SDK as
168
+ a local MCP server — the agent's tools run on your machine, on your RPC.
140
169
 
141
- ## Deployed contracts (verified)
170
+ ## Examples
142
171
 
143
- ![solvency](https://img.shields.io/endpoint?url=https%3A%2F%2Fblazephoenix.xyz%2Fapi%2Fbadge)
144
- — live `isSolvent()` read from the Base staking contract ·
145
- [full proof-of-solvency report](https://blazephoenix.xyz/solvency)
172
+ [`examples/`](examples): `quote.ts`, `watch-fills.ts`, `telegram-bot.ts`, and
173
+ [`phoenix-bot.ts`](examples/phoenix-bot.ts) — a complete zero-custody Telegram bot on your own nodes.
146
174
 
147
- | Chain | Contract | Address |
148
- |---|---|---|
149
- | Base (8453) | Router | [`0x2a779f9Be49aac57495A8B6467Cc325a8a47Eb9f`](https://basescan.org/address/0x2a779f9Be49aac57495A8B6467Cc325a8a47Eb9f) |
150
- | Base (8453) | Quoter | [`0x4cEF0615614B212895F45Aa1D4833B16666E18d3`](https://basescan.org/address/0x4cEF0615614B212895F45Aa1D4833B16666E18d3) |
151
- | Base (8453) | Staking | [`0x3f60C7aa0c36a78D200405feBE143d2Cf3fA0c77`](https://basescan.org/address/0x3f60C7aa0c36a78D200405feBE143d2Cf3fA0c77) |
152
- | Base (8453) | BZPX token | [`0x23113e72165a034265Ab8Bf2277CCB7a85Cb7483`](https://basescan.org/address/0x23113e72165a034265Ab8Bf2277CCB7a85Cb7483) |
153
- | Ethereum (1) | Router | [`0xE1aE5f49013920CF71De8CED4043e14C4d63416b`](https://etherscan.io/address/0xE1aE5f49013920CF71De8CED4043e14C4d63416b) |
154
- | Ethereum (1) | Quoter | [`0x4a20AA0912388ff7A9221Ab6BFC224cc20Baa0c3`](https://etherscan.io/address/0x4a20AA0912388ff7A9221Ab6BFC224cc20Baa0c3) |
155
- | Optimism (10) | Router | [`0x7262e7483ab6f0db7b8f90eC3a9de3B02Ab36F6A`](https://optimistic.etherscan.io/address/0x7262e7483ab6f0db7b8f90eC3a9de3B02Ab36F6A) |
156
- | Optimism (10) | Quoter | [`0xfB18EF6f62A0278A273Af4b7A46b454F9E482dc2`](https://optimistic.etherscan.io/address/0xfB18EF6f62A0278A273Af4b7A46b454F9E482dc2) |
157
- | Arbitrum (42161) | Router | [`0x7262e7483ab6f0db7b8f90eC3a9de3B02Ab36F6A`](https://arbiscan.io/address/0x7262e7483ab6f0db7b8f90eC3a9de3B02Ab36F6A) |
158
- | Arbitrum (42161) | Quoter | [`0xfB18EF6f62A0278A273Af4b7A46b454F9E482dc2`](https://arbiscan.io/address/0xfB18EF6f62A0278A273Af4b7A46b454F9E482dc2) |
159
-
160
- Always cross-check against the live manifest: `https://blazephoenix.xyz/api/manifest`.
161
-
162
- ## Learn the engineering
163
-
164
- The protocol is documented from the deployed bytecode — every article ends with
165
- a command to reproduce its claims:
166
-
167
- - **The mathematics** (every formula; the originals are ours): https://blazephoenix.xyz/learn/the-mathematics
168
- - **Integrate any bot** (keyless / keyed / ethers / viem / Python / AI-agent): https://blazephoenix.xyz/learn/integrate-any-bot
169
- - **Web 2.5 vs Web 3.0** (the decision on-chain, not just settlement): https://blazephoenix.xyz/learn/web25-vs-web30
170
- - **Machine-readable measured cases**: https://blazephoenix.xyz/measured-cases.json
171
- - **Agent guide**: https://blazephoenix.xyz/llms.txt
172
-
173
- ## Citing BlazePhoenix
174
-
175
- This repository ships a `CITATION.cff`, so GitHub shows a **“Cite this
176
- repository”** button. Please cite with attribution and a link — the protocol's
177
- original constructions (the Iron Law Φ, the Vitality Field Ψ, the
178
- Capital-Anchored Filter, the Master Conservation Identity) are © 2026
179
- BlazePhoenix.
175
+ ## Regenerating the ABIs
176
+
177
+ The protocol ABIs are compiled from the Solidity sources, never written by hand:
178
+
179
+ ```bash
180
+ npm i --no-save solc@0.8.36 && npm run gen:abis # expects ../Blaze-Phoenix-Dex
181
+ ```
180
182
 
181
183
  ## License
182
184
 
183
- MIT — the SDK is deliberately permissive so anyone can integrate.
184
- (The BlazePhoenix protocol and site carry their own licenses.)
185
+ MIT — deliberately permissive so anyone can integrate. The protocol contracts are BUSL-1.1.