@cowprotocol/sdk-bridging 0.3.3 → 0.4.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/dist/index.d.mts CHANGED
@@ -2,7 +2,7 @@ import { cowAppDataLatestScheme } from '@cowprotocol/sdk-app-data';
2
2
  import { Amounts, OrderKind, Address, EnrichedOrder, OrderBookApi } from '@cowprotocol/sdk-order-book';
3
3
  import { ChainInfo, TargetChainId, SupportedChainId, TokenInfo, EvmCall, ChainId, CowEnv } from '@cowprotocol/sdk-config';
4
4
  import { QuoterParameters, TraderParameters, TradeOptionalParameters, QuoteAndPost, QuoteResults, SwapAdvancedSettings, SigningStepManager, OrderPostingResult, TradingSdk } from '@cowprotocol/sdk-trading';
5
- import { AccountAddress, SignerLike, AbstractProviderAdapter } from '@cowprotocol/sdk-common';
5
+ import { AccountAddress, SignerLike, TTLCache, AbstractProviderAdapter } from '@cowprotocol/sdk-common';
6
6
  import { CowShedSdk, CowShedSdkOptions } from '@cowprotocol/sdk-cow-shed';
7
7
 
8
8
  interface BridgeProviderInfo {
@@ -363,6 +363,8 @@ interface MultiQuoteOptions {
363
363
  }
364
364
  interface MultiQuoteRequest {
365
365
  quoteBridgeRequest: QuoteBridgeRequest;
366
+ intermediateTokensCache?: TTLCache<TokenInfo[]>;
367
+ intermediateTokensTtl?: number;
366
368
  providerDappIds?: string[];
367
369
  advancedSettings?: SwapAdvancedSettings;
368
370
  options?: MultiQuoteOptions;
@@ -417,24 +419,24 @@ declare function assertIsQuoteAndPost(quote: CrossChainQuoteAndPost): asserts qu
417
419
  declare function getPostHooks(fullAppData?: string): cowAppDataLatestScheme.CoWHook[];
418
420
  declare function isAppDoc(appData: unknown): appData is cowAppDataLatestScheme.AppDataRootSchema;
419
421
 
422
+ type BridgingSdkConfig = Required<Omit<BridgingSdkOptions, 'enableLogging' | 'cacheConfig'>>;
420
423
  /**
421
- * Parameters for the `getOrder` method.
424
+ * Cache configuration for BridgingSdk
422
425
  */
423
- interface GetOrderParams {
426
+ interface BridgingSdkCacheConfig {
424
427
  /**
425
- * Id of a network where order was settled
428
+ * Enable caching for target networks and buy tokens
426
429
  */
427
- chainId: SupportedChainId;
430
+ enabled: boolean;
428
431
  /**
429
- * The unique identifier of the order.
432
+ * TTL in milliseconds for getIntermediateTokens cache
430
433
  */
431
- orderId: string;
434
+ intermediateTokensTtl: number;
432
435
  /**
433
- * The environment of the order
436
+ * TTL in milliseconds for getBuyTokens cache
434
437
  */
435
- env?: CowEnv;
438
+ buyTokensTtl: number;
436
439
  }
437
-
438
440
  interface BridgingSdkOptions {
439
441
  /**
440
442
  * Providers for the bridging.
@@ -452,14 +454,41 @@ interface BridgingSdkOptions {
452
454
  * Enable logging for the bridging SDK.
453
455
  */
454
456
  enableLogging?: boolean;
457
+ /**
458
+ * Cache configuration for BridgingSdk
459
+ */
460
+ cacheConfig?: BridgingSdkCacheConfig;
461
+ }
462
+ /**
463
+ * Parameters for the `getOrder` method.
464
+ */
465
+ interface GetOrderParams {
466
+ /**
467
+ * Id of a network where order was settled
468
+ */
469
+ chainId: SupportedChainId;
470
+ /**
471
+ * The unique identifier of the order.
472
+ */
473
+ orderId: string;
474
+ /**
475
+ * The environment of the order
476
+ */
477
+ env?: CowEnv;
455
478
  }
456
- type BridgingSdkConfig = Required<Omit<BridgingSdkOptions, 'enableLogging'>>;
479
+
457
480
  /**
458
481
  * SDK for bridging for swapping tokens between different chains.
459
482
  */
460
483
  declare class BridgingSdk {
461
484
  readonly options: BridgingSdkOptions;
462
485
  protected config: BridgingSdkConfig;
486
+ private cacheConfig;
487
+ private intermediateTokensCache;
488
+ private buyTokensCache;
489
+ private singleQuoteStrategy;
490
+ private multiQuoteStrategy;
491
+ private bestQuoteStrategy;
463
492
  constructor(options: BridgingSdkOptions, adapter?: AbstractProviderAdapter);
464
493
  private get provider();
465
494
  /**
@@ -531,6 +560,21 @@ declare class BridgingSdk {
531
560
  getOrder(params: GetOrderParams): Promise<CrossChainOrder | null>;
532
561
  getOrderBridgingStatus(bridgingId: string, originChainId: SupportedChainId): Promise<BridgeStatusResult>;
533
562
  getProviderFromAppData(fullAppData: string): BridgeProvider<BridgeQuoteResult> | undefined;
563
+ /**
564
+ * Clear all caches. Useful for testing and debugging.
565
+ */
566
+ clearCache(): void;
567
+ /**
568
+ * Clean up expired cache entries. Useful for maintenance.
569
+ */
570
+ cleanupExpiredCache(): void;
571
+ /**
572
+ * Get cache statistics for debugging.
573
+ */
574
+ getCacheStats(): {
575
+ intermediateTokens: number;
576
+ buyTokens: number;
577
+ };
534
578
  getProviderByDappId(dappId: string): BridgeProvider<BridgeQuoteResult> | undefined;
535
579
  }
536
580
 
@@ -1152,4 +1196,4 @@ declare class BungeeBridgeProvider implements BridgeProvider<BungeeQuoteResult>
1152
1196
  private isExtraGasRequired;
1153
1197
  }
1154
1198
 
1155
- export { AcrossBridgeProvider, type AcrossBridgeProviderOptions, type AcrossQuoteResult, type BestQuoteProgressCallback, type BestQuoteProviderContext, type BridgeCallDetails, type BridgeCosts, type BridgeDeposit, type BridgeHook, BridgeOrderParsingError, type BridgeProvider, BridgeProviderError, type BridgeProviderInfo, BridgeProviderQuoteError, type BridgeQuoteAmountsAndCosts, type BridgeQuoteAndPost, BridgeQuoteErrors, type BridgeQuoteResult, type BridgeQuoteResults, BridgeStatus, type BridgeStatusResult, type BridgingDepositParams, BridgingSdk, type BridgingSdkConfig, type BridgingSdkOptions, BungeeBridgeProvider, type BungeeBridgeProviderOptions, type BungeeQuoteResult, type BuyTokensParams, COW_SHED_PROXY_CREATION_GAS, type CrossChainOrder, type CrossChainQuoteAndPost, DEFAULT_EXTRA_GAS_FOR_HOOK_ESTIMATION, DEFAULT_EXTRA_GAS_PROXY_CREATION, DEFAULT_GAS_COST_FOR_HOOK_ESTIMATION, type GetProviderBuyTokens, HOOK_DAPP_BRIDGE_PROVIDER_PREFIX, type MultiQuoteOptions, type MultiQuoteProgressCallback, type MultiQuoteRequest, type MultiQuoteResult, type ProviderQuoteContext, type QuoteBridgeRequest, type QuoteBridgeRequestWithoutAmount, RAW_PROVIDERS_FILES_PATH, assertIsBridgeQuoteAndPost, assertIsQuoteAndPost, getCrossChainOrder, getPostHooks, isAppDoc, isBridgeQuoteAndPost, isQuoteAndPost };
1199
+ export { AcrossBridgeProvider, type AcrossBridgeProviderOptions, type AcrossQuoteResult, type BestQuoteProgressCallback, type BestQuoteProviderContext, type BridgeCallDetails, type BridgeCosts, type BridgeDeposit, type BridgeHook, BridgeOrderParsingError, type BridgeProvider, BridgeProviderError, type BridgeProviderInfo, BridgeProviderQuoteError, type BridgeQuoteAmountsAndCosts, type BridgeQuoteAndPost, BridgeQuoteErrors, type BridgeQuoteResult, type BridgeQuoteResults, BridgeStatus, type BridgeStatusResult, type BridgingDepositParams, BridgingSdk, BungeeBridgeProvider, type BungeeBridgeProviderOptions, type BungeeQuoteResult, type BuyTokensParams, COW_SHED_PROXY_CREATION_GAS, type CrossChainOrder, type CrossChainQuoteAndPost, DEFAULT_EXTRA_GAS_FOR_HOOK_ESTIMATION, DEFAULT_EXTRA_GAS_PROXY_CREATION, DEFAULT_GAS_COST_FOR_HOOK_ESTIMATION, type GetProviderBuyTokens, HOOK_DAPP_BRIDGE_PROVIDER_PREFIX, type MultiQuoteOptions, type MultiQuoteProgressCallback, type MultiQuoteRequest, type MultiQuoteResult, type ProviderQuoteContext, type QuoteBridgeRequest, type QuoteBridgeRequestWithoutAmount, RAW_PROVIDERS_FILES_PATH, assertIsBridgeQuoteAndPost, assertIsQuoteAndPost, getCrossChainOrder, getPostHooks, isAppDoc, isBridgeQuoteAndPost, isQuoteAndPost };
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ import { cowAppDataLatestScheme } from '@cowprotocol/sdk-app-data';
2
2
  import { Amounts, OrderKind, Address, EnrichedOrder, OrderBookApi } from '@cowprotocol/sdk-order-book';
3
3
  import { ChainInfo, TargetChainId, SupportedChainId, TokenInfo, EvmCall, ChainId, CowEnv } from '@cowprotocol/sdk-config';
4
4
  import { QuoterParameters, TraderParameters, TradeOptionalParameters, QuoteAndPost, QuoteResults, SwapAdvancedSettings, SigningStepManager, OrderPostingResult, TradingSdk } from '@cowprotocol/sdk-trading';
5
- import { AccountAddress, SignerLike, AbstractProviderAdapter } from '@cowprotocol/sdk-common';
5
+ import { AccountAddress, SignerLike, TTLCache, AbstractProviderAdapter } from '@cowprotocol/sdk-common';
6
6
  import { CowShedSdk, CowShedSdkOptions } from '@cowprotocol/sdk-cow-shed';
7
7
 
8
8
  interface BridgeProviderInfo {
@@ -363,6 +363,8 @@ interface MultiQuoteOptions {
363
363
  }
364
364
  interface MultiQuoteRequest {
365
365
  quoteBridgeRequest: QuoteBridgeRequest;
366
+ intermediateTokensCache?: TTLCache<TokenInfo[]>;
367
+ intermediateTokensTtl?: number;
366
368
  providerDappIds?: string[];
367
369
  advancedSettings?: SwapAdvancedSettings;
368
370
  options?: MultiQuoteOptions;
@@ -417,24 +419,24 @@ declare function assertIsQuoteAndPost(quote: CrossChainQuoteAndPost): asserts qu
417
419
  declare function getPostHooks(fullAppData?: string): cowAppDataLatestScheme.CoWHook[];
418
420
  declare function isAppDoc(appData: unknown): appData is cowAppDataLatestScheme.AppDataRootSchema;
419
421
 
422
+ type BridgingSdkConfig = Required<Omit<BridgingSdkOptions, 'enableLogging' | 'cacheConfig'>>;
420
423
  /**
421
- * Parameters for the `getOrder` method.
424
+ * Cache configuration for BridgingSdk
422
425
  */
423
- interface GetOrderParams {
426
+ interface BridgingSdkCacheConfig {
424
427
  /**
425
- * Id of a network where order was settled
428
+ * Enable caching for target networks and buy tokens
426
429
  */
427
- chainId: SupportedChainId;
430
+ enabled: boolean;
428
431
  /**
429
- * The unique identifier of the order.
432
+ * TTL in milliseconds for getIntermediateTokens cache
430
433
  */
431
- orderId: string;
434
+ intermediateTokensTtl: number;
432
435
  /**
433
- * The environment of the order
436
+ * TTL in milliseconds for getBuyTokens cache
434
437
  */
435
- env?: CowEnv;
438
+ buyTokensTtl: number;
436
439
  }
437
-
438
440
  interface BridgingSdkOptions {
439
441
  /**
440
442
  * Providers for the bridging.
@@ -452,14 +454,41 @@ interface BridgingSdkOptions {
452
454
  * Enable logging for the bridging SDK.
453
455
  */
454
456
  enableLogging?: boolean;
457
+ /**
458
+ * Cache configuration for BridgingSdk
459
+ */
460
+ cacheConfig?: BridgingSdkCacheConfig;
461
+ }
462
+ /**
463
+ * Parameters for the `getOrder` method.
464
+ */
465
+ interface GetOrderParams {
466
+ /**
467
+ * Id of a network where order was settled
468
+ */
469
+ chainId: SupportedChainId;
470
+ /**
471
+ * The unique identifier of the order.
472
+ */
473
+ orderId: string;
474
+ /**
475
+ * The environment of the order
476
+ */
477
+ env?: CowEnv;
455
478
  }
456
- type BridgingSdkConfig = Required<Omit<BridgingSdkOptions, 'enableLogging'>>;
479
+
457
480
  /**
458
481
  * SDK for bridging for swapping tokens between different chains.
459
482
  */
460
483
  declare class BridgingSdk {
461
484
  readonly options: BridgingSdkOptions;
462
485
  protected config: BridgingSdkConfig;
486
+ private cacheConfig;
487
+ private intermediateTokensCache;
488
+ private buyTokensCache;
489
+ private singleQuoteStrategy;
490
+ private multiQuoteStrategy;
491
+ private bestQuoteStrategy;
463
492
  constructor(options: BridgingSdkOptions, adapter?: AbstractProviderAdapter);
464
493
  private get provider();
465
494
  /**
@@ -531,6 +560,21 @@ declare class BridgingSdk {
531
560
  getOrder(params: GetOrderParams): Promise<CrossChainOrder | null>;
532
561
  getOrderBridgingStatus(bridgingId: string, originChainId: SupportedChainId): Promise<BridgeStatusResult>;
533
562
  getProviderFromAppData(fullAppData: string): BridgeProvider<BridgeQuoteResult> | undefined;
563
+ /**
564
+ * Clear all caches. Useful for testing and debugging.
565
+ */
566
+ clearCache(): void;
567
+ /**
568
+ * Clean up expired cache entries. Useful for maintenance.
569
+ */
570
+ cleanupExpiredCache(): void;
571
+ /**
572
+ * Get cache statistics for debugging.
573
+ */
574
+ getCacheStats(): {
575
+ intermediateTokens: number;
576
+ buyTokens: number;
577
+ };
534
578
  getProviderByDappId(dappId: string): BridgeProvider<BridgeQuoteResult> | undefined;
535
579
  }
536
580
 
@@ -1152,4 +1196,4 @@ declare class BungeeBridgeProvider implements BridgeProvider<BungeeQuoteResult>
1152
1196
  private isExtraGasRequired;
1153
1197
  }
1154
1198
 
1155
- export { AcrossBridgeProvider, type AcrossBridgeProviderOptions, type AcrossQuoteResult, type BestQuoteProgressCallback, type BestQuoteProviderContext, type BridgeCallDetails, type BridgeCosts, type BridgeDeposit, type BridgeHook, BridgeOrderParsingError, type BridgeProvider, BridgeProviderError, type BridgeProviderInfo, BridgeProviderQuoteError, type BridgeQuoteAmountsAndCosts, type BridgeQuoteAndPost, BridgeQuoteErrors, type BridgeQuoteResult, type BridgeQuoteResults, BridgeStatus, type BridgeStatusResult, type BridgingDepositParams, BridgingSdk, type BridgingSdkConfig, type BridgingSdkOptions, BungeeBridgeProvider, type BungeeBridgeProviderOptions, type BungeeQuoteResult, type BuyTokensParams, COW_SHED_PROXY_CREATION_GAS, type CrossChainOrder, type CrossChainQuoteAndPost, DEFAULT_EXTRA_GAS_FOR_HOOK_ESTIMATION, DEFAULT_EXTRA_GAS_PROXY_CREATION, DEFAULT_GAS_COST_FOR_HOOK_ESTIMATION, type GetProviderBuyTokens, HOOK_DAPP_BRIDGE_PROVIDER_PREFIX, type MultiQuoteOptions, type MultiQuoteProgressCallback, type MultiQuoteRequest, type MultiQuoteResult, type ProviderQuoteContext, type QuoteBridgeRequest, type QuoteBridgeRequestWithoutAmount, RAW_PROVIDERS_FILES_PATH, assertIsBridgeQuoteAndPost, assertIsQuoteAndPost, getCrossChainOrder, getPostHooks, isAppDoc, isBridgeQuoteAndPost, isQuoteAndPost };
1199
+ export { AcrossBridgeProvider, type AcrossBridgeProviderOptions, type AcrossQuoteResult, type BestQuoteProgressCallback, type BestQuoteProviderContext, type BridgeCallDetails, type BridgeCosts, type BridgeDeposit, type BridgeHook, BridgeOrderParsingError, type BridgeProvider, BridgeProviderError, type BridgeProviderInfo, BridgeProviderQuoteError, type BridgeQuoteAmountsAndCosts, type BridgeQuoteAndPost, BridgeQuoteErrors, type BridgeQuoteResult, type BridgeQuoteResults, BridgeStatus, type BridgeStatusResult, type BridgingDepositParams, BridgingSdk, BungeeBridgeProvider, type BungeeBridgeProviderOptions, type BungeeQuoteResult, type BuyTokensParams, COW_SHED_PROXY_CREATION_GAS, type CrossChainOrder, type CrossChainQuoteAndPost, DEFAULT_EXTRA_GAS_FOR_HOOK_ESTIMATION, DEFAULT_EXTRA_GAS_PROXY_CREATION, DEFAULT_GAS_COST_FOR_HOOK_ESTIMATION, type GetProviderBuyTokens, HOOK_DAPP_BRIDGE_PROVIDER_PREFIX, type MultiQuoteOptions, type MultiQuoteProgressCallback, type MultiQuoteRequest, type MultiQuoteResult, type ProviderQuoteContext, type QuoteBridgeRequest, type QuoteBridgeRequestWithoutAmount, RAW_PROVIDERS_FILES_PATH, assertIsBridgeQuoteAndPost, assertIsQuoteAndPost, getCrossChainOrder, getPostHooks, isAppDoc, isBridgeQuoteAndPost, isQuoteAndPost };
package/dist/index.js CHANGED
@@ -199,6 +199,16 @@ var import_sdk_order_book2 = require("@cowprotocol/sdk-order-book");
199
199
  var import_sdk_config2 = require("@cowprotocol/sdk-config");
200
200
  var import_sdk_common4 = require("@cowprotocol/sdk-common");
201
201
 
202
+ // src/BridgingSdk/helpers.ts
203
+ var getCacheKey = ({
204
+ id,
205
+ buyChainId,
206
+ sellChainId = "noSellChainID",
207
+ tokenAddress = "noTokenAddress"
208
+ }) => {
209
+ return `${id}-${buyChainId}-${sellChainId}-${tokenAddress.toLowerCase()}`;
210
+ };
211
+
202
212
  // src/BridgingSdk/getQuoteWithoutBridge.ts
203
213
  var import_sdk_common = require("@cowprotocol/sdk-common");
204
214
  function getQuoteWithoutBridge(params) {
@@ -218,6 +228,8 @@ function getQuoteWithoutBridge(params) {
218
228
 
219
229
  // src/BridgingSdk/getQuoteWithBridge.ts
220
230
  var import_sdk_trading = require("@cowprotocol/sdk-trading");
231
+ var import_sdk_common3 = require("@cowprotocol/sdk-common");
232
+ var import_sdk_order_book = require("@cowprotocol/sdk-order-book");
221
233
 
222
234
  // src/BridgingSdk/getBridgeSignedHook.ts
223
235
  var import_sdk_common2 = require("@cowprotocol/sdk-common");
@@ -245,10 +257,6 @@ async function getBridgeSignedHook(bridgeRequest, { provider, signer, hookGasLim
245
257
  };
246
258
  }
247
259
 
248
- // src/BridgingSdk/getQuoteWithBridge.ts
249
- var import_sdk_order_book = require("@cowprotocol/sdk-order-book");
250
- var import_sdk_common3 = require("@cowprotocol/sdk-common");
251
-
252
260
  // src/hooks/utils.ts
253
261
  function getHookMockForCostEstimation(gasLimit) {
254
262
  return {
@@ -282,7 +290,8 @@ async function getQuoteWithBridge(params) {
282
290
  );
283
291
  const bridgeRequestWithoutAmount = await getBaseBridgeQuoteRequest({
284
292
  swapAndBridgeRequest,
285
- provider
293
+ provider,
294
+ intermediateTokensCache: params.intermediateTokensCache
286
295
  });
287
296
  const hookEstimatedGasLimit = await provider.getGasLimitEstimationForHook(bridgeRequestWithoutAmount);
288
297
  const mockedHook = getHookMockForCostEstimation(hookEstimatedGasLimit);
@@ -324,7 +333,7 @@ async function getQuoteWithBridge(params) {
324
333
  });
325
334
  const intermediateTokenAmount = swapResult.amountsAndCosts.afterSlippage.buyAmount;
326
335
  (0, import_sdk_common3.log)(
327
- `Expected to receive ${intermediateTokenAmount} of the intermediate token (${(intermediateTokenAmount / BigInt(10 ** intermediaryTokenDecimals)).toString()} formatted)`
336
+ `Expected to receive ${intermediateTokenAmount} of the intermediate token (${(intermediateTokenAmount / 10n ** BigInt(intermediaryTokenDecimals)).toString()} formatted)`
328
337
  );
329
338
  async function signHooksAndSetSwapResult(signer2, hookGasLimit, advancedSettings2) {
330
339
  const appDataOverride = advancedSettings2?.appData;
@@ -418,13 +427,26 @@ async function getQuoteWithBridge(params) {
418
427
  };
419
428
  }
420
429
  async function getBaseBridgeQuoteRequest(params) {
421
- const { provider, swapAndBridgeRequest: quoteBridgeRequest } = params;
422
- const intermediateTokens = await provider.getIntermediateTokens(quoteBridgeRequest);
430
+ const { provider, swapAndBridgeRequest: quoteBridgeRequest, intermediateTokensCache } = params;
431
+ let intermediateTokens = [];
432
+ const cacheKey = getCacheKey({
433
+ id: provider.info.dappId,
434
+ buyChainId: quoteBridgeRequest.buyTokenChainId.toString(),
435
+ sellChainId: quoteBridgeRequest.sellTokenChainId.toString(),
436
+ tokenAddress: quoteBridgeRequest.buyTokenAddress
437
+ });
438
+ const cached = intermediateTokensCache?.get(cacheKey);
439
+ if (cached) {
440
+ intermediateTokens = cached;
441
+ } else {
442
+ intermediateTokens = await provider.getIntermediateTokens(quoteBridgeRequest);
443
+ intermediateTokensCache?.set(cacheKey, intermediateTokens);
444
+ }
423
445
  if (intermediateTokens.length === 0) {
424
446
  throw new BridgeProviderQuoteError("NO_INTERMEDIATE_TOKENS" /* NO_INTERMEDIATE_TOKENS */);
425
447
  }
426
448
  const intermediateToken = intermediateTokens[0];
427
- (0, import_sdk_common3.log)(`Using ${intermediateToken} as intermediate tokens`);
449
+ (0, import_sdk_common3.log)(`Using ${intermediateToken?.name ?? intermediateToken?.address} as intermediate tokens`);
428
450
  if (!intermediateToken) {
429
451
  throw new BridgeProviderQuoteError("NO_INTERMEDIATE_TOKENS" /* NO_INTERMEDIATE_TOKENS */, { intermediateTokens });
430
452
  }
@@ -472,9 +494,25 @@ async function getBridgeResult(context) {
472
494
  return { bridgeResult, bridgeHook, appDataInfo };
473
495
  }
474
496
 
497
+ // src/BridgingSdk/strategies/QuoteStrategy.ts
498
+ var QuoteStrategy = class {
499
+ constructor(intermediateTokensCache) {
500
+ this.intermediateTokensCache = intermediateTokensCache;
501
+ }
502
+ };
503
+ var BaseSingleQuoteStrategy = class extends QuoteStrategy {
504
+ };
505
+ var BaseMultiQuoteStrategy = class extends QuoteStrategy {
506
+ };
507
+ var BaseBestQuoteStrategy = class extends QuoteStrategy {
508
+ };
509
+
475
510
  // src/BridgingSdk/strategies/SingleQuoteStrategy.ts
476
- var SingleQuoteStrategyImpl = class {
511
+ var SingleQuoteStrategy = class extends BaseSingleQuoteStrategy {
477
512
  strategyName = "SingleQuoteStrategy";
513
+ constructor(intermediateTokensCache) {
514
+ super(intermediateTokensCache);
515
+ }
478
516
  async execute(request, config) {
479
517
  const { quoteBridgeRequest, advancedSettings } = request;
480
518
  const { sellTokenChainId, buyTokenChainId } = quoteBridgeRequest;
@@ -484,13 +522,18 @@ var SingleQuoteStrategyImpl = class {
484
522
  if (!provider) {
485
523
  throw new Error("No provider found for cross-chain swap");
486
524
  }
487
- return getQuoteWithBridge({
525
+ const baseParams = {
488
526
  swapAndBridgeRequest: quoteBridgeRequest,
489
527
  advancedSettings,
490
528
  tradingSdk,
491
529
  provider,
492
530
  bridgeHookSigner: advancedSettings?.quoteSigner
493
- });
531
+ };
532
+ const request2 = this.intermediateTokensCache ? {
533
+ ...baseParams,
534
+ intermediateTokensCache: this.intermediateTokensCache
535
+ } : baseParams;
536
+ return getQuoteWithBridge(request2);
494
537
  } else {
495
538
  return getQuoteWithoutBridge({
496
539
  quoteBridgeRequest,
@@ -589,8 +632,11 @@ function resolveProvidersToQuery(providerDappIds, providers) {
589
632
  // src/BridgingSdk/strategies/MultiQuoteStrategy.ts
590
633
  var DEFAULT_TOTAL_TIMEOUT_MS = 4e4;
591
634
  var DEFAULT_PROVIDER_TIMEOUT_MS = 2e4;
592
- var MultiQuoteStrategyImpl = class {
635
+ var MultiQuoteStrategy = class extends BaseMultiQuoteStrategy {
593
636
  strategyName = "MultiQuoteStrategy";
637
+ constructor(intermediateTokensCache) {
638
+ super(intermediateTokensCache);
639
+ }
594
640
  async execute(request, config) {
595
641
  const { quoteBridgeRequest, providerDappIds, advancedSettings, options } = request;
596
642
  const { sellTokenChainId, buyTokenChainId } = quoteBridgeRequest;
@@ -635,14 +681,19 @@ var MultiQuoteStrategyImpl = class {
635
681
  const { provider, quoteBridgeRequest, advancedSettings, providerTimeout, onQuoteResult, results, index } = context;
636
682
  return (async () => {
637
683
  try {
684
+ const baseParams = {
685
+ swapAndBridgeRequest: quoteBridgeRequest,
686
+ advancedSettings,
687
+ tradingSdk: config.tradingSdk,
688
+ provider,
689
+ bridgeHookSigner: advancedSettings?.quoteSigner
690
+ };
691
+ const request = this.intermediateTokensCache ? {
692
+ ...baseParams,
693
+ intermediateTokensCache: this.intermediateTokensCache
694
+ } : baseParams;
638
695
  const quote = await Promise.race([
639
- getQuoteWithBridge({
640
- swapAndBridgeRequest: quoteBridgeRequest,
641
- advancedSettings,
642
- tradingSdk: config.tradingSdk,
643
- provider,
644
- bridgeHookSigner: advancedSettings?.quoteSigner
645
- }),
696
+ getQuoteWithBridge(request),
646
697
  createBridgeQuoteTimeoutPromise(providerTimeout, `Provider ${provider.info.dappId}`)
647
698
  ]);
648
699
  const result = {
@@ -668,8 +719,11 @@ var MultiQuoteStrategyImpl = class {
668
719
  // src/BridgingSdk/strategies/BestQuoteStrategy.ts
669
720
  var DEFAULT_TOTAL_TIMEOUT_MS2 = 4e4;
670
721
  var DEFAULT_PROVIDER_TIMEOUT_MS2 = 2e4;
671
- var BestQuoteStrategyImpl = class {
722
+ var BestQuoteStrategy = class extends BaseBestQuoteStrategy {
672
723
  strategyName = "BestQuoteStrategy";
724
+ constructor(intermediateTokensCache) {
725
+ super(intermediateTokensCache);
726
+ }
673
727
  async execute(request, config) {
674
728
  const { quoteBridgeRequest, providerDappIds, advancedSettings, options } = request;
675
729
  const { sellTokenChainId, buyTokenChainId } = quoteBridgeRequest;
@@ -703,14 +757,19 @@ var BestQuoteStrategyImpl = class {
703
757
  const { provider, quoteBridgeRequest, advancedSettings, providerTimeout, onQuoteResult, bestResult, firstError } = context;
704
758
  return (async () => {
705
759
  try {
760
+ const baseParams = {
761
+ swapAndBridgeRequest: quoteBridgeRequest,
762
+ advancedSettings,
763
+ tradingSdk: config.tradingSdk,
764
+ provider,
765
+ bridgeHookSigner: advancedSettings?.quoteSigner
766
+ };
767
+ const request = this.intermediateTokensCache ? {
768
+ ...baseParams,
769
+ intermediateTokensCache: this.intermediateTokensCache
770
+ } : baseParams;
706
771
  const quote = await Promise.race([
707
- getQuoteWithBridge({
708
- swapAndBridgeRequest: quoteBridgeRequest,
709
- advancedSettings,
710
- tradingSdk: config.tradingSdk,
711
- provider,
712
- bridgeHookSigner: advancedSettings?.quoteSigner
713
- }),
772
+ getQuoteWithBridge(request),
714
773
  createBridgeQuoteTimeoutPromise(providerTimeout, `Provider ${provider.info.dappId}`)
715
774
  ]);
716
775
  const result = {
@@ -736,17 +795,30 @@ var BestQuoteStrategyImpl = class {
736
795
  }
737
796
  };
738
797
 
798
+ // src/BridgingSdk/strategies/createStrategies.ts
799
+ function createStrategies(intermediateTokensCache) {
800
+ return {
801
+ singleQuoteStrategy: new SingleQuoteStrategy(intermediateTokensCache),
802
+ multiQuoteStrategy: new MultiQuoteStrategy(intermediateTokensCache),
803
+ bestQuoteStrategy: new BestQuoteStrategy(intermediateTokensCache)
804
+ };
805
+ }
806
+
739
807
  // src/BridgingSdk/BridgingSdk.ts
740
- var singleQuoteStrategy = new SingleQuoteStrategyImpl();
741
- var multiQuoteStrategy = new MultiQuoteStrategyImpl();
742
- var bestQuoteStrategy = new BestQuoteStrategyImpl();
808
+ var DEFAULT_CACHE_CONFIG = {
809
+ enabled: true,
810
+ intermediateTokensTtl: 5 * 60 * 1e3,
811
+ // 5 minutes
812
+ buyTokensTtl: 2 * 60 * 1e3
813
+ // 2 minutes
814
+ };
743
815
  var BridgingSdk = class {
744
816
  constructor(options, adapter) {
745
817
  this.options = options;
746
818
  if (adapter) {
747
819
  (0, import_sdk_common4.setGlobalAdapter)(adapter);
748
820
  }
749
- const { providers, ...restOptions } = options;
821
+ const { providers, cacheConfig, ...restOptions } = options;
750
822
  if (!providers || providers.length === 0) {
751
823
  throw new Error("At least one bridge provider is required");
752
824
  }
@@ -761,8 +833,31 @@ var BridgingSdk = class {
761
833
  tradingSdk,
762
834
  orderBookApi
763
835
  };
836
+ this.cacheConfig = { ...DEFAULT_CACHE_CONFIG, ...cacheConfig };
837
+ this.intermediateTokensCache = new import_sdk_common4.TTLCache(
838
+ "bridging-intermediate-tokens",
839
+ this.cacheConfig.enabled,
840
+ this.cacheConfig.intermediateTokensTtl
841
+ );
842
+ this.buyTokensCache = new import_sdk_common4.TTLCache(
843
+ "bridging-buy-tokens",
844
+ this.cacheConfig.enabled,
845
+ this.cacheConfig.buyTokensTtl
846
+ );
847
+ const { singleQuoteStrategy, multiQuoteStrategy, bestQuoteStrategy } = createStrategies(
848
+ this.cacheConfig.enabled ? this.intermediateTokensCache : void 0
849
+ );
850
+ this.singleQuoteStrategy = singleQuoteStrategy;
851
+ this.multiQuoteStrategy = multiQuoteStrategy;
852
+ this.bestQuoteStrategy = bestQuoteStrategy;
764
853
  }
765
854
  config;
855
+ cacheConfig;
856
+ intermediateTokensCache;
857
+ buyTokensCache;
858
+ singleQuoteStrategy;
859
+ multiQuoteStrategy;
860
+ bestQuoteStrategy;
766
861
  get provider() {
767
862
  const { providers } = this.config;
768
863
  if (!providers[0]) {
@@ -794,7 +889,22 @@ var BridgingSdk = class {
794
889
  * @param params
795
890
  */
796
891
  async getBuyTokens(params) {
797
- return this.provider.getBuyTokens(params);
892
+ const providerId = this.provider.info.dappId;
893
+ const cacheKey = getCacheKey({
894
+ id: providerId,
895
+ buyChainId: params.buyChainId.toString(),
896
+ sellChainId: params.sellChainId?.toString(),
897
+ tokenAddress: params.sellTokenAddress
898
+ });
899
+ const cached = this.cacheConfig.enabled && this.buyTokensCache.get(cacheKey);
900
+ if (cached) {
901
+ return cached;
902
+ }
903
+ const result = await this.provider.getBuyTokens(params);
904
+ if (this.cacheConfig.enabled) {
905
+ this.buyTokensCache.set(cacheKey, result);
906
+ }
907
+ return result;
798
908
  }
799
909
  /**
800
910
  * Get quote details, including a callback function to post the order on-chain.
@@ -812,11 +922,13 @@ var BridgingSdk = class {
812
922
  * @throws Error if no path is found
813
923
  */
814
924
  async getQuote(quoteBridgeRequest, advancedSettings) {
815
- const request = {
816
- quoteBridgeRequest,
817
- advancedSettings
818
- };
819
- return singleQuoteStrategy.execute(request, this.config);
925
+ return this.singleQuoteStrategy.execute(
926
+ {
927
+ quoteBridgeRequest,
928
+ advancedSettings
929
+ },
930
+ this.config
931
+ );
820
932
  }
821
933
  /**
822
934
  * Get quotes from multiple bridge providers in parallel with progressive results.
@@ -834,7 +946,7 @@ var BridgingSdk = class {
834
946
  * ```
835
947
  */
836
948
  async getMultiQuotes(request) {
837
- return multiQuoteStrategy.execute(request, this.config);
949
+ return this.multiQuoteStrategy.execute(request, this.config);
838
950
  }
839
951
  /**
840
952
  * Get the best quote from multiple bridge providers with progressive updates.
@@ -852,7 +964,7 @@ var BridgingSdk = class {
852
964
  * @throws Error if the request is for a single-chain swap (sellTokenChainId === buyTokenChainId)
853
965
  */
854
966
  async getBestQuote(request) {
855
- return bestQuoteStrategy.execute(request, this.config);
967
+ return this.bestQuoteStrategy.execute(request, this.config);
856
968
  }
857
969
  async getOrder(params) {
858
970
  const { orderBookApi } = this.config;
@@ -871,6 +983,29 @@ var BridgingSdk = class {
871
983
  getProviderFromAppData(fullAppData) {
872
984
  return findBridgeProviderFromHook(fullAppData, this.getProviders());
873
985
  }
986
+ /**
987
+ * Clear all caches. Useful for testing and debugging.
988
+ */
989
+ clearCache() {
990
+ this.intermediateTokensCache.clear();
991
+ this.buyTokensCache.clear();
992
+ }
993
+ /**
994
+ * Clean up expired cache entries. Useful for maintenance.
995
+ */
996
+ cleanupExpiredCache() {
997
+ this.intermediateTokensCache.cleanup();
998
+ this.buyTokensCache.cleanup();
999
+ }
1000
+ /**
1001
+ * Get cache statistics for debugging.
1002
+ */
1003
+ getCacheStats() {
1004
+ return {
1005
+ intermediateTokens: this.intermediateTokensCache.size(),
1006
+ buyTokens: this.buyTokensCache.size()
1007
+ };
1008
+ }
874
1009
  getProviderByDappId(dappId) {
875
1010
  return this.config.providers.find((provider) => provider.info.dappId === dappId);
876
1011
  }
package/dist/index.mjs CHANGED
@@ -151,7 +151,17 @@ async function getCrossChainOrder(params) {
151
151
  import { TradingSdk } from "@cowprotocol/sdk-trading";
152
152
  import { OrderBookApi } from "@cowprotocol/sdk-order-book";
153
153
  import { ALL_SUPPORTED_CHAINS } from "@cowprotocol/sdk-config";
154
- import { enableLogging, setGlobalAdapter } from "@cowprotocol/sdk-common";
154
+ import { enableLogging, setGlobalAdapter, TTLCache as TTLCache2 } from "@cowprotocol/sdk-common";
155
+
156
+ // src/BridgingSdk/helpers.ts
157
+ var getCacheKey = ({
158
+ id,
159
+ buyChainId,
160
+ sellChainId = "noSellChainID",
161
+ tokenAddress = "noTokenAddress"
162
+ }) => {
163
+ return `${id}-${buyChainId}-${sellChainId}-${tokenAddress.toLowerCase()}`;
164
+ };
155
165
 
156
166
  // src/BridgingSdk/getQuoteWithoutBridge.ts
157
167
  import { jsonWithBigintReplacer, log } from "@cowprotocol/sdk-common";
@@ -176,6 +186,8 @@ import {
176
186
  mergeAppDataDoc,
177
187
  postSwapOrderFromQuote
178
188
  } from "@cowprotocol/sdk-trading";
189
+ import { getGlobalAdapter as getGlobalAdapter2, jsonWithBigintReplacer as jsonWithBigintReplacer2, log as log2 } from "@cowprotocol/sdk-common";
190
+ import { OrderKind } from "@cowprotocol/sdk-order-book";
179
191
 
180
192
  // src/BridgingSdk/getBridgeSignedHook.ts
181
193
  import { getGlobalAdapter } from "@cowprotocol/sdk-common";
@@ -203,10 +215,6 @@ async function getBridgeSignedHook(bridgeRequest, { provider, signer, hookGasLim
203
215
  };
204
216
  }
205
217
 
206
- // src/BridgingSdk/getQuoteWithBridge.ts
207
- import { OrderKind } from "@cowprotocol/sdk-order-book";
208
- import { getGlobalAdapter as getGlobalAdapter2, jsonWithBigintReplacer as jsonWithBigintReplacer2, log as log2 } from "@cowprotocol/sdk-common";
209
-
210
218
  // src/hooks/utils.ts
211
219
  function getHookMockForCostEstimation(gasLimit) {
212
220
  return {
@@ -240,7 +248,8 @@ async function getQuoteWithBridge(params) {
240
248
  );
241
249
  const bridgeRequestWithoutAmount = await getBaseBridgeQuoteRequest({
242
250
  swapAndBridgeRequest,
243
- provider
251
+ provider,
252
+ intermediateTokensCache: params.intermediateTokensCache
244
253
  });
245
254
  const hookEstimatedGasLimit = await provider.getGasLimitEstimationForHook(bridgeRequestWithoutAmount);
246
255
  const mockedHook = getHookMockForCostEstimation(hookEstimatedGasLimit);
@@ -282,7 +291,7 @@ async function getQuoteWithBridge(params) {
282
291
  });
283
292
  const intermediateTokenAmount = swapResult.amountsAndCosts.afterSlippage.buyAmount;
284
293
  log2(
285
- `Expected to receive ${intermediateTokenAmount} of the intermediate token (${(intermediateTokenAmount / BigInt(10 ** intermediaryTokenDecimals)).toString()} formatted)`
294
+ `Expected to receive ${intermediateTokenAmount} of the intermediate token (${(intermediateTokenAmount / 10n ** BigInt(intermediaryTokenDecimals)).toString()} formatted)`
286
295
  );
287
296
  async function signHooksAndSetSwapResult(signer2, hookGasLimit, advancedSettings2) {
288
297
  const appDataOverride = advancedSettings2?.appData;
@@ -376,13 +385,26 @@ async function getQuoteWithBridge(params) {
376
385
  };
377
386
  }
378
387
  async function getBaseBridgeQuoteRequest(params) {
379
- const { provider, swapAndBridgeRequest: quoteBridgeRequest } = params;
380
- const intermediateTokens = await provider.getIntermediateTokens(quoteBridgeRequest);
388
+ const { provider, swapAndBridgeRequest: quoteBridgeRequest, intermediateTokensCache } = params;
389
+ let intermediateTokens = [];
390
+ const cacheKey = getCacheKey({
391
+ id: provider.info.dappId,
392
+ buyChainId: quoteBridgeRequest.buyTokenChainId.toString(),
393
+ sellChainId: quoteBridgeRequest.sellTokenChainId.toString(),
394
+ tokenAddress: quoteBridgeRequest.buyTokenAddress
395
+ });
396
+ const cached = intermediateTokensCache?.get(cacheKey);
397
+ if (cached) {
398
+ intermediateTokens = cached;
399
+ } else {
400
+ intermediateTokens = await provider.getIntermediateTokens(quoteBridgeRequest);
401
+ intermediateTokensCache?.set(cacheKey, intermediateTokens);
402
+ }
381
403
  if (intermediateTokens.length === 0) {
382
404
  throw new BridgeProviderQuoteError("NO_INTERMEDIATE_TOKENS" /* NO_INTERMEDIATE_TOKENS */);
383
405
  }
384
406
  const intermediateToken = intermediateTokens[0];
385
- log2(`Using ${intermediateToken} as intermediate tokens`);
407
+ log2(`Using ${intermediateToken?.name ?? intermediateToken?.address} as intermediate tokens`);
386
408
  if (!intermediateToken) {
387
409
  throw new BridgeProviderQuoteError("NO_INTERMEDIATE_TOKENS" /* NO_INTERMEDIATE_TOKENS */, { intermediateTokens });
388
410
  }
@@ -430,9 +452,25 @@ async function getBridgeResult(context) {
430
452
  return { bridgeResult, bridgeHook, appDataInfo };
431
453
  }
432
454
 
455
+ // src/BridgingSdk/strategies/QuoteStrategy.ts
456
+ var QuoteStrategy = class {
457
+ constructor(intermediateTokensCache) {
458
+ this.intermediateTokensCache = intermediateTokensCache;
459
+ }
460
+ };
461
+ var BaseSingleQuoteStrategy = class extends QuoteStrategy {
462
+ };
463
+ var BaseMultiQuoteStrategy = class extends QuoteStrategy {
464
+ };
465
+ var BaseBestQuoteStrategy = class extends QuoteStrategy {
466
+ };
467
+
433
468
  // src/BridgingSdk/strategies/SingleQuoteStrategy.ts
434
- var SingleQuoteStrategyImpl = class {
469
+ var SingleQuoteStrategy = class extends BaseSingleQuoteStrategy {
435
470
  strategyName = "SingleQuoteStrategy";
471
+ constructor(intermediateTokensCache) {
472
+ super(intermediateTokensCache);
473
+ }
436
474
  async execute(request, config) {
437
475
  const { quoteBridgeRequest, advancedSettings } = request;
438
476
  const { sellTokenChainId, buyTokenChainId } = quoteBridgeRequest;
@@ -442,13 +480,18 @@ var SingleQuoteStrategyImpl = class {
442
480
  if (!provider) {
443
481
  throw new Error("No provider found for cross-chain swap");
444
482
  }
445
- return getQuoteWithBridge({
483
+ const baseParams = {
446
484
  swapAndBridgeRequest: quoteBridgeRequest,
447
485
  advancedSettings,
448
486
  tradingSdk,
449
487
  provider,
450
488
  bridgeHookSigner: advancedSettings?.quoteSigner
451
- });
489
+ };
490
+ const request2 = this.intermediateTokensCache ? {
491
+ ...baseParams,
492
+ intermediateTokensCache: this.intermediateTokensCache
493
+ } : baseParams;
494
+ return getQuoteWithBridge(request2);
452
495
  } else {
453
496
  return getQuoteWithoutBridge({
454
497
  quoteBridgeRequest,
@@ -547,8 +590,11 @@ function resolveProvidersToQuery(providerDappIds, providers) {
547
590
  // src/BridgingSdk/strategies/MultiQuoteStrategy.ts
548
591
  var DEFAULT_TOTAL_TIMEOUT_MS = 4e4;
549
592
  var DEFAULT_PROVIDER_TIMEOUT_MS = 2e4;
550
- var MultiQuoteStrategyImpl = class {
593
+ var MultiQuoteStrategy = class extends BaseMultiQuoteStrategy {
551
594
  strategyName = "MultiQuoteStrategy";
595
+ constructor(intermediateTokensCache) {
596
+ super(intermediateTokensCache);
597
+ }
552
598
  async execute(request, config) {
553
599
  const { quoteBridgeRequest, providerDappIds, advancedSettings, options } = request;
554
600
  const { sellTokenChainId, buyTokenChainId } = quoteBridgeRequest;
@@ -593,14 +639,19 @@ var MultiQuoteStrategyImpl = class {
593
639
  const { provider, quoteBridgeRequest, advancedSettings, providerTimeout, onQuoteResult, results, index } = context;
594
640
  return (async () => {
595
641
  try {
642
+ const baseParams = {
643
+ swapAndBridgeRequest: quoteBridgeRequest,
644
+ advancedSettings,
645
+ tradingSdk: config.tradingSdk,
646
+ provider,
647
+ bridgeHookSigner: advancedSettings?.quoteSigner
648
+ };
649
+ const request = this.intermediateTokensCache ? {
650
+ ...baseParams,
651
+ intermediateTokensCache: this.intermediateTokensCache
652
+ } : baseParams;
596
653
  const quote = await Promise.race([
597
- getQuoteWithBridge({
598
- swapAndBridgeRequest: quoteBridgeRequest,
599
- advancedSettings,
600
- tradingSdk: config.tradingSdk,
601
- provider,
602
- bridgeHookSigner: advancedSettings?.quoteSigner
603
- }),
654
+ getQuoteWithBridge(request),
604
655
  createBridgeQuoteTimeoutPromise(providerTimeout, `Provider ${provider.info.dappId}`)
605
656
  ]);
606
657
  const result = {
@@ -626,8 +677,11 @@ var MultiQuoteStrategyImpl = class {
626
677
  // src/BridgingSdk/strategies/BestQuoteStrategy.ts
627
678
  var DEFAULT_TOTAL_TIMEOUT_MS2 = 4e4;
628
679
  var DEFAULT_PROVIDER_TIMEOUT_MS2 = 2e4;
629
- var BestQuoteStrategyImpl = class {
680
+ var BestQuoteStrategy = class extends BaseBestQuoteStrategy {
630
681
  strategyName = "BestQuoteStrategy";
682
+ constructor(intermediateTokensCache) {
683
+ super(intermediateTokensCache);
684
+ }
631
685
  async execute(request, config) {
632
686
  const { quoteBridgeRequest, providerDappIds, advancedSettings, options } = request;
633
687
  const { sellTokenChainId, buyTokenChainId } = quoteBridgeRequest;
@@ -661,14 +715,19 @@ var BestQuoteStrategyImpl = class {
661
715
  const { provider, quoteBridgeRequest, advancedSettings, providerTimeout, onQuoteResult, bestResult, firstError } = context;
662
716
  return (async () => {
663
717
  try {
718
+ const baseParams = {
719
+ swapAndBridgeRequest: quoteBridgeRequest,
720
+ advancedSettings,
721
+ tradingSdk: config.tradingSdk,
722
+ provider,
723
+ bridgeHookSigner: advancedSettings?.quoteSigner
724
+ };
725
+ const request = this.intermediateTokensCache ? {
726
+ ...baseParams,
727
+ intermediateTokensCache: this.intermediateTokensCache
728
+ } : baseParams;
664
729
  const quote = await Promise.race([
665
- getQuoteWithBridge({
666
- swapAndBridgeRequest: quoteBridgeRequest,
667
- advancedSettings,
668
- tradingSdk: config.tradingSdk,
669
- provider,
670
- bridgeHookSigner: advancedSettings?.quoteSigner
671
- }),
730
+ getQuoteWithBridge(request),
672
731
  createBridgeQuoteTimeoutPromise(providerTimeout, `Provider ${provider.info.dappId}`)
673
732
  ]);
674
733
  const result = {
@@ -694,17 +753,30 @@ var BestQuoteStrategyImpl = class {
694
753
  }
695
754
  };
696
755
 
756
+ // src/BridgingSdk/strategies/createStrategies.ts
757
+ function createStrategies(intermediateTokensCache) {
758
+ return {
759
+ singleQuoteStrategy: new SingleQuoteStrategy(intermediateTokensCache),
760
+ multiQuoteStrategy: new MultiQuoteStrategy(intermediateTokensCache),
761
+ bestQuoteStrategy: new BestQuoteStrategy(intermediateTokensCache)
762
+ };
763
+ }
764
+
697
765
  // src/BridgingSdk/BridgingSdk.ts
698
- var singleQuoteStrategy = new SingleQuoteStrategyImpl();
699
- var multiQuoteStrategy = new MultiQuoteStrategyImpl();
700
- var bestQuoteStrategy = new BestQuoteStrategyImpl();
766
+ var DEFAULT_CACHE_CONFIG = {
767
+ enabled: true,
768
+ intermediateTokensTtl: 5 * 60 * 1e3,
769
+ // 5 minutes
770
+ buyTokensTtl: 2 * 60 * 1e3
771
+ // 2 minutes
772
+ };
701
773
  var BridgingSdk = class {
702
774
  constructor(options, adapter) {
703
775
  this.options = options;
704
776
  if (adapter) {
705
777
  setGlobalAdapter(adapter);
706
778
  }
707
- const { providers, ...restOptions } = options;
779
+ const { providers, cacheConfig, ...restOptions } = options;
708
780
  if (!providers || providers.length === 0) {
709
781
  throw new Error("At least one bridge provider is required");
710
782
  }
@@ -719,8 +791,31 @@ var BridgingSdk = class {
719
791
  tradingSdk,
720
792
  orderBookApi
721
793
  };
794
+ this.cacheConfig = { ...DEFAULT_CACHE_CONFIG, ...cacheConfig };
795
+ this.intermediateTokensCache = new TTLCache2(
796
+ "bridging-intermediate-tokens",
797
+ this.cacheConfig.enabled,
798
+ this.cacheConfig.intermediateTokensTtl
799
+ );
800
+ this.buyTokensCache = new TTLCache2(
801
+ "bridging-buy-tokens",
802
+ this.cacheConfig.enabled,
803
+ this.cacheConfig.buyTokensTtl
804
+ );
805
+ const { singleQuoteStrategy, multiQuoteStrategy, bestQuoteStrategy } = createStrategies(
806
+ this.cacheConfig.enabled ? this.intermediateTokensCache : void 0
807
+ );
808
+ this.singleQuoteStrategy = singleQuoteStrategy;
809
+ this.multiQuoteStrategy = multiQuoteStrategy;
810
+ this.bestQuoteStrategy = bestQuoteStrategy;
722
811
  }
723
812
  config;
813
+ cacheConfig;
814
+ intermediateTokensCache;
815
+ buyTokensCache;
816
+ singleQuoteStrategy;
817
+ multiQuoteStrategy;
818
+ bestQuoteStrategy;
724
819
  get provider() {
725
820
  const { providers } = this.config;
726
821
  if (!providers[0]) {
@@ -752,7 +847,22 @@ var BridgingSdk = class {
752
847
  * @param params
753
848
  */
754
849
  async getBuyTokens(params) {
755
- return this.provider.getBuyTokens(params);
850
+ const providerId = this.provider.info.dappId;
851
+ const cacheKey = getCacheKey({
852
+ id: providerId,
853
+ buyChainId: params.buyChainId.toString(),
854
+ sellChainId: params.sellChainId?.toString(),
855
+ tokenAddress: params.sellTokenAddress
856
+ });
857
+ const cached = this.cacheConfig.enabled && this.buyTokensCache.get(cacheKey);
858
+ if (cached) {
859
+ return cached;
860
+ }
861
+ const result = await this.provider.getBuyTokens(params);
862
+ if (this.cacheConfig.enabled) {
863
+ this.buyTokensCache.set(cacheKey, result);
864
+ }
865
+ return result;
756
866
  }
757
867
  /**
758
868
  * Get quote details, including a callback function to post the order on-chain.
@@ -770,11 +880,13 @@ var BridgingSdk = class {
770
880
  * @throws Error if no path is found
771
881
  */
772
882
  async getQuote(quoteBridgeRequest, advancedSettings) {
773
- const request = {
774
- quoteBridgeRequest,
775
- advancedSettings
776
- };
777
- return singleQuoteStrategy.execute(request, this.config);
883
+ return this.singleQuoteStrategy.execute(
884
+ {
885
+ quoteBridgeRequest,
886
+ advancedSettings
887
+ },
888
+ this.config
889
+ );
778
890
  }
779
891
  /**
780
892
  * Get quotes from multiple bridge providers in parallel with progressive results.
@@ -792,7 +904,7 @@ var BridgingSdk = class {
792
904
  * ```
793
905
  */
794
906
  async getMultiQuotes(request) {
795
- return multiQuoteStrategy.execute(request, this.config);
907
+ return this.multiQuoteStrategy.execute(request, this.config);
796
908
  }
797
909
  /**
798
910
  * Get the best quote from multiple bridge providers with progressive updates.
@@ -810,7 +922,7 @@ var BridgingSdk = class {
810
922
  * @throws Error if the request is for a single-chain swap (sellTokenChainId === buyTokenChainId)
811
923
  */
812
924
  async getBestQuote(request) {
813
- return bestQuoteStrategy.execute(request, this.config);
925
+ return this.bestQuoteStrategy.execute(request, this.config);
814
926
  }
815
927
  async getOrder(params) {
816
928
  const { orderBookApi } = this.config;
@@ -829,6 +941,29 @@ var BridgingSdk = class {
829
941
  getProviderFromAppData(fullAppData) {
830
942
  return findBridgeProviderFromHook(fullAppData, this.getProviders());
831
943
  }
944
+ /**
945
+ * Clear all caches. Useful for testing and debugging.
946
+ */
947
+ clearCache() {
948
+ this.intermediateTokensCache.clear();
949
+ this.buyTokensCache.clear();
950
+ }
951
+ /**
952
+ * Clean up expired cache entries. Useful for maintenance.
953
+ */
954
+ cleanupExpiredCache() {
955
+ this.intermediateTokensCache.cleanup();
956
+ this.buyTokensCache.cleanup();
957
+ }
958
+ /**
959
+ * Get cache statistics for debugging.
960
+ */
961
+ getCacheStats() {
962
+ return {
963
+ intermediateTokens: this.intermediateTokensCache.size(),
964
+ buyTokens: this.buyTokensCache.size()
965
+ };
966
+ }
832
967
  getProviderByDappId(dappId) {
833
968
  return this.config.providers.find((provider) => provider.info.dappId === dappId);
834
969
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cowprotocol/sdk-bridging",
3
- "version": "0.3.3",
3
+ "version": "0.4.0",
4
4
  "description": "Bridging for CoW Protocol",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -14,14 +14,14 @@
14
14
  "access": "public"
15
15
  },
16
16
  "dependencies": {
17
- "@cowprotocol/sdk-app-data": "4.0.0",
18
- "@cowprotocol/sdk-common": "0.1.0",
17
+ "@cowprotocol/sdk-common": "0.2.0",
18
+ "@cowprotocol/sdk-app-data": "4.0.1",
19
19
  "@cowprotocol/sdk-config": "0.1.0",
20
- "@cowprotocol/sdk-contracts-ts": "0.2.1",
21
- "@cowprotocol/sdk-cow-shed": "0.1.3",
22
- "@cowprotocol/sdk-order-book": "0.1.0",
23
- "@cowprotocol/sdk-trading": "0.1.3",
24
- "@cowprotocol/sdk-weiroll": "0.1.0"
20
+ "@cowprotocol/sdk-contracts-ts": "0.3.0",
21
+ "@cowprotocol/sdk-cow-shed": "0.1.4",
22
+ "@cowprotocol/sdk-order-book": "0.1.1",
23
+ "@cowprotocol/sdk-trading": "0.2.0",
24
+ "@cowprotocol/sdk-weiroll": "0.1.1"
25
25
  },
26
26
  "devDependencies": {
27
27
  "ethers-v5": "npm:ethers@^5.7.2",
@@ -36,11 +36,11 @@
36
36
  "ts-jest": "^29.0.0",
37
37
  "ethers": "^5.7.2",
38
38
  "viem": "^2.28.4",
39
+ "@cowprotocol/sdk-order-signing": "0.1.4",
39
40
  "@cow-sdk/typescript-config": "0.0.0-beta.0",
40
- "@cowprotocol/sdk-order-signing": "0.1.3",
41
- "@cowprotocol/sdk-ethers-v6-adapter": "0.1.0",
42
- "@cowprotocol/sdk-viem-adapter": "0.1.0",
43
- "@cowprotocol/sdk-ethers-v5-adapter": "0.1.0"
41
+ "@cowprotocol/sdk-ethers-v5-adapter": "0.1.1",
42
+ "@cowprotocol/sdk-ethers-v6-adapter": "0.1.1",
43
+ "@cowprotocol/sdk-viem-adapter": "0.1.1"
44
44
  },
45
45
  "scripts": {
46
46
  "build": "tsup src/index.ts --format esm,cjs --dts",