@anywalletkit/protocol-swap2-core 0.4.1 → 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 +1 -0
- package/dist/{chunk-4H2JVYXT.js → chunk-3Y6HV2OL.js} +2 -2
- package/dist/{chunk-Y3VUEWYI.js → chunk-IC3MZIMB.js} +68 -13
- 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-GDRKGFLH.js → chunk-OWO27YBK.js} +2 -2
- package/dist/index.cjs +79 -21
- 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 +8 -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 +8 -5
- package/dist/server.js.map +1 -1
- package/dist/swap2/base.cjs +63 -11
- package/dist/swap2/base.cjs.map +1 -1
- package/dist/swap2/base.d.cts +21 -1
- package/dist/swap2/base.d.ts +21 -1
- package/dist/swap2/base.js +1 -1
- package/dist/swap2/single.cjs +63 -11
- 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-Y3VUEWYI.js.map +0 -1
- /package/dist/{chunk-4H2JVYXT.js.map → chunk-3Y6HV2OL.js.map} +0 -0
- /package/dist/{chunk-GDRKGFLH.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
|
/**
|
|
@@ -89,6 +90,15 @@ interface Swap2EngineConfig extends Swap2ProtocolConfig {
|
|
|
89
90
|
* called again with `requoted: true`, and throwing then revokes the allowance.
|
|
90
91
|
*/
|
|
91
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;
|
|
92
102
|
}
|
|
93
103
|
/** What `swap2()` is about to sign, handed to {@link Swap2EngineConfig.reviewExecution}. */
|
|
94
104
|
interface Swap2ExecutionPlan {
|
|
@@ -202,8 +212,18 @@ declare abstract class BaseSwap2Protocol extends Swap2Protocol {
|
|
|
202
212
|
protected protocolEnabled(): boolean;
|
|
203
213
|
/** Pair-level capability used when discovery specifies both endpoints. */
|
|
204
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>;
|
|
205
225
|
/** Swap2Options → the engine's QuoteParams (exact-in only). */
|
|
206
|
-
protected toParams(
|
|
226
|
+
protected toParams(given: Swap2Options, dry: boolean): QuoteParams;
|
|
207
227
|
private assertAccountChain;
|
|
208
228
|
protected assertFeeConfig(config?: Swap2ProtocolConfig): void;
|
|
209
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
|
/**
|
|
@@ -89,6 +90,15 @@ interface Swap2EngineConfig extends Swap2ProtocolConfig {
|
|
|
89
90
|
* called again with `requoted: true`, and throwing then revokes the allowance.
|
|
90
91
|
*/
|
|
91
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;
|
|
92
102
|
}
|
|
93
103
|
/** What `swap2()` is about to sign, handed to {@link Swap2EngineConfig.reviewExecution}. */
|
|
94
104
|
interface Swap2ExecutionPlan {
|
|
@@ -202,8 +212,18 @@ declare abstract class BaseSwap2Protocol extends Swap2Protocol {
|
|
|
202
212
|
protected protocolEnabled(): boolean;
|
|
203
213
|
/** Pair-level capability used when discovery specifies both endpoints. */
|
|
204
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>;
|
|
205
225
|
/** Swap2Options → the engine's QuoteParams (exact-in only). */
|
|
206
|
-
protected toParams(
|
|
226
|
+
protected toParams(given: Swap2Options, dry: boolean): QuoteParams;
|
|
207
227
|
private assertAccountChain;
|
|
208
228
|
protected assertFeeConfig(config?: Swap2ProtocolConfig): void;
|
|
209
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
|
@@ -273,10 +273,11 @@ function toSymbol(caip2, ref) {
|
|
|
273
273
|
if ((0, import_swap2_assets.ccAsset)(caip2, ref)) return ref;
|
|
274
274
|
return ref;
|
|
275
275
|
}
|
|
276
|
-
function toDestAddress(caip2, ref) {
|
|
276
|
+
function toDestAddress(caip2, ref, allowUnlisted = false) {
|
|
277
277
|
if (ref.startsWith("0x")) return ref;
|
|
278
278
|
const asset = (0, import_swap2_assets.ccAssetByToken)(caip2, ref) ?? (0, import_swap2_assets.ccAsset)(caip2, ref);
|
|
279
279
|
if (!asset) {
|
|
280
|
+
if (allowUnlisted && (0, import_swap2_assets.isTokenAddress)(caip2, ref)) return ref;
|
|
280
281
|
throw new Error(`swap2: unknown destination token '${ref}' on ${caip2}`);
|
|
281
282
|
}
|
|
282
283
|
return asset.contract ?? ZERO;
|
|
@@ -358,6 +359,15 @@ function mapStatus(s) {
|
|
|
358
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";
|
|
359
360
|
return s.destTxHash ? { status, transactions: [{ hash: s.destTxHash, type: "destination" }] } : { status };
|
|
360
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
|
+
}
|
|
361
371
|
var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
362
372
|
fromChain;
|
|
363
373
|
constructor(account, config) {
|
|
@@ -390,19 +400,61 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
390
400
|
pairSupported(fromChain, toChain) {
|
|
391
401
|
return this.chainSupported(fromChain) && this.chainSupported(toChain);
|
|
392
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
|
+
}
|
|
393
442
|
/** Swap2Options → the engine's QuoteParams (exact-in only). */
|
|
394
|
-
toParams(
|
|
443
|
+
toParams(given, dry) {
|
|
444
|
+
const options = withoutBlankAddresses(given);
|
|
395
445
|
if (options.fromTokenAmount == null) {
|
|
396
446
|
throw new Swap2UnsupportedOperationError("swap2: exact-out swap2 is not supported by the engine");
|
|
397
447
|
}
|
|
398
448
|
const destChain = toCaip2(options.toChain, this.fromChain);
|
|
399
449
|
const constraints = callerConstraints(options);
|
|
400
450
|
const amountIn = exactPositiveAmount(options.fromTokenAmount, "fromTokenAmount");
|
|
451
|
+
const source = this.sourceAsset(options);
|
|
401
452
|
const params = {
|
|
402
453
|
sourceChain: this.fromChain,
|
|
403
|
-
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 } : {},
|
|
404
456
|
destChain,
|
|
405
|
-
destToken: toDestAddress(destChain, options.toToken),
|
|
457
|
+
destToken: toDestAddress(destChain, options.toToken, this.unlistedAllowed()),
|
|
406
458
|
amountIn: amountIn.toString(),
|
|
407
459
|
destAddress: options.recipient ?? "",
|
|
408
460
|
dry,
|
|
@@ -458,7 +510,7 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
458
510
|
}
|
|
459
511
|
}
|
|
460
512
|
assertQuoteFeeCaps(q, options, config) {
|
|
461
|
-
const source =
|
|
513
|
+
const source = this.sourceAsset(options);
|
|
462
514
|
if (!source) throw new Error(`swap2: unknown source token '${options.fromToken}' on ${this.fromChain}`);
|
|
463
515
|
const token = source.contract ?? source.assetId;
|
|
464
516
|
const fees = q.fees?.map((fee) => ({ ...fee, amount: BigInt(fee.amount) }));
|
|
@@ -503,7 +555,7 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
503
555
|
* gave one.
|
|
504
556
|
*/
|
|
505
557
|
async quoteSwap2(options) {
|
|
506
|
-
const snapshot = snapshotOptions(options);
|
|
558
|
+
const snapshot = await this.prepareOptions(snapshotOptions(options));
|
|
507
559
|
const q = await this.resolveQuote(this.toParams(snapshot, true));
|
|
508
560
|
if (!q) {
|
|
509
561
|
const detail = this.noRouteDetail();
|
|
@@ -545,9 +597,9 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
545
597
|
this.assertFeeConfig(configSnapshot);
|
|
546
598
|
await this.assertAccountChain(signer);
|
|
547
599
|
const selfAddress = await signer.getAddress();
|
|
548
|
-
const recipient = snapshot.recipient ?? selfAddress;
|
|
549
|
-
const refundAddress = snapshot.refundAddress ?? selfAddress;
|
|
550
|
-
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 }));
|
|
551
603
|
const params = this.toParams(executionOptions, false);
|
|
552
604
|
const resolved = await this.resolveQuote(params);
|
|
553
605
|
if (!resolved) {
|
|
@@ -628,7 +680,7 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
628
680
|
}
|
|
629
681
|
let tokenId;
|
|
630
682
|
if (!unsigned.data && !unsigned.bodyBoc && !unsigned.typedData && !serialized) {
|
|
631
|
-
const src =
|
|
683
|
+
const src = this.sourceAsset(executionOptions);
|
|
632
684
|
if (src?.contract) {
|
|
633
685
|
if (this.fromChain.startsWith("eip155:")) {
|
|
634
686
|
unsigned = {
|
|
@@ -654,7 +706,7 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
654
706
|
if (tokenId && (cellBody !== void 0 || unsigned.memo !== void 0 && !tronSource && !nearSource && !tonSource)) {
|
|
655
707
|
throw new Error("swap2: token deposit with memo/cell payload is not implemented");
|
|
656
708
|
}
|
|
657
|
-
const source =
|
|
709
|
+
const source = this.sourceAsset(executionOptions);
|
|
658
710
|
if (!source) throw new Error(`swap2: unknown source token '${executionOptions.fromToken}' on ${this.fromChain}`);
|
|
659
711
|
const executionValue = BigInt(unsigned.value);
|
|
660
712
|
if (serialized) {
|