@anywalletkit/protocol-swap2-core 0.4.0 → 0.5.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 +2 -1
- package/dist/{chunk-4H2JVYXT.js → chunk-3Y6HV2OL.js} +2 -2
- package/dist/{chunk-W2PHJINC.js → chunk-IC3MZIMB.js} +95 -19
- package/dist/chunk-IC3MZIMB.js.map +1 -0
- package/dist/{chunk-SKV5BVXK.js → chunk-MNJTMSFN.js} +8 -2
- package/dist/chunk-MNJTMSFN.js.map +1 -0
- package/dist/{chunk-5RR76RKH.js → chunk-OWO27YBK.js} +2 -2
- package/dist/index.cjs +106 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +7 -5
- package/dist/remote.cjs +1 -0
- package/dist/remote.cjs.map +1 -1
- package/dist/remote.js +2 -2
- package/dist/server.cjs +50 -4
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +7 -0
- package/dist/server.d.ts +7 -0
- package/dist/server.js +14 -5
- package/dist/server.js.map +1 -1
- package/dist/swap2/base.cjs +90 -17
- package/dist/swap2/base.cjs.map +1 -1
- package/dist/swap2/base.d.cts +31 -2
- package/dist/swap2/base.d.ts +31 -2
- package/dist/swap2/base.js +1 -1
- package/dist/swap2/single.cjs +90 -17
- package/dist/swap2/single.cjs.map +1 -1
- package/dist/swap2/single.d.cts +1 -0
- package/dist/swap2/single.d.ts +1 -0
- package/dist/swap2/single.js +2 -2
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +6 -0
- package/dist/types.d.ts +6 -0
- package/dist/util.cjs +6 -0
- package/dist/util.cjs.map +1 -1
- package/dist/util.d.cts +12 -1
- package/dist/util.d.ts +12 -1
- package/dist/util.js +3 -1
- package/package.json +6 -6
- package/dist/chunk-SKV5BVXK.js.map +0 -1
- package/dist/chunk-W2PHJINC.js.map +0 -1
- /package/dist/{chunk-4H2JVYXT.js.map → chunk-3Y6HV2OL.js.map} +0 -0
- /package/dist/{chunk-5RR76RKH.js.map → chunk-OWO27YBK.js.map} +0 -0
package/dist/swap2/base.d.cts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Swap2Protocol, Swap2ProtocolConfig, Swap2Options, Swap2Fee, Swap2Quote, Swap2Result, Swap2StatusOptions, Swap2StatusResult, BridgeOptions, BridgeResult, SwapOptions, SwapResult, Swap2SupportedChain, Swap2SupportedTokensOptions, Swap2SupportedToken } from '@anywalletkit/core';
|
|
2
|
+
import { CcAsset } from '@anywalletkit/swap2-assets';
|
|
2
3
|
import { QuoteParams, Quote, CrossChainProvider } from '../types.cjs';
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -83,9 +84,21 @@ interface Swap2EngineConfig extends Swap2ProtocolConfig {
|
|
|
83
84
|
* check has passed, BEFORE any approval or signature. It receives a copy of
|
|
84
85
|
* exactly what will be signed; throwing (the user cancelled) aborts with
|
|
85
86
|
* nothing sent. A quote that expires while the gate is open is refused
|
|
86
|
-
* before the first approval.
|
|
87
|
+
* before the first approval. When the quote expires while the engine's own
|
|
88
|
+
* approval is being mined, the engine re-quotes once; if the fresh quote
|
|
89
|
+
* differs from the reviewed one (payload, gas, a worse output) the gate is
|
|
90
|
+
* called again with `requoted: true`, and throwing then revokes the allowance.
|
|
87
91
|
*/
|
|
88
92
|
reviewExecution?: (plan: Swap2ExecutionPlan) => Promise<void> | void;
|
|
93
|
+
/**
|
|
94
|
+
* Accept tokens the swap catalog does not list, named by their contract (EVM) or mint (Solana):
|
|
95
|
+
* tokens the user added at their own risk. Off by default. The source token's decimals are read
|
|
96
|
+
* with the account's `getTokenInfo` (a `fromTokenDecimals` that disagrees is refused); an account
|
|
97
|
+
* without it must be given `fromTokenDecimals`. Only providers that trade any token (LI.FI,
|
|
98
|
+
* Uniswap, Balancer, Fynd, Jupiter) quote them, and they have no USD value: the router cannot
|
|
99
|
+
* judge their price, so show the user the amounts.
|
|
100
|
+
*/
|
|
101
|
+
allowUnlistedTokens?: boolean;
|
|
89
102
|
}
|
|
90
103
|
/** What `swap2()` is about to sign, handed to {@link Swap2EngineConfig.reviewExecution}. */
|
|
91
104
|
interface Swap2ExecutionPlan {
|
|
@@ -108,6 +121,12 @@ interface Swap2ExecutionPlan {
|
|
|
108
121
|
amount: bigint;
|
|
109
122
|
chainId?: number;
|
|
110
123
|
}[];
|
|
124
|
+
/**
|
|
125
|
+
* `true` on a second review: the first quote expired while its approval was being mined, and
|
|
126
|
+
* the fresh one differs from what was reviewed (another payload, a worse output). The allowance
|
|
127
|
+
* is already in place, so `approvals` is empty; cancelling revokes it.
|
|
128
|
+
*/
|
|
129
|
+
requoted?: true;
|
|
111
130
|
/** The source leg exactly as the account will receive it. */
|
|
112
131
|
source: {
|
|
113
132
|
kind: "call";
|
|
@@ -193,8 +212,18 @@ declare abstract class BaseSwap2Protocol extends Swap2Protocol {
|
|
|
193
212
|
protected protocolEnabled(): boolean;
|
|
194
213
|
/** Pair-level capability used when discovery specifies both endpoints. */
|
|
195
214
|
protected pairSupported(fromChain: string, toChain: string): boolean;
|
|
215
|
+
private unlistedAllowed;
|
|
216
|
+
/** The source asset the options name: the catalog's, or (allowUnlistedTokens) an unlisted one with its decimals. */
|
|
217
|
+
protected sourceAsset(options: Swap2Options): CcAsset | undefined;
|
|
218
|
+
private readonly unlistedDecimals;
|
|
219
|
+
/**
|
|
220
|
+
* Options ready to quote: with `allowUnlistedTokens`, an unlisted source token gets its decimals,
|
|
221
|
+
* read from the chain through the account (cached per token) — a caller's `fromTokenDecimals` that
|
|
222
|
+
* disagrees is refused. Listed tokens and every option otherwise pass through unchanged.
|
|
223
|
+
*/
|
|
224
|
+
protected prepareOptions(options: Swap2Options): Promise<Swap2Options>;
|
|
196
225
|
/** Swap2Options → the engine's QuoteParams (exact-in only). */
|
|
197
|
-
protected toParams(
|
|
226
|
+
protected toParams(given: Swap2Options, dry: boolean): QuoteParams;
|
|
198
227
|
private assertAccountChain;
|
|
199
228
|
protected assertFeeConfig(config?: Swap2ProtocolConfig): void;
|
|
200
229
|
protected assertFeeCaps(fees: readonly Swap2Fee[] | undefined, sourceAmount: bigint, sourceToken: string, config?: Swap2ProtocolConfig): void;
|
package/dist/swap2/base.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Swap2Protocol, Swap2ProtocolConfig, Swap2Options, Swap2Fee, Swap2Quote, Swap2Result, Swap2StatusOptions, Swap2StatusResult, BridgeOptions, BridgeResult, SwapOptions, SwapResult, Swap2SupportedChain, Swap2SupportedTokensOptions, Swap2SupportedToken } from '@anywalletkit/core';
|
|
2
|
+
import { CcAsset } from '@anywalletkit/swap2-assets';
|
|
2
3
|
import { QuoteParams, Quote, CrossChainProvider } from '../types.js';
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -83,9 +84,21 @@ interface Swap2EngineConfig extends Swap2ProtocolConfig {
|
|
|
83
84
|
* check has passed, BEFORE any approval or signature. It receives a copy of
|
|
84
85
|
* exactly what will be signed; throwing (the user cancelled) aborts with
|
|
85
86
|
* nothing sent. A quote that expires while the gate is open is refused
|
|
86
|
-
* before the first approval.
|
|
87
|
+
* before the first approval. When the quote expires while the engine's own
|
|
88
|
+
* approval is being mined, the engine re-quotes once; if the fresh quote
|
|
89
|
+
* differs from the reviewed one (payload, gas, a worse output) the gate is
|
|
90
|
+
* called again with `requoted: true`, and throwing then revokes the allowance.
|
|
87
91
|
*/
|
|
88
92
|
reviewExecution?: (plan: Swap2ExecutionPlan) => Promise<void> | void;
|
|
93
|
+
/**
|
|
94
|
+
* Accept tokens the swap catalog does not list, named by their contract (EVM) or mint (Solana):
|
|
95
|
+
* tokens the user added at their own risk. Off by default. The source token's decimals are read
|
|
96
|
+
* with the account's `getTokenInfo` (a `fromTokenDecimals` that disagrees is refused); an account
|
|
97
|
+
* without it must be given `fromTokenDecimals`. Only providers that trade any token (LI.FI,
|
|
98
|
+
* Uniswap, Balancer, Fynd, Jupiter) quote them, and they have no USD value: the router cannot
|
|
99
|
+
* judge their price, so show the user the amounts.
|
|
100
|
+
*/
|
|
101
|
+
allowUnlistedTokens?: boolean;
|
|
89
102
|
}
|
|
90
103
|
/** What `swap2()` is about to sign, handed to {@link Swap2EngineConfig.reviewExecution}. */
|
|
91
104
|
interface Swap2ExecutionPlan {
|
|
@@ -108,6 +121,12 @@ interface Swap2ExecutionPlan {
|
|
|
108
121
|
amount: bigint;
|
|
109
122
|
chainId?: number;
|
|
110
123
|
}[];
|
|
124
|
+
/**
|
|
125
|
+
* `true` on a second review: the first quote expired while its approval was being mined, and
|
|
126
|
+
* the fresh one differs from what was reviewed (another payload, a worse output). The allowance
|
|
127
|
+
* is already in place, so `approvals` is empty; cancelling revokes it.
|
|
128
|
+
*/
|
|
129
|
+
requoted?: true;
|
|
111
130
|
/** The source leg exactly as the account will receive it. */
|
|
112
131
|
source: {
|
|
113
132
|
kind: "call";
|
|
@@ -193,8 +212,18 @@ declare abstract class BaseSwap2Protocol extends Swap2Protocol {
|
|
|
193
212
|
protected protocolEnabled(): boolean;
|
|
194
213
|
/** Pair-level capability used when discovery specifies both endpoints. */
|
|
195
214
|
protected pairSupported(fromChain: string, toChain: string): boolean;
|
|
215
|
+
private unlistedAllowed;
|
|
216
|
+
/** The source asset the options name: the catalog's, or (allowUnlistedTokens) an unlisted one with its decimals. */
|
|
217
|
+
protected sourceAsset(options: Swap2Options): CcAsset | undefined;
|
|
218
|
+
private readonly unlistedDecimals;
|
|
219
|
+
/**
|
|
220
|
+
* Options ready to quote: with `allowUnlistedTokens`, an unlisted source token gets its decimals,
|
|
221
|
+
* read from the chain through the account (cached per token) — a caller's `fromTokenDecimals` that
|
|
222
|
+
* disagrees is refused. Listed tokens and every option otherwise pass through unchanged.
|
|
223
|
+
*/
|
|
224
|
+
protected prepareOptions(options: Swap2Options): Promise<Swap2Options>;
|
|
196
225
|
/** Swap2Options → the engine's QuoteParams (exact-in only). */
|
|
197
|
-
protected toParams(
|
|
226
|
+
protected toParams(given: Swap2Options, dry: boolean): QuoteParams;
|
|
198
227
|
private assertAccountChain;
|
|
199
228
|
protected assertFeeConfig(config?: Swap2ProtocolConfig): void;
|
|
200
229
|
protected assertFeeCaps(fees: readonly Swap2Fee[] | undefined, sourceAmount: bigint, sourceToken: string, config?: Swap2ProtocolConfig): void;
|
package/dist/swap2/base.js
CHANGED
package/dist/swap2/single.cjs
CHANGED
|
@@ -195,6 +195,10 @@ function normalizeTypedDomain(domain) {
|
|
|
195
195
|
return chainId === void 0 || !Number.isSafeInteger(chainId) ? domain : { ...domain, chainId };
|
|
196
196
|
}
|
|
197
197
|
var DEFAULT_SERIALIZED_NATIVE_ALLOWANCE = 20000000n;
|
|
198
|
+
function reviewedIdentity(plan) {
|
|
199
|
+
const { feeUsd: _fee, etaSeconds: _eta, validUntilMs: _valid, approvals: _approvals, destAmount: _dest, requoted: _requoted, ...pinned } = plan;
|
|
200
|
+
return JSON.stringify(pinned, (_k, v) => typeof v === "bigint" ? v.toString() : v);
|
|
201
|
+
}
|
|
198
202
|
var SWAP2_ID_PREFIX = "awk1";
|
|
199
203
|
function encodeId(provider, intentId, sourceTxHash) {
|
|
200
204
|
const enc = (v) => encodeURIComponent(v).replace(/\./g, "%2E");
|
|
@@ -269,10 +273,11 @@ function toSymbol(caip2, ref) {
|
|
|
269
273
|
if ((0, import_swap2_assets.ccAsset)(caip2, ref)) return ref;
|
|
270
274
|
return ref;
|
|
271
275
|
}
|
|
272
|
-
function toDestAddress(caip2, ref) {
|
|
276
|
+
function toDestAddress(caip2, ref, allowUnlisted = false) {
|
|
273
277
|
if (ref.startsWith("0x")) return ref;
|
|
274
278
|
const asset = (0, import_swap2_assets.ccAssetByToken)(caip2, ref) ?? (0, import_swap2_assets.ccAsset)(caip2, ref);
|
|
275
279
|
if (!asset) {
|
|
280
|
+
if (allowUnlisted && (0, import_swap2_assets.isTokenAddress)(caip2, ref)) return ref;
|
|
276
281
|
throw new Error(`swap2: unknown destination token '${ref}' on ${caip2}`);
|
|
277
282
|
}
|
|
278
283
|
return asset.contract ?? ZERO;
|
|
@@ -354,6 +359,15 @@ function mapStatus(s) {
|
|
|
354
359
|
const status = s.state === "completed" ? "completed" : s.state === "action-required" ? "action-required" : s.state === "refund-pending" ? "refund-pending" : s.state === "partial" ? "partial" : s.state === "failed" ? "failed" : s.state === "refunded" ? "refunded" : s.state === "cancelled" ? "cancelled" : s.state === "expired" ? "expired" : "pending";
|
|
355
360
|
return s.destTxHash ? { status, transactions: [{ hash: s.destTxHash, type: "destination" }] } : { status };
|
|
356
361
|
}
|
|
362
|
+
function blankToUndefined(v) {
|
|
363
|
+
return typeof v === "string" && v.trim() === "" ? void 0 : v;
|
|
364
|
+
}
|
|
365
|
+
function withoutBlankAddresses(o) {
|
|
366
|
+
const { recipient, refundAddress, ...rest } = o;
|
|
367
|
+
const r = blankToUndefined(recipient);
|
|
368
|
+
const f = blankToUndefined(refundAddress);
|
|
369
|
+
return { ...rest, ...r !== void 0 ? { recipient: r } : {}, ...f !== void 0 ? { refundAddress: f } : {} };
|
|
370
|
+
}
|
|
357
371
|
var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
358
372
|
fromChain;
|
|
359
373
|
constructor(account, config) {
|
|
@@ -386,19 +400,61 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
386
400
|
pairSupported(fromChain, toChain) {
|
|
387
401
|
return this.chainSupported(fromChain) && this.chainSupported(toChain);
|
|
388
402
|
}
|
|
403
|
+
unlistedAllowed() {
|
|
404
|
+
return this._config.allowUnlistedTokens === true;
|
|
405
|
+
}
|
|
406
|
+
/** The source asset the options name: the catalog's, or (allowUnlistedTokens) an unlisted one with its decimals. */
|
|
407
|
+
sourceAsset(options) {
|
|
408
|
+
const decimals = options.fromTokenDecimals;
|
|
409
|
+
return (0, import_swap2_assets.resolveAsset)(this.fromChain, toSymbol(this.fromChain, options.fromToken), {
|
|
410
|
+
allowUnlisted: this.unlistedAllowed(),
|
|
411
|
+
...decimals !== void 0 ? { decimals } : {}
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
unlistedDecimals = /* @__PURE__ */ new Map();
|
|
415
|
+
/**
|
|
416
|
+
* Options ready to quote: with `allowUnlistedTokens`, an unlisted source token gets its decimals,
|
|
417
|
+
* read from the chain through the account (cached per token) — a caller's `fromTokenDecimals` that
|
|
418
|
+
* disagrees is refused. Listed tokens and every option otherwise pass through unchanged.
|
|
419
|
+
*/
|
|
420
|
+
async prepareOptions(options) {
|
|
421
|
+
if (!this.unlistedAllowed()) return options;
|
|
422
|
+
const ref = toSymbol(this.fromChain, options.fromToken);
|
|
423
|
+
if ((0, import_swap2_assets.resolveAsset)(this.fromChain, ref) || !(0, import_swap2_assets.isTokenAddress)(this.fromChain, ref)) return options;
|
|
424
|
+
const key = ref.startsWith("0x") ? ref.toLowerCase() : ref;
|
|
425
|
+
let decimals = this.unlistedDecimals.get(key);
|
|
426
|
+
if (decimals === void 0) {
|
|
427
|
+
const reader = this._account;
|
|
428
|
+
if (typeof reader?.getTokenInfo !== "function") {
|
|
429
|
+
if (options.fromTokenDecimals === void 0) {
|
|
430
|
+
throw new Swap2ValidationError(`swap2: '${ref}' is not in the catalog \u2014 pass fromTokenDecimals, or use an account that can read token info`);
|
|
431
|
+
}
|
|
432
|
+
return options;
|
|
433
|
+
}
|
|
434
|
+
decimals = (await reader.getTokenInfo(ref)).decimals;
|
|
435
|
+
this.unlistedDecimals.set(key, decimals);
|
|
436
|
+
}
|
|
437
|
+
if (options.fromTokenDecimals !== void 0 && options.fromTokenDecimals !== decimals) {
|
|
438
|
+
throw new Swap2ValidationError(`swap2: fromTokenDecimals ${options.fromTokenDecimals} does not match the token's ${decimals}`);
|
|
439
|
+
}
|
|
440
|
+
return snapshotOptions({ ...options, fromTokenDecimals: decimals });
|
|
441
|
+
}
|
|
389
442
|
/** Swap2Options → the engine's QuoteParams (exact-in only). */
|
|
390
|
-
toParams(
|
|
443
|
+
toParams(given, dry) {
|
|
444
|
+
const options = withoutBlankAddresses(given);
|
|
391
445
|
if (options.fromTokenAmount == null) {
|
|
392
446
|
throw new Swap2UnsupportedOperationError("swap2: exact-out swap2 is not supported by the engine");
|
|
393
447
|
}
|
|
394
448
|
const destChain = toCaip2(options.toChain, this.fromChain);
|
|
395
449
|
const constraints = callerConstraints(options);
|
|
396
450
|
const amountIn = exactPositiveAmount(options.fromTokenAmount, "fromTokenAmount");
|
|
451
|
+
const source = this.sourceAsset(options);
|
|
397
452
|
const params = {
|
|
398
453
|
sourceChain: this.fromChain,
|
|
399
|
-
sourceToken: toSymbol(this.fromChain, options.fromToken),
|
|
454
|
+
sourceToken: (0, import_swap2_assets.isUnlisted)(source) ? source.contract : toSymbol(this.fromChain, options.fromToken),
|
|
455
|
+
...(0, import_swap2_assets.isUnlisted)(source) ? { sourceDecimals: source.decimals } : {},
|
|
400
456
|
destChain,
|
|
401
|
-
destToken: toDestAddress(destChain, options.toToken),
|
|
457
|
+
destToken: toDestAddress(destChain, options.toToken, this.unlistedAllowed()),
|
|
402
458
|
amountIn: amountIn.toString(),
|
|
403
459
|
destAddress: options.recipient ?? "",
|
|
404
460
|
dry,
|
|
@@ -454,7 +510,7 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
454
510
|
}
|
|
455
511
|
}
|
|
456
512
|
assertQuoteFeeCaps(q, options, config) {
|
|
457
|
-
const source =
|
|
513
|
+
const source = this.sourceAsset(options);
|
|
458
514
|
if (!source) throw new Error(`swap2: unknown source token '${options.fromToken}' on ${this.fromChain}`);
|
|
459
515
|
const token = source.contract ?? source.assetId;
|
|
460
516
|
const fees = q.fees?.map((fee) => ({ ...fee, amount: BigInt(fee.amount) }));
|
|
@@ -499,7 +555,7 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
499
555
|
* gave one.
|
|
500
556
|
*/
|
|
501
557
|
async quoteSwap2(options) {
|
|
502
|
-
const snapshot = snapshotOptions(options);
|
|
558
|
+
const snapshot = await this.prepareOptions(snapshotOptions(options));
|
|
503
559
|
const q = await this.resolveQuote(this.toParams(snapshot, true));
|
|
504
560
|
if (!q) {
|
|
505
561
|
const detail = this.noRouteDetail();
|
|
@@ -541,9 +597,9 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
541
597
|
this.assertFeeConfig(configSnapshot);
|
|
542
598
|
await this.assertAccountChain(signer);
|
|
543
599
|
const selfAddress = await signer.getAddress();
|
|
544
|
-
const recipient = snapshot.recipient ?? selfAddress;
|
|
545
|
-
const refundAddress = snapshot.refundAddress ?? selfAddress;
|
|
546
|
-
const executionOptions = snapshotOptions({ ...snapshot, recipient, refundAddress });
|
|
600
|
+
const recipient = blankToUndefined(snapshot.recipient) ?? selfAddress;
|
|
601
|
+
const refundAddress = blankToUndefined(snapshot.refundAddress) ?? selfAddress;
|
|
602
|
+
const executionOptions = await this.prepareOptions(snapshotOptions({ ...snapshot, recipient, refundAddress }));
|
|
547
603
|
const params = this.toParams(executionOptions, false);
|
|
548
604
|
const resolved = await this.resolveQuote(params);
|
|
549
605
|
if (!resolved) {
|
|
@@ -624,7 +680,7 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
624
680
|
}
|
|
625
681
|
let tokenId;
|
|
626
682
|
if (!unsigned.data && !unsigned.bodyBoc && !unsigned.typedData && !serialized) {
|
|
627
|
-
const src =
|
|
683
|
+
const src = this.sourceAsset(executionOptions);
|
|
628
684
|
if (src?.contract) {
|
|
629
685
|
if (this.fromChain.startsWith("eip155:")) {
|
|
630
686
|
unsigned = {
|
|
@@ -650,7 +706,7 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
650
706
|
if (tokenId && (cellBody !== void 0 || unsigned.memo !== void 0 && !tronSource && !nearSource && !tonSource)) {
|
|
651
707
|
throw new Error("swap2: token deposit with memo/cell payload is not implemented");
|
|
652
708
|
}
|
|
653
|
-
const source =
|
|
709
|
+
const source = this.sourceAsset(executionOptions);
|
|
654
710
|
if (!source) throw new Error(`swap2: unknown source token '${executionOptions.fromToken}' on ${this.fromChain}`);
|
|
655
711
|
const executionValue = BigInt(unsigned.value);
|
|
656
712
|
if (serialized) {
|
|
@@ -706,7 +762,8 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
706
762
|
approvalAmounts = current === approvalAmount ? [] : [...usdtMainnet && current !== 0n ? [0n] : [], approvalAmount];
|
|
707
763
|
}
|
|
708
764
|
const review = this._config.reviewExecution;
|
|
709
|
-
|
|
765
|
+
let reviewed;
|
|
766
|
+
if (review && (!carried || carried.reviewed)) {
|
|
710
767
|
const chainId = unsigned.chainId !== void 0 ? { chainId: unsigned.chainId } : {};
|
|
711
768
|
const approvals = approvalAmounts.map((amount) => ({ token: source.contract, spender: unsigned.approvalAddress, amount, ...chainId }));
|
|
712
769
|
const plan = {
|
|
@@ -734,12 +791,28 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
734
791
|
...cellBody !== void 0 ? { cellBody: true } : {}
|
|
735
792
|
}
|
|
736
793
|
};
|
|
737
|
-
|
|
738
|
-
if (
|
|
739
|
-
|
|
794
|
+
const previous = carried?.reviewed;
|
|
795
|
+
if (!previous || reviewedIdentity(previous) !== reviewedIdentity(plan) || plan.destAmount < previous.destAmount) {
|
|
796
|
+
try {
|
|
797
|
+
reviewed = deepFreeze(structuredCloneSafe(previous ? { ...plan, requoted: true } : plan));
|
|
798
|
+
await review(reviewed);
|
|
799
|
+
if (q.validUntilMs > 0 && q.validUntilMs <= Date.now()) {
|
|
800
|
+
throw new Swap2QuoteError(`swap2: quote expired during review \u2014 ${previous ? "the allowance was revoked" : "nothing was signed"}`);
|
|
801
|
+
}
|
|
802
|
+
} catch (error) {
|
|
803
|
+
if (previous) await revokeApproval?.().catch(() => {
|
|
804
|
+
});
|
|
805
|
+
throw error;
|
|
806
|
+
}
|
|
740
807
|
}
|
|
741
808
|
}
|
|
742
|
-
|
|
809
|
+
try {
|
|
810
|
+
await this.assertNativeGas(signer, unsigned, approvalAmounts, source.contract ?? void 0, !!unsigned.typedData || serialized || !!tokenId);
|
|
811
|
+
} catch (error) {
|
|
812
|
+
if (carried) await revokeApproval?.().catch(() => {
|
|
813
|
+
});
|
|
814
|
+
throw error;
|
|
815
|
+
}
|
|
743
816
|
if (approvalAmounts.length) {
|
|
744
817
|
const approve = async (amount) => {
|
|
745
818
|
const sent2 = await signer.sendTransaction({
|
|
@@ -768,7 +841,7 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
768
841
|
if (q.validUntilMs > 0 && q.validUntilMs <= Date.now()) {
|
|
769
842
|
if (!carried && approvalAmounts.length && revokeApproval) {
|
|
770
843
|
this.emitPhase("requoting");
|
|
771
|
-
const handoff = { token: source.contract, spender: unsigned.approvalAddress, amount: approvalAmount, revoke: revokeApproval, adopted: false };
|
|
844
|
+
const handoff = { token: source.contract, spender: unsigned.approvalAddress, amount: approvalAmount, revoke: revokeApproval, adopted: false, ...reviewed ? { reviewed } : {} };
|
|
772
845
|
try {
|
|
773
846
|
return await this.executeSwap2(signer, snapshot, config, handoff);
|
|
774
847
|
} catch (error) {
|