@blazephoenix/sdk 1.0.1 → 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 +37 -5
- package/dist/index.cjs +96 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +23 -2
- package/dist/index.d.ts +23 -2
- package/dist/index.js +96 -12
- package/dist/index.js.map +1 -1
- package/llms.txt +8 -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;
|
|
@@ -385,6 +397,12 @@ interface RegistryOptions {
|
|
|
385
397
|
* delay a call, and by at most this much; later refreshes run in the
|
|
386
398
|
* background (stale-while-revalidate). */
|
|
387
399
|
timeoutMs?: number;
|
|
400
|
+
/** Route to addresses that only the fetched document supplies (a version
|
|
401
|
+
* released after this SDK). Default false: the document can list them, but
|
|
402
|
+
* resolve() only returns Router/Quoter addresses pinned in this package —
|
|
403
|
+
* the on-chain check of a remote entry reads the entry's own contracts, so
|
|
404
|
+
* it cannot tell a real deployment from a look-alike. */
|
|
405
|
+
remoteVersions?: boolean;
|
|
388
406
|
/** Called for every pin conflict or rejected document — never silently. */
|
|
389
407
|
onWarning?: (msg: string) => void;
|
|
390
408
|
}
|
|
@@ -394,6 +412,7 @@ declare class Registry {
|
|
|
394
412
|
private fetchedAt;
|
|
395
413
|
private lastError?;
|
|
396
414
|
private readonly mode;
|
|
415
|
+
private readonly remoteVersions;
|
|
397
416
|
private readonly url;
|
|
398
417
|
private readonly ttlMs;
|
|
399
418
|
private readonly fetchFn?;
|
|
@@ -422,6 +441,8 @@ declare class Registry {
|
|
|
422
441
|
/** Every deployed version on a chain, newest first. */
|
|
423
442
|
versionsOn(chainId: SupportedChainId): string[];
|
|
424
443
|
resolve(chainId: SupportedChainId, selector?: VersionSelector): ResolvedDeployment;
|
|
444
|
+
/** Router and Quoter both pinned in this package (not filled by a fetched document). */
|
|
445
|
+
private isPinned;
|
|
425
446
|
private latestKnownVersion;
|
|
426
447
|
/** chains × versions table (for dashboards, the MCP, debugging). */
|
|
427
448
|
table(): {
|
|
@@ -4240,7 +4261,7 @@ declare const CAUTION_IMPACT_BPS = 200;
|
|
|
4240
4261
|
declare function routeIsConsistent(route: Route, tokenIn: Address, tokenOut: Address): boolean;
|
|
4241
4262
|
declare function phoenixCheck(pv: Preview, tokenIn: Address, tokenOut: Address): QuoteChecks;
|
|
4242
4263
|
|
|
4243
|
-
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';
|
|
4244
4265
|
declare class BlazeError extends Error {
|
|
4245
4266
|
readonly code: BlazeErrorCode;
|
|
4246
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;
|
|
@@ -385,6 +397,12 @@ interface RegistryOptions {
|
|
|
385
397
|
* delay a call, and by at most this much; later refreshes run in the
|
|
386
398
|
* background (stale-while-revalidate). */
|
|
387
399
|
timeoutMs?: number;
|
|
400
|
+
/** Route to addresses that only the fetched document supplies (a version
|
|
401
|
+
* released after this SDK). Default false: the document can list them, but
|
|
402
|
+
* resolve() only returns Router/Quoter addresses pinned in this package —
|
|
403
|
+
* the on-chain check of a remote entry reads the entry's own contracts, so
|
|
404
|
+
* it cannot tell a real deployment from a look-alike. */
|
|
405
|
+
remoteVersions?: boolean;
|
|
388
406
|
/** Called for every pin conflict or rejected document — never silently. */
|
|
389
407
|
onWarning?: (msg: string) => void;
|
|
390
408
|
}
|
|
@@ -394,6 +412,7 @@ declare class Registry {
|
|
|
394
412
|
private fetchedAt;
|
|
395
413
|
private lastError?;
|
|
396
414
|
private readonly mode;
|
|
415
|
+
private readonly remoteVersions;
|
|
397
416
|
private readonly url;
|
|
398
417
|
private readonly ttlMs;
|
|
399
418
|
private readonly fetchFn?;
|
|
@@ -422,6 +441,8 @@ declare class Registry {
|
|
|
422
441
|
/** Every deployed version on a chain, newest first. */
|
|
423
442
|
versionsOn(chainId: SupportedChainId): string[];
|
|
424
443
|
resolve(chainId: SupportedChainId, selector?: VersionSelector): ResolvedDeployment;
|
|
444
|
+
/** Router and Quoter both pinned in this package (not filled by a fetched document). */
|
|
445
|
+
private isPinned;
|
|
425
446
|
private latestKnownVersion;
|
|
426
447
|
/** chains × versions table (for dashboards, the MCP, debugging). */
|
|
427
448
|
table(): {
|
|
@@ -4240,7 +4261,7 @@ declare const CAUTION_IMPACT_BPS = 200;
|
|
|
4240
4261
|
declare function routeIsConsistent(route: Route, tokenIn: Address, tokenOut: Address): boolean;
|
|
4241
4262
|
declare function phoenixCheck(pv: Preview, tokenIn: Address, tokenOut: Address): QuoteChecks;
|
|
4242
4263
|
|
|
4243
|
-
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';
|
|
4244
4265
|
declare class BlazeError extends Error {
|
|
4245
4266
|
readonly code: BlazeErrorCode;
|
|
4246
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: {
|
|
@@ -5354,6 +5353,7 @@ var Registry = class {
|
|
|
5354
5353
|
fetchedAt = 0;
|
|
5355
5354
|
lastError;
|
|
5356
5355
|
mode;
|
|
5356
|
+
remoteVersions;
|
|
5357
5357
|
url;
|
|
5358
5358
|
ttlMs;
|
|
5359
5359
|
fetchFn;
|
|
@@ -5362,6 +5362,7 @@ var Registry = class {
|
|
|
5362
5362
|
overrides = /* @__PURE__ */ new Map();
|
|
5363
5363
|
constructor(opts = {}, overrides) {
|
|
5364
5364
|
this.mode = opts.mode ?? "auto";
|
|
5365
|
+
this.remoteVersions = opts.remoteVersions ?? false;
|
|
5365
5366
|
this.url = opts.url ?? DEPLOYMENTS_URL;
|
|
5366
5367
|
this.ttlMs = opts.ttlMs ?? 10 * 6e4;
|
|
5367
5368
|
this.fetchFn = opts.fetchFn ?? globalThis.fetch;
|
|
@@ -5493,7 +5494,7 @@ var Registry = class {
|
|
|
5493
5494
|
if (!isValidSelector(selector)) throw new BlazeError("bad_request", `bad version selector "${selector}"`);
|
|
5494
5495
|
const ov = this.overrides.get(chainId);
|
|
5495
5496
|
const sel = ov?.version && selector === "latest" ? ov.version : selector;
|
|
5496
|
-
const candidates = this.doc.versions.filter((v) => matchesSelector(v.version, sel) && isDeployed(v.chains[chainId])).sort((a, b) => compareVersions(b.version, a.version));
|
|
5497
|
+
const candidates = this.doc.versions.filter((v) => matchesSelector(v.version, sel) && isDeployed(v.chains[chainId])).filter((v) => this.remoteVersions || this.isPinned(v.version, chainId)).sort((a, b) => compareVersions(b.version, a.version));
|
|
5497
5498
|
const pick = candidates[0];
|
|
5498
5499
|
if (ov && (ov.router || ov.quoter)) {
|
|
5499
5500
|
const base = pick ? { ...pick.chains[chainId] } : {
|
|
@@ -5513,9 +5514,10 @@ var Registry = class {
|
|
|
5513
5514
|
}
|
|
5514
5515
|
if (!pick) {
|
|
5515
5516
|
const deployed = this.versionsOn(chainId);
|
|
5517
|
+
const remoteOnly = this.remoteVersions ? [] : deployed.filter((v) => matchesSelector(v, sel) && !this.isPinned(v, chainId));
|
|
5516
5518
|
throw new BlazeError(
|
|
5517
5519
|
"not_deployed",
|
|
5518
|
-
`no BlazePhoenix deployment matching version "${selector}" on chain ${chainId}` + (deployed.length ? ` (deployed: ${deployed.join(", ")})` : ""),
|
|
5520
|
+
`no BlazePhoenix deployment matching version "${selector}" on chain ${chainId}` + (deployed.length ? ` (deployed: ${deployed.join(", ")})` : "") + (remoteOnly.length ? ` \u2014 ${remoteOnly.join(", ")} is known only from the fetched registry; update the SDK, or set registry.remoteVersions after checking the addresses yourself` : ""),
|
|
5519
5521
|
{ details: { chainId, selector, deployed } }
|
|
5520
5522
|
);
|
|
5521
5523
|
}
|
|
@@ -5524,6 +5526,11 @@ var Registry = class {
|
|
|
5524
5526
|
const source = src("router") === "remote" || src("quoter") === "remote" ? "remote" : "embedded";
|
|
5525
5527
|
return { chainId, version: pick.version, status: pick.status, contracts: { ...set }, source };
|
|
5526
5528
|
}
|
|
5529
|
+
/** Router and Quoter both pinned in this package (not filled by a fetched document). */
|
|
5530
|
+
isPinned(version, chainId) {
|
|
5531
|
+
const src = (k) => this.fieldSource[`${version}|${chainId}|${k}`];
|
|
5532
|
+
return src("router") === "embedded" && src("quoter") === "embedded";
|
|
5533
|
+
}
|
|
5527
5534
|
latestKnownVersion(selector) {
|
|
5528
5535
|
const all = this.doc.versions.map((v) => v.version).sort((a, b) => compareVersions(b, a));
|
|
5529
5536
|
const m = selector ? all.find((v) => matchesSelector(v, selector)) : void 0;
|
|
@@ -5771,16 +5778,19 @@ var BlazePhoenix = class {
|
|
|
5771
5778
|
return { address: c.weth, native: true };
|
|
5772
5779
|
case "WETH":
|
|
5773
5780
|
return { address: c.weth, native: false };
|
|
5781
|
+
// `usdc` holds each chain's one dollar asset: USDG on Robinhood Chain, USDC
|
|
5782
|
+
// elsewhere. The other symbol names a different token there, so it is refused.
|
|
5774
5783
|
case "USDC":
|
|
5775
5784
|
case "USDG":
|
|
5776
|
-
return { address: c.usdc, native: false };
|
|
5785
|
+
if (s.toUpperCase() === (chainId === 4663 ? "USDG" : "USDC")) return { address: c.usdc, native: false };
|
|
5786
|
+
break;
|
|
5777
5787
|
case "BZPX":
|
|
5778
5788
|
if (c.bzpx) return { address: c.bzpx, native: false };
|
|
5779
5789
|
break;
|
|
5780
5790
|
}
|
|
5781
5791
|
throw new BlazeError(
|
|
5782
5792
|
"bad_request",
|
|
5783
|
-
`${side}: "${ref}" is not a 0x address or a built-in symbol (ETH, WETH, USDC, BZPX) on ${c.name} \u2014 pass the token address`
|
|
5793
|
+
`${side}: "${ref}" is not a 0x address or a built-in symbol (ETH, WETH, ${chainId === 4663 ? "USDG" : "USDC"}, BZPX) on ${c.name} \u2014 pass the token address`
|
|
5784
5794
|
);
|
|
5785
5795
|
}
|
|
5786
5796
|
async decimalsOf(client, chainId, t) {
|
|
@@ -6022,6 +6032,60 @@ var BlazePhoenix = class {
|
|
|
6022
6032
|
let encodedBy = "sdk";
|
|
6023
6033
|
let entry;
|
|
6024
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
|
+
};
|
|
6025
6089
|
if (features.previewAndEncode && !tIn.native && mode === "route") {
|
|
6026
6090
|
let call;
|
|
6027
6091
|
try {
|
|
@@ -6029,19 +6093,21 @@ var BlazePhoenix = class {
|
|
|
6029
6093
|
address: ctx.dep.contracts.quoter,
|
|
6030
6094
|
abi: QUOTER_ABI,
|
|
6031
6095
|
functionName: "previewAndEncodeWithMinOut",
|
|
6032
|
-
args: [tIn.address, tOut.address, amountIn, userMinOut, recipient, deadline]
|
|
6096
|
+
args: [tIn.address, tOut.address, amountIn, userMinOut, recipient, deadline],
|
|
6097
|
+
...pin
|
|
6033
6098
|
}) : await ctx.client.readContract({
|
|
6034
6099
|
address: ctx.dep.contracts.quoter,
|
|
6035
6100
|
abi: QUOTER_ABI,
|
|
6036
6101
|
functionName: "previewAndEncode",
|
|
6037
|
-
args: [tIn.address, tOut.address, amountIn, recipient, deadline]
|
|
6102
|
+
args: [tIn.address, tOut.address, amountIn, recipient, deadline],
|
|
6103
|
+
...pin
|
|
6038
6104
|
});
|
|
6039
6105
|
[pv, call] = r;
|
|
6040
6106
|
} catch (e) {
|
|
6041
6107
|
this.wrapReadError(e, "previewAndEncode");
|
|
6042
6108
|
}
|
|
6043
6109
|
assertExecutable(pv, tIn.address, tOut.address, call);
|
|
6044
|
-
minOut =
|
|
6110
|
+
minOut = await settleMin(pv);
|
|
6045
6111
|
verifySwapExactIn(call, {
|
|
6046
6112
|
tokenIn: tIn.address,
|
|
6047
6113
|
tokenOut: tOut.address,
|
|
@@ -6055,9 +6121,9 @@ var BlazePhoenix = class {
|
|
|
6055
6121
|
encodedBy = "quoter";
|
|
6056
6122
|
entry = "swapExactIn";
|
|
6057
6123
|
} else {
|
|
6058
|
-
({ 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));
|
|
6059
6125
|
assertExecutable(pv, tIn.address, tOut.address);
|
|
6060
|
-
minOut =
|
|
6126
|
+
minOut = await settleMin(pv);
|
|
6061
6127
|
if (mode === "best") {
|
|
6062
6128
|
entry = "swapBestExactIn";
|
|
6063
6129
|
data = encodeSwapBestExactIn(tIn.address, tOut.address, amountIn, minOut, recipient, deadline);
|
|
@@ -6104,7 +6170,8 @@ var BlazePhoenix = class {
|
|
|
6104
6170
|
slippageBps,
|
|
6105
6171
|
approval,
|
|
6106
6172
|
unwrapAfter: tOut.native,
|
|
6107
|
-
steps: approval ? [approval.tx, tx] : [tx]
|
|
6173
|
+
steps: approval ? [approval.tx, tx] : [tx],
|
|
6174
|
+
...exactOut !== void 0 ? { exactOut } : {}
|
|
6108
6175
|
};
|
|
6109
6176
|
}
|
|
6110
6177
|
/** eth_call the swap from `from` on your RPC: the realised amountOut if it
|
|
@@ -6170,6 +6237,12 @@ var BlazePhoenix = class {
|
|
|
6170
6237
|
if (r.status !== "success") throw new BlazeError("reverted", `approval transaction reverted (${approvalHash})`);
|
|
6171
6238
|
}
|
|
6172
6239
|
plan = { ...plan, approval: { ...plan.approval, current: plan.approval.amount } };
|
|
6240
|
+
if (Date.now() - plan.quote.quotedAt > maxAge) {
|
|
6241
|
+
if (!req) {
|
|
6242
|
+
throw new BlazeError("bad_request", `plan went older than ${maxAge}ms while the approval confirmed${approvalHash ? ` (${approvalHash})` : ""} \u2014 the swap was NOT sent; rebuild the plan, or pass \`request\` so it can be rebuilt`);
|
|
6243
|
+
}
|
|
6244
|
+
plan = await this.buildSwap({ ...req, from: req.from ?? account.address });
|
|
6245
|
+
}
|
|
6173
6246
|
}
|
|
6174
6247
|
if (opts.simulate ?? true) {
|
|
6175
6248
|
const sim = await this.simulate(plan, account.address);
|
|
@@ -6339,6 +6412,17 @@ function checkDeadlineSec(n) {
|
|
|
6339
6412
|
return n;
|
|
6340
6413
|
}
|
|
6341
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
|
+
}
|
|
6342
6426
|
function deepLink(opts = {}) {
|
|
6343
6427
|
const base = (opts.baseUrl ?? "https://blazephoenix.xyz").replace(/\/+$/, "");
|
|
6344
6428
|
const sp = new URLSearchParams();
|