@blazephoenix/sdk 1.1.0 → 1.2.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 +5 -1
- package/dist/index.cjs +75 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -2
- package/dist/index.d.ts +14 -2
- package/dist/index.js +75 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -145,7 +145,8 @@ interface QuoteRequest {
|
|
|
145
145
|
amountIn?: bigint | string;
|
|
146
146
|
/** Input in HUMAN units ("1.5"); decimals are read from the token on your RPC. */
|
|
147
147
|
amount?: string;
|
|
148
|
-
/**
|
|
148
|
+
/** Your own minimum (base units of tokenOut). In buildSwap it is the signed minimum as given,
|
|
149
|
+
* and it is refused (`min_implausible`) below the quote net of slippageBps or the on-chain floor. */
|
|
149
150
|
userMinOut?: bigint | string;
|
|
150
151
|
/** Protocol version for this call (default: the client's, itself 'latest'). */
|
|
151
152
|
version?: string;
|
|
@@ -211,6 +212,15 @@ interface SwapRequest extends QuoteRequest {
|
|
|
211
212
|
mode?: 'route' | 'best';
|
|
212
213
|
/** Allowance to request when approval is needed: 'exact' (default) or 'max'. */
|
|
213
214
|
approve?: 'exact' | 'max';
|
|
215
|
+
/**
|
|
216
|
+
* true — also read previewPlanExact (every concentrated leg dry-run) in the same block and
|
|
217
|
+
* derive minOut from its exactOut: a fixed 50 bps safety margin first, then slippageBps off
|
|
218
|
+
* that, never below the default minimum. The calldata still executes the route of the default
|
|
219
|
+
* path; the exact read must price that same route, or buildSwap refuses. A userMinOut above
|
|
220
|
+
* exactOut less the margin is refused (`min_above_exact`). One more eth_call; the swap reverts
|
|
221
|
+
* instead of filling short when the pool moves past the tolerance.
|
|
222
|
+
*/
|
|
223
|
+
exact?: boolean;
|
|
214
224
|
}
|
|
215
225
|
interface ApprovalStep {
|
|
216
226
|
token: Address;
|
|
@@ -237,6 +247,8 @@ interface SwapPlan {
|
|
|
237
247
|
unwrapAfter: boolean;
|
|
238
248
|
/** Ordered transactions to send: [approval?, swap]. */
|
|
239
249
|
steps: TxRequest[];
|
|
250
|
+
/** With `exact: true`: the previewPlanExact output minOut was derived from. */
|
|
251
|
+
exactOut?: bigint;
|
|
240
252
|
}
|
|
241
253
|
interface SimulationResult {
|
|
242
254
|
ok: boolean;
|
|
@@ -4249,7 +4261,7 @@ declare const CAUTION_IMPACT_BPS = 200;
|
|
|
4249
4261
|
declare function routeIsConsistent(route: Route, tokenIn: Address, tokenOut: Address): boolean;
|
|
4250
4262
|
declare function phoenixCheck(pv: Preview, tokenIn: Address, tokenOut: Address): QuoteChecks;
|
|
4251
4263
|
|
|
4252
|
-
type BlazeErrorCode = 'rpc_required' | 'rpc_chain_mismatch' | 'rpc_error' | 'bad_request' | 'not_deployed' | 'unsupported_by_version' | 'no_route' | 'not_executable' | 'calldata_mismatch' | 'deployment_unverified' | 'reverted' | 'wallet_chain_mismatch';
|
|
4264
|
+
type BlazeErrorCode = 'rpc_required' | 'rpc_chain_mismatch' | 'rpc_error' | 'bad_request' | 'not_deployed' | 'unsupported_by_version' | 'no_route' | 'not_executable' | 'calldata_mismatch' | 'min_implausible' | 'min_above_exact' | 'deployment_unverified' | 'reverted' | 'wallet_chain_mismatch';
|
|
4253
4265
|
declare class BlazeError extends Error {
|
|
4254
4266
|
readonly code: BlazeErrorCode;
|
|
4255
4267
|
readonly details?: Record<string, unknown>;
|
package/dist/index.d.ts
CHANGED
|
@@ -145,7 +145,8 @@ interface QuoteRequest {
|
|
|
145
145
|
amountIn?: bigint | string;
|
|
146
146
|
/** Input in HUMAN units ("1.5"); decimals are read from the token on your RPC. */
|
|
147
147
|
amount?: string;
|
|
148
|
-
/**
|
|
148
|
+
/** Your own minimum (base units of tokenOut). In buildSwap it is the signed minimum as given,
|
|
149
|
+
* and it is refused (`min_implausible`) below the quote net of slippageBps or the on-chain floor. */
|
|
149
150
|
userMinOut?: bigint | string;
|
|
150
151
|
/** Protocol version for this call (default: the client's, itself 'latest'). */
|
|
151
152
|
version?: string;
|
|
@@ -211,6 +212,15 @@ interface SwapRequest extends QuoteRequest {
|
|
|
211
212
|
mode?: 'route' | 'best';
|
|
212
213
|
/** Allowance to request when approval is needed: 'exact' (default) or 'max'. */
|
|
213
214
|
approve?: 'exact' | 'max';
|
|
215
|
+
/**
|
|
216
|
+
* true — also read previewPlanExact (every concentrated leg dry-run) in the same block and
|
|
217
|
+
* derive minOut from its exactOut: a fixed 50 bps safety margin first, then slippageBps off
|
|
218
|
+
* that, never below the default minimum. The calldata still executes the route of the default
|
|
219
|
+
* path; the exact read must price that same route, or buildSwap refuses. A userMinOut above
|
|
220
|
+
* exactOut less the margin is refused (`min_above_exact`). One more eth_call; the swap reverts
|
|
221
|
+
* instead of filling short when the pool moves past the tolerance.
|
|
222
|
+
*/
|
|
223
|
+
exact?: boolean;
|
|
214
224
|
}
|
|
215
225
|
interface ApprovalStep {
|
|
216
226
|
token: Address;
|
|
@@ -237,6 +247,8 @@ interface SwapPlan {
|
|
|
237
247
|
unwrapAfter: boolean;
|
|
238
248
|
/** Ordered transactions to send: [approval?, swap]. */
|
|
239
249
|
steps: TxRequest[];
|
|
250
|
+
/** With `exact: true`: the previewPlanExact output minOut was derived from. */
|
|
251
|
+
exactOut?: bigint;
|
|
240
252
|
}
|
|
241
253
|
interface SimulationResult {
|
|
242
254
|
ok: boolean;
|
|
@@ -4249,7 +4261,7 @@ declare const CAUTION_IMPACT_BPS = 200;
|
|
|
4249
4261
|
declare function routeIsConsistent(route: Route, tokenIn: Address, tokenOut: Address): boolean;
|
|
4250
4262
|
declare function phoenixCheck(pv: Preview, tokenIn: Address, tokenOut: Address): QuoteChecks;
|
|
4251
4263
|
|
|
4252
|
-
type BlazeErrorCode = 'rpc_required' | 'rpc_chain_mismatch' | 'rpc_error' | 'bad_request' | 'not_deployed' | 'unsupported_by_version' | 'no_route' | 'not_executable' | 'calldata_mismatch' | 'deployment_unverified' | 'reverted' | 'wallet_chain_mismatch';
|
|
4264
|
+
type BlazeErrorCode = 'rpc_required' | 'rpc_chain_mismatch' | 'rpc_error' | 'bad_request' | 'not_deployed' | 'unsupported_by_version' | 'no_route' | 'not_executable' | 'calldata_mismatch' | 'min_implausible' | 'min_above_exact' | 'deployment_unverified' | 'reverted' | 'wallet_chain_mismatch';
|
|
4253
4265
|
declare class BlazeError extends Error {
|
|
4254
4266
|
readonly code: BlazeErrorCode;
|
|
4255
4267
|
readonly details?: Record<string, unknown>;
|
package/dist/index.js
CHANGED
|
@@ -4736,8 +4736,7 @@ var CHAINS = {
|
|
|
4736
4736
|
explorer: "https://basescan.org",
|
|
4737
4737
|
weth: "0x4200000000000000000000000000000000000006",
|
|
4738
4738
|
usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
4739
|
-
bzpx: "
|
|
4740
|
-
staking: "0x3f60C7aa0c36a78D200405feBE143d2Cf3fA0c77",
|
|
4739
|
+
bzpx: "0x053D75c00FdD571538492e3B1686Bd963a0911A7",
|
|
4741
4740
|
blockTime: 2
|
|
4742
4741
|
},
|
|
4743
4742
|
10: {
|
|
@@ -6033,6 +6032,60 @@ var BlazePhoenix = class {
|
|
|
6033
6032
|
let encodedBy = "sdk";
|
|
6034
6033
|
let entry;
|
|
6035
6034
|
let minOut;
|
|
6035
|
+
let at;
|
|
6036
|
+
if (req.exact) {
|
|
6037
|
+
try {
|
|
6038
|
+
at = await ctx.client.getBlockNumber();
|
|
6039
|
+
} catch (e) {
|
|
6040
|
+
this.wrapReadError(e, "block number");
|
|
6041
|
+
}
|
|
6042
|
+
}
|
|
6043
|
+
const pin = at !== void 0 ? { blockNumber: at } : {};
|
|
6044
|
+
let exactOut;
|
|
6045
|
+
const exactRead = async (route) => {
|
|
6046
|
+
let ex;
|
|
6047
|
+
try {
|
|
6048
|
+
ex = await ctx.client.readContract({
|
|
6049
|
+
address: ctx.dep.contracts.quoter,
|
|
6050
|
+
abi: QUOTER_ABI,
|
|
6051
|
+
functionName: "previewPlanExact",
|
|
6052
|
+
args: [tIn.address, tOut.address, amountIn],
|
|
6053
|
+
...pin
|
|
6054
|
+
});
|
|
6055
|
+
} catch (e) {
|
|
6056
|
+
this.wrapReadError(e, "exact quote");
|
|
6057
|
+
}
|
|
6058
|
+
if (!samePath(ex[0], route)) {
|
|
6059
|
+
throw new BlazeError("calldata_mismatch", "previewPlanExact priced a different route than the one to execute");
|
|
6060
|
+
}
|
|
6061
|
+
exactOut = ex[1];
|
|
6062
|
+
return ex[1];
|
|
6063
|
+
};
|
|
6064
|
+
const settleMin = async (p) => {
|
|
6065
|
+
let floor = minOutFor(p.netOut, slippageBps, p.ironFloor);
|
|
6066
|
+
let ceil;
|
|
6067
|
+
if (req.exact) {
|
|
6068
|
+
const ex = await exactRead(p.route);
|
|
6069
|
+
ceil = minOutFor(ex, EXACT_MARGIN_BPS, 0n);
|
|
6070
|
+
floor = maxBig(floor, minOutFor(ceil, slippageBps, 0n));
|
|
6071
|
+
}
|
|
6072
|
+
if (userMinOut === 0n) return floor;
|
|
6073
|
+
if (userMinOut < floor) {
|
|
6074
|
+
throw new BlazeError(
|
|
6075
|
+
"min_implausible",
|
|
6076
|
+
`userMinOut is below ${floor} (this quote net of slippageBps): set it from a price you trust, or raise slippageBps if a lower minimum is intended`,
|
|
6077
|
+
{ details: { userMinOut: userMinOut.toString(), floor: floor.toString() } }
|
|
6078
|
+
);
|
|
6079
|
+
}
|
|
6080
|
+
if (ceil !== void 0 && userMinOut > ceil && userMinOut > floor) {
|
|
6081
|
+
throw new BlazeError(
|
|
6082
|
+
"min_above_exact",
|
|
6083
|
+
`userMinOut is above ${ceil} (exactOut less ${EXACT_MARGIN_BPS} bps): an honest swap at this minimum may revert`,
|
|
6084
|
+
{ details: { userMinOut: userMinOut.toString(), ceiling: ceil.toString() } }
|
|
6085
|
+
);
|
|
6086
|
+
}
|
|
6087
|
+
return userMinOut;
|
|
6088
|
+
};
|
|
6036
6089
|
if (features.previewAndEncode && !tIn.native && mode === "route") {
|
|
6037
6090
|
let call;
|
|
6038
6091
|
try {
|
|
@@ -6040,19 +6093,21 @@ var BlazePhoenix = class {
|
|
|
6040
6093
|
address: ctx.dep.contracts.quoter,
|
|
6041
6094
|
abi: QUOTER_ABI,
|
|
6042
6095
|
functionName: "previewAndEncodeWithMinOut",
|
|
6043
|
-
args: [tIn.address, tOut.address, amountIn, userMinOut, recipient, deadline]
|
|
6096
|
+
args: [tIn.address, tOut.address, amountIn, userMinOut, recipient, deadline],
|
|
6097
|
+
...pin
|
|
6044
6098
|
}) : await ctx.client.readContract({
|
|
6045
6099
|
address: ctx.dep.contracts.quoter,
|
|
6046
6100
|
abi: QUOTER_ABI,
|
|
6047
6101
|
functionName: "previewAndEncode",
|
|
6048
|
-
args: [tIn.address, tOut.address, amountIn, recipient, deadline]
|
|
6102
|
+
args: [tIn.address, tOut.address, amountIn, recipient, deadline],
|
|
6103
|
+
...pin
|
|
6049
6104
|
});
|
|
6050
6105
|
[pv, call] = r;
|
|
6051
6106
|
} catch (e) {
|
|
6052
6107
|
this.wrapReadError(e, "previewAndEncode");
|
|
6053
6108
|
}
|
|
6054
6109
|
assertExecutable(pv, tIn.address, tOut.address, call);
|
|
6055
|
-
minOut =
|
|
6110
|
+
minOut = await settleMin(pv);
|
|
6056
6111
|
verifySwapExactIn(call, {
|
|
6057
6112
|
tokenIn: tIn.address,
|
|
6058
6113
|
tokenOut: tOut.address,
|
|
@@ -6066,9 +6121,9 @@ var BlazePhoenix = class {
|
|
|
6066
6121
|
encodedBy = "quoter";
|
|
6067
6122
|
entry = "swapExactIn";
|
|
6068
6123
|
} else {
|
|
6069
|
-
({ pv, fb } = await this.readPreview(ctx, tIn.address, tOut.address, amountIn, userMinOut));
|
|
6124
|
+
({ pv, fb } = await this.readPreview(ctx, tIn.address, tOut.address, amountIn, userMinOut, at));
|
|
6070
6125
|
assertExecutable(pv, tIn.address, tOut.address);
|
|
6071
|
-
minOut =
|
|
6126
|
+
minOut = await settleMin(pv);
|
|
6072
6127
|
if (mode === "best") {
|
|
6073
6128
|
entry = "swapBestExactIn";
|
|
6074
6129
|
data = encodeSwapBestExactIn(tIn.address, tOut.address, amountIn, minOut, recipient, deadline);
|
|
@@ -6115,7 +6170,8 @@ var BlazePhoenix = class {
|
|
|
6115
6170
|
slippageBps,
|
|
6116
6171
|
approval,
|
|
6117
6172
|
unwrapAfter: tOut.native,
|
|
6118
|
-
steps: approval ? [approval.tx, tx] : [tx]
|
|
6173
|
+
steps: approval ? [approval.tx, tx] : [tx],
|
|
6174
|
+
...exactOut !== void 0 ? { exactOut } : {}
|
|
6119
6175
|
};
|
|
6120
6176
|
}
|
|
6121
6177
|
/** eth_call the swap from `from` on your RPC: the realised amountOut if it
|
|
@@ -6356,6 +6412,17 @@ function checkDeadlineSec(n) {
|
|
|
6356
6412
|
return n;
|
|
6357
6413
|
}
|
|
6358
6414
|
var maxBig = (a, b) => a > b ? a : b;
|
|
6415
|
+
var EXACT_MARGIN_BPS = 50;
|
|
6416
|
+
function samePath(a, b) {
|
|
6417
|
+
const eqA = (x, y) => x.toLowerCase() === y.toLowerCase();
|
|
6418
|
+
return a.hops.length === b.hops.length && a.hops.every((h, i) => {
|
|
6419
|
+
const g = b.hops[i];
|
|
6420
|
+
return eqA(h.tokenIn, g.tokenIn) && eqA(h.tokenOut, g.tokenOut) && h.legs.length === g.legs.length && h.legs.every((l, j) => {
|
|
6421
|
+
const m = g.legs[j];
|
|
6422
|
+
return eqA(l.pool, m.pool) && eqA(l.hooks, m.hooks) && l.kind === m.kind && l.fee === m.fee && l.tickSpacing === m.tickSpacing && l.zeroForOne === m.zeroForOne && l.stable === m.stable;
|
|
6423
|
+
});
|
|
6424
|
+
});
|
|
6425
|
+
}
|
|
6359
6426
|
function deepLink(opts = {}) {
|
|
6360
6427
|
const base = (opts.baseUrl ?? "https://blazephoenix.xyz").replace(/\/+$/, "");
|
|
6361
6428
|
const sp = new URLSearchParams();
|