@imtbl/sdk 0.35.0 → 0.35.2

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.cjs CHANGED
@@ -3791,7 +3791,7 @@ class MultiRollupApiClients {
3791
3791
  }
3792
3792
 
3793
3793
  // eslint-disable-next-line @typescript-eslint/naming-convention
3794
- const defaultHeaders$1 = { 'x-sdk-version': 'ts-immutable-sdk-0.35.0' };
3794
+ const defaultHeaders$1 = { 'x-sdk-version': 'ts-immutable-sdk-0.35.2' };
3795
3795
  const createConfig = ({ basePath, headers, }) => {
3796
3796
  if (!basePath.trim()) {
3797
3797
  throw Error('basePath can not be empty');
@@ -3851,7 +3851,7 @@ class APIError extends Error {
3851
3851
 
3852
3852
  /* eslint-disable implicit-arrow-linebreak */
3853
3853
  const defaultHeaders = {
3854
- sdkVersion: 'ts-immutable-sdk-multi-rollup-api-client-0.35.0',
3854
+ sdkVersion: 'ts-immutable-sdk-multi-rollup-api-client-0.35.2',
3855
3855
  };
3856
3856
  /**
3857
3857
  * createAPIConfiguration to create a custom Configuration
@@ -4262,7 +4262,7 @@ const createImmutableXConfiguration = ({ basePath, chainID, coreContractAddress,
4262
4262
  chainID,
4263
4263
  coreContractAddress,
4264
4264
  registrationContractAddress,
4265
- sdkVersion: 'ts-immutable-sdk-0.35.0',
4265
+ sdkVersion: 'ts-immutable-sdk-0.35.2',
4266
4266
  });
4267
4267
  /**
4268
4268
  * Sets `sdkVersion` at the time of build
@@ -8790,7 +8790,7 @@ var ChainId$1;
8790
8790
  (function (ChainId) {
8791
8791
  ChainId[ChainId["IMTBL_ZKEVM_MAINNET"] = 13371] = "IMTBL_ZKEVM_MAINNET";
8792
8792
  ChainId[ChainId["IMTBL_ZKEVM_TESTNET"] = 13473] = "IMTBL_ZKEVM_TESTNET";
8793
- ChainId[ChainId["IMTBL_ZKEVM_DEVNET"] = 13433] = "IMTBL_ZKEVM_DEVNET";
8793
+ ChainId[ChainId["IMTBL_ZKEVM_DEVNET"] = 15003] = "IMTBL_ZKEVM_DEVNET";
8794
8794
  ChainId[ChainId["ETHEREUM"] = 1] = "ETHEREUM";
8795
8795
  ChainId[ChainId["SEPOLIA"] = 11155111] = "SEPOLIA";
8796
8796
  })(ChainId$1 || (ChainId$1 = {}));
@@ -28439,7 +28439,6 @@ class UniswapV3Pool__factory extends ethers.ContractFactory {
28439
28439
  }
28440
28440
  }
28441
28441
 
28442
- const DEFAULT_GAS_QUOTE = 2000000;
28443
28442
  // TODO: Better description of function and args
28444
28443
  async function multicallSingleCallDataMultipleContracts(multicallContract, functionName, addresses) {
28445
28444
  // Encode args - generate calldata for contract
@@ -28461,22 +28460,6 @@ async function multicallSingleCallDataMultipleContracts(multicallContract, funct
28461
28460
  }
28462
28461
  return multicallContract.callStatic.multicall(calls);
28463
28462
  }
28464
- // TODO: Better description of function and args
28465
- async function multicallMultipleCallDataSingContract(multicallContract, calldata, address, options) {
28466
- // Create call objects
28467
- const calls = new Array(calldata.length);
28468
- // TODO: use object.keys of something similar to avoid iterating over
28469
- // entire object prototype
28470
- // eslint-disable-next-line no-restricted-syntax, guard-for-in
28471
- for (const i in calldata) {
28472
- calls[i] = {
28473
- target: address,
28474
- callData: calldata[i],
28475
- gasLimit: options?.gasRequired ?? DEFAULT_GAS_QUOTE,
28476
- };
28477
- }
28478
- return multicallContract.callStatic.multicall(calls);
28479
- }
28480
28463
  const getCallData = (methodName, contractInterface) => {
28481
28464
  // Create ethers function fragment
28482
28465
  const fragment = contractInterface?.getFunction(methodName);
@@ -28636,35 +28619,27 @@ const getDefaultDeadlineSeconds = () => Math.floor(Date.now() / 1000) + DEFAULT_
28636
28619
 
28637
28620
  const amountIndex = 0;
28638
28621
  const gasEstimateIndex = 3;
28639
- async function getQuotesForRoutes(multicallContract, quoterContractAddress, routes, amountSpecified, tradeType) {
28640
- const callData = routes.map((route) => v3Sdk.SwapQuoter.quoteCallParameters(route, toCurrencyAmount(amountSpecified), tradeType, {
28622
+ async function getQuotesForRoutes(provider, quoterContractAddress, routes, amountSpecified, tradeType) {
28623
+ const callDatas = routes.map((route) => v3Sdk.SwapQuoter.quoteCallParameters(route, toCurrencyAmount(amountSpecified), tradeType, {
28641
28624
  useQuoterV2: true,
28642
28625
  }).calldata);
28643
- let quoteResults;
28644
- try {
28645
- quoteResults = await multicallMultipleCallDataSingContract(multicallContract, callData, quoterContractAddress);
28646
- }
28647
- catch (e) {
28648
- const message = e instanceof Error ? e.message : 'Unknown Error';
28649
- throw new ProviderCallError(`failed multicall: ${message}`);
28650
- }
28651
- const decodedQuoteResults = [];
28652
- // TODO: for..in loops iterate over the entire prototype chain,
28653
- // Use Object.{keys,values,entries}, and iterate over the resulting array.
28654
- // eslint-disable-next-line no-restricted-syntax, guard-for-in
28655
- for (const i in quoteResults.returnData) {
28656
- const functionSig = callData[i].substring(0, 10);
28626
+ const promises = await Promise.allSettled(callDatas.map((data) => provider.send('eth_call', [
28627
+ { to: quoterContractAddress, data }, 'latest',
28628
+ ])));
28629
+ const decodedQuoteResults = promises.reduce((quoteResults, promiseResult, i) => {
28630
+ if (promiseResult.status === 'rejected')
28631
+ return quoteResults;
28632
+ const functionSig = callDatas[i].substring(0, 10);
28657
28633
  const returnTypes = quoteReturnMapping[functionSig];
28658
28634
  if (!returnTypes) {
28659
28635
  throw new Error('No quoting function signature found');
28660
28636
  }
28661
- if (quoteResults.returnData[i].returnData === '0x') {
28637
+ if (promiseResult.value === '0x') {
28662
28638
  // There is no quote result for the swap using this route, so don't include it in results
28663
- // eslint-disable-next-line no-continue
28664
- continue;
28639
+ return quoteResults;
28665
28640
  }
28666
28641
  try {
28667
- const decodedQuoteResult = ethers.ethers.utils.defaultAbiCoder.decode(returnTypes, quoteResults.returnData[i].returnData);
28642
+ const decodedQuoteResult = ethers.utils.defaultAbiCoder.decode(returnTypes, promiseResult.value);
28668
28643
  if (decodedQuoteResult) {
28669
28644
  // The 0th element in each decoded data is going to be the amountOut or amountIn.
28670
28645
  const quoteAmount = decodedQuoteResult[amountIndex];
@@ -28672,11 +28647,11 @@ async function getQuotesForRoutes(multicallContract, quoterContractAddress, rout
28672
28647
  throw new Error('Expected BigNumber');
28673
28648
  const input = uniswapTokenToERC20(routes[i].input);
28674
28649
  const output = uniswapTokenToERC20(routes[i].output);
28675
- decodedQuoteResults.push({
28650
+ quoteResults.push({
28676
28651
  route: routes[i],
28677
28652
  amountIn: tradeType === Uniswap.TradeType.EXACT_INPUT ? amountSpecified : newAmount(quoteAmount, input),
28678
28653
  amountOut: tradeType === Uniswap.TradeType.EXACT_INPUT ? newAmount(quoteAmount, output) : amountSpecified,
28679
- gasEstimate: ethers.ethers.BigNumber.from(decodedQuoteResult[gasEstimateIndex]),
28654
+ gasEstimate: ethers.BigNumber.from(decodedQuoteResult[gasEstimateIndex]),
28680
28655
  tradeType,
28681
28656
  });
28682
28657
  }
@@ -28686,7 +28661,8 @@ async function getQuotesForRoutes(multicallContract, quoterContractAddress, rout
28686
28661
  // Other quotes for routes may still succeed, so do nothing
28687
28662
  // and continue processing
28688
28663
  }
28689
- }
28664
+ return quoteResults;
28665
+ }, new Array());
28690
28666
  return decodedQuoteResults;
28691
28667
  }
28692
28668
 
@@ -28814,19 +28790,24 @@ const fetchValidPools = async (multicallContract, erc20Pair, commonRoutingERC20s
28814
28790
 
28815
28791
  class Router {
28816
28792
  provider;
28793
+ multicallContract;
28817
28794
  routingTokens;
28818
28795
  routingContracts;
28819
- constructor(provider, routingTokens, routingContracts) {
28796
+ constructor(provider, multicallContract, routingTokens, routingContracts) {
28820
28797
  this.provider = provider;
28798
+ this.multicallContract = multicallContract;
28799
+ this.routingTokens = routingTokens;
28800
+ this.routingContracts = routingContracts;
28801
+ this.provider = provider;
28802
+ this.multicallContract = multicallContract;
28821
28803
  this.routingTokens = routingTokens;
28822
28804
  this.routingContracts = routingContracts;
28823
28805
  }
28824
28806
  async findOptimalRoute(amountSpecified, otherToken, tradeType, maxHops = 2) {
28825
28807
  const [tokenIn, tokenOut] = this.determineERC20InAndERC20Out(tradeType, amountSpecified, otherToken);
28826
- const multicallContract = Multicall__factory.connect(this.routingContracts.multicallAddress, this.provider);
28827
28808
  const erc20Pair = [tokenIn, tokenOut];
28828
28809
  // Get all pools and use these to get all possible routes.
28829
- const pools = await fetchValidPools(multicallContract, erc20Pair, this.routingTokens, this.routingContracts.factoryAddress);
28810
+ const pools = await fetchValidPools(this.multicallContract, erc20Pair, this.routingTokens, this.routingContracts.coreFactory);
28830
28811
  const noValidPools = pools.length === 0;
28831
28812
  if (noValidPools) {
28832
28813
  throw new NoRoutesAvailableError();
@@ -28840,10 +28821,10 @@ class Router {
28840
28821
  throw new NoRoutesAvailableError();
28841
28822
  }
28842
28823
  // Get the best quote from all of the given routes
28843
- return await this.getBestQuoteFromRoutes(multicallContract, routes, amountSpecified, tradeType);
28824
+ return await this.getBestQuoteFromRoutes(routes, amountSpecified, tradeType);
28844
28825
  }
28845
- async getBestQuoteFromRoutes(multicallContract, routes, amountSpecified, tradeType) {
28846
- const quotes = await getQuotesForRoutes(multicallContract, this.routingContracts.quoterAddress, routes, amountSpecified, tradeType);
28826
+ async getBestQuoteFromRoutes(routes, amountSpecified, tradeType) {
28827
+ const quotes = await getQuotesForRoutes(this.provider, this.routingContracts.quoterV2, routes, amountSpecified, tradeType);
28847
28828
  if (quotes.length === 0) {
28848
28829
  throw new NoRoutesAvailableError();
28849
28830
  }
@@ -28919,36 +28900,38 @@ startTokenIn = tokenIn) => {
28919
28900
  return routes;
28920
28901
  };
28921
28902
 
28922
- /**
28923
- * Determines whether or not the chain supports EIP-1559 by checking for the existence
28924
- * of {@link FeeData.maxFeePerGas} and {@link FeeData.maxPriorityFeePerGas}
28925
- *
28926
- * @param {FeeData} fee - The fee data for the chain
28927
- */
28928
- const doesChainSupportEIP1559$1 = (fee) => {
28929
- const supportsEIP1559 = !!fee.maxFeePerGas && !!fee.maxPriorityFeePerGas;
28930
- return supportsEIP1559;
28903
+ const getFeeData = async (provider) => {
28904
+ const [block, maxPriorityFeePerGas] = await Promise.all([
28905
+ provider.getBlock('latest'),
28906
+ provider.send('eth_maxPriorityFeePerGas', []),
28907
+ ]);
28908
+ if (!block.baseFeePerGas)
28909
+ throw new Error('Base fee per gas not found in block');
28910
+ return {
28911
+ // https://www.blocknative.com/blog/eip-1559-fees
28912
+ maxFeePerGas: block.baseFeePerGas.mul(2).add(maxPriorityFeePerGas),
28913
+ maxPriorityFeePerGas,
28914
+ lastBaseFeePerGas: block.baseFeePerGas,
28915
+ };
28931
28916
  };
28932
28917
  /**
28933
28918
  * Fetch the current gas price estimate. Supports both EIP-1559 and non-EIP1559 chains
28934
- * @param {JsonRpcProvider} provider - The JSON RPC provider used to fetch fee data
28919
+ * @param {Provider} provider - The JSON RPC provider used to fetch fee data
28935
28920
  * @param {Native} nativeToken - The native token of the chain. Gas prices will be denominated in this token
28936
- * @returns {Amount | null} - The gas price in the smallest denomination of the chain's currency,
28921
+ * @returns {CoinAmount<Native> | null} - The gas price in the smallest denomination of the chain's currency,
28937
28922
  * or null if no gas price is available
28938
28923
  */
28924
+ // eslint-disable-next-line max-len
28939
28925
  const fetchGasPrice = async (provider, nativeToken) => {
28940
- const feeData = await provider.getFeeData().catch(() => null);
28926
+ const feeData = await getFeeData(provider).catch(() => null);
28941
28927
  if (!feeData)
28942
28928
  return null;
28943
- if (doesChainSupportEIP1559$1(feeData)) {
28944
- return newAmount(feeData.maxFeePerGas.add(feeData.maxPriorityFeePerGas), nativeToken);
28945
- }
28946
- return feeData.gasPrice ? newAmount(feeData.gasPrice, nativeToken) : null;
28929
+ return newAmount(feeData.maxFeePerGas, nativeToken);
28947
28930
  };
28948
28931
  /**
28949
28932
  * Calculate the gas fee from the gas price and gas units used for the transaction
28950
28933
  *
28951
- * @param {Amount} gasPrice - The price of gas
28934
+ * @param {CoinAmount<Native>} gasPrice - The price of gas
28952
28935
  * @param {BigNumber} gasEstimate - The total gas units that will be used for the transaction
28953
28936
  * @returns - The cost of the transaction in the gas token's smallest denomination (e.g. WEI)
28954
28937
  */
@@ -29572,6 +29555,7 @@ const toPublicQuote = (amount, amountWithMaxSlippage, slippage, fees) => ({
29572
29555
  });
29573
29556
  class Exchange {
29574
29557
  provider;
29558
+ batchProvider;
29575
29559
  router;
29576
29560
  chainId;
29577
29561
  nativeToken;
@@ -29589,12 +29573,16 @@ class Exchange {
29589
29573
  this.secondaryFees = config.secondaryFees;
29590
29574
  this.routerContractAddress = config.chain.contracts.peripheryRouter;
29591
29575
  this.secondaryFeeContractAddress = config.chain.contracts.secondaryFee;
29592
- this.provider = new ethers.ethers.providers.JsonRpcProvider(config.chain.rpcUrl);
29593
- this.router = new Router(this.provider, config.chain.commonRoutingTokens, {
29594
- multicallAddress: config.chain.contracts.multicall,
29595
- factoryAddress: config.chain.contracts.coreFactory,
29596
- quoterAddress: config.chain.contracts.quoterV2,
29597
- });
29576
+ this.provider = new ethers.ethers.providers.StaticJsonRpcProvider({
29577
+ url: config.chain.rpcUrl,
29578
+ skipFetchSetup: true,
29579
+ }, config.chain.chainId);
29580
+ this.batchProvider = new ethers.ethers.providers.JsonRpcBatchProvider({
29581
+ url: config.chain.rpcUrl,
29582
+ skipFetchSetup: true,
29583
+ }, config.chain.chainId);
29584
+ const multicallContract = Multicall__factory.connect(config.chain.contracts.multicall, this.provider);
29585
+ this.router = new Router(this.batchProvider, multicallContract, config.chain.commonRoutingTokens, config.chain.contracts);
29598
29586
  }
29599
29587
  static validate(tokenInAddress, tokenOutAddress, maxHops, slippagePercent, fromAddress) {
29600
29588
  assert(isValidNonZeroAddress(fromAddress), new InvalidAddressError('invalid from address'));
@@ -29606,11 +29594,11 @@ class Exchange {
29606
29594
  assert(slippagePercent <= 50, new InvalidSlippageError('slippage percent must be less than or equal to 50'));
29607
29595
  assert(slippagePercent >= 0, new InvalidSlippageError('slippage percent must be greater than or equal to 0'));
29608
29596
  }
29609
- async getSecondaryFees() {
29597
+ async getSecondaryFees(provider) {
29610
29598
  if (this.secondaryFees.length === 0) {
29611
29599
  return [];
29612
29600
  }
29613
- const secondaryFeeContract = SecondaryFee__factory.connect(this.secondaryFeeContractAddress, this.provider);
29601
+ const secondaryFeeContract = SecondaryFee__factory.connect(this.secondaryFeeContractAddress, provider);
29614
29602
  if (await secondaryFeeContract.paused()) {
29615
29603
  // Do not use secondary fees if the contract is paused
29616
29604
  return [];
@@ -29631,11 +29619,13 @@ class Exchange {
29631
29619
  async getUnsignedSwapTx(fromAddress, tokenInLiteral, tokenOutLiteral, amount, slippagePercent, maxHops, deadline, tradeType) {
29632
29620
  Exchange.validate(tokenInLiteral, tokenOutLiteral, maxHops, slippagePercent, fromAddress);
29633
29621
  // get the decimals of the tokens that will be swapped
29634
- const [tokenInDecimals, tokenOutDecimals, secondaryFees] = await Promise.all([
29635
- getTokenDecimals(tokenInLiteral, this.provider, this.nativeToken),
29636
- getTokenDecimals(tokenOutLiteral, this.provider, this.nativeToken),
29637
- this.getSecondaryFees(),
29638
- ]);
29622
+ const promises = [
29623
+ getTokenDecimals(tokenInLiteral, this.batchProvider, this.nativeToken),
29624
+ getTokenDecimals(tokenOutLiteral, this.batchProvider, this.nativeToken),
29625
+ this.getSecondaryFees(this.batchProvider),
29626
+ fetchGasPrice(this.batchProvider, this.nativeToken),
29627
+ ];
29628
+ const [tokenInDecimals, tokenOutDecimals, secondaryFees, gasPrice] = await Promise.all(promises);
29639
29629
  const tokenIn = this.parseTokenLiteral(tokenInLiteral, tokenInDecimals);
29640
29630
  const tokenOut = this.parseTokenLiteral(tokenOutLiteral, tokenOutDecimals);
29641
29631
  // determine which amount was specified for the swap from the TradeType
@@ -29644,10 +29634,7 @@ class Exchange {
29644
29634
  const fees = new Fees(secondaryFees, tokenIn);
29645
29635
  const ourQuoteReqAmount = getOurQuoteReqAmount(amountSpecified, fees, tradeType, this.nativeTokenService);
29646
29636
  // Quotes will always use ERC20s. If the user-specified token is Native, we use the Wrapped Native Token pool
29647
- const [ourQuote, gasPrice] = await Promise.all([
29648
- this.router.findOptimalRoute(ourQuoteReqAmount, this.nativeTokenService.maybeWrapToken(otherToken), tradeType, maxHops),
29649
- fetchGasPrice(this.provider, this.nativeToken),
29650
- ]);
29637
+ const ourQuote = await this.router.findOptimalRoute(ourQuoteReqAmount, this.nativeTokenService.maybeWrapToken(otherToken), tradeType, maxHops);
29651
29638
  const adjustedQuote = adjustQuoteWithFees(ourQuote, amountSpecified, fees, this.nativeTokenService);
29652
29639
  const swap = getSwap(tokenIn, tokenOut, adjustedQuote, fromAddress, slippagePercent, deadline, this.routerContractAddress, this.secondaryFeeContractAddress, gasPrice, secondaryFees);
29653
29640
  const { quotedAmount, quotedAmountWithMaxSlippage } = prepareUserQuote(this.nativeTokenService, adjustedQuote, slippagePercent, otherToken);
@@ -30584,7 +30571,7 @@ const GAS_OVERRIDES = {
30584
30571
  maxPriorityFeePerGas: ethers.BigNumber.from(101e9),
30585
30572
  };
30586
30573
 
30587
- const SDK_VERSION_MARKER = '0.35.0';
30574
+ const SDK_VERSION_MARKER = '0.35.2';
30588
30575
  // This SDK version is replaced by the `yarn build` command ran on the root level
30589
30576
  const globalPackageVersion = () => SDK_VERSION_MARKER;
30590
30577
 
package/dist/index.js CHANGED
@@ -3769,7 +3769,7 @@ class MultiRollupApiClients {
3769
3769
  }
3770
3770
 
3771
3771
  // eslint-disable-next-line @typescript-eslint/naming-convention
3772
- const defaultHeaders$1 = { 'x-sdk-version': 'ts-immutable-sdk-0.35.0' };
3772
+ const defaultHeaders$1 = { 'x-sdk-version': 'ts-immutable-sdk-0.35.2' };
3773
3773
  const createConfig = ({ basePath, headers, }) => {
3774
3774
  if (!basePath.trim()) {
3775
3775
  throw Error('basePath can not be empty');
@@ -3829,7 +3829,7 @@ class APIError extends Error {
3829
3829
 
3830
3830
  /* eslint-disable implicit-arrow-linebreak */
3831
3831
  const defaultHeaders = {
3832
- sdkVersion: 'ts-immutable-sdk-multi-rollup-api-client-0.35.0',
3832
+ sdkVersion: 'ts-immutable-sdk-multi-rollup-api-client-0.35.2',
3833
3833
  };
3834
3834
  /**
3835
3835
  * createAPIConfiguration to create a custom Configuration
@@ -4240,7 +4240,7 @@ const createImmutableXConfiguration = ({ basePath, chainID, coreContractAddress,
4240
4240
  chainID,
4241
4241
  coreContractAddress,
4242
4242
  registrationContractAddress,
4243
- sdkVersion: 'ts-immutable-sdk-0.35.0',
4243
+ sdkVersion: 'ts-immutable-sdk-0.35.2',
4244
4244
  });
4245
4245
  /**
4246
4246
  * Sets `sdkVersion` at the time of build
@@ -8768,7 +8768,7 @@ var ChainId$1;
8768
8768
  (function (ChainId) {
8769
8769
  ChainId[ChainId["IMTBL_ZKEVM_MAINNET"] = 13371] = "IMTBL_ZKEVM_MAINNET";
8770
8770
  ChainId[ChainId["IMTBL_ZKEVM_TESTNET"] = 13473] = "IMTBL_ZKEVM_TESTNET";
8771
- ChainId[ChainId["IMTBL_ZKEVM_DEVNET"] = 13433] = "IMTBL_ZKEVM_DEVNET";
8771
+ ChainId[ChainId["IMTBL_ZKEVM_DEVNET"] = 15003] = "IMTBL_ZKEVM_DEVNET";
8772
8772
  ChainId[ChainId["ETHEREUM"] = 1] = "ETHEREUM";
8773
8773
  ChainId[ChainId["SEPOLIA"] = 11155111] = "SEPOLIA";
8774
8774
  })(ChainId$1 || (ChainId$1 = {}));
@@ -28417,7 +28417,6 @@ class UniswapV3Pool__factory extends ContractFactory {
28417
28417
  }
28418
28418
  }
28419
28419
 
28420
- const DEFAULT_GAS_QUOTE = 2000000;
28421
28420
  // TODO: Better description of function and args
28422
28421
  async function multicallSingleCallDataMultipleContracts(multicallContract, functionName, addresses) {
28423
28422
  // Encode args - generate calldata for contract
@@ -28439,22 +28438,6 @@ async function multicallSingleCallDataMultipleContracts(multicallContract, funct
28439
28438
  }
28440
28439
  return multicallContract.callStatic.multicall(calls);
28441
28440
  }
28442
- // TODO: Better description of function and args
28443
- async function multicallMultipleCallDataSingContract(multicallContract, calldata, address, options) {
28444
- // Create call objects
28445
- const calls = new Array(calldata.length);
28446
- // TODO: use object.keys of something similar to avoid iterating over
28447
- // entire object prototype
28448
- // eslint-disable-next-line no-restricted-syntax, guard-for-in
28449
- for (const i in calldata) {
28450
- calls[i] = {
28451
- target: address,
28452
- callData: calldata[i],
28453
- gasLimit: options?.gasRequired ?? DEFAULT_GAS_QUOTE,
28454
- };
28455
- }
28456
- return multicallContract.callStatic.multicall(calls);
28457
- }
28458
28441
  const getCallData = (methodName, contractInterface) => {
28459
28442
  // Create ethers function fragment
28460
28443
  const fragment = contractInterface?.getFunction(methodName);
@@ -28614,35 +28597,27 @@ const getDefaultDeadlineSeconds = () => Math.floor(Date.now() / 1000) + DEFAULT_
28614
28597
 
28615
28598
  const amountIndex = 0;
28616
28599
  const gasEstimateIndex = 3;
28617
- async function getQuotesForRoutes(multicallContract, quoterContractAddress, routes, amountSpecified, tradeType) {
28618
- const callData = routes.map((route) => SwapQuoter.quoteCallParameters(route, toCurrencyAmount(amountSpecified), tradeType, {
28600
+ async function getQuotesForRoutes(provider, quoterContractAddress, routes, amountSpecified, tradeType) {
28601
+ const callDatas = routes.map((route) => SwapQuoter.quoteCallParameters(route, toCurrencyAmount(amountSpecified), tradeType, {
28619
28602
  useQuoterV2: true,
28620
28603
  }).calldata);
28621
- let quoteResults;
28622
- try {
28623
- quoteResults = await multicallMultipleCallDataSingContract(multicallContract, callData, quoterContractAddress);
28624
- }
28625
- catch (e) {
28626
- const message = e instanceof Error ? e.message : 'Unknown Error';
28627
- throw new ProviderCallError(`failed multicall: ${message}`);
28628
- }
28629
- const decodedQuoteResults = [];
28630
- // TODO: for..in loops iterate over the entire prototype chain,
28631
- // Use Object.{keys,values,entries}, and iterate over the resulting array.
28632
- // eslint-disable-next-line no-restricted-syntax, guard-for-in
28633
- for (const i in quoteResults.returnData) {
28634
- const functionSig = callData[i].substring(0, 10);
28604
+ const promises = await Promise.allSettled(callDatas.map((data) => provider.send('eth_call', [
28605
+ { to: quoterContractAddress, data }, 'latest',
28606
+ ])));
28607
+ const decodedQuoteResults = promises.reduce((quoteResults, promiseResult, i) => {
28608
+ if (promiseResult.status === 'rejected')
28609
+ return quoteResults;
28610
+ const functionSig = callDatas[i].substring(0, 10);
28635
28611
  const returnTypes = quoteReturnMapping[functionSig];
28636
28612
  if (!returnTypes) {
28637
28613
  throw new Error('No quoting function signature found');
28638
28614
  }
28639
- if (quoteResults.returnData[i].returnData === '0x') {
28615
+ if (promiseResult.value === '0x') {
28640
28616
  // There is no quote result for the swap using this route, so don't include it in results
28641
- // eslint-disable-next-line no-continue
28642
- continue;
28617
+ return quoteResults;
28643
28618
  }
28644
28619
  try {
28645
- const decodedQuoteResult = ethers.utils.defaultAbiCoder.decode(returnTypes, quoteResults.returnData[i].returnData);
28620
+ const decodedQuoteResult = utils$1.defaultAbiCoder.decode(returnTypes, promiseResult.value);
28646
28621
  if (decodedQuoteResult) {
28647
28622
  // The 0th element in each decoded data is going to be the amountOut or amountIn.
28648
28623
  const quoteAmount = decodedQuoteResult[amountIndex];
@@ -28650,11 +28625,11 @@ async function getQuotesForRoutes(multicallContract, quoterContractAddress, rout
28650
28625
  throw new Error('Expected BigNumber');
28651
28626
  const input = uniswapTokenToERC20(routes[i].input);
28652
28627
  const output = uniswapTokenToERC20(routes[i].output);
28653
- decodedQuoteResults.push({
28628
+ quoteResults.push({
28654
28629
  route: routes[i],
28655
28630
  amountIn: tradeType === TradeType.EXACT_INPUT ? amountSpecified : newAmount(quoteAmount, input),
28656
28631
  amountOut: tradeType === TradeType.EXACT_INPUT ? newAmount(quoteAmount, output) : amountSpecified,
28657
- gasEstimate: ethers.BigNumber.from(decodedQuoteResult[gasEstimateIndex]),
28632
+ gasEstimate: BigNumber$1.from(decodedQuoteResult[gasEstimateIndex]),
28658
28633
  tradeType,
28659
28634
  });
28660
28635
  }
@@ -28664,7 +28639,8 @@ async function getQuotesForRoutes(multicallContract, quoterContractAddress, rout
28664
28639
  // Other quotes for routes may still succeed, so do nothing
28665
28640
  // and continue processing
28666
28641
  }
28667
- }
28642
+ return quoteResults;
28643
+ }, new Array());
28668
28644
  return decodedQuoteResults;
28669
28645
  }
28670
28646
 
@@ -28792,19 +28768,24 @@ const fetchValidPools = async (multicallContract, erc20Pair, commonRoutingERC20s
28792
28768
 
28793
28769
  class Router {
28794
28770
  provider;
28771
+ multicallContract;
28795
28772
  routingTokens;
28796
28773
  routingContracts;
28797
- constructor(provider, routingTokens, routingContracts) {
28774
+ constructor(provider, multicallContract, routingTokens, routingContracts) {
28798
28775
  this.provider = provider;
28776
+ this.multicallContract = multicallContract;
28777
+ this.routingTokens = routingTokens;
28778
+ this.routingContracts = routingContracts;
28779
+ this.provider = provider;
28780
+ this.multicallContract = multicallContract;
28799
28781
  this.routingTokens = routingTokens;
28800
28782
  this.routingContracts = routingContracts;
28801
28783
  }
28802
28784
  async findOptimalRoute(amountSpecified, otherToken, tradeType, maxHops = 2) {
28803
28785
  const [tokenIn, tokenOut] = this.determineERC20InAndERC20Out(tradeType, amountSpecified, otherToken);
28804
- const multicallContract = Multicall__factory.connect(this.routingContracts.multicallAddress, this.provider);
28805
28786
  const erc20Pair = [tokenIn, tokenOut];
28806
28787
  // Get all pools and use these to get all possible routes.
28807
- const pools = await fetchValidPools(multicallContract, erc20Pair, this.routingTokens, this.routingContracts.factoryAddress);
28788
+ const pools = await fetchValidPools(this.multicallContract, erc20Pair, this.routingTokens, this.routingContracts.coreFactory);
28808
28789
  const noValidPools = pools.length === 0;
28809
28790
  if (noValidPools) {
28810
28791
  throw new NoRoutesAvailableError();
@@ -28818,10 +28799,10 @@ class Router {
28818
28799
  throw new NoRoutesAvailableError();
28819
28800
  }
28820
28801
  // Get the best quote from all of the given routes
28821
- return await this.getBestQuoteFromRoutes(multicallContract, routes, amountSpecified, tradeType);
28802
+ return await this.getBestQuoteFromRoutes(routes, amountSpecified, tradeType);
28822
28803
  }
28823
- async getBestQuoteFromRoutes(multicallContract, routes, amountSpecified, tradeType) {
28824
- const quotes = await getQuotesForRoutes(multicallContract, this.routingContracts.quoterAddress, routes, amountSpecified, tradeType);
28804
+ async getBestQuoteFromRoutes(routes, amountSpecified, tradeType) {
28805
+ const quotes = await getQuotesForRoutes(this.provider, this.routingContracts.quoterV2, routes, amountSpecified, tradeType);
28825
28806
  if (quotes.length === 0) {
28826
28807
  throw new NoRoutesAvailableError();
28827
28808
  }
@@ -28897,36 +28878,38 @@ startTokenIn = tokenIn) => {
28897
28878
  return routes;
28898
28879
  };
28899
28880
 
28900
- /**
28901
- * Determines whether or not the chain supports EIP-1559 by checking for the existence
28902
- * of {@link FeeData.maxFeePerGas} and {@link FeeData.maxPriorityFeePerGas}
28903
- *
28904
- * @param {FeeData} fee - The fee data for the chain
28905
- */
28906
- const doesChainSupportEIP1559$1 = (fee) => {
28907
- const supportsEIP1559 = !!fee.maxFeePerGas && !!fee.maxPriorityFeePerGas;
28908
- return supportsEIP1559;
28881
+ const getFeeData = async (provider) => {
28882
+ const [block, maxPriorityFeePerGas] = await Promise.all([
28883
+ provider.getBlock('latest'),
28884
+ provider.send('eth_maxPriorityFeePerGas', []),
28885
+ ]);
28886
+ if (!block.baseFeePerGas)
28887
+ throw new Error('Base fee per gas not found in block');
28888
+ return {
28889
+ // https://www.blocknative.com/blog/eip-1559-fees
28890
+ maxFeePerGas: block.baseFeePerGas.mul(2).add(maxPriorityFeePerGas),
28891
+ maxPriorityFeePerGas,
28892
+ lastBaseFeePerGas: block.baseFeePerGas,
28893
+ };
28909
28894
  };
28910
28895
  /**
28911
28896
  * Fetch the current gas price estimate. Supports both EIP-1559 and non-EIP1559 chains
28912
- * @param {JsonRpcProvider} provider - The JSON RPC provider used to fetch fee data
28897
+ * @param {Provider} provider - The JSON RPC provider used to fetch fee data
28913
28898
  * @param {Native} nativeToken - The native token of the chain. Gas prices will be denominated in this token
28914
- * @returns {Amount | null} - The gas price in the smallest denomination of the chain's currency,
28899
+ * @returns {CoinAmount<Native> | null} - The gas price in the smallest denomination of the chain's currency,
28915
28900
  * or null if no gas price is available
28916
28901
  */
28902
+ // eslint-disable-next-line max-len
28917
28903
  const fetchGasPrice = async (provider, nativeToken) => {
28918
- const feeData = await provider.getFeeData().catch(() => null);
28904
+ const feeData = await getFeeData(provider).catch(() => null);
28919
28905
  if (!feeData)
28920
28906
  return null;
28921
- if (doesChainSupportEIP1559$1(feeData)) {
28922
- return newAmount(feeData.maxFeePerGas.add(feeData.maxPriorityFeePerGas), nativeToken);
28923
- }
28924
- return feeData.gasPrice ? newAmount(feeData.gasPrice, nativeToken) : null;
28907
+ return newAmount(feeData.maxFeePerGas, nativeToken);
28925
28908
  };
28926
28909
  /**
28927
28910
  * Calculate the gas fee from the gas price and gas units used for the transaction
28928
28911
  *
28929
- * @param {Amount} gasPrice - The price of gas
28912
+ * @param {CoinAmount<Native>} gasPrice - The price of gas
28930
28913
  * @param {BigNumber} gasEstimate - The total gas units that will be used for the transaction
28931
28914
  * @returns - The cost of the transaction in the gas token's smallest denomination (e.g. WEI)
28932
28915
  */
@@ -29550,6 +29533,7 @@ const toPublicQuote = (amount, amountWithMaxSlippage, slippage, fees) => ({
29550
29533
  });
29551
29534
  class Exchange {
29552
29535
  provider;
29536
+ batchProvider;
29553
29537
  router;
29554
29538
  chainId;
29555
29539
  nativeToken;
@@ -29567,12 +29551,16 @@ class Exchange {
29567
29551
  this.secondaryFees = config.secondaryFees;
29568
29552
  this.routerContractAddress = config.chain.contracts.peripheryRouter;
29569
29553
  this.secondaryFeeContractAddress = config.chain.contracts.secondaryFee;
29570
- this.provider = new ethers.providers.JsonRpcProvider(config.chain.rpcUrl);
29571
- this.router = new Router(this.provider, config.chain.commonRoutingTokens, {
29572
- multicallAddress: config.chain.contracts.multicall,
29573
- factoryAddress: config.chain.contracts.coreFactory,
29574
- quoterAddress: config.chain.contracts.quoterV2,
29575
- });
29554
+ this.provider = new ethers.providers.StaticJsonRpcProvider({
29555
+ url: config.chain.rpcUrl,
29556
+ skipFetchSetup: true,
29557
+ }, config.chain.chainId);
29558
+ this.batchProvider = new ethers.providers.JsonRpcBatchProvider({
29559
+ url: config.chain.rpcUrl,
29560
+ skipFetchSetup: true,
29561
+ }, config.chain.chainId);
29562
+ const multicallContract = Multicall__factory.connect(config.chain.contracts.multicall, this.provider);
29563
+ this.router = new Router(this.batchProvider, multicallContract, config.chain.commonRoutingTokens, config.chain.contracts);
29576
29564
  }
29577
29565
  static validate(tokenInAddress, tokenOutAddress, maxHops, slippagePercent, fromAddress) {
29578
29566
  assert(isValidNonZeroAddress(fromAddress), new InvalidAddressError('invalid from address'));
@@ -29584,11 +29572,11 @@ class Exchange {
29584
29572
  assert(slippagePercent <= 50, new InvalidSlippageError('slippage percent must be less than or equal to 50'));
29585
29573
  assert(slippagePercent >= 0, new InvalidSlippageError('slippage percent must be greater than or equal to 0'));
29586
29574
  }
29587
- async getSecondaryFees() {
29575
+ async getSecondaryFees(provider) {
29588
29576
  if (this.secondaryFees.length === 0) {
29589
29577
  return [];
29590
29578
  }
29591
- const secondaryFeeContract = SecondaryFee__factory.connect(this.secondaryFeeContractAddress, this.provider);
29579
+ const secondaryFeeContract = SecondaryFee__factory.connect(this.secondaryFeeContractAddress, provider);
29592
29580
  if (await secondaryFeeContract.paused()) {
29593
29581
  // Do not use secondary fees if the contract is paused
29594
29582
  return [];
@@ -29609,11 +29597,13 @@ class Exchange {
29609
29597
  async getUnsignedSwapTx(fromAddress, tokenInLiteral, tokenOutLiteral, amount, slippagePercent, maxHops, deadline, tradeType) {
29610
29598
  Exchange.validate(tokenInLiteral, tokenOutLiteral, maxHops, slippagePercent, fromAddress);
29611
29599
  // get the decimals of the tokens that will be swapped
29612
- const [tokenInDecimals, tokenOutDecimals, secondaryFees] = await Promise.all([
29613
- getTokenDecimals(tokenInLiteral, this.provider, this.nativeToken),
29614
- getTokenDecimals(tokenOutLiteral, this.provider, this.nativeToken),
29615
- this.getSecondaryFees(),
29616
- ]);
29600
+ const promises = [
29601
+ getTokenDecimals(tokenInLiteral, this.batchProvider, this.nativeToken),
29602
+ getTokenDecimals(tokenOutLiteral, this.batchProvider, this.nativeToken),
29603
+ this.getSecondaryFees(this.batchProvider),
29604
+ fetchGasPrice(this.batchProvider, this.nativeToken),
29605
+ ];
29606
+ const [tokenInDecimals, tokenOutDecimals, secondaryFees, gasPrice] = await Promise.all(promises);
29617
29607
  const tokenIn = this.parseTokenLiteral(tokenInLiteral, tokenInDecimals);
29618
29608
  const tokenOut = this.parseTokenLiteral(tokenOutLiteral, tokenOutDecimals);
29619
29609
  // determine which amount was specified for the swap from the TradeType
@@ -29622,10 +29612,7 @@ class Exchange {
29622
29612
  const fees = new Fees(secondaryFees, tokenIn);
29623
29613
  const ourQuoteReqAmount = getOurQuoteReqAmount(amountSpecified, fees, tradeType, this.nativeTokenService);
29624
29614
  // Quotes will always use ERC20s. If the user-specified token is Native, we use the Wrapped Native Token pool
29625
- const [ourQuote, gasPrice] = await Promise.all([
29626
- this.router.findOptimalRoute(ourQuoteReqAmount, this.nativeTokenService.maybeWrapToken(otherToken), tradeType, maxHops),
29627
- fetchGasPrice(this.provider, this.nativeToken),
29628
- ]);
29615
+ const ourQuote = await this.router.findOptimalRoute(ourQuoteReqAmount, this.nativeTokenService.maybeWrapToken(otherToken), tradeType, maxHops);
29629
29616
  const adjustedQuote = adjustQuoteWithFees(ourQuote, amountSpecified, fees, this.nativeTokenService);
29630
29617
  const swap = getSwap(tokenIn, tokenOut, adjustedQuote, fromAddress, slippagePercent, deadline, this.routerContractAddress, this.secondaryFeeContractAddress, gasPrice, secondaryFees);
29631
29618
  const { quotedAmount, quotedAmountWithMaxSlippage } = prepareUserQuote(this.nativeTokenService, adjustedQuote, slippagePercent, otherToken);
@@ -30562,7 +30549,7 @@ const GAS_OVERRIDES = {
30562
30549
  maxPriorityFeePerGas: BigNumber$1.from(101e9),
30563
30550
  };
30564
30551
 
30565
- const SDK_VERSION_MARKER = '0.35.0';
30552
+ const SDK_VERSION_MARKER = '0.35.2';
30566
30553
  // This SDK version is replaced by the `yarn build` command ran on the root level
30567
30554
  const globalPackageVersion = () => SDK_VERSION_MARKER;
30568
30555