@imtbl/sdk 0.27.7 → 0.27.9

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
@@ -3609,7 +3609,7 @@ class MultiRollupApiClients {
3609
3609
  }
3610
3610
 
3611
3611
  // eslint-disable-next-line @typescript-eslint/naming-convention
3612
- const defaultHeaders$1 = { 'x-sdk-version': 'ts-immutable-sdk-0.27.7' };
3612
+ const defaultHeaders$1 = { 'x-sdk-version': 'ts-immutable-sdk-0.27.9' };
3613
3613
  const createConfig = ({ basePath, headers, }) => {
3614
3614
  if (!basePath.trim()) {
3615
3615
  throw Error('basePath can not be empty');
@@ -3669,7 +3669,7 @@ class APIError extends Error {
3669
3669
 
3670
3670
  /* eslint-disable implicit-arrow-linebreak */
3671
3671
  const defaultHeaders = {
3672
- sdkVersion: 'ts-immutable-sdk-multi-rollup-api-client-0.27.7',
3672
+ sdkVersion: 'ts-immutable-sdk-multi-rollup-api-client-0.27.9',
3673
3673
  };
3674
3674
  /**
3675
3675
  * createAPIConfiguration to create a custom Configuration
@@ -4080,7 +4080,7 @@ const createImmutableXConfiguration = ({ basePath, chainID, coreContractAddress,
4080
4080
  chainID,
4081
4081
  coreContractAddress,
4082
4082
  registrationContractAddress,
4083
- sdkVersion: 'ts-immutable-sdk-0.27.7',
4083
+ sdkVersion: 'ts-immutable-sdk-0.27.9',
4084
4084
  });
4085
4085
  /**
4086
4086
  * Sets `sdkVersion` at the time of build
@@ -11771,9 +11771,6 @@ class Seaport {
11771
11771
  };
11772
11772
  }
11773
11773
  async fulfillBulkOrders(fulfillingOrders, account) {
11774
- // TODO: this function right now does not handle errors from the seaport.js
11775
- // we should figure out why orders are rejected and return a submission
11776
- // transaction on best efforts basis
11777
11774
  const fulfillOrderDetails = fulfillingOrders.map((o) => {
11778
11775
  const { orderComponents, tips } = this.mapImmutableOrderToSeaportOrderComponents(o.order);
11779
11776
  return {
@@ -12192,14 +12189,34 @@ class Orderbook {
12192
12189
  recipient: fee.recipient,
12193
12190
  })),
12194
12191
  })));
12195
- return {
12196
- ...(await this.seaport.fulfillBulkOrders(fulfillmentDataRes.result.fulfillable_orders, takerAddress)),
12197
- fulfillableOrders: fulfillmentDataRes.result.fulfillable_orders.map((o) => mapFromOpenApiOrder(o.order)),
12198
- unfulfillableOrders: fulfillmentDataRes.result.unfulfillable_orders.map((o) => ({
12199
- orderId: o.order_id,
12200
- reason: o.reason,
12201
- })),
12202
- };
12192
+ try {
12193
+ return {
12194
+ ...(await this.seaport.fulfillBulkOrders(fulfillmentDataRes.result.fulfillable_orders, takerAddress)),
12195
+ fulfillableOrders: fulfillmentDataRes.result.fulfillable_orders.map((o) => mapFromOpenApiOrder(o.order)),
12196
+ unfulfillableOrders: fulfillmentDataRes.result.unfulfillable_orders.map((o) => ({
12197
+ orderId: o.order_id,
12198
+ reason: o.reason,
12199
+ })),
12200
+ sufficientBalance: true,
12201
+ };
12202
+ }
12203
+ catch (e) {
12204
+ // if insufficient balance error, we return FulfillBulkOrdersInsufficientBalanceResponse
12205
+ if (String(e).includes('The fulfiller does not have the balances needed to fulfill.')) {
12206
+ return {
12207
+ fulfillableOrders: fulfillmentDataRes.result.fulfillable_orders.map((o) => mapFromOpenApiOrder(o.order)),
12208
+ unfulfillableOrders: fulfillmentDataRes.result.unfulfillable_orders.map((o) => ({
12209
+ orderId: o.order_id,
12210
+ reason: o.reason,
12211
+ })),
12212
+ sufficientBalance: false,
12213
+ };
12214
+ }
12215
+ // if some other error is thrown,
12216
+ // there likely is a race condition of the original order validity
12217
+ // we throw the error back out
12218
+ throw e;
12219
+ }
12203
12220
  }
12204
12221
  /**
12205
12222
  * Get an unsigned cancel order transaction. Orders can only be cancelled by
@@ -27995,25 +28012,65 @@ function isValidNonZeroAddress(address) {
27995
28012
  return false;
27996
28013
  }
27997
28014
  }
27998
- const tokenInfoToUniswapToken = (tokenInfo) => new Token(tokenInfo.chainId, tokenInfo.address, tokenInfo.decimals, tokenInfo.symbol, tokenInfo.name);
28015
+ const erc20ToUniswapToken = (token) =>
28016
+ // eslint-disable-next-line implicit-arrow-linebreak
28017
+ new Token(token.chainId, token.address, token.decimals, token.symbol, token.name);
28018
+ const uniswapTokenToERC20 = (token) => ({
28019
+ chainId: token.chainId,
28020
+ address: token.address,
28021
+ decimals: token.decimals,
28022
+ symbol: token.symbol,
28023
+ name: token.name,
28024
+ type: 'erc20',
28025
+ });
27999
28026
  const toCurrencyAmount = (amount) => {
28000
- const token = tokenInfoToUniswapToken(amount.token);
28027
+ const token = erc20ToUniswapToken(amount.token);
28001
28028
  return CurrencyAmount.fromRawAmount(token, amount.value.toString());
28002
28029
  };
28003
28030
  const newAmount = (amount, token) => ({
28004
28031
  value: amount,
28005
28032
  token,
28006
28033
  });
28007
- const addAmount = (a, b) => {
28034
+ const isERC20Amount = (amount) => amount.token.type === 'erc20';
28035
+ const isNativeAmount = (amount) => amount.token.type === 'native';
28036
+ const addERC20Amount = (a, b) => {
28037
+ // Make sure the ERC20s have the same address
28008
28038
  if (a.token.address !== b.token.address)
28009
- throw new Error('Token mismatch');
28039
+ throw new Error('Token mismatch: token addresses must be the same');
28010
28040
  return { value: a.value.add(b.value), token: a.token };
28011
28041
  };
28012
- const subtractAmount = (a, b) => {
28042
+ const addNativeAmount = (a, b) => ({
28043
+ value: a.value.add(b.value),
28044
+ token: a.token,
28045
+ });
28046
+ const addAmount = (a, b) => {
28047
+ if (isERC20Amount(a) && isERC20Amount(b)) {
28048
+ return addERC20Amount(a, b);
28049
+ }
28050
+ if (isNativeAmount(a) && isNativeAmount(b)) {
28051
+ return addNativeAmount(a, b);
28052
+ }
28053
+ throw new Error('Token mismatch: token types must be the same');
28054
+ };
28055
+ const subtractERC20Amount = (a, b) => {
28056
+ // Make sure the ERC20s have the same address
28013
28057
  if (a.token.address !== b.token.address)
28014
- throw new Error('Token mismatch');
28058
+ throw new Error('Token mismatch: token addresses must be the same');
28015
28059
  return { value: a.value.sub(b.value), token: a.token };
28016
28060
  };
28061
+ const subtractNativeAmount = (a, b) => ({
28062
+ value: a.value.sub(b.value),
28063
+ token: a.token,
28064
+ });
28065
+ const subtractAmount = (a, b) => {
28066
+ if (isERC20Amount(a) && isERC20Amount(b)) {
28067
+ return subtractERC20Amount(a, b);
28068
+ }
28069
+ if (isNativeAmount(a) && isNativeAmount(b)) {
28070
+ return subtractNativeAmount(a, b);
28071
+ }
28072
+ throw new Error('Token mismatch: token types must be the same');
28073
+ };
28017
28074
 
28018
28075
  const amountIndex = 0;
28019
28076
  const gasEstimateIndex = 3;
@@ -28051,10 +28108,12 @@ async function getQuotesForRoutes(multicallContract, quoterContractAddress, rout
28051
28108
  const quoteAmount = decodedQuoteResult[amountIndex];
28052
28109
  if (!(quoteAmount instanceof BigNumber$1))
28053
28110
  throw new Error('Expected BigNumber');
28111
+ const input = uniswapTokenToERC20(routes[i].input);
28112
+ const output = uniswapTokenToERC20(routes[i].output);
28054
28113
  decodedQuoteResults.push({
28055
28114
  route: routes[i],
28056
- amountIn: tradeType === TradeType.EXACT_INPUT ? amountSpecified : newAmount(quoteAmount, routes[i].input),
28057
- amountOut: tradeType === TradeType.EXACT_INPUT ? newAmount(quoteAmount, routes[i].output) : amountSpecified,
28115
+ amountIn: tradeType === TradeType.EXACT_INPUT ? amountSpecified : newAmount(quoteAmount, input),
28116
+ amountOut: tradeType === TradeType.EXACT_INPUT ? newAmount(quoteAmount, output) : amountSpecified,
28058
28117
  gasEstimate: ethers.BigNumber.from(decodedQuoteResult[gasEstimateIndex]),
28059
28118
  tradeType,
28060
28119
  });
@@ -28185,7 +28244,7 @@ const fetchValidPools = async (multicallContract, erc20Pair, commonRoutingERC20s
28185
28244
  if (zeroPrice || zeroLiquidity) {
28186
28245
  return;
28187
28246
  }
28188
- const validPool = new Pool(tokenInfoToUniswapToken(poolID.erc20Pair[0]), tokenInfoToUniswapToken(poolID.erc20Pair[1]), poolID.fee, poolSlot0.sqrtPriceX96.toString(), poolLiquidity.toString(), poolSlot0.tick);
28247
+ const validPool = new Pool(erc20ToUniswapToken(poolID.erc20Pair[0]), erc20ToUniswapToken(poolID.erc20Pair[1]), poolID.fee, poolSlot0.sqrtPriceX96.toString(), poolLiquidity.toString(), poolSlot0.tick);
28189
28248
  validPools.push(validPool);
28190
28249
  });
28191
28250
  return validPools;
@@ -28271,9 +28330,9 @@ maxHops, // the maximum number of pools that can be traversed
28271
28330
  currentRoute = [], // list of pools already traversed
28272
28331
  routes = [], // list of all routes found so far
28273
28332
  startTokenIn = tokenIn) => {
28274
- const currencyIn = tokenInfoToUniswapToken(tokenIn);
28275
- const currencyOut = tokenInfoToUniswapToken(tokenOut);
28276
- const startCurrencyIn = tokenInfoToUniswapToken(startTokenIn);
28333
+ const currencyIn = erc20ToUniswapToken(tokenIn);
28334
+ const currencyOut = erc20ToUniswapToken(tokenOut);
28335
+ const startCurrencyIn = erc20ToUniswapToken(startTokenIn);
28277
28336
  for (const pool of pools) {
28278
28337
  // if the pool doesn't have the tokenIn or if it has already been traversed,
28279
28338
  // skip to the next pool
@@ -28292,7 +28351,7 @@ startTokenIn = tokenIn) => {
28292
28351
  else if (maxHops > 1) {
28293
28352
  // otherwise, if we haven't exceeded the maximum number of pools that can be traversed,
28294
28353
  // recursively call this function with the output token as the new starting currency
28295
- generateAllAcyclicPaths(outputToken, tokenOut, pools, maxHops - 1, [...currentRoute, pool], routes, startTokenIn);
28354
+ generateAllAcyclicPaths(uniswapTokenToERC20(outputToken), tokenOut, pools, maxHops - 1, [...currentRoute, pool], routes, startTokenIn);
28296
28355
  }
28297
28356
  }
28298
28357
  return routes;
@@ -28385,11 +28444,11 @@ const getUnsignedERC20ApproveTransaction = (ownerAddress, tokenAmount, spenderAd
28385
28444
  from: ownerAddress,
28386
28445
  };
28387
28446
  };
28388
- const prepareApproval = (tradeType, amountSpecified, amountWithSlippage, routingContracts, secondaryFees) => {
28447
+ const prepareApproval = (tradeType, amountSpecified, amountWithSlippage, contracts, secondaryFees) => {
28389
28448
  const amountOfTokenIn = tradeType === TradeType.EXACT_INPUT ? amountSpecified : amountWithSlippage;
28390
28449
  const spender = secondaryFees.length === 0
28391
- ? routingContracts.peripheryRouterAddress
28392
- : routingContracts.secondaryFeeAddress;
28450
+ ? contracts.routerAddress
28451
+ : contracts.secondaryFeeAddress;
28393
28452
  return { spender, amount: amountOfTokenIn };
28394
28453
  };
28395
28454
  /**
@@ -28422,7 +28481,7 @@ async function getApproveGasEstimate(provider, ownerAddress, spenderAddress, tok
28422
28481
  from: ownerAddress,
28423
28482
  });
28424
28483
  }
28425
- const getApproval = async (provider, ownerAddress, preparedApproval, gasPrice) => {
28484
+ const getApproval = async (provider, ownerAddress, preparedApproval, gasPrice, nativeTokenService) => {
28426
28485
  const approveTransaction = await getApproveTransaction(provider, ownerAddress, preparedApproval.amount, preparedApproval.spender);
28427
28486
  if (!approveTransaction) {
28428
28487
  return null;
@@ -28431,7 +28490,8 @@ const getApproval = async (provider, ownerAddress, preparedApproval, gasPrice) =
28431
28490
  const gasFeeEstimate = gasPrice ? calculateGasFee(gasPrice, gasEstimate) : null;
28432
28491
  return {
28433
28492
  transaction: approveTransaction,
28434
- gasFeeEstimate,
28493
+ // TODO: TP-1649: Remove the wrapping here
28494
+ gasFeeEstimate: gasFeeEstimate ? nativeTokenService.maybeWrapAmount(gasFeeEstimate) : null,
28435
28495
  };
28436
28496
  };
28437
28497
 
@@ -28467,7 +28527,7 @@ function applySlippage(tradeType, amount, slippage) {
28467
28527
  const amountWithSlippage = maybeInverted.multiply(amount.toString()).quotient;
28468
28528
  return ethers.BigNumber.from(amountWithSlippage.toString());
28469
28529
  }
28470
- function prepareUserQuote(otherToken, tradeInfo, slippage, fees) {
28530
+ function prepareUserQuote(otherToken, tradeInfo, slippage, fees, nativeTokenService) {
28471
28531
  const quote = getQuoteAmountFromTradeType(tradeInfo);
28472
28532
  const amountWithSlippage = applySlippage(tradeInfo.tradeType, quote.value, slippage);
28473
28533
  return {
@@ -28477,16 +28537,20 @@ function prepareUserQuote(otherToken, tradeInfo, slippage, fees) {
28477
28537
  value: amountWithSlippage,
28478
28538
  },
28479
28539
  slippage,
28480
- fees: fees.withAmounts(),
28540
+ fees: fees.withAmounts().map((fee) => ({
28541
+ ...fee,
28542
+ amount: nativeTokenService.maybeWrapAmount(fee.amount),
28543
+ })),
28481
28544
  };
28482
28545
  }
28483
- function getOurQuoteReqAmount(amount, fees, tradeType) {
28546
+ function getOurQuoteReqAmount(amountSpecified, // the amount specified by the user, either exactIn or exactOut
28547
+ fees, tradeType, nativeTokenService) {
28484
28548
  if (tradeType === TradeType.EXACT_OUTPUT) {
28485
28549
  // For an exact output swap, we do not need to subtract fees from the given amount
28486
- return amount;
28550
+ return nativeTokenService.maybeWrapAmount(amountSpecified);
28487
28551
  }
28488
- fees.addAmount(amount);
28489
- return fees.amountLessFees();
28552
+ fees.addAmount(amountSpecified);
28553
+ return nativeTokenService.maybeWrapAmount(fees.amountLessFees());
28490
28554
  }
28491
28555
 
28492
28556
  // 0.1% default slippage
@@ -28502,7 +28566,7 @@ const MIN_MAX_HOPS = 1;
28502
28566
  // precision used to calculate percentage from basis points
28503
28567
  const BASIS_POINT_PRECISION = 10000;
28504
28568
  // 10% maximum secondary fee
28505
- const MAX_SECONDARY_FEE_BASIS_POINTS = 10000;
28569
+ const MAX_SECONDARY_FEE_BASIS_POINTS = 1000;
28506
28570
 
28507
28571
  class Fees {
28508
28572
  secondaryFees;
@@ -28511,6 +28575,9 @@ class Fees {
28511
28575
  this.secondaryFees = secondaryFees;
28512
28576
  this.amount = newAmount(BigNumber$1.from(0), token);
28513
28577
  }
28578
+ get token() {
28579
+ return this.amount.token;
28580
+ }
28514
28581
  addAmount(amount) {
28515
28582
  this.amount = addAmount(this.amount, amount);
28516
28583
  }
@@ -28543,18 +28610,65 @@ class Fees {
28543
28610
  }
28544
28611
  }
28545
28612
 
28613
+ class NativeTokenService {
28614
+ nativeToken;
28615
+ wrappedToken;
28616
+ constructor(nativeToken, wrappedToken) {
28617
+ this.nativeToken = nativeToken;
28618
+ this.wrappedToken = wrappedToken;
28619
+ }
28620
+ wrapAmount(amount) {
28621
+ return newAmount(amount.value, this.wrappedToken);
28622
+ }
28623
+ unwrapAmount(amount) {
28624
+ if (amount.token !== this.wrappedToken) {
28625
+ throw new Error(`token ${amount.token.address} is not wrapped`);
28626
+ }
28627
+ return newAmount(amount.value, this.nativeToken);
28628
+ }
28629
+ maybeWrapToken(token) {
28630
+ if (this.isNativeToken(token)) {
28631
+ return this.wrappedToken;
28632
+ }
28633
+ return token;
28634
+ }
28635
+ maybeWrapAmount(amount) {
28636
+ return newAmount(amount.value, this.maybeWrapToken(amount.token));
28637
+ }
28638
+ isNativeToken(token) {
28639
+ return token === this.nativeToken;
28640
+ }
28641
+ }
28642
+
28546
28643
  const IMMUTABLE_TESTNET_RPC_URL = 'https://rpc.testnet.immutable.com';
28547
28644
  const IMMUTABLE_TESTNET_CHAIN_ID = 13472;
28548
28645
 
28646
+ const NATIVE_IMX_IMMUTABLE_TESTNET = {
28647
+ chainId: IMMUTABLE_TESTNET_CHAIN_ID,
28648
+ decimals: 18,
28649
+ symbol: 'tIMX',
28650
+ name: 'Immutable Testnet Token',
28651
+ type: 'native',
28652
+ };
28549
28653
  const TIMX_IMMUTABLE_TESTNET = {
28550
28654
  chainId: IMMUTABLE_TESTNET_CHAIN_ID,
28551
28655
  address: '0x0000000000000000000000000000000000001010',
28552
28656
  decimals: 18,
28553
28657
  symbol: 'tIMX',
28554
28658
  name: 'Immutable Testnet Token',
28659
+ type: 'erc20',
28660
+ };
28661
+ const WIMX_IMMUTABLE_TESTNET = {
28662
+ chainId: IMMUTABLE_TESTNET_CHAIN_ID,
28663
+ address: '0xAf7cf5D4Af0BFAa85d384d42b8D410762Ccbce69',
28664
+ decimals: 18,
28665
+ symbol: 'WIMX',
28666
+ name: 'Wrapped Immutable Testnet Token',
28667
+ type: 'erc20',
28555
28668
  };
28556
28669
  const IMMUTABLE_TESTNET_COMMON_ROUTING_TOKENS = [
28557
28670
  TIMX_IMMUTABLE_TESTNET,
28671
+ WIMX_IMMUTABLE_TESTNET,
28558
28672
  ];
28559
28673
 
28560
28674
  const zeroNativeCurrencyValue = '0x00';
@@ -28651,7 +28765,7 @@ function createSwapParameters(adjustedQuote, fromAddress, slippage, deadline, se
28651
28765
  }
28652
28766
  return createSwapCallParametersWithFees(uncheckedTrade, fromAddress, options, secondaryFees);
28653
28767
  }
28654
- function getSwap(adjustedQuote, fromAddress, slippage, deadline, peripheryRouterAddress, secondaryFeesAddress, gasPrice, secondaryFees) {
28768
+ function getSwap(adjustedQuote, fromAddress, slippage, deadline, peripheryRouterAddress, secondaryFeesAddress, gasPrice, secondaryFees, nativeTokenService) {
28655
28769
  const calldata = createSwapParameters(adjustedQuote, fromAddress, slippage, deadline, secondaryFees);
28656
28770
  // TODO: Add additional gas fee estimates for secondary fees
28657
28771
  const gasFeeEstimate = gasPrice ? calculateGasFee(gasPrice, adjustedQuote.gasEstimate) : null;
@@ -28662,24 +28776,37 @@ function getSwap(adjustedQuote, fromAddress, slippage, deadline, peripheryRouter
28662
28776
  value: zeroNativeCurrencyValue,
28663
28777
  from: fromAddress,
28664
28778
  },
28665
- gasFeeEstimate,
28779
+ // TODO: TP-1649: Remove the wrapping here
28780
+ gasFeeEstimate: gasFeeEstimate ? nativeTokenService.maybeWrapAmount(gasFeeEstimate) : null,
28666
28781
  };
28667
28782
  }
28668
- function prepareSwap(ourQuote, amountSpecified, fees) {
28783
+ const adjustAmountIn = (ourQuote, amountSpecified, fees, nativeTokenService) => {
28669
28784
  if (ourQuote.tradeType === TradeType.EXACT_OUTPUT) {
28670
- fees.addAmount(ourQuote.amountIn);
28671
- return {
28672
- gasEstimate: ourQuote.gasEstimate,
28673
- route: ourQuote.route,
28674
- amountIn: fees.amountWithFeesApplied(),
28675
- amountOut: amountSpecified,
28676
- tradeType: ourQuote.tradeType,
28677
- };
28785
+ // when doing exact output, calculate the fees based on the amountIn
28786
+ const amountToAdd = nativeTokenService.isNativeToken(fees.token)
28787
+ ? nativeTokenService.unwrapAmount(ourQuote.amountIn)
28788
+ : ourQuote.amountIn;
28789
+ fees.addAmount(amountToAdd);
28790
+ return nativeTokenService.maybeWrapAmount(fees.amountWithFeesApplied());
28678
28791
  }
28792
+ return nativeTokenService.maybeWrapAmount(amountSpecified);
28793
+ };
28794
+ /**
28795
+ * adjustQuoteWithFees adjusts the amountIn of the quote to account for fees
28796
+ * EXACT_OUTPUT swaps will have the fees added to the amountIn if there are fees specified
28797
+ * EXACT_INPUT swaps will have amountIn set to the user-specified amount
28798
+ * @param ourQuote The quote from calling the Quoter contract
28799
+ * @param amountSpecified The user-specified amount for the swap (EXACT...)
28800
+ * @param fees The fees applied to the swap
28801
+ * @param tokenWrapper Helper class for the native token and associated ERC20
28802
+ * @returns {QuoteResult} The adjusted quote
28803
+ */
28804
+ function adjustQuoteWithFees(ourQuote, amountSpecified, fees, nativeTokenService) {
28805
+ const adjustedAmountIn = adjustAmountIn(ourQuote, amountSpecified, fees, nativeTokenService);
28679
28806
  return {
28680
28807
  gasEstimate: ourQuote.gasEstimate,
28681
28808
  route: ourQuote.route,
28682
- amountIn: amountSpecified,
28809
+ amountIn: adjustedAmountIn,
28683
28810
  amountOut: ourQuote.amountOut,
28684
28811
  tradeType: ourQuote.tradeType,
28685
28812
  };
@@ -28700,7 +28827,8 @@ const SUPPORTED_SANDBOX_CHAINS = {
28700
28827
  rpcUrl: IMMUTABLE_TESTNET_RPC_URL,
28701
28828
  contracts: CONTRACTS_FOR_CHAIN_ID[IMMUTABLE_TESTNET_CHAIN_ID],
28702
28829
  commonRoutingTokens: IMMUTABLE_TESTNET_COMMON_ROUTING_TOKENS,
28703
- nativeToken: TIMX_IMMUTABLE_TESTNET,
28830
+ nativeToken: NATIVE_IMX_IMMUTABLE_TESTNET,
28831
+ wrappedNativeToken: TIMX_IMMUTABLE_TESTNET, // TODO: TP-1649: Change to WIMX when ready.
28704
28832
  },
28705
28833
  };
28706
28834
  const SUPPORTED_PRODUCTION_CHAINS = {};
@@ -28758,6 +28886,7 @@ class ExchangeConfiguration {
28758
28886
  contracts: overrides.exchangeContracts,
28759
28887
  commonRoutingTokens: overrides.commonRoutingTokens,
28760
28888
  nativeToken: overrides.nativeToken,
28889
+ wrappedNativeToken: overrides.wrappedNativeToken,
28761
28890
  };
28762
28891
  this.secondaryFees = secondaryFees || [];
28763
28892
  return;
@@ -28775,19 +28904,25 @@ class Exchange {
28775
28904
  router;
28776
28905
  chainId;
28777
28906
  nativeToken;
28907
+ wrappedNativeToken;
28778
28908
  secondaryFees;
28909
+ nativeTokenService;
28910
+ secondaryFeeContractAddress;
28911
+ routerContractAddress;
28779
28912
  constructor(configuration) {
28780
28913
  const config = new ExchangeConfiguration(configuration);
28781
28914
  this.chainId = config.chain.chainId;
28782
28915
  this.nativeToken = config.chain.nativeToken;
28916
+ this.wrappedNativeToken = config.chain.wrappedNativeToken;
28917
+ this.nativeTokenService = new NativeTokenService(this.nativeToken, this.wrappedNativeToken);
28783
28918
  this.secondaryFees = config.secondaryFees;
28919
+ this.routerContractAddress = config.chain.contracts.peripheryRouter;
28920
+ this.secondaryFeeContractAddress = config.chain.contracts.secondaryFee;
28784
28921
  this.provider = new ethers.providers.JsonRpcProvider(config.chain.rpcUrl);
28785
28922
  this.router = new Router(this.provider, config.chain.commonRoutingTokens, {
28786
28923
  multicallAddress: config.chain.contracts.multicall,
28787
28924
  factoryAddress: config.chain.contracts.coreFactory,
28788
28925
  quoterAddress: config.chain.contracts.quoterV2,
28789
- peripheryRouterAddress: config.chain.contracts.peripheryRouter,
28790
- secondaryFeeAddress: config.chain.contracts.secondaryFee,
28791
28926
  });
28792
28927
  }
28793
28928
  static validate(tokenInAddress, tokenOutAddress, maxHops, slippagePercent, fromAddress) {
@@ -28804,7 +28939,7 @@ class Exchange {
28804
28939
  if (this.secondaryFees.length === 0) {
28805
28940
  return [];
28806
28941
  }
28807
- const secondaryFeeContract = SecondaryFee__factory.connect(this.router.routingContracts.secondaryFeeAddress, this.provider);
28942
+ const secondaryFeeContract = SecondaryFee__factory.connect(this.secondaryFeeContractAddress, this.provider);
28808
28943
  if (await secondaryFeeContract.paused()) {
28809
28944
  // Do not use secondary fees if the contract is paused
28810
28945
  return [];
@@ -28820,32 +28955,36 @@ class Exchange {
28820
28955
  this.getSecondaryFees(),
28821
28956
  ]);
28822
28957
  const tokenIn = {
28958
+ type: 'erc20',
28823
28959
  address: tokenInAddress,
28824
28960
  chainId: this.chainId,
28825
28961
  decimals: tokenInDecimals,
28826
28962
  };
28827
28963
  const tokenOut = {
28964
+ type: 'erc20',
28828
28965
  address: tokenOutAddress,
28829
28966
  chainId: this.chainId,
28830
28967
  decimals: tokenOutDecimals,
28831
28968
  };
28832
28969
  // determine which amount was specified for the swap from the TradeType
28833
- const [tokenSpecified, otherToken] = tradeType === TradeType.EXACT_INPUT
28834
- ? [tokenIn, tokenOut] : [tokenOut, tokenIn];
28970
+ const [tokenSpecified, otherToken] = tradeType === TradeType.EXACT_INPUT ? [tokenIn, tokenOut] : [tokenOut, tokenIn];
28835
28971
  const amountSpecified = newAmount(amount, tokenSpecified);
28836
28972
  const fees = new Fees(secondaryFees, tokenIn);
28837
- const ourQuoteReqAmount = getOurQuoteReqAmount(amountSpecified, fees, tradeType);
28973
+ const ourQuoteReqAmount = getOurQuoteReqAmount(amountSpecified, fees, tradeType, this.nativeTokenService);
28838
28974
  // get quote and gas details
28839
28975
  const [ourQuote, gasPrice] = await Promise.all([
28840
28976
  this.router.findOptimalRoute(ourQuoteReqAmount, otherToken, tradeType, maxHops),
28841
28977
  fetchGasPrice(this.provider, this.nativeToken),
28842
28978
  ]);
28843
- const adjustedQuote = prepareSwap(ourQuote, amountSpecified, fees);
28844
- const swap = getSwap(adjustedQuote, fromAddress, slippagePercent, deadline, this.router.routingContracts.peripheryRouterAddress, this.router.routingContracts.secondaryFeeAddress, gasPrice, secondaryFees);
28845
- const userQuote = prepareUserQuote(otherToken, adjustedQuote, slippagePercent, fees);
28846
- const preparedApproval = prepareApproval(tradeType, amountSpecified, userQuote.amountWithMaxSlippage, this.router.routingContracts, secondaryFees);
28979
+ const adjustedQuote = adjustQuoteWithFees(ourQuote, amountSpecified, fees, this.nativeTokenService);
28980
+ const swap = getSwap(adjustedQuote, fromAddress, slippagePercent, deadline, this.routerContractAddress, this.secondaryFeeContractAddress, gasPrice, secondaryFees, this.nativeTokenService);
28981
+ const userQuote = prepareUserQuote(otherToken, adjustedQuote, slippagePercent, fees, this.nativeTokenService);
28982
+ const preparedApproval = prepareApproval(tradeType, amountSpecified, userQuote.amountWithMaxSlippage, {
28983
+ routerAddress: this.routerContractAddress,
28984
+ secondaryFeeAddress: this.secondaryFeeContractAddress,
28985
+ }, secondaryFees);
28847
28986
  // preparedApproval always uses the tokenIn address because we are always selling the tokenIn
28848
- const approval = await getApproval(this.provider, fromAddress, preparedApproval, gasPrice);
28987
+ const approval = await getApproval(this.provider, fromAddress, preparedApproval, gasPrice, this.nativeTokenService);
28849
28988
  return {
28850
28989
  approval,
28851
28990
  swap,
@@ -31023,8 +31162,6 @@ const $5e9bcae98dc8ff19$export$1165ca270f090a66 = (isDevelopment, isProduction)=
31023
31162
  return ($d85ad1457a3f1a83$export$89133ca13c5ee30)[(Environment$1).SANDBOX];
31024
31163
  };
31025
31164
  const checkDexAvailability = async ()=>{
31026
- // TEMP FIX: Returns true for sandbox environment
31027
- if (!isDevelopment && !isProduction) return true;
31028
31165
  let response;
31029
31166
  try {
31030
31167
  response = await (0, globalAxios$1).post(`${postEndpoint()}/v1/availability/checkout/swap`);
@@ -31189,7 +31326,7 @@ const $049bba630af05555$export$6946a1f17c2bbf26 = async (config, chainId, wallet
31189
31326
  const swappableToken = fromToken[index];
31190
31327
  dexQuotes.set(swappableToken, {
31191
31328
  quote: response.value.quote,
31192
- approval: response.value.approval?.gasFeeEstimate,
31329
+ approval: response.value.approval?.gasFeeEstimate ?? null,
31193
31330
  swap: response.value.swap.gasFeeEstimate
31194
31331
  });
31195
31332
  });
@@ -33044,7 +33181,7 @@ var $045213b18e9f1f94$export$75be0f6af9650f2c;
33044
33181
  })($045213b18e9f1f94$export$75be0f6af9650f2c || ($045213b18e9f1f94$export$75be0f6af9650f2c = {}));
33045
33182
 
33046
33183
 
33047
- const $d663162fd5a0853f$export$38a083d9fb5551ca = "0.27.7";
33184
+ const $d663162fd5a0853f$export$38a083d9fb5551ca = "0.27.9";
33048
33185
  const $d663162fd5a0853f$export$83bf90b30cdfd29f = ()=>false;
33049
33186
  const $d663162fd5a0853f$export$1169f5475725171b = ()=>$d663162fd5a0853f$export$38a083d9fb5551ca;
33050
33187
 
@@ -1327,12 +1327,19 @@ interface FulfillmentListing {
1327
1327
  listingId: string;
1328
1328
  takerFees: Array<FeeValue>;
1329
1329
  }
1330
- interface FulfillBulkOrdersResponse {
1330
+ type FulfillBulkOrdersResponse = FulfillBulkOrdersInsufficientBalanceResponse | FulfillBulkOrdersSufficientBalanceResponse;
1331
+ interface FulfillBulkOrdersSufficientBalanceResponse {
1332
+ sufficientBalance: true;
1331
1333
  actions: Action[];
1332
1334
  expiration: string;
1333
1335
  fulfillableOrders: Order[];
1334
1336
  unfulfillableOrders: UnfulfillableOrder[];
1335
1337
  }
1338
+ interface FulfillBulkOrdersInsufficientBalanceResponse {
1339
+ sufficientBalance: false;
1340
+ fulfillableOrders: Order[];
1341
+ unfulfillableOrders: UnfulfillableOrder[];
1342
+ }
1336
1343
  interface UnfulfillableOrder {
1337
1344
  orderId: string;
1338
1345
  reason: string;
@@ -1522,4 +1529,4 @@ declare const constants: {
1522
1529
  estimatedFulfillmentGasGwei: number;
1523
1530
  };
1524
1531
 
1525
- export { Action, ActionType, CancelOrderResponse, CreateListingParams, ERC20Item, ERC721Item, Fee, FeeType, FeeValue, FulfillBulkOrdersResponse, FulfillOrderResponse, FulfillmentListing, ListListingsParams, ListListingsResult, ListTradesParams, ListTradesResult, ListingResult, NativeItem, Order, OrderStatusName, Orderbook, Page, PrepareListingParams, PrepareListingResponse, RoyaltyInfo, SignableAction, SignablePurpose, Trade, TradeResult, TransactionAction, TransactionBuilder, TransactionPurpose, UnfulfillableOrder, constants };
1532
+ export { Action, ActionType, CancelOrderResponse, CreateListingParams, ERC20Item, ERC721Item, Fee, FeeType, FeeValue, FulfillBulkOrdersInsufficientBalanceResponse, FulfillBulkOrdersResponse, FulfillBulkOrdersSufficientBalanceResponse, FulfillOrderResponse, FulfillmentListing, ListListingsParams, ListListingsResult, ListTradesParams, ListTradesResult, ListingResult, NativeItem, Order, OrderStatusName, Orderbook, Page, PrepareListingParams, PrepareListingResponse, RoyaltyInfo, SignableAction, SignablePurpose, Trade, TradeResult, TransactionAction, TransactionBuilder, TransactionPurpose, UnfulfillableOrder, constants };
package/dist/orderbook.js CHANGED
@@ -1007,9 +1007,6 @@ class Seaport {
1007
1007
  };
1008
1008
  }
1009
1009
  async fulfillBulkOrders(fulfillingOrders, account) {
1010
- // TODO: this function right now does not handle errors from the seaport.js
1011
- // we should figure out why orders are rejected and return a submission
1012
- // transaction on best efforts basis
1013
1010
  const fulfillOrderDetails = fulfillingOrders.map((o) => {
1014
1011
  const { orderComponents, tips } = this.mapImmutableOrderToSeaportOrderComponents(o.order);
1015
1012
  return {
@@ -1428,14 +1425,34 @@ class Orderbook {
1428
1425
  recipient: fee.recipient,
1429
1426
  })),
1430
1427
  })));
1431
- return {
1432
- ...(await this.seaport.fulfillBulkOrders(fulfillmentDataRes.result.fulfillable_orders, takerAddress)),
1433
- fulfillableOrders: fulfillmentDataRes.result.fulfillable_orders.map((o) => mapFromOpenApiOrder(o.order)),
1434
- unfulfillableOrders: fulfillmentDataRes.result.unfulfillable_orders.map((o) => ({
1435
- orderId: o.order_id,
1436
- reason: o.reason,
1437
- })),
1438
- };
1428
+ try {
1429
+ return {
1430
+ ...(await this.seaport.fulfillBulkOrders(fulfillmentDataRes.result.fulfillable_orders, takerAddress)),
1431
+ fulfillableOrders: fulfillmentDataRes.result.fulfillable_orders.map((o) => mapFromOpenApiOrder(o.order)),
1432
+ unfulfillableOrders: fulfillmentDataRes.result.unfulfillable_orders.map((o) => ({
1433
+ orderId: o.order_id,
1434
+ reason: o.reason,
1435
+ })),
1436
+ sufficientBalance: true,
1437
+ };
1438
+ }
1439
+ catch (e) {
1440
+ // if insufficient balance error, we return FulfillBulkOrdersInsufficientBalanceResponse
1441
+ if (String(e).includes('The fulfiller does not have the balances needed to fulfill.')) {
1442
+ return {
1443
+ fulfillableOrders: fulfillmentDataRes.result.fulfillable_orders.map((o) => mapFromOpenApiOrder(o.order)),
1444
+ unfulfillableOrders: fulfillmentDataRes.result.unfulfillable_orders.map((o) => ({
1445
+ orderId: o.order_id,
1446
+ reason: o.reason,
1447
+ })),
1448
+ sufficientBalance: false,
1449
+ };
1450
+ }
1451
+ // if some other error is thrown,
1452
+ // there likely is a race condition of the original order validity
1453
+ // we throw the error back out
1454
+ throw e;
1455
+ }
1439
1456
  }
1440
1457
  /**
1441
1458
  * Get an unsigned cancel order transaction. Orders can only be cancelled by
package/dist/passport.js CHANGED
@@ -2072,7 +2072,7 @@ class MultiRollupApiClients {
2072
2072
  }
2073
2073
 
2074
2074
  // eslint-disable-next-line @typescript-eslint/naming-convention
2075
- const defaultHeaders = { 'x-sdk-version': 'ts-immutable-sdk-0.27.7' };
2075
+ const defaultHeaders = { 'x-sdk-version': 'ts-immutable-sdk-0.27.9' };
2076
2076
  const createConfig = ({ basePath, headers, }) => {
2077
2077
  if (!basePath.trim()) {
2078
2078
  throw Error('basePath can not be empty');
@@ -2128,7 +2128,7 @@ const createImmutableXConfiguration = ({ basePath, chainID, coreContractAddress,
2128
2128
  chainID,
2129
2129
  coreContractAddress,
2130
2130
  registrationContractAddress,
2131
- sdkVersion: 'ts-immutable-sdk-0.27.7',
2131
+ sdkVersion: 'ts-immutable-sdk-0.27.9',
2132
2132
  });
2133
2133
  /**
2134
2134
  * Sets `sdkVersion` at the time of build
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@imtbl/sdk",
3
3
  "description": "Immutable Unified SDK",
4
- "version": "0.27.7",
4
+ "version": "0.27.9",
5
5
  "author": "Immutable",
6
6
  "browser": "./dist/index.browser.js",
7
7
  "bugs": "https://github.com/immutable/ts-immutable-sdk/issues",