@blazephoenix/sdk 1.2.1 → 1.3.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
@@ -15,7 +15,7 @@ npm i @blazephoenix/sdk viem
15
15
 
16
16
  ## BlazePhoenix in one sentence
17
17
 
18
- BlazePhoenix is the fully on-chain DEX aggregator — the route is computed inside the transaction that executes it — paired with an oracle-free staking engine that proves its own solvency on every transaction. It runs on Base, Ethereum, Optimism, Arbitrum and Robinhood Chain.
18
+ BlazePhoenix is the fully on-chain DEX aggregator — the route is computed inside the transaction that executes it — paired with an oracle-free staking engine that proves its own solvency on every transaction. V2, the generation now in development, targets Base, Optimism, Arbitrum, Robinhood Chain and further L2s and is not planned for Ethereum L1. The V1 generation deployed today runs on Base, Ethereum, Optimism, Arbitrum and Robinhood Chain.
19
19
 
20
20
  **Swap** in the [app](https://blazephoenix.xyz/?tab=swap) · **integrate** with the [SDK](https://github.com/blazephoenixxyz-crypto/SDK) (`npm i @blazephoenix/sdk`) · **connect an agent** to the [MCP server](https://github.com/blazephoenixxyz-crypto/blazephoenix-mcp) (`https://blazephoenix.xyz/mcp`, no key)
21
21
 
@@ -53,12 +53,14 @@ q.amountOut; // net output after the 0.28% fee (bigint, base units)
53
53
  q.checks.verdict; // Phoenix Check: ok | caution | danger | blocked (fails closed)
54
54
  q.version; // protocol version that answered ('1.0.0' today, '2.0.0' once deployed)
55
55
 
56
- // 2) the swap transaction(s): verified calldata + the approval step if needed
56
+ // 2) the swap transaction(s): calldata verified against the request (swap math; `simulate: true`
57
+ // asks the Router from `from` whether it settles) + the approval step if needed
57
58
  const plan = await blaze.buildSwap({
58
59
  chain: 'base', tokenIn: 'WETH', tokenOut: 'USDC', amount: '1.5',
59
60
  recipient: me, from: me, // `from` enables the allowance check
60
61
  slippageBps: 50, // default 50; never below the on-chain floor
61
62
  exact: true, // optional: minOut from previewPlanExact (one more eth_call)
63
+ simulate: true, // optional: eth_call the swap from `from`; a revert throws not_executable
62
64
  });
63
65
  plan.steps; // [approve?, swap] — { chainId, to, data, value }
64
66
  plan.minOut; // the minimum the Router will enforce for you
@@ -71,6 +73,12 @@ const res = await blaze.execute({ wallet, plan }); // approve → simulate → s
71
73
  res.amountOut; // realised, from the Router's Swap event
72
74
  ```
73
75
 
76
+ The Quoter's `canExecute` is swap math: it does not see what the tokens do to the payer (a transfer tax,
77
+ a per-account cap, the payer's own balance). Whether the bytes settle is answered only by the Router's own
78
+ call from the account that will send them: `simulate(plan, from)`, `buildSwap({ simulate: true })` or
79
+ `execute`. With `simulate: true` and the approval still missing, no eth_call is made: `plan.simulation` is
80
+ `{ ok: false, error.name: 'allowance' }`; send the approval, then simulate again before the swap.
81
+
74
82
  `execute` takes a viem `WalletClient`. The SDK never asks for, stores or touches a key.
75
83
 
76
84
  ## Your RPC, your way
@@ -100,7 +108,7 @@ Protocol versions are deployments, not SDK versions:
100
108
  | version | status | what it is |
101
109
  |---|---|---|
102
110
  | `1.0.0` | **live** on all five chains | the generation deployed at launch |
103
- | `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"`) |
111
+ | `2.0.0` | pending | the generation in development (Router, Solver, Hub, Quoter and Gate, with the Core and Math libraries; Balancer V2/V3 and Curve NG are reached through the Gate), targeting Base, Optimism, Arbitrum, Robinhood Chain and further L2s and not Ethereum L1, from [BlazePhoenix-Dex](https://github.com/blazephoenixxyz-crypto/Blaze-Phoenix-Dex) (`VERSION()` = `"2.0.0"`) |
104
112
 
105
113
  ```ts
106
114
  new BlazePhoenix({ rpc, version: 'latest' }); // default: newest version deployed on each chain
@@ -158,7 +166,9 @@ on-chain floor all match what you asked. Your slippage then only ever **tightens
158
166
  ## More
159
167
 
160
168
  ```ts
161
- await blaze.quoteExact(req); // previewPlanExact: every concentrated leg dry-run on the pool
169
+ await blaze.quoteExact(req); // previewPlanExact: every concentrated leg dry-run on its venue.
170
+ // `exactOut` is net of the protocol fee on every Quoter; `quoterOut` is the
171
+ // scalar exactly as the Quoter returned it (gross of the fee on a 1.x Quoter)
162
172
  await blaze.quoteBatch([req1, req2]); // per-item { ok, quote } | { ok:false, error }
163
173
  await blaze.getFills({ chain: 'base', lookbackBlocks: 5_000n }); // Swap (+ ExecutionProof on 2.x)
164
174
  const stop = await blaze.watchFills({ chain: 'base', onFill: console.log });
@@ -168,7 +178,8 @@ toJSON(quote); // bigint → string, for HTTP / queues /
168
178
  ```
169
179
 
170
180
  Pure helpers (no RPC): `buildApproveTx`, `buildWrapTx`, `buildUnwrapTx`, `permit2TypedData`,
171
- `encodeSwapExactInWithPermit2`, `encodeSwapExactIn`, `verifySwapExactIn`, `minOutFor`,
181
+ `encodeSwapExactInWithPermit2`, `encodeSwapExactIn`, `encodeSwapExactInNative`, `encodeSwapBestExactIn`,
182
+ `decodeSwapExactIn`, `verifySwapExactIn`, `tightenMinOut`, `minOutFor`, `phoenixCheck`,
172
183
  `decodeBlazeError`, `toBaseUnits`, `fromBaseUnits`, `deepLink`.
173
184
 
174
185
  Tokens: `0x` addresses, or the universal symbols `ETH` (native), `WETH`, `USDC` (the chain's
@@ -186,7 +197,7 @@ Every failure, `solvency()` included, is a `BlazeError` with a stable `code`; pr
186
197
  | `rpc_chain_mismatch` | the node serves a different chain |
187
198
  | `rpc_error` | your node failed (network, rate limit) |
188
199
  | `no_route` | the Solver found no executable path (`SolverE(5)`) or the quote reverted |
189
- | `not_executable` | the Quoter says the route cannot settle now (`canExecute = false`) |
200
+ | `not_executable` | the Quoter's swap math says the route cannot execute now (`canExecute = false`), or, with `simulate: true`, the Router's eth_call from `from` reverts |
190
201
  | `calldata_mismatch` | Quoter bytes did not match your request — refused |
191
202
  | `min_implausible` | `buildSwap`: `userMinOut` below the quote net of `slippageBps` (or the on-chain floor) |
192
203
  | `min_above_exact` | `buildSwap({ exact: true })`: `userMinOut` above `exactOut` less the 50 bps safety margin |
package/dist/index.cjs CHANGED
@@ -5163,9 +5163,9 @@ var EMBEDDED_DEPLOYMENTS = {
5163
5163
  {
5164
5164
  version: "2.0.0",
5165
5165
  status: "pending",
5166
- source: "blazephoenixxyz-crypto/Blaze-Phoenix-Dex@07c8563",
5166
+ source: "blazephoenixxyz-crypto/Blaze-Phoenix-Dex@f746a48",
5167
5167
  notes: "Final generation (Core/Hub/Solver/Quoter/Router). Addresses arrive through the registry the day they are deployed.",
5168
- chains: { 8453: pending(), 1: pending(), 10: pending(), 42161: pending(), 4663: pending() }
5168
+ chains: { 8453: pending(), 10: pending(), 42161: pending(), 4663: pending() }
5169
5169
  },
5170
5170
  {
5171
5171
  version: "1.0.0",
@@ -5658,6 +5658,9 @@ function fromBaseUnits(v, decimals, maxDp) {
5658
5658
  var HEX_ADDR2 = /^0x[0-9a-fA-F]{40}$/;
5659
5659
  var INT = /^\d{1,78}$/;
5660
5660
  var UINT128_MAX = (1n << 128n) - 1n;
5661
+ function netExactOutput(version, exactOut) {
5662
+ return featuresOf(version).previewAndEncode ? exactOut : exactOut - (exactOut * BigInt(FEE_BPS) + 9999n) / 10000n;
5663
+ }
5661
5664
  var BlazePhoenix = class {
5662
5665
  registry;
5663
5666
  rpc;
@@ -5937,7 +5940,7 @@ var BlazePhoenix = class {
5937
5940
  args: [tIn.address, tOut.address, amountIn],
5938
5941
  ...req.blockNumber !== void 0 ? { blockNumber: req.blockNumber } : {}
5939
5942
  });
5940
- const net = featuresOf(ctx.dep.version).previewAndEncode ? exactOut : exactOut - (exactOut * BigInt(FEE_BPS) + 9999n) / 10000n;
5943
+ const net = netExactOutput(ctx.dep.version, exactOut);
5941
5944
  return {
5942
5945
  chainId: ctx.chainId,
5943
5946
  version: ctx.dep.version,
@@ -6080,8 +6083,8 @@ var BlazePhoenix = class {
6080
6083
  if (!samePath(ex[0], route)) {
6081
6084
  throw new BlazeError("calldata_mismatch", "previewPlanExact priced a different route than the one to execute");
6082
6085
  }
6083
- exactOut = ex[1];
6084
- return ex[1];
6086
+ exactOut = netExactOutput(ctx.dep.version, ex[1]);
6087
+ return exactOut;
6085
6088
  };
6086
6089
  const settleMin = async (p) => {
6087
6090
  let floor = minOutFor(p.netOut, slippageBps, p.ironFloor);
@@ -6181,7 +6184,7 @@ var BlazePhoenix = class {
6181
6184
  }
6182
6185
  }
6183
6186
  const quote = this.buildQuote(ctx, tIn, tOut, amountIn, pv, fb);
6184
- return {
6187
+ const plan = {
6185
6188
  quote,
6186
6189
  entry,
6187
6190
  encodedBy,
@@ -6195,6 +6198,18 @@ var BlazePhoenix = class {
6195
6198
  steps: approval ? [approval.tx, tx] : [tx],
6196
6199
  ...exactOut !== void 0 ? { exactOut } : {}
6197
6200
  };
6201
+ if (!req.simulate) return plan;
6202
+ if (!from) throw new BlazeError("bad_request", "simulate: true needs `from` (the account that will send the swap)");
6203
+ const simulation = await this.simulate(plan, from);
6204
+ if (!simulation.ok && simulation.error?.name !== "allowance") {
6205
+ const err = simulation.error;
6206
+ throw new BlazeError(
6207
+ "not_executable",
6208
+ `the Router refuses these bytes from ${from}: ${err?.name ?? "revert"}${err?.code !== void 0 ? `(${err.code})` : ""} \u2014 ${err?.reason ?? "execution reverted"}`,
6209
+ { details: { from, error: err } }
6210
+ );
6211
+ }
6212
+ return { ...plan, simulation };
6198
6213
  }
6199
6214
  /** eth_call the swap from `from` on your RPC: the realised amountOut if it
6200
6215
  * would settle now, or the decoded reason it would revert. */