@defuse-protocol/intents-sdk 0.16.4 → 0.17.1

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/dist/index.js CHANGED
@@ -3,9 +3,9 @@ import {
3
3
  assert as assert11,
4
4
  PUBLIC_NEAR_RPC_URLS,
5
5
  RETRY_CONFIGS as RETRY_CONFIGS2,
6
- configsByEnvironment as configsByEnvironment7,
6
+ configsByEnvironment as configsByEnvironment6,
7
7
  nearFailoverRpcProvider,
8
- solverRelay as solverRelay5
8
+ solverRelay as solverRelay3
9
9
  } from "@defuse-protocol/internal-utils";
10
10
  import hotOmniSdk from "@hot-labs/omni-sdk";
11
11
  import { stringify } from "viem";
@@ -13,11 +13,9 @@ import { stringify } from "viem";
13
13
  // src/bridges/aurora-engine-bridge/aurora-engine-bridge.ts
14
14
  import {
15
15
  assert as assert2,
16
- configsByEnvironment,
17
16
  getNearNep141MinStorageBalance,
18
17
  getNearNep141StorageBalance,
19
- solverRelay,
20
- utils as utils2
18
+ utils as utils3
21
19
  } from "@defuse-protocol/internal-utils";
22
20
 
23
21
  // src/constants/route-enum.ts
@@ -72,6 +70,194 @@ function withdrawalParamsInvariant(params) {
72
70
  );
73
71
  }
74
72
 
73
+ // src/lib/parse-defuse-asset-id.ts
74
+ import { utils as utils2 } from "@defuse-protocol/internal-utils";
75
+
76
+ // src/classes/errors.ts
77
+ import { BaseError } from "@defuse-protocol/internal-utils";
78
+ var FeeExceedsAmountError = class extends BaseError {
79
+ constructor(feeEstimation, amount) {
80
+ super("Amount too small to pay fee.", {
81
+ metaMessages: [
82
+ `Required fee: ${feeEstimation.amount}`,
83
+ `Withdrawal amount: ${amount}`
84
+ ],
85
+ name: "FeeExceedsAmountError"
86
+ });
87
+ this.feeEstimation = feeEstimation;
88
+ this.amount = amount;
89
+ }
90
+ };
91
+ var MinWithdrawalAmountError = class extends BaseError {
92
+ constructor(minAmount, requestedAmount, assetId) {
93
+ super("Withdrawal amount is below minimum required by the bridge.", {
94
+ metaMessages: [
95
+ `Asset ID: ${assetId}`,
96
+ `Minimum amount: ${minAmount}`,
97
+ `Requested amount: ${requestedAmount}`
98
+ ],
99
+ name: "MinWithdrawalAmountError"
100
+ });
101
+ this.minAmount = minAmount;
102
+ this.requestedAmount = requestedAmount;
103
+ this.assetId = assetId;
104
+ }
105
+ };
106
+ var UnsupportedDestinationMemoError = class extends BaseError {
107
+ constructor(blockchain, assetId) {
108
+ super("Destination memo is not supported for this blockchain.", {
109
+ details: "Destination memo is only supported for XRP Ledger withdrawals.",
110
+ metaMessages: [`Blockchain: ${blockchain}`, `Asset ID: ${assetId}`],
111
+ name: "UnsupportedDestinationMemoError"
112
+ });
113
+ this.blockchain = blockchain;
114
+ this.assetId = assetId;
115
+ }
116
+ };
117
+ var TrustlineNotFoundError = class extends BaseError {
118
+ constructor(destinationAddress, assetId, blockchain, tokenAddress) {
119
+ super("Destination address does not have a trustline for this asset.", {
120
+ details: "The destination address must establish a trustline before receiving this asset.",
121
+ metaMessages: [
122
+ `Blockchain: ${blockchain}`,
123
+ `Asset ID: ${assetId}`,
124
+ `Destination address: ${destinationAddress}`,
125
+ `Token address: ${tokenAddress}`
126
+ ],
127
+ name: "TrustlineNotFoundError"
128
+ });
129
+ this.destinationAddress = destinationAddress;
130
+ this.assetId = assetId;
131
+ this.blockchain = blockchain;
132
+ this.tokenAddress = tokenAddress;
133
+ }
134
+ };
135
+ var UnsupportedAssetIdError = class extends BaseError {
136
+ constructor(assetId, details) {
137
+ super("Asset ID is not supported.", {
138
+ details,
139
+ metaMessages: [`Asset ID: ${assetId}`],
140
+ name: "UnsupportedAssetIdError"
141
+ });
142
+ this.assetId = assetId;
143
+ }
144
+ };
145
+
146
+ // src/lib/parse-defuse-asset-id.ts
147
+ function parseDefuseAssetId(assetId) {
148
+ try {
149
+ return utils2.parseDefuseAssetId(assetId);
150
+ } catch {
151
+ throw new UnsupportedAssetIdError(assetId, "Invalid asset id format.");
152
+ }
153
+ }
154
+
155
+ // src/lib/estimate-fee.ts
156
+ import {
157
+ configsByEnvironment as configsByEnvironment2,
158
+ QuoteError,
159
+ solverRelay
160
+ } from "@defuse-protocol/internal-utils";
161
+
162
+ // src/lib/tokensUsdPricesHttpClient/apis.ts
163
+ import { request, configsByEnvironment } from "@defuse-protocol/internal-utils";
164
+ async function tokens(config) {
165
+ const response = await request({
166
+ url: new URL(
167
+ "tokens",
168
+ configsByEnvironment[config.env].managerConsoleBaseURL
169
+ ),
170
+ ...config,
171
+ fetchOptions: {
172
+ ...config.fetchOptions,
173
+ method: "GET"
174
+ }
175
+ });
176
+ return response.json();
177
+ }
178
+
179
+ // src/lib/estimate-fee.ts
180
+ async function getFeeQuote({
181
+ feeAmount,
182
+ feeAssetId,
183
+ tokenAssetId,
184
+ quoteOptions,
185
+ env,
186
+ logger
187
+ }) {
188
+ try {
189
+ return await solverRelay.getQuote({
190
+ quoteParams: {
191
+ defuse_asset_identifier_in: tokenAssetId,
192
+ defuse_asset_identifier_out: feeAssetId,
193
+ exact_amount_out: feeAmount.toString(),
194
+ wait_ms: quoteOptions?.waitMs
195
+ },
196
+ config: {
197
+ baseURL: configsByEnvironment2[env].solverRelayBaseURL,
198
+ logBalanceSufficient: false,
199
+ logger
200
+ }
201
+ });
202
+ } catch (err) {
203
+ if (!(err instanceof QuoteError)) {
204
+ throw err;
205
+ }
206
+ logger?.info(
207
+ "Can't get exact out quote, trying to get exact in quote with x1.2"
208
+ );
209
+ const prices = await tokens({ env });
210
+ const feeAssetPrice = prices.items.find(
211
+ (t) => t.defuse_asset_id === feeAssetId
212
+ );
213
+ const tokenAssetPrice = prices.items.find(
214
+ (t) => t.defuse_asset_id === tokenAssetId
215
+ );
216
+ if (feeAssetPrice == null || tokenAssetPrice == null) {
217
+ throw err;
218
+ }
219
+ const USD_SCALE = 1e6;
220
+ const feePriceScaled = BigInt(Math.round(feeAssetPrice.price * USD_SCALE));
221
+ const tokenPriceScaled = BigInt(
222
+ Math.round(tokenAssetPrice.price * USD_SCALE)
223
+ );
224
+ const feeDecimals = BigInt(feeAssetPrice.decimals);
225
+ const tokenDecimals = BigInt(tokenAssetPrice.decimals);
226
+ const num = feeAmount * feePriceScaled * 12n * 10n ** tokenDecimals;
227
+ const den = tokenPriceScaled * 10n ** feeDecimals * 10n;
228
+ let exactAmountIn = num / den;
229
+ if (num % den !== 0n) exactAmountIn += 1n;
230
+ if (exactAmountIn === 0n) exactAmountIn = 1n;
231
+ const quote = await solverRelay.getQuote({
232
+ quoteParams: {
233
+ defuse_asset_identifier_in: tokenAssetId,
234
+ defuse_asset_identifier_out: feeAssetId,
235
+ exact_amount_in: exactAmountIn.toString(),
236
+ wait_ms: quoteOptions?.waitMs
237
+ },
238
+ config: {
239
+ baseURL: configsByEnvironment2[env].solverRelayBaseURL,
240
+ logBalanceSufficient: false,
241
+ logger
242
+ }
243
+ });
244
+ const RATIO_SCALE = 1000n;
245
+ const actualRatio = BigInt(quote.amount_out) * RATIO_SCALE / feeAmount;
246
+ const actualRatioNumber = Number(actualRatio) / Number(RATIO_SCALE);
247
+ if (actualRatio > 1500n) {
248
+ logger?.warn(
249
+ `Quote amount_out ratio is too high: ${actualRatioNumber.toFixed(2)}x`
250
+ );
251
+ throw err;
252
+ }
253
+ if (BigInt(quote.amount_out) < feeAmount) {
254
+ logger?.warn("Quote amount_out is less than feeAmount");
255
+ throw err;
256
+ }
257
+ return quote;
258
+ }
259
+ }
260
+
75
261
  // src/bridges/aurora-engine-bridge/aurora-engine-bridge.ts
76
262
  var AuroraEngineBridge = class {
77
263
  constructor({
@@ -84,11 +270,19 @@ var AuroraEngineBridge = class {
84
270
  is(routeConfig) {
85
271
  return routeConfig.route === RouteEnum.VirtualChain;
86
272
  }
87
- supports(params) {
88
- if ("routeConfig" in params && params.routeConfig != null) {
89
- return this.is(params.routeConfig);
273
+ async supports(params) {
274
+ if (params.routeConfig == null || !this.is(params.routeConfig)) {
275
+ return false;
90
276
  }
91
- return false;
277
+ const assetInfo = parseDefuseAssetId(params.assetId);
278
+ const isValid = assetInfo.standard === "nep141";
279
+ if (!isValid) {
280
+ throw new UnsupportedAssetIdError(
281
+ params.assetId,
282
+ "`assetId` does not match `routeConfig`."
283
+ );
284
+ }
285
+ return isValid;
92
286
  }
93
287
  parseAssetId() {
94
288
  return null;
@@ -125,7 +319,7 @@ var AuroraEngineBridge = class {
125
319
  }
126
320
  async estimateWithdrawalFee(args) {
127
321
  withdrawalParamsInvariant(args.withdrawalParams);
128
- const { contractId: tokenAccountId, standard } = utils2.parseDefuseAssetId(
322
+ const { contractId: tokenAccountId, standard } = utils3.parseDefuseAssetId(
129
323
  args.withdrawalParams.assetId
130
324
  );
131
325
  assert2(standard === "nep141", "Only NEP-141 is supported");
@@ -148,18 +342,13 @@ var AuroraEngineBridge = class {
148
342
  }
149
343
  const feeAssetId = NEAR_NATIVE_ASSET_ID;
150
344
  const feeAmount = minStorageBalance - userStorageBalance;
151
- const feeQuote = args.withdrawalParams.assetId === feeAssetId ? null : await solverRelay.getQuote({
152
- quoteParams: {
153
- defuse_asset_identifier_in: args.withdrawalParams.assetId,
154
- defuse_asset_identifier_out: feeAssetId,
155
- exact_amount_out: feeAmount.toString(),
156
- wait_ms: args.quoteOptions?.waitMs
157
- },
158
- config: {
159
- baseURL: configsByEnvironment[this.env].solverRelayBaseURL,
160
- logBalanceSufficient: false,
161
- logger: args.logger
162
- }
345
+ const feeQuote = args.withdrawalParams.assetId === feeAssetId ? null : await getFeeQuote({
346
+ feeAmount,
347
+ feeAssetId,
348
+ tokenAssetId: args.withdrawalParams.assetId,
349
+ logger: args.logger,
350
+ env: this.env,
351
+ quoteOptions: args.quoteOptions
163
352
  });
164
353
  return {
165
354
  amount: feeQuote ? BigInt(feeQuote.amount_in) : feeAmount,
@@ -174,11 +363,9 @@ var AuroraEngineBridge = class {
174
363
  // src/bridges/direct-bridge/direct-bridge.ts
175
364
  import {
176
365
  assert as assert5,
177
- configsByEnvironment as configsByEnvironment2,
178
366
  getNearNep141MinStorageBalance as getNearNep141MinStorageBalance2,
179
367
  getNearNep141StorageBalance as getNearNep141StorageBalance2,
180
- solverRelay as solverRelay2,
181
- utils as utils4
368
+ utils as utils5
182
369
  } from "@defuse-protocol/internal-utils";
183
370
 
184
371
  // src/constants/bridge-name-enum.ts
@@ -227,7 +414,7 @@ function getEIP155ChainId(chain) {
227
414
  var NEAR_NATIVE_ASSET_ID2 = "nep141:wrap.near";
228
415
 
229
416
  // src/bridges/direct-bridge/direct-bridge-utils.ts
230
- import { assert as assert4, utils as utils3 } from "@defuse-protocol/internal-utils";
417
+ import { assert as assert4, utils as utils4 } from "@defuse-protocol/internal-utils";
231
418
  function createWithdrawIntentPrimitive2(params) {
232
419
  if (params.assetId === NEAR_NATIVE_ASSET_ID2 && // Ensure `msg` is not passed, because `native_withdraw` intent doesn't support `msg`
233
420
  params.msg === void 0) {
@@ -237,7 +424,7 @@ function createWithdrawIntentPrimitive2(params) {
237
424
  amount: params.amount.toString()
238
425
  };
239
426
  }
240
- const { contractId: tokenAccountId, standard } = utils3.parseDefuseAssetId(
427
+ const { contractId: tokenAccountId, standard } = utils4.parseDefuseAssetId(
241
428
  params.assetId
242
429
  );
243
430
  assert4(standard === "nep141", "Only NEP-141 is supported");
@@ -269,19 +456,22 @@ var DirectBridge = class {
269
456
  is(routeConfig) {
270
457
  return routeConfig.route === RouteEnum.NearWithdrawal;
271
458
  }
272
- supports(params) {
273
- let result = true;
274
- if ("routeConfig" in params && params.routeConfig != null) {
275
- result && (result = this.is(params.routeConfig));
276
- }
277
- try {
278
- return result && this.parseAssetId(params.assetId) != null;
279
- } catch {
459
+ async supports(params) {
460
+ if (params.routeConfig != null && !this.is(params.routeConfig)) {
280
461
  return false;
281
462
  }
463
+ const assetInfo = this.parseAssetId(params.assetId);
464
+ const isValid = assetInfo != null;
465
+ if (!isValid && params.routeConfig != null) {
466
+ throw new UnsupportedAssetIdError(
467
+ params.assetId,
468
+ "`assetId` does not match `routeConfig`."
469
+ );
470
+ }
471
+ return isValid;
282
472
  }
283
473
  parseAssetId(assetId) {
284
- const parsed = utils4.parseDefuseAssetId(assetId);
474
+ const parsed = parseDefuseAssetId(assetId);
285
475
  if (parsed.standard === "nep141") {
286
476
  return Object.assign(parsed, {
287
477
  blockchain: Chains.Near,
@@ -322,7 +512,7 @@ var DirectBridge = class {
322
512
  }
323
513
  async estimateWithdrawalFee(args) {
324
514
  withdrawalParamsInvariant2(args.withdrawalParams);
325
- const { contractId: tokenAccountId, standard } = utils4.parseDefuseAssetId(
515
+ const { contractId: tokenAccountId, standard } = utils5.parseDefuseAssetId(
326
516
  args.withdrawalParams.assetId
327
517
  );
328
518
  assert5(standard === "nep141", "Only NEP-141 is supported");
@@ -354,18 +544,13 @@ var DirectBridge = class {
354
544
  }
355
545
  const feeAssetId = NEAR_NATIVE_ASSET_ID2;
356
546
  const feeAmount = minStorageBalance - userStorageBalance;
357
- const feeQuote = args.withdrawalParams.assetId === feeAssetId ? null : await solverRelay2.getQuote({
358
- quoteParams: {
359
- defuse_asset_identifier_in: args.withdrawalParams.assetId,
360
- defuse_asset_identifier_out: feeAssetId,
361
- exact_amount_out: feeAmount.toString(),
362
- wait_ms: args.quoteOptions?.waitMs
363
- },
364
- config: {
365
- baseURL: configsByEnvironment2[this.env].solverRelayBaseURL,
366
- logBalanceSufficient: false,
367
- logger: args.logger
368
- }
547
+ const feeQuote = args.withdrawalParams.assetId === feeAssetId ? null : await getFeeQuote({
548
+ feeAmount,
549
+ feeAssetId,
550
+ tokenAssetId: args.withdrawalParams.assetId,
551
+ logger: args.logger,
552
+ env: this.env,
553
+ quoteOptions: args.quoteOptions
369
554
  });
370
555
  return {
371
556
  amount: feeQuote ? BigInt(feeQuote.amount_in) : feeAmount,
@@ -380,74 +565,12 @@ var DirectBridge = class {
380
565
  // src/bridges/hot-bridge/hot-bridge.ts
381
566
  import {
382
567
  assert as assert7,
383
- RETRY_CONFIGS,
384
- configsByEnvironment as configsByEnvironment3,
385
- utils as internalUtils,
386
- solverRelay as solverRelay3
568
+ RETRY_CONFIGS
387
569
  } from "@defuse-protocol/internal-utils";
388
- import { utils as utils5 } from "@hot-labs/omni-sdk";
570
+ import { OMNI_HOT_V2 } from "@hot-labs/omni-sdk";
571
+ import { utils as utils6 } from "@hot-labs/omni-sdk";
389
572
  import { retry } from "@lifeomic/attempt";
390
573
 
391
- // src/classes/errors.ts
392
- import { BaseError } from "@defuse-protocol/internal-utils";
393
- var FeeExceedsAmountError = class extends BaseError {
394
- constructor(feeEstimation, amount) {
395
- super("Amount too small to pay fee.", {
396
- metaMessages: [
397
- `Required fee: ${feeEstimation.amount}`,
398
- `Withdrawal amount: ${amount}`
399
- ],
400
- name: "FeeExceedsAmountError"
401
- });
402
- this.feeEstimation = feeEstimation;
403
- this.amount = amount;
404
- }
405
- };
406
- var MinWithdrawalAmountError = class extends BaseError {
407
- constructor(minAmount, requestedAmount, assetId) {
408
- super("Withdrawal amount is below minimum required by the bridge.", {
409
- metaMessages: [
410
- `Asset ID: ${assetId}`,
411
- `Minimum amount: ${minAmount}`,
412
- `Requested amount: ${requestedAmount}`
413
- ],
414
- name: "MinWithdrawalAmountError"
415
- });
416
- this.minAmount = minAmount;
417
- this.requestedAmount = requestedAmount;
418
- this.assetId = assetId;
419
- }
420
- };
421
- var UnsupportedDestinationMemoError = class extends BaseError {
422
- constructor(blockchain, assetId) {
423
- super("Destination memo is not supported for this blockchain.", {
424
- details: "Destination memo is only supported for XRP Ledger withdrawals.",
425
- metaMessages: [`Blockchain: ${blockchain}`, `Asset ID: ${assetId}`],
426
- name: "UnsupportedDestinationMemoError"
427
- });
428
- this.blockchain = blockchain;
429
- this.assetId = assetId;
430
- }
431
- };
432
- var TrustlineNotFoundError = class extends BaseError {
433
- constructor(destinationAddress, assetId, blockchain, tokenAddress) {
434
- super("Destination address does not have a trustline for this asset.", {
435
- details: "The destination address must establish a trustline before receiving this asset.",
436
- metaMessages: [
437
- `Blockchain: ${blockchain}`,
438
- `Asset ID: ${assetId}`,
439
- `Destination address: ${destinationAddress}`,
440
- `Token address: ${tokenAddress}`
441
- ],
442
- name: "TrustlineNotFoundError"
443
- });
444
- this.destinationAddress = destinationAddress;
445
- this.assetId = assetId;
446
- this.blockchain = blockchain;
447
- this.tokenAddress = tokenAddress;
448
- }
449
- };
450
-
451
574
  // src/bridges/hot-bridge/error.ts
452
575
  import { BaseError as BaseError2 } from "@defuse-protocol/internal-utils";
453
576
  var HotWithdrawalPendingError = class extends BaseError2 {
@@ -557,37 +680,56 @@ var HotBridge = class {
557
680
  is(routeConfig) {
558
681
  return routeConfig.route === RouteEnum.HotBridge;
559
682
  }
560
- supports(params) {
561
- let result = true;
562
- if ("routeConfig" in params && params.routeConfig != null) {
563
- result && (result = this.is(params.routeConfig));
564
- }
565
- try {
566
- return result && this.parseAssetId(params.assetId) != null;
567
- } catch {
683
+ async supports(params) {
684
+ if (params.routeConfig != null && !this.is(params.routeConfig)) {
568
685
  return false;
569
686
  }
687
+ const assetInfo = this.parseAssetId(params.assetId);
688
+ const isValid = assetInfo != null;
689
+ if (!isValid && params.routeConfig != null) {
690
+ throw new UnsupportedAssetIdError(
691
+ params.assetId,
692
+ "`assetId` does not match `routeConfig`."
693
+ );
694
+ }
695
+ return isValid;
570
696
  }
571
697
  parseAssetId(assetId) {
572
- const parsed = internalUtils.parseDefuseAssetId(assetId);
573
- if (parsed.contractId === utils5.OMNI_HOT_V2) {
574
- assert7(
575
- parsed.standard === "nep245",
576
- "NEP-245 is supported only for HOT bridge"
698
+ const parsed = parseDefuseAssetId(assetId);
699
+ const contractIdSatisfies = parsed.contractId === OMNI_HOT_V2;
700
+ if (!contractIdSatisfies) {
701
+ return null;
702
+ }
703
+ if (parsed.standard !== "nep245") {
704
+ throw new UnsupportedAssetIdError(
705
+ assetId,
706
+ 'Should start with "nep245:".'
577
707
  );
578
- const [chainId, address] = utils5.fromOmni(parsed.tokenId).split(":");
579
- assert7(chainId != null, "Chain ID is not found");
580
- assert7(address != null, "Address is not found");
581
- return Object.assign(
582
- parsed,
583
- {
584
- blockchain: hotNetworkIdToCAIP2(chainId),
585
- bridgeName: BridgeNameEnum.Hot
586
- },
587
- address === "native" ? { native: true } : { address }
708
+ }
709
+ const [chainId, address] = utils6.fromOmni(parsed.tokenId).split(":");
710
+ if (chainId == null || address == null) {
711
+ throw new UnsupportedAssetIdError(
712
+ assetId,
713
+ "Asset has invalid token id format."
588
714
  );
589
715
  }
590
- return null;
716
+ let blockchain;
717
+ try {
718
+ blockchain = hotNetworkIdToCAIP2(chainId);
719
+ } catch {
720
+ throw new UnsupportedAssetIdError(
721
+ assetId,
722
+ "Asset belongs to unknown blockchain."
723
+ );
724
+ }
725
+ return Object.assign(
726
+ parsed,
727
+ {
728
+ blockchain,
729
+ bridgeName: BridgeNameEnum.Hot
730
+ },
731
+ address === "native" ? { native: true } : { address }
732
+ );
591
733
  }
592
734
  async createWithdrawalIntents(args) {
593
735
  const assetInfo = this.parseAssetId(args.withdrawalParams.assetId);
@@ -664,23 +806,19 @@ var HotBridge = class {
664
806
  const assetInfo = this.parseAssetId(args.withdrawalParams.assetId);
665
807
  assert7(assetInfo != null, "Asset is not supported");
666
808
  hotBlockchainInvariant(assetInfo.blockchain);
667
- const { gasPrice: feeAmount } = await this.hotSdk.getGaslessWithdrawFee(
668
- toHotNetworkId(assetInfo.blockchain),
669
- args.withdrawalParams.destinationAddress
670
- );
809
+ const { gasPrice: feeAmount } = await this.hotSdk.getGaslessWithdrawFee({
810
+ chain: toHotNetworkId(assetInfo.blockchain),
811
+ token: "native" in assetInfo ? "native" : assetInfo.address,
812
+ receiver: args.withdrawalParams.destinationAddress
813
+ });
671
814
  const feeAssetId = getFeeAssetIdForChain(assetInfo.blockchain);
672
- const feeQuote = args.withdrawalParams.assetId === feeAssetId || feeAmount === 0n ? null : await solverRelay3.getQuote({
673
- quoteParams: {
674
- defuse_asset_identifier_in: args.withdrawalParams.assetId,
675
- defuse_asset_identifier_out: feeAssetId,
676
- exact_amount_out: feeAmount.toString(),
677
- wait_ms: args.quoteOptions?.waitMs
678
- },
679
- config: {
680
- baseURL: configsByEnvironment3[this.env].solverRelayBaseURL,
681
- logBalanceSufficient: false,
682
- logger: args.logger
683
- }
815
+ const feeQuote = args.withdrawalParams.assetId === feeAssetId || feeAmount === 0n ? null : await getFeeQuote({
816
+ feeAmount,
817
+ feeAssetId,
818
+ tokenAssetId: args.withdrawalParams.assetId,
819
+ logger: args.logger,
820
+ env: this.env,
821
+ quoteOptions: args.quoteOptions
684
822
  });
685
823
  return {
686
824
  amount: feeQuote ? BigInt(feeQuote.amount_in) : feeAmount,
@@ -734,7 +872,7 @@ var IntentsBridge = class {
734
872
  is(routeConfig) {
735
873
  return routeConfig.route === RouteEnum.InternalTransfer;
736
874
  }
737
- supports(params) {
875
+ async supports(params) {
738
876
  if ("routeConfig" in params && params.routeConfig != null) {
739
877
  return this.is(params.routeConfig);
740
878
  }
@@ -775,16 +913,16 @@ var IntentsBridge = class {
775
913
  // src/bridges/poa-bridge/poa-bridge.ts
776
914
  import {
777
915
  assert as assert8,
778
- configsByEnvironment as configsByEnvironment4,
916
+ configsByEnvironment as configsByEnvironment3,
779
917
  poaBridge,
780
- utils as utils7
918
+ utils as utils8
781
919
  } from "@defuse-protocol/internal-utils";
782
920
  import TTLCache from "@isaacs/ttlcache";
783
921
 
784
922
  // src/bridges/poa-bridge/poa-bridge-utils.ts
785
- import { utils as utils6 } from "@defuse-protocol/internal-utils";
923
+ import { utils as utils7 } from "@defuse-protocol/internal-utils";
786
924
  function createWithdrawIntentPrimitive3(params) {
787
- const { contractId: tokenAccountId } = utils6.parseDefuseAssetId(
925
+ const { contractId: tokenAccountId } = utils7.parseDefuseAssetId(
788
926
  params.assetId
789
927
  );
790
928
  return {
@@ -865,30 +1003,43 @@ var PoaBridge = class {
865
1003
  is(routeConfig) {
866
1004
  return routeConfig.route === RouteEnum.PoaBridge;
867
1005
  }
868
- supports(params) {
869
- let result = true;
870
- if ("routeConfig" in params && params.routeConfig != null) {
871
- result && (result = this.is(params.routeConfig));
872
- }
873
- try {
874
- return result && this.parseAssetId(params.assetId) != null;
875
- } catch {
1006
+ async supports(params) {
1007
+ if (params.routeConfig != null && !this.is(params.routeConfig)) {
876
1008
  return false;
877
1009
  }
1010
+ const assetInfo = this.parseAssetId(params.assetId);
1011
+ const isValid = assetInfo != null;
1012
+ if (!isValid && params.routeConfig != null) {
1013
+ throw new UnsupportedAssetIdError(
1014
+ params.assetId,
1015
+ "`assetId` does not match `routeConfig`."
1016
+ );
1017
+ }
1018
+ return isValid;
878
1019
  }
879
1020
  parseAssetId(assetId) {
880
- const parsed = utils7.parseDefuseAssetId(assetId);
881
- if (parsed.contractId.endsWith(
882
- `.${configsByEnvironment4[this.env].poaTokenFactoryContractID}`
883
- )) {
884
- return Object.assign(parsed, {
885
- blockchain: contractIdToCaip2(parsed.contractId),
886
- bridgeName: BridgeNameEnum.Poa,
887
- address: ""
888
- // todo: derive address (or native)
889
- });
1021
+ const parsed = parseDefuseAssetId(assetId);
1022
+ const contractIdSatisfies = parsed.contractId.endsWith(
1023
+ `.${configsByEnvironment3[this.env].poaTokenFactoryContractID}`
1024
+ );
1025
+ if (!contractIdSatisfies) {
1026
+ return null;
890
1027
  }
891
- return null;
1028
+ let blockchain;
1029
+ try {
1030
+ blockchain = contractIdToCaip2(parsed.contractId);
1031
+ } catch {
1032
+ throw new UnsupportedAssetIdError(
1033
+ assetId,
1034
+ "Asset belongs to unknown blockchain."
1035
+ );
1036
+ }
1037
+ return Object.assign(parsed, {
1038
+ blockchain,
1039
+ bridgeName: BridgeNameEnum.Poa,
1040
+ address: ""
1041
+ // todo: derive address (or native)
1042
+ });
892
1043
  }
893
1044
  createWithdrawalIntents(args) {
894
1045
  const intent = createWithdrawIntentPrimitive3({
@@ -907,11 +1058,11 @@ var PoaBridge = class {
907
1058
  async validateWithdrawal(args) {
908
1059
  const assetInfo = this.parseAssetId(args.assetId);
909
1060
  assert8(assetInfo != null, "Asset is not supported");
910
- const { tokens } = await this.getCachedSupportedTokens(
1061
+ const { tokens: tokens2 } = await this.getCachedSupportedTokens(
911
1062
  [toPoaNetwork(assetInfo.blockchain)],
912
1063
  args.logger
913
1064
  );
914
- const tokenInfo = tokens.find(
1065
+ const tokenInfo = tokens2.find(
915
1066
  (token) => token.intents_token_id === args.assetId
916
1067
  );
917
1068
  if (tokenInfo != null) {
@@ -930,13 +1081,13 @@ var PoaBridge = class {
930
1081
  assert8(assetInfo != null, "Asset is not supported");
931
1082
  const estimation = await poaBridge.httpClient.getWithdrawalEstimate(
932
1083
  {
933
- token: utils7.getTokenAccountId(args.withdrawalParams.assetId),
1084
+ token: utils8.getTokenAccountId(args.withdrawalParams.assetId),
934
1085
  address: args.withdrawalParams.destinationAddress,
935
1086
  // biome-ignore lint/suspicious/noExplicitAny: <explanation>
936
1087
  chain: toPoaNetwork(assetInfo.blockchain)
937
1088
  },
938
1089
  {
939
- baseURL: configsByEnvironment4[this.env].poaBridgeBaseURL,
1090
+ baseURL: configsByEnvironment3[this.env].poaBridgeBaseURL,
940
1091
  logger: args.logger
941
1092
  }
942
1093
  );
@@ -951,7 +1102,7 @@ var PoaBridge = class {
951
1102
  index: args.index,
952
1103
  signal: args.signal ?? new AbortController().signal,
953
1104
  retryOptions: args.retryOptions,
954
- baseURL: configsByEnvironment4[this.env].poaBridgeBaseURL,
1105
+ baseURL: configsByEnvironment3[this.env].poaBridgeBaseURL,
955
1106
  logger: args.logger
956
1107
  });
957
1108
  return { hash: withdrawalStatus.destinationTxHash };
@@ -969,7 +1120,7 @@ var PoaBridge = class {
969
1120
  const data = await poaBridge.httpClient.getSupportedTokens(
970
1121
  { chains },
971
1122
  {
972
- baseURL: configsByEnvironment4[this.env].poaBridgeBaseURL,
1123
+ baseURL: configsByEnvironment3[this.env].poaBridgeBaseURL,
973
1124
  logger
974
1125
  }
975
1126
  );
@@ -992,7 +1143,7 @@ var PUBLIC_STELLAR_RPC_URLS = {
992
1143
 
993
1144
  // src/intents/intent-executer-impl/intent-executer.ts
994
1145
  import {
995
- configsByEnvironment as configsByEnvironment5
1146
+ configsByEnvironment as configsByEnvironment4
996
1147
  } from "@defuse-protocol/internal-utils";
997
1148
 
998
1149
  // ../../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/_u64.js
@@ -1374,7 +1525,7 @@ var IntentExecuter = class {
1374
1525
  relayParams: relayParamsFactory,
1375
1526
  ...intentParams
1376
1527
  }) {
1377
- const verifyingContract = configsByEnvironment5[this.env].contractID;
1528
+ const verifyingContract = configsByEnvironment4[this.env].contractID;
1378
1529
  let intentPayload = defaultIntentPayloadFactory({
1379
1530
  verifying_contract: verifyingContract,
1380
1531
  ...intentParams
@@ -1425,8 +1576,8 @@ async function mergeIntentPayloads(basePayload, intentPayloadFactory) {
1425
1576
 
1426
1577
  // src/intents/intent-relayer-impl/intent-relayer-public.ts
1427
1578
  import {
1428
- configsByEnvironment as configsByEnvironment6,
1429
- solverRelay as solverRelay4
1579
+ configsByEnvironment as configsByEnvironment5,
1580
+ solverRelay as solverRelay2
1430
1581
  } from "@defuse-protocol/internal-utils";
1431
1582
  var IntentRelayerPublic = class {
1432
1583
  constructor({ env }) {
@@ -1449,13 +1600,13 @@ var IntentRelayerPublic = class {
1449
1600
  multiPayloads,
1450
1601
  quoteHashes
1451
1602
  }, ctx = {}) {
1452
- const a = await solverRelay4.publishIntents(
1603
+ const a = await solverRelay2.publishIntents(
1453
1604
  {
1454
1605
  quote_hashes: quoteHashes,
1455
1606
  signed_datas: multiPayloads
1456
1607
  },
1457
1608
  {
1458
- baseURL: configsByEnvironment6[this.env].solverRelayBaseURL,
1609
+ baseURL: configsByEnvironment5[this.env].solverRelayBaseURL,
1459
1610
  logger: ctx.logger
1460
1611
  }
1461
1612
  );
@@ -1465,10 +1616,10 @@ var IntentRelayerPublic = class {
1465
1616
  throw a.unwrapErr();
1466
1617
  }
1467
1618
  async waitForSettlement(ticket, ctx = {}) {
1468
- const result = await solverRelay4.waitForIntentSettlement({
1619
+ const result = await solverRelay2.waitForIntentSettlement({
1469
1620
  intentHash: ticket,
1470
1621
  signal: new AbortController().signal,
1471
- baseURL: configsByEnvironment6[this.env].solverRelayBaseURL,
1622
+ baseURL: configsByEnvironment5[this.env].solverRelayBaseURL,
1472
1623
  logger: ctx.logger
1473
1624
  });
1474
1625
  return {
@@ -1476,7 +1627,7 @@ var IntentRelayerPublic = class {
1476
1627
  hash: result.txHash,
1477
1628
  // Usually relayer's account id is the verifying contract (`intents.near`),
1478
1629
  // but it is not set in stone and may change in the future.
1479
- accountId: configsByEnvironment6[this.env].contractID
1630
+ accountId: configsByEnvironment5[this.env].contractID
1480
1631
  }
1481
1632
  };
1482
1633
  }
@@ -1547,7 +1698,7 @@ function createInternalTransferRoute() {
1547
1698
  function createNearWithdrawalRoute(msg) {
1548
1699
  return { route: RouteEnum.NearWithdrawal, msg };
1549
1700
  }
1550
- function createOmniWithdrawalRoute() {
1701
+ function createOmniBridgeRoute() {
1551
1702
  return { route: RouteEnum.OmniBridge };
1552
1703
  }
1553
1704
  function createVirtualChainRoute(auroraEngineContractId, proxyTokenContractId) {
@@ -1581,17 +1732,11 @@ function determineRouteConfig(sdk, withdrawalParams) {
1581
1732
  const bridgeName = parseAssetId.bridgeName;
1582
1733
  switch (bridgeName) {
1583
1734
  case BridgeNameEnum.Hot:
1584
- return {
1585
- route: RouteEnum.HotBridge,
1586
- chain: parseAssetId.blockchain
1587
- };
1735
+ return createHotBridgeRoute(parseAssetId.blockchain);
1588
1736
  case BridgeNameEnum.Poa:
1589
- return {
1590
- route: RouteEnum.PoaBridge,
1591
- chain: parseAssetId.blockchain
1592
- };
1737
+ return createPoaBridgeRoute(parseAssetId.blockchain);
1593
1738
  case BridgeNameEnum.Omni:
1594
- return createOmniWithdrawalRoute();
1739
+ return createOmniBridgeRoute();
1595
1740
  case BridgeNameEnum.None:
1596
1741
  return createNearWithdrawalRoute();
1597
1742
  default:
@@ -1656,7 +1801,7 @@ var IntentsSDK = class {
1656
1801
  }
1657
1802
  async createWithdrawalIntents(args) {
1658
1803
  for (const bridge of this.bridges) {
1659
- if (bridge.supports(args.withdrawalParams)) {
1804
+ if (await bridge.supports(args.withdrawalParams)) {
1660
1805
  const actualAmount = args.withdrawalParams.feeInclusive ? args.withdrawalParams.amount - args.feeEstimation.amount : args.withdrawalParams.amount;
1661
1806
  await bridge.validateWithdrawal({
1662
1807
  assetId: args.withdrawalParams.assetId,
@@ -1698,7 +1843,7 @@ var IntentsSDK = class {
1698
1843
  }
1699
1844
  async _estimateWithdrawalFee(args) {
1700
1845
  for (const bridge of this.bridges) {
1701
- if (bridge.supports(args.withdrawalParams)) {
1846
+ if (await bridge.supports(args.withdrawalParams)) {
1702
1847
  const fee = await bridge.estimateWithdrawalFee({
1703
1848
  withdrawalParams: args.withdrawalParams,
1704
1849
  quoteOptions: args.quoteOptions,
@@ -1850,12 +1995,12 @@ var IntentsSDK = class {
1850
1995
  intentHash,
1851
1996
  logger
1852
1997
  }) {
1853
- return solverRelay5.getStatus(
1998
+ return solverRelay3.getStatus(
1854
1999
  {
1855
2000
  intent_hash: intentHash
1856
2001
  },
1857
2002
  {
1858
- baseURL: configsByEnvironment7[this.env].solverRelayBaseURL,
2003
+ baseURL: configsByEnvironment6[this.env].solverRelayBaseURL,
1859
2004
  logger
1860
2005
  }
1861
2006
  );
@@ -1965,14 +2110,14 @@ var IntentSignerNearKeypair = class extends IntentSignerNEP413 {
1965
2110
  };
1966
2111
 
1967
2112
  // src/intents/intent-signer-impl/intent-signer-viem.ts
1968
- import { utils as utils8 } from "@defuse-protocol/internal-utils";
2113
+ import { utils as utils9 } from "@defuse-protocol/internal-utils";
1969
2114
  var IntentSignerViem = class {
1970
2115
  constructor(account) {
1971
2116
  this.account = account;
1972
2117
  }
1973
2118
  async signIntent(intent) {
1974
2119
  const payload = JSON.stringify({
1975
- signer_id: intent.signer_id ?? utils8.authHandleToIntentsUserId({
2120
+ signer_id: intent.signer_id ?? utils9.authHandleToIntentsUserId({
1976
2121
  identifier: this.account.address,
1977
2122
  method: "evm"
1978
2123
  }),
@@ -1990,7 +2135,7 @@ var IntentSignerViem = class {
1990
2135
  return {
1991
2136
  standard: "erc191",
1992
2137
  payload,
1993
- signature: utils8.transformERC191Signature(signature)
2138
+ signature: utils9.transformERC191Signature(signature)
1994
2139
  };
1995
2140
  }
1996
2141
  };
@@ -2072,7 +2217,7 @@ import {
2072
2217
  AssertionError
2073
2218
  } from "@defuse-protocol/internal-utils";
2074
2219
  import {
2075
- QuoteError,
2220
+ QuoteError as QuoteError2,
2076
2221
  IntentSettlementError,
2077
2222
  RelayPublishError
2078
2223
  } from "@defuse-protocol/internal-utils";
@@ -2094,7 +2239,7 @@ export {
2094
2239
  PoaWithdrawalInvariantError,
2095
2240
  PoaWithdrawalNotFoundError,
2096
2241
  PoaWithdrawalPendingError,
2097
- QuoteError,
2242
+ QuoteError2 as QuoteError,
2098
2243
  RelayPublishError,
2099
2244
  RouteEnum,
2100
2245
  RpcRequestError,
@@ -2102,6 +2247,7 @@ export {
2102
2247
  TokenNotFoundInDestinationChainError,
2103
2248
  TokenNotSupportedByOmniRelayerError,
2104
2249
  TrustlineNotFoundError,
2250
+ UnsupportedAssetIdError,
2105
2251
  UnsupportedDestinationMemoError,
2106
2252
  createDefaultRoute,
2107
2253
  createHotBridgeRoute,
@@ -2110,7 +2256,7 @@ export {
2110
2256
  createIntentSignerViem,
2111
2257
  createInternalTransferRoute,
2112
2258
  createNearWithdrawalRoute,
2113
- createOmniWithdrawalRoute,
2259
+ createOmniBridgeRoute,
2114
2260
  createPoaBridgeRoute,
2115
2261
  createVirtualChainRoute
2116
2262
  };