@imtbl/sdk 0.27.9 → 0.27.11

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
@@ -17,7 +17,8 @@ import { Seaport as Seaport$1 } from '@opensea/seaport-js';
17
17
  import { parseUnits } from '@ethersproject/units';
18
18
  import { BigNumber as BigNumber$2 } from '@ethersproject/bignumber';
19
19
  import detectEthereumProvider from '@metamask/detect-provider';
20
- import { TradeType, Token, CurrencyAmount, Percent } from '@uniswap/sdk-core';
20
+ import * as Uniswap from '@uniswap/sdk-core';
21
+ import { TradeType, Percent } from '@uniswap/sdk-core';
21
22
  import assert from 'assert';
22
23
  import { FeeAmount, Route, SwapQuoter, Pool, Trade, toHex as toHex$1, encodeRouteToPath } from '@uniswap/v3-sdk';
23
24
  import { keccak256 as keccak256$1 } from '@ethersproject/solidity';
@@ -3609,7 +3610,7 @@ class MultiRollupApiClients {
3609
3610
  }
3610
3611
 
3611
3612
  // eslint-disable-next-line @typescript-eslint/naming-convention
3612
- const defaultHeaders$1 = { 'x-sdk-version': 'ts-immutable-sdk-0.27.9' };
3613
+ const defaultHeaders$1 = { 'x-sdk-version': 'ts-immutable-sdk-0.27.11' };
3613
3614
  const createConfig = ({ basePath, headers, }) => {
3614
3615
  if (!basePath.trim()) {
3615
3616
  throw Error('basePath can not be empty');
@@ -3669,7 +3670,7 @@ class APIError extends Error {
3669
3670
 
3670
3671
  /* eslint-disable implicit-arrow-linebreak */
3671
3672
  const defaultHeaders = {
3672
- sdkVersion: 'ts-immutable-sdk-multi-rollup-api-client-0.27.9',
3673
+ sdkVersion: 'ts-immutable-sdk-multi-rollup-api-client-0.27.11',
3673
3674
  };
3674
3675
  /**
3675
3676
  * createAPIConfiguration to create a custom Configuration
@@ -4080,7 +4081,7 @@ const createImmutableXConfiguration = ({ basePath, chainID, coreContractAddress,
4080
4081
  chainID,
4081
4082
  coreContractAddress,
4082
4083
  registrationContractAddress,
4083
- sdkVersion: 'ts-immutable-sdk-0.27.9',
4084
+ sdkVersion: 'ts-immutable-sdk-0.27.11',
4084
4085
  });
4085
4086
  /**
4086
4087
  * Sets `sdkVersion` at the time of build
@@ -8560,6 +8561,7 @@ var PassportErrorType;
8560
8561
  PassportErrorType["SILENT_LOGIN_ERROR"] = "SILENT_LOGIN_ERROR";
8561
8562
  PassportErrorType["REFRESH_TOKEN_ERROR"] = "REFRESH_TOKEN_ERROR";
8562
8563
  PassportErrorType["USER_REGISTRATION_ERROR"] = "USER_REGISTRATION_ERROR";
8564
+ PassportErrorType["USER_NOT_REGISTERED_ERROR"] = "USER_NOT_REGISTERED_ERROR";
8563
8565
  PassportErrorType["LOGOUT_ERROR"] = "LOGOUT_ERROR";
8564
8566
  PassportErrorType["TRANSFER_ERROR"] = "TRANSFER_ERROR";
8565
8567
  PassportErrorType["CREATE_ORDER_ERROR"] = "CREATE_ORDER_ERROR";
@@ -8709,6 +8711,10 @@ class AuthManager {
8709
8711
  config;
8710
8712
  deviceCredentialsManager;
8711
8713
  logoutMode;
8714
+ /**
8715
+ * Promise that is used to prevent multiple concurrent calls to the refresh token endpoint.
8716
+ */
8717
+ refreshingPromise = null;
8712
8718
  constructor(config) {
8713
8719
  this.config = config;
8714
8720
  this.userManager = new UserManager(getAuthConfiguration(config));
@@ -8953,32 +8959,52 @@ class AuthManager {
8953
8959
  * @param forceRefresh If set to true, force an HTTP call to the OIDC server's authorization endpoint. This call will
8954
8960
  * throw an error if there's no refresh token.
8955
8961
  */
8956
- async getWebUser({ forceRefresh = false }) {
8962
+ async getAuthenticatedUser({ forceRefresh = false }) {
8957
8963
  if (forceRefresh) {
8958
- const newOidcUser = await this.userManager.signinSilent();
8959
- return newOidcUser ? AuthManager.mapOidcUserToDomainModel(newOidcUser) : null;
8964
+ return this.refreshTokenAndUpdatePromise();
8960
8965
  }
8961
8966
  const oidcUser = await this.userManager.getUser();
8962
8967
  if (!oidcUser)
8963
8968
  return null;
8964
- const tokenExpired = isTokenExpired(oidcUser);
8965
- if (!tokenExpired) {
8969
+ if (!isTokenExpired(oidcUser)) {
8966
8970
  return AuthManager.mapOidcUserToDomainModel(oidcUser);
8967
8971
  }
8968
8972
  if (oidcUser.refresh_token) {
8969
- const newOidcUser = await this.userManager.signinSilent();
8970
- if (newOidcUser) {
8971
- return AuthManager.mapOidcUserToDomainModel(newOidcUser);
8972
- }
8973
+ return this.refreshTokenAndUpdatePromise();
8973
8974
  }
8974
8975
  return null;
8975
8976
  }
8977
+ /**
8978
+ * Refreshes the token and returns the user.
8979
+ * If the token is already being refreshed, returns the existing promise.
8980
+ */
8981
+ async refreshTokenAndUpdatePromise() {
8982
+ if (this.refreshingPromise)
8983
+ return this.refreshingPromise;
8984
+ // eslint-disable-next-line no-async-promise-executor
8985
+ this.refreshingPromise = new Promise(async (resolve, reject) => {
8986
+ try {
8987
+ const newOidcUser = await this.userManager.signinSilent();
8988
+ if (newOidcUser) {
8989
+ resolve(AuthManager.mapOidcUserToDomainModel(newOidcUser));
8990
+ return;
8991
+ }
8992
+ resolve(null);
8993
+ }
8994
+ catch (err) {
8995
+ reject(err);
8996
+ }
8997
+ finally {
8998
+ this.refreshingPromise = null; // Reset the promise after completion
8999
+ }
9000
+ });
9001
+ return this.refreshingPromise;
9002
+ }
8976
9003
  async getUser({ forceRefresh } = { forceRefresh: false }) {
8977
9004
  return withPassportError(async () => {
8978
- const user = await this.getWebUser({ forceRefresh });
8979
- if (user) {
9005
+ const user = await this.getAuthenticatedUser({ forceRefresh });
9006
+ if (user)
8980
9007
  return user;
8981
- }
8982
9008
  const deviceToken = this.deviceCredentialsManager.getCredentials();
8983
9009
  if (deviceToken) {
8984
9010
  return AuthManager.mapDeviceTokenResponseToDomainUserModel(deviceToken);
@@ -9005,14 +9031,16 @@ class MagicAdapter {
9005
9031
  magicClient;
9006
9032
  constructor(config) {
9007
9033
  this.config = config;
9008
- this.magicClient = new Magic(this.config.magicPublishableApiKey, {
9009
- extensions: [new OpenIdExtension()],
9010
- network: config.network,
9011
- });
9012
- this.magicClient.preload();
9034
+ if (window) {
9035
+ this.magicClient = this.initMagicClient();
9036
+ this.magicClient.preload();
9037
+ }
9013
9038
  }
9014
9039
  async login(idToken) {
9015
9040
  return withPassportError(async () => {
9041
+ if (!this.magicClient) {
9042
+ this.magicClient = this.initMagicClient();
9043
+ }
9016
9044
  await this.magicClient.openid.loginWithOIDC({
9017
9045
  jwt: idToken,
9018
9046
  providerId: this.config.magicProviderId,
@@ -9021,10 +9049,16 @@ class MagicAdapter {
9021
9049
  }, PassportErrorType.WALLET_CONNECTION_ERROR);
9022
9050
  }
9023
9051
  async logout() {
9024
- if (this.magicClient.user) {
9052
+ if (this.magicClient?.user) {
9025
9053
  await this.magicClient.user.logout();
9026
9054
  }
9027
9055
  }
9056
+ initMagicClient() {
9057
+ return new Magic(this.config.magicPublishableApiKey, {
9058
+ extensions: [new OpenIdExtension()],
9059
+ network: this.config.network,
9060
+ });
9061
+ }
9028
9062
  }
9029
9063
 
9030
9064
  const getStarkSigner = async (signer) => withPassportError(async () => {
@@ -9111,16 +9145,13 @@ class GuardianClient {
9111
9145
  transactionAPI;
9112
9146
  messageAPI;
9113
9147
  confirmationScreen;
9114
- // TODO: ID-977, make this rollup agnostic
9115
- imxEtherAddress;
9116
9148
  crossSdkBridgeEnabled;
9117
- constructor({ accessToken, confirmationScreen, imxEtherAddress, config, }) {
9118
- const guardianConfiguration = new Configuration({ accessToken, basePath: config.imxPublicApiDomain });
9149
+ constructor({ confirmationScreen, config }) {
9150
+ const guardianConfiguration = new Configuration({ basePath: config.imxPublicApiDomain });
9119
9151
  this.confirmationScreen = confirmationScreen;
9120
- this.transactionAPI = new TransactionsApi(new Configuration(guardianConfiguration));
9121
- this.imxEtherAddress = imxEtherAddress;
9122
9152
  this.crossSdkBridgeEnabled = config.crossSdkBridgeEnabled;
9123
9153
  this.messageAPI = new MessagesApi(guardianConfiguration);
9154
+ this.transactionAPI = new TransactionsApi(guardianConfiguration);
9124
9155
  }
9125
9156
  /**
9126
9157
  * Open confirmation screen and close it automatically if the
@@ -9144,29 +9175,30 @@ class GuardianClient {
9144
9175
  withDefaultConfirmationScreenTask(task) {
9145
9176
  return this.withConfirmationScreenTask()(task);
9146
9177
  }
9147
- async validate({ payloadHash }) {
9178
+ async evaluateImxTransaction({ payloadHash, user }) {
9148
9179
  const finallyFn = () => {
9149
9180
  this.confirmationScreen.closeWindow();
9150
9181
  };
9182
+ const headers = { Authorization: `Bearer ${user.accessToken}` };
9151
9183
  const transactionRes = await retryWithDelay(async () => this.transactionAPI.getTransactionByID({
9152
9184
  transactionID: payloadHash,
9153
9185
  chainType: 'starkex',
9154
- }), { finallyFn });
9186
+ }, { headers }), { finallyFn });
9155
9187
  if (!transactionRes.data.id) {
9156
9188
  throw new Error("Transaction doesn't exists");
9157
9189
  }
9158
- const evaluateStarkexRes = await this.transactionAPI.evaluateTransaction({
9190
+ const evaluateImxRes = await this.transactionAPI.evaluateTransaction({
9159
9191
  id: payloadHash,
9160
9192
  transactionEvaluationRequest: {
9161
9193
  chainType: 'starkex',
9162
9194
  },
9163
- });
9164
- const { confirmationRequired } = evaluateStarkexRes.data;
9195
+ }, { headers });
9196
+ const { confirmationRequired } = evaluateImxRes.data;
9165
9197
  if (confirmationRequired) {
9166
9198
  if (this.crossSdkBridgeEnabled) {
9167
9199
  throw new Error(transactionRejectedCrossSdkBridgeError);
9168
9200
  }
9169
- const confirmationResult = await this.confirmationScreen.requestConfirmation(payloadHash, this.imxEtherAddress, TransactionApprovalRequestChainTypeEnum.Starkex);
9201
+ const confirmationResult = await this.confirmationScreen.requestConfirmation(payloadHash, user.imx.ethAddress, TransactionApprovalRequestChainTypeEnum.Starkex);
9170
9202
  if (!confirmationResult.confirmed) {
9171
9203
  throw new Error('Transaction rejected by user');
9172
9204
  }
@@ -9210,7 +9242,7 @@ class GuardianClient {
9210
9242
  throw new JsonRpcError(RpcErrorCode.TRANSACTION_REJECTED, transactionRejectedCrossSdkBridgeError);
9211
9243
  }
9212
9244
  if (confirmationRequired && !!transactionId) {
9213
- const confirmationResult = await this.confirmationScreen.requestConfirmation(transactionId, this.imxEtherAddress, TransactionApprovalRequestChainTypeEnum.Evm, chainId);
9245
+ const confirmationResult = await this.confirmationScreen.requestConfirmation(transactionId, user.zkEvm.ethAddress, TransactionApprovalRequestChainTypeEnum.Evm, chainId);
9214
9246
  if (!confirmationResult.confirmed) {
9215
9247
  throw new JsonRpcError(RpcErrorCode.TRANSACTION_REJECTED, 'Transaction rejected by user');
9216
9248
  }
@@ -9306,10 +9338,7 @@ async function createOrder$1({ starkSigner, user, request, ordersApi, guardianCl
9306
9338
  const { ethAddress } = user.imx;
9307
9339
  const amountSell = request.sell.type === ERC721$1 ? '1' : request.sell.amount;
9308
9340
  const amountBuy = request.buy.type === ERC721$1 ? '1' : request.buy.amount;
9309
- const headers = {
9310
- // eslint-disable-next-line @typescript-eslint/naming-convention
9311
- Authorization: `Bearer ${user.accessToken}`,
9312
- };
9341
+ const headers = { Authorization: `Bearer ${user.accessToken}` };
9313
9342
  const getSignableOrderRequestV3 = {
9314
9343
  user: ethAddress,
9315
9344
  amount_buy: amountBuy,
@@ -9323,7 +9352,8 @@ async function createOrder$1({ starkSigner, user, request, ordersApi, guardianCl
9323
9352
  const getSignableOrderResponse = await ordersApi.getSignableOrder({
9324
9353
  getSignableOrderRequestV3,
9325
9354
  }, { headers });
9326
- await guardianClient.validate({
9355
+ await guardianClient.evaluateImxTransaction({
9356
+ user,
9327
9357
  payloadHash: getSignableOrderResponse.data.payload_hash,
9328
9358
  });
9329
9359
  const { payload_hash: payloadHash } = getSignableOrderResponse.data;
@@ -9365,7 +9395,8 @@ async function cancelOrder$1({ user, starkSigner, request, ordersApi, guardianCl
9365
9395
  const getSignableCancelOrderResponse = await ordersApi.getSignableCancelOrderV3({
9366
9396
  getSignableCancelOrderRequest,
9367
9397
  }, { headers });
9368
- await guardianClient.validate({
9398
+ await guardianClient.evaluateImxTransaction({
9399
+ user,
9369
9400
  payloadHash: getSignableCancelOrderResponse.data.payload_hash,
9370
9401
  });
9371
9402
  const { payload_hash: payloadHash } = getSignableCancelOrderResponse.data;
@@ -9428,7 +9459,8 @@ async function createTrade$1({ request, tradesApi, user, starkSigner, guardianCl
9428
9459
  const getSignableTradeResponse = await tradesApi.getSignableTrade({
9429
9460
  getSignableTradeRequest,
9430
9461
  }, { headers });
9431
- await guardianClient.validate({
9462
+ await guardianClient.evaluateImxTransaction({
9463
+ user,
9432
9464
  payloadHash: getSignableTradeResponse.data.payload_hash,
9433
9465
  });
9434
9466
  const { payload_hash: payloadHash } = getSignableTradeResponse.data;
@@ -9475,7 +9507,8 @@ async function transfer$1({ request, transfersApi, starkSigner, user, guardianCl
9475
9507
  const signableResult = await transfersApi.getSignableTransferV1({
9476
9508
  getSignableTransferRequest,
9477
9509
  }, { headers });
9478
- await guardianClient.validate({
9510
+ await guardianClient.evaluateImxTransaction({
9511
+ user,
9479
9512
  payloadHash: signableResult.data.payload_hash,
9480
9513
  });
9481
9514
  const signableResultData = signableResult.data;
@@ -9522,14 +9555,12 @@ async function batchNftTransfer({ user, starkSigner, request, transfersApi, guar
9522
9555
  sender_ether_key: ethAddress,
9523
9556
  signable_requests: signableRequests,
9524
9557
  };
9525
- const headers = {
9526
- // eslint-disable-next-line @typescript-eslint/naming-convention
9527
- Authorization: `Bearer ${user.accessToken}`,
9528
- };
9558
+ const headers = { Authorization: `Bearer ${user.accessToken}` };
9529
9559
  const signableResult = await transfersApi.getSignableTransfer({
9530
9560
  getSignableTransferRequestV2,
9531
9561
  }, { headers });
9532
- await guardianClient.validate({
9562
+ await guardianClient.evaluateImxTransaction({
9563
+ user,
9533
9564
  payloadHash: signableResult.data.signable_responses[0]?.payload_hash,
9534
9565
  });
9535
9566
  const requests = await Promise.all(signableResult.data.signable_responses.map(async (resp) => {
@@ -9559,39 +9590,40 @@ async function batchNftTransfer({ user, starkSigner, request, transfersApi, guar
9559
9590
  }
9560
9591
 
9561
9592
  class PassportImxProvider {
9562
- user;
9593
+ authManager;
9563
9594
  starkSigner;
9564
9595
  immutableXClient;
9565
- confirmationScreen;
9566
9596
  guardianClient;
9567
- constructor({ user, starkSigner, immutableXClient, confirmationScreen, config, passportEventEmitter, }) {
9568
- this.user = user;
9597
+ constructor({ authManager, starkSigner, immutableXClient, confirmationScreen, config, passportEventEmitter, }) {
9598
+ this.authManager = authManager;
9569
9599
  this.starkSigner = starkSigner;
9570
9600
  this.immutableXClient = immutableXClient;
9571
- this.confirmationScreen = confirmationScreen;
9572
9601
  this.guardianClient = new GuardianClient({
9573
- accessToken: user.accessToken,
9574
9602
  confirmationScreen,
9575
- imxEtherAddress: user.imx.ethAddress,
9576
9603
  config,
9577
9604
  });
9578
9605
  passportEventEmitter.on(PassportEvents.LOGGED_OUT, this.handleLogout);
9579
9606
  }
9580
9607
  handleLogout = () => {
9581
- this.user = undefined;
9582
9608
  this.starkSigner = undefined;
9583
9609
  };
9584
- checkIsLoggedIn() {
9585
- if (this.user === undefined || this.starkSigner === undefined) {
9610
+ async getAuthenticatedUserSigner() {
9611
+ const user = await this.authManager.getUser();
9612
+ if (!user || this.starkSigner === undefined) {
9586
9613
  throw new PassportError('User has been logged out', PassportErrorType.NOT_LOGGED_IN_ERROR);
9587
9614
  }
9615
+ const isUserImx = (oidcUser) => oidcUser?.imx !== undefined;
9616
+ if (!isUserImx(user)) {
9617
+ throw new PassportError('User has not been registered with StarkEx', PassportErrorType.USER_NOT_REGISTERED_ERROR);
9618
+ }
9619
+ return { user, starkSigner: this.starkSigner };
9588
9620
  }
9589
9621
  async transfer(request) {
9590
- this.checkIsLoggedIn();
9622
+ const { user, starkSigner } = await this.getAuthenticatedUserSigner();
9591
9623
  return transfer$1({
9592
9624
  request,
9593
- user: this.user,
9594
- starkSigner: this.starkSigner,
9625
+ user,
9626
+ starkSigner,
9595
9627
  transfersApi: this.immutableXClient.transfersApi,
9596
9628
  guardianClient: this.guardianClient,
9597
9629
  });
@@ -9606,52 +9638,52 @@ class PassportImxProvider {
9606
9638
  isRegisteredOnchain() {
9607
9639
  throw new PassportError('Operation not supported', PassportErrorType.OPERATION_NOT_SUPPORTED_ERROR);
9608
9640
  }
9609
- createOrder(request) {
9610
- this.checkIsLoggedIn();
9641
+ async createOrder(request) {
9642
+ const { user, starkSigner } = await this.getAuthenticatedUserSigner();
9611
9643
  return createOrder$1({
9612
9644
  request,
9613
- user: this.user,
9614
- starkSigner: this.starkSigner,
9645
+ user,
9646
+ starkSigner,
9615
9647
  ordersApi: this.immutableXClient.ordersApi,
9616
9648
  guardianClient: this.guardianClient,
9617
9649
  });
9618
9650
  }
9619
- cancelOrder(request) {
9620
- this.checkIsLoggedIn();
9651
+ async cancelOrder(request) {
9652
+ const { user, starkSigner } = await this.getAuthenticatedUserSigner();
9621
9653
  return cancelOrder$1({
9622
9654
  request,
9623
- user: this.user,
9624
- starkSigner: this.starkSigner,
9655
+ user,
9656
+ starkSigner,
9625
9657
  ordersApi: this.immutableXClient.ordersApi,
9626
9658
  guardianClient: this.guardianClient,
9627
9659
  });
9628
9660
  }
9629
- createTrade(request) {
9630
- this.checkIsLoggedIn();
9661
+ async createTrade(request) {
9662
+ const { user, starkSigner } = await this.getAuthenticatedUserSigner();
9631
9663
  return createTrade$1({
9632
9664
  request,
9633
- user: this.user,
9634
- starkSigner: this.starkSigner,
9665
+ user,
9666
+ starkSigner,
9635
9667
  tradesApi: this.immutableXClient.tradesApi,
9636
9668
  guardianClient: this.guardianClient,
9637
9669
  });
9638
9670
  }
9639
- batchNftTransfer(request) {
9640
- this.checkIsLoggedIn();
9671
+ async batchNftTransfer(request) {
9672
+ const { user, starkSigner } = await this.getAuthenticatedUserSigner();
9641
9673
  return batchNftTransfer({
9642
9674
  request,
9643
- user: this.user,
9644
- starkSigner: this.starkSigner,
9675
+ user,
9676
+ starkSigner,
9645
9677
  transfersApi: this.immutableXClient.transfersApi,
9646
9678
  guardianClient: this.guardianClient,
9647
9679
  });
9648
9680
  }
9649
- exchangeTransfer(request) {
9650
- this.checkIsLoggedIn();
9681
+ async exchangeTransfer(request) {
9682
+ const { user, starkSigner } = await this.getAuthenticatedUserSigner();
9651
9683
  return exchangeTransfer$1({
9652
9684
  request,
9653
- user: this.user,
9654
- starkSigner: this.starkSigner,
9685
+ user,
9686
+ starkSigner,
9655
9687
  exchangesApi: this.immutableXClient.exchangeApi,
9656
9688
  });
9657
9689
  }
@@ -9674,9 +9706,9 @@ class PassportImxProvider {
9674
9706
  token) {
9675
9707
  throw new PassportError('Operation not supported', PassportErrorType.OPERATION_NOT_SUPPORTED_ERROR);
9676
9708
  }
9677
- getAddress() {
9678
- this.checkIsLoggedIn();
9679
- return Promise.resolve(this.user.imx.ethAddress);
9709
+ async getAddress() {
9710
+ const { user } = await this.getAuthenticatedUserSigner();
9711
+ return Promise.resolve(user.imx.ethAddress);
9680
9712
  }
9681
9713
  }
9682
9714
 
@@ -9730,9 +9762,9 @@ class PassportImxProviderFactory {
9730
9762
  const ethSigner = web3Provider.getSigner();
9731
9763
  const starkSigner = await getStarkSigner(ethSigner);
9732
9764
  if (!user.imx?.ethAddress) {
9733
- const userImx = await this.registerStarkEx(ethSigner, starkSigner, user.accessToken);
9765
+ await this.registerStarkEx(ethSigner, starkSigner, user.accessToken);
9734
9766
  return new PassportImxProvider({
9735
- user: userImx,
9767
+ authManager: this.authManager,
9736
9768
  starkSigner,
9737
9769
  immutableXClient: this.immutableXClient,
9738
9770
  confirmationScreen: this.confirmationScreen,
@@ -9741,7 +9773,7 @@ class PassportImxProviderFactory {
9741
9773
  });
9742
9774
  }
9743
9775
  return new PassportImxProvider({
9744
- user: user,
9776
+ authManager: this.authManager,
9745
9777
  starkSigner,
9746
9778
  immutableXClient: this.immutableXClient,
9747
9779
  confirmationScreen: this.confirmationScreen,
@@ -10486,9 +10518,7 @@ class ZkEvmProvider {
10486
10518
  user: this.user,
10487
10519
  });
10488
10520
  this.guardianClient = new GuardianClient({
10489
- accessToken: this.user.accessToken,
10490
10521
  confirmationScreen: this.confirmationScreen,
10491
- imxEtherAddress: this.user.zkEvm.ethAddress,
10492
10522
  config: this.config,
10493
10523
  });
10494
10524
  this.eventEmitter.emit(ProviderEvent.ACCOUNTS_CHANGED, [this.user.zkEvm.ethAddress]);
@@ -27978,13 +28008,14 @@ const quoteReturnMapping = {
27978
28008
  * @param poolB the other pool
27979
28009
  */
27980
28010
  function poolEquals(poolA, poolB) {
27981
- return (poolA === poolB
27982
- || (poolA.token0.equals(poolB.token0)
27983
- && poolA.token1.equals(poolB.token1)
27984
- && poolA.fee === poolB.fee));
28011
+ return (poolA === poolB ||
28012
+ (poolA.token0.equals(poolB.token0) && poolA.token1.equals(poolB.token1) && poolA.fee === poolB.fee));
27985
28013
  }
27986
- async function getERC20Decimals(tokenAddress, provider) {
27987
- const decimalsFunctionSig = ethers.utils.id('decimals()').substring(0, 10);
28014
+ const decimalsFunctionSig = ethers.utils.id('decimals()').substring(0, 10);
28015
+ async function getTokenDecimals(tokenAddress, provider, nativeToken) {
28016
+ if (tokenAddress === 'native') {
28017
+ return nativeToken.decimals;
28018
+ }
27988
28019
  try {
27989
28020
  const decimalsResult = await provider.call({
27990
28021
  to: tokenAddress,
@@ -28012,9 +28043,10 @@ function isValidNonZeroAddress(address) {
28012
28043
  return false;
28013
28044
  }
28014
28045
  }
28046
+ const isValidTokenLiteral = (address) => address === 'native' ? true : isValidNonZeroAddress(address);
28015
28047
  const erc20ToUniswapToken = (token) =>
28016
28048
  // eslint-disable-next-line implicit-arrow-linebreak
28017
- new Token(token.chainId, token.address, token.decimals, token.symbol, token.name);
28049
+ new Uniswap.Token(token.chainId, token.address, token.decimals, token.symbol, token.name);
28018
28050
  const uniswapTokenToERC20 = (token) => ({
28019
28051
  chainId: token.chainId,
28020
28052
  address: token.address,
@@ -28025,7 +28057,7 @@ const uniswapTokenToERC20 = (token) => ({
28025
28057
  });
28026
28058
  const toCurrencyAmount = (amount) => {
28027
28059
  const token = erc20ToUniswapToken(amount.token);
28028
- return CurrencyAmount.fromRawAmount(token, amount.value.toString());
28060
+ return Uniswap.CurrencyAmount.fromRawAmount(token, amount.value.toString());
28029
28061
  };
28030
28062
  const newAmount = (amount, token) => ({
28031
28063
  value: amount,
@@ -28071,6 +28103,28 @@ const subtractAmount = (a, b) => {
28071
28103
  }
28072
28104
  throw new Error('Token mismatch: token types must be the same');
28073
28105
  };
28106
+ /**
28107
+ * Converts our internal token type which could be ERC20 or Native
28108
+ * into a format consumable by Checkout. They require an address to be
28109
+ * present. We populate the address with empty string if it's Native.
28110
+ * If it's ERC20, we don't need to change it.
28111
+ */
28112
+ const toPublicTokenType = (token) => {
28113
+ if (token.type === 'native') {
28114
+ return {
28115
+ address: '',
28116
+ chainId: token.chainId,
28117
+ decimals: token.decimals,
28118
+ symbol: token.symbol,
28119
+ name: token.name,
28120
+ };
28121
+ }
28122
+ return token;
28123
+ };
28124
+ const toPublicAmount = (amount) => ({
28125
+ token: toPublicTokenType(amount.token),
28126
+ value: amount.value,
28127
+ });
28074
28128
 
28075
28129
  const amountIndex = 0;
28076
28130
  const gasEstimateIndex = 3;
@@ -28444,12 +28498,13 @@ const getUnsignedERC20ApproveTransaction = (ownerAddress, tokenAmount, spenderAd
28444
28498
  from: ownerAddress,
28445
28499
  };
28446
28500
  };
28447
- const prepareApproval = (tradeType, amountSpecified, amountWithSlippage, contracts, secondaryFees) => {
28448
- const amountOfTokenIn = tradeType === TradeType.EXACT_INPUT ? amountSpecified : amountWithSlippage;
28449
- const spender = secondaryFees.length === 0
28450
- ? contracts.routerAddress
28451
- : contracts.secondaryFeeAddress;
28452
- return { spender, amount: amountOfTokenIn };
28501
+ const prepareApproval = (tradeType, userSpecifiedAmount, quotedAmountWithSlippage, contracts, secondaryFees) => {
28502
+ const amountInToApprove = tradeType === TradeType.EXACT_INPUT ? userSpecifiedAmount : quotedAmountWithSlippage;
28503
+ if (!isERC20Amount(amountInToApprove)) {
28504
+ return null;
28505
+ }
28506
+ const spender = secondaryFees.length === 0 ? contracts.routerAddress : contracts.secondaryFeeAddress;
28507
+ return { spender, amount: amountInToApprove };
28453
28508
  };
28454
28509
  /**
28455
28510
  * Get an unsigned approval transaction if needed
@@ -28481,7 +28536,7 @@ async function getApproveGasEstimate(provider, ownerAddress, spenderAddress, tok
28481
28536
  from: ownerAddress,
28482
28537
  });
28483
28538
  }
28484
- const getApproval = async (provider, ownerAddress, preparedApproval, gasPrice, nativeTokenService) => {
28539
+ const getApproval = async (provider, ownerAddress, preparedApproval, gasPrice) => {
28485
28540
  const approveTransaction = await getApproveTransaction(provider, ownerAddress, preparedApproval.amount, preparedApproval.spender);
28486
28541
  if (!approveTransaction) {
28487
28542
  return null;
@@ -28490,11 +28545,42 @@ const getApproval = async (provider, ownerAddress, preparedApproval, gasPrice, n
28490
28545
  const gasFeeEstimate = gasPrice ? calculateGasFee(gasPrice, gasEstimate) : null;
28491
28546
  return {
28492
28547
  transaction: approveTransaction,
28493
- // TODO: TP-1649: Remove the wrapping here
28494
- gasFeeEstimate: gasFeeEstimate ? nativeTokenService.maybeWrapAmount(gasFeeEstimate) : null,
28548
+ gasFeeEstimate: gasFeeEstimate ? toPublicAmount(gasFeeEstimate) : null,
28495
28549
  };
28496
28550
  };
28497
28551
 
28552
+ const canUnwrapToken = (token) => token.type === 'native';
28553
+ class NativeTokenService {
28554
+ nativeToken;
28555
+ wrappedToken;
28556
+ constructor(nativeToken, wrappedToken) {
28557
+ this.nativeToken = nativeToken;
28558
+ this.wrappedToken = wrappedToken;
28559
+ }
28560
+ wrapAmount(amount) {
28561
+ if (!canUnwrapToken(amount.token)) {
28562
+ throw new Error(`cannot wrap non-native token: ${amount.token.address}`);
28563
+ }
28564
+ return newAmount(amount.value, this.wrappedToken);
28565
+ }
28566
+ unwrapAmount(amount) {
28567
+ const isWrappedToken = amount.token.address.toLowerCase() !== this.wrappedToken.address.toLowerCase();
28568
+ if (isWrappedToken) {
28569
+ throw new Error(`cannot unwrap non-wrapped token ${amount.token.address}`);
28570
+ }
28571
+ return newAmount(amount.value, this.nativeToken);
28572
+ }
28573
+ maybeWrapToken(token) {
28574
+ if (canUnwrapToken(token)) {
28575
+ return this.wrappedToken;
28576
+ }
28577
+ return token;
28578
+ }
28579
+ maybeWrapAmount(amount) {
28580
+ return newAmount(amount.value, this.maybeWrapToken(amount.token));
28581
+ }
28582
+ }
28583
+
28498
28584
  // slippageToPercent takes the slippage as a percentage (e.g. 0.1) and
28499
28585
  // converts it to the Uniswap equivalent type
28500
28586
  const slippageToFraction = (slippage) => {
@@ -28514,11 +28600,11 @@ const slippageToFraction = (slippage) => {
28514
28600
  return new Percent(numerator, denominator);
28515
28601
  };
28516
28602
 
28517
- function getQuoteAmountFromTradeType(tradeInfo) {
28518
- if (tradeInfo.tradeType === TradeType.EXACT_INPUT) {
28519
- return tradeInfo.amountOut;
28603
+ function getQuoteAmountFromTradeType(routerQuote) {
28604
+ if (routerQuote.tradeType === TradeType.EXACT_INPUT) {
28605
+ return routerQuote.amountOut;
28520
28606
  }
28521
- return tradeInfo.amountIn;
28607
+ return routerQuote.amountIn;
28522
28608
  }
28523
28609
  function applySlippage(tradeType, amount, slippage) {
28524
28610
  const slippageTolerance = slippageToFraction(slippage);
@@ -28527,22 +28613,18 @@ function applySlippage(tradeType, amount, slippage) {
28527
28613
  const amountWithSlippage = maybeInverted.multiply(amount.toString()).quotient;
28528
28614
  return ethers.BigNumber.from(amountWithSlippage.toString());
28529
28615
  }
28530
- function prepareUserQuote(otherToken, tradeInfo, slippage, fees, nativeTokenService) {
28531
- const quote = getQuoteAmountFromTradeType(tradeInfo);
28532
- const amountWithSlippage = applySlippage(tradeInfo.tradeType, quote.value, slippage);
28616
+ const prepareUserQuote = (nativeTokenService, routerQuote, slippage, tokenOfQuotedAmount) => {
28617
+ const erc20QuoteAmount = getQuoteAmountFromTradeType(routerQuote);
28618
+ // If the quote amount is the native token, we need to unwrap it if the user originally specified the native token
28619
+ const quotedAmount = canUnwrapToken(tokenOfQuotedAmount)
28620
+ ? nativeTokenService.unwrapAmount(erc20QuoteAmount)
28621
+ : erc20QuoteAmount;
28622
+ const quotedAmountWithMaxSlippage = newAmount(applySlippage(routerQuote.tradeType, quotedAmount.value, slippage), tokenOfQuotedAmount);
28533
28623
  return {
28534
- amount: quote,
28535
- amountWithMaxSlippage: {
28536
- token: otherToken,
28537
- value: amountWithSlippage,
28538
- },
28539
- slippage,
28540
- fees: fees.withAmounts().map((fee) => ({
28541
- ...fee,
28542
- amount: nativeTokenService.maybeWrapAmount(fee.amount),
28543
- })),
28624
+ quotedAmount,
28625
+ quotedAmountWithMaxSlippage,
28544
28626
  };
28545
- }
28627
+ };
28546
28628
  function getOurQuoteReqAmount(amountSpecified, // the amount specified by the user, either exactIn or exactOut
28547
28629
  fees, tradeType, nativeTokenService) {
28548
28630
  if (tradeType === TradeType.EXACT_OUTPUT) {
@@ -28610,46 +28692,8 @@ class Fees {
28610
28692
  }
28611
28693
  }
28612
28694
 
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
-
28643
28695
  const IMMUTABLE_TESTNET_RPC_URL = 'https://rpc.testnet.immutable.com';
28644
28696
  const IMMUTABLE_TESTNET_CHAIN_ID = 13472;
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
- };
28653
28697
  const TIMX_IMMUTABLE_TESTNET = {
28654
28698
  chainId: IMMUTABLE_TESTNET_CHAIN_ID,
28655
28699
  address: '0x0000000000000000000000000000000000001010',
@@ -28679,7 +28723,9 @@ function buildSwapParametersForSinglePoolSwap(fromAddress, trade, route, amountI
28679
28723
  recipient: fee.recipient,
28680
28724
  }));
28681
28725
  if (trade.tradeType === TradeType.EXACT_INPUT) {
28682
- return secondaryFeeContract.encodeFunctionData('exactInputSingleWithSecondaryFee', [secondaryFeeValues, {
28726
+ return secondaryFeeContract.encodeFunctionData('exactInputSingleWithSecondaryFee', [
28727
+ secondaryFeeValues,
28728
+ {
28683
28729
  tokenIn: route.tokenPath[0].address,
28684
28730
  tokenOut: route.tokenPath[1].address,
28685
28731
  fee: route.pools[0].fee,
@@ -28687,9 +28733,12 @@ function buildSwapParametersForSinglePoolSwap(fromAddress, trade, route, amountI
28687
28733
  amountIn,
28688
28734
  amountOutMinimum: amountOut,
28689
28735
  sqrtPriceLimitX96: 0,
28690
- }]);
28736
+ },
28737
+ ]);
28691
28738
  }
28692
- return secondaryFeeContract.encodeFunctionData('exactOutputSingleWithSecondaryFee', [secondaryFeeValues, {
28739
+ return secondaryFeeContract.encodeFunctionData('exactOutputSingleWithSecondaryFee', [
28740
+ secondaryFeeValues,
28741
+ {
28693
28742
  tokenIn: route.tokenPath[0].address,
28694
28743
  tokenOut: route.tokenPath[1].address,
28695
28744
  fee: route.pools[0].fee,
@@ -28697,7 +28746,8 @@ function buildSwapParametersForSinglePoolSwap(fromAddress, trade, route, amountI
28697
28746
  amountInMaximum: amountIn,
28698
28747
  amountOut,
28699
28748
  sqrtPriceLimitX96: 0,
28700
- }]);
28749
+ },
28750
+ ]);
28701
28751
  }
28702
28752
  function buildSwapParametersForMultiPoolSwap(fromAddress, trade, route, amountIn, amountOut, secondaryFees, secondaryFeeContract) {
28703
28753
  const path = encodeRouteToPath(route, trade.tradeType === TradeType.EXACT_OUTPUT);
@@ -28706,19 +28756,25 @@ function buildSwapParametersForMultiPoolSwap(fromAddress, trade, route, amountIn
28706
28756
  recipient: fee.recipient,
28707
28757
  }));
28708
28758
  if (trade.tradeType === TradeType.EXACT_INPUT) {
28709
- return secondaryFeeContract.encodeFunctionData('exactInputWithSecondaryFee', [secondaryFeeValues, {
28759
+ return secondaryFeeContract.encodeFunctionData('exactInputWithSecondaryFee', [
28760
+ secondaryFeeValues,
28761
+ {
28710
28762
  path,
28711
28763
  recipient: fromAddress,
28712
28764
  amountIn,
28713
28765
  amountOutMinimum: amountOut,
28714
- }]);
28766
+ },
28767
+ ]);
28715
28768
  }
28716
- return secondaryFeeContract.encodeFunctionData('exactOutputWithSecondaryFee', [secondaryFeeValues, {
28769
+ return secondaryFeeContract.encodeFunctionData('exactOutputWithSecondaryFee', [
28770
+ secondaryFeeValues,
28771
+ {
28717
28772
  path,
28718
28773
  recipient: fromAddress,
28719
28774
  amountInMaximum: amountIn,
28720
28775
  amountOut,
28721
- }]);
28776
+ },
28777
+ ]);
28722
28778
  }
28723
28779
  /**
28724
28780
  * Builds swap parameters
@@ -28743,7 +28799,10 @@ function buildSwapParameters(fromAddress, trade, options, secondaryFees, seconda
28743
28799
  function createSwapCallParametersWithFees(trade, fromAddress, swapOptions, secondaryFees) {
28744
28800
  const secondaryFeeContract = SecondaryFee__factory.createInterface();
28745
28801
  const swapWithFeesCalldata = buildSwapParameters(fromAddress, trade, swapOptions, secondaryFees, secondaryFeeContract);
28746
- return secondaryFeeContract.encodeFunctionData(multicallWithDeadlineFunctionSignature, [swapOptions.deadlineOrPreviousBlockhash, [swapWithFeesCalldata]]);
28802
+ return secondaryFeeContract.encodeFunctionData(multicallWithDeadlineFunctionSignature, [
28803
+ swapOptions.deadlineOrPreviousBlockhash,
28804
+ [swapWithFeesCalldata],
28805
+ ]);
28747
28806
  }
28748
28807
  function createSwapParameters(adjustedQuote, fromAddress, slippage, deadline, secondaryFees) {
28749
28808
  // Create an unchecked trade to be used in generating swap parameters.
@@ -28783,7 +28842,7 @@ function getSwap(adjustedQuote, fromAddress, slippage, deadline, peripheryRouter
28783
28842
  const adjustAmountIn = (ourQuote, amountSpecified, fees, nativeTokenService) => {
28784
28843
  if (ourQuote.tradeType === TradeType.EXACT_OUTPUT) {
28785
28844
  // when doing exact output, calculate the fees based on the amountIn
28786
- const amountToAdd = nativeTokenService.isNativeToken(fees.token)
28845
+ const amountToAdd = canUnwrapToken(fees.token)
28787
28846
  ? nativeTokenService.unwrapAmount(ourQuote.amountIn)
28788
28847
  : ourQuote.amountIn;
28789
28848
  fees.addAmount(amountToAdd);
@@ -28827,7 +28886,7 @@ const SUPPORTED_SANDBOX_CHAINS = {
28827
28886
  rpcUrl: IMMUTABLE_TESTNET_RPC_URL,
28828
28887
  contracts: CONTRACTS_FOR_CHAIN_ID[IMMUTABLE_TESTNET_CHAIN_ID],
28829
28888
  commonRoutingTokens: IMMUTABLE_TESTNET_COMMON_ROUTING_TOKENS,
28830
- nativeToken: NATIVE_IMX_IMMUTABLE_TESTNET,
28889
+ nativeToken: TIMX_IMMUTABLE_TESTNET,
28831
28890
  wrappedNativeToken: TIMX_IMMUTABLE_TESTNET, // TODO: TP-1649: Change to WIMX when ready.
28832
28891
  },
28833
28892
  };
@@ -28899,6 +28958,15 @@ class ExchangeConfiguration {
28899
28958
  }
28900
28959
  }
28901
28960
 
28961
+ const toPublicQuote = (amount, amountWithMaxSlippage, slippage, fees) => ({
28962
+ amount: toPublicAmount(amount),
28963
+ amountWithMaxSlippage: toPublicAmount(amountWithMaxSlippage),
28964
+ slippage,
28965
+ fees: fees.withAmounts().map((fee) => ({
28966
+ ...fee,
28967
+ amount: toPublicAmount(fee.amount),
28968
+ })),
28969
+ });
28902
28970
  class Exchange {
28903
28971
  provider;
28904
28972
  router;
@@ -28927,8 +28995,8 @@ class Exchange {
28927
28995
  }
28928
28996
  static validate(tokenInAddress, tokenOutAddress, maxHops, slippagePercent, fromAddress) {
28929
28997
  assert(isValidNonZeroAddress(fromAddress), new InvalidAddressError('invalid from address'));
28930
- assert(isValidNonZeroAddress(tokenInAddress), new InvalidAddressError('invalid token in address'));
28931
- assert(isValidNonZeroAddress(tokenOutAddress), new InvalidAddressError('invalid token out address'));
28998
+ assert(isValidTokenLiteral(tokenInAddress), new InvalidAddressError('invalid token in address'));
28999
+ assert(isValidTokenLiteral(tokenOutAddress), new InvalidAddressError('invalid token out address'));
28932
29000
  assert(tokenInAddress.toLocaleLowerCase() !== tokenOutAddress.toLocaleLowerCase(), new DuplicateAddressesError());
28933
29001
  assert(maxHops <= MAX_MAX_HOPS, new InvalidMaxHopsError('max hops must be less than or equal to 10'));
28934
29002
  assert(maxHops >= MIN_MAX_HOPS, new InvalidMaxHopsError('max hops must be greater than or equal to 1'));
@@ -28946,63 +29014,63 @@ class Exchange {
28946
29014
  }
28947
29015
  return this.secondaryFees;
28948
29016
  }
28949
- async getUnsignedSwapTx(fromAddress, tokenInAddress, tokenOutAddress, amount, slippagePercent, maxHops, deadline, tradeType) {
28950
- Exchange.validate(tokenInAddress, tokenOutAddress, maxHops, slippagePercent, fromAddress);
29017
+ parseTokenLiteral(tokenLiteral, decimals) {
29018
+ if (tokenLiteral === 'native') {
29019
+ return this.nativeToken;
29020
+ }
29021
+ return {
29022
+ type: 'erc20',
29023
+ address: tokenLiteral,
29024
+ chainId: this.chainId,
29025
+ decimals,
29026
+ };
29027
+ }
29028
+ async getUnsignedSwapTx(fromAddress, tokenInLiteral, tokenOutLiteral, amount, slippagePercent, maxHops, deadline, tradeType) {
29029
+ Exchange.validate(tokenInLiteral, tokenOutLiteral, maxHops, slippagePercent, fromAddress);
28951
29030
  // get the decimals of the tokens that will be swapped
28952
29031
  const [tokenInDecimals, tokenOutDecimals, secondaryFees] = await Promise.all([
28953
- getERC20Decimals(tokenInAddress, this.provider),
28954
- getERC20Decimals(tokenOutAddress, this.provider),
29032
+ getTokenDecimals(tokenInLiteral, this.provider, this.nativeToken),
29033
+ getTokenDecimals(tokenOutLiteral, this.provider, this.nativeToken),
28955
29034
  this.getSecondaryFees(),
28956
29035
  ]);
28957
- const tokenIn = {
28958
- type: 'erc20',
28959
- address: tokenInAddress,
28960
- chainId: this.chainId,
28961
- decimals: tokenInDecimals,
28962
- };
28963
- const tokenOut = {
28964
- type: 'erc20',
28965
- address: tokenOutAddress,
28966
- chainId: this.chainId,
28967
- decimals: tokenOutDecimals,
28968
- };
29036
+ const tokenIn = this.parseTokenLiteral(tokenInLiteral, tokenInDecimals);
29037
+ const tokenOut = this.parseTokenLiteral(tokenOutLiteral, tokenOutDecimals);
28969
29038
  // determine which amount was specified for the swap from the TradeType
28970
29039
  const [tokenSpecified, otherToken] = tradeType === TradeType.EXACT_INPUT ? [tokenIn, tokenOut] : [tokenOut, tokenIn];
28971
29040
  const amountSpecified = newAmount(amount, tokenSpecified);
28972
29041
  const fees = new Fees(secondaryFees, tokenIn);
28973
29042
  const ourQuoteReqAmount = getOurQuoteReqAmount(amountSpecified, fees, tradeType, this.nativeTokenService);
28974
- // get quote and gas details
29043
+ // Quotes will always use ERC20s. If the user-specified token is Native, we use the Wrapped Native Token pool
28975
29044
  const [ourQuote, gasPrice] = await Promise.all([
28976
- this.router.findOptimalRoute(ourQuoteReqAmount, otherToken, tradeType, maxHops),
29045
+ this.router.findOptimalRoute(ourQuoteReqAmount, this.nativeTokenService.maybeWrapToken(otherToken), tradeType, maxHops),
28977
29046
  fetchGasPrice(this.provider, this.nativeToken),
28978
29047
  ]);
28979
29048
  const adjustedQuote = adjustQuoteWithFees(ourQuote, amountSpecified, fees, this.nativeTokenService);
28980
29049
  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, {
29050
+ const { quotedAmount, quotedAmountWithMaxSlippage } = prepareUserQuote(this.nativeTokenService, adjustedQuote, slippagePercent, otherToken);
29051
+ const preparedApproval = prepareApproval(tradeType, amountSpecified, quotedAmountWithMaxSlippage, {
28983
29052
  routerAddress: this.routerContractAddress,
28984
29053
  secondaryFeeAddress: this.secondaryFeeContractAddress,
28985
29054
  }, secondaryFees);
28986
29055
  // preparedApproval always uses the tokenIn address because we are always selling the tokenIn
28987
- const approval = await getApproval(this.provider, fromAddress, preparedApproval, gasPrice, this.nativeTokenService);
28988
- return {
28989
- approval,
28990
- swap,
28991
- quote: userQuote,
28992
- };
29056
+ const approval = preparedApproval
29057
+ ? await getApproval(this.provider, fromAddress, preparedApproval, gasPrice)
29058
+ : null;
29059
+ const quote = toPublicQuote(quotedAmount, quotedAmountWithMaxSlippage, slippagePercent, fees);
29060
+ return { quote, approval, swap };
28993
29061
  }
28994
29062
  /**
28995
29063
  * Get the unsigned swap transaction given the amount to sell.
28996
29064
  * Includes quote details for the swap.
28997
29065
  *
28998
- * @param {string} fromAddress The public address that will sign and submit the transaction.
28999
- * @param {string} tokenInAddress Token address to sell.
29000
- * @param {string} tokenOutAddress Token address to buy.
29001
- * @param {ethers.BigNumberish} amountIn Amount to sell.
29002
- * @param {number} slippagePercent (optional) The percentage of slippage tolerance. Default = 0.1. Max = 50. Min = 0.
29003
- * @param {number} maxHops (optional) Maximum hops allowed in optimal route. Default is 2.
29004
- * @param {number} deadline (optional) Latest time swap can execute. Default is 15 minutes.
29005
- * @return {TransactionResponse} The result containing the unsigned transaction and details of the swap.
29066
+ * @param {string} fromAddress The public address that will sign and submit the transaction
29067
+ * @param {string} tokenInAddress Token address or 'native' to sell
29068
+ * @param {string} tokenOutAddress Token address or 'native' to buy
29069
+ * @param {ethers.BigNumberish} amountIn Amount to sell in the smallest unit of the token-in
29070
+ * @param {number} slippagePercent (optional) The percentage of slippage tolerance. Default = 0.1. Max = 50. Min = 0
29071
+ * @param {number} maxHops (optional) Maximum hops allowed in optimal route. Default is 2
29072
+ * @param {number} deadline (optional) Latest time swap can execute. Default is 15 minutes
29073
+ * @return {TransactionResponse} The result containing the unsigned transaction and details of the swap
29006
29074
  */
29007
29075
  async getUnsignedSwapTxFromAmountIn(fromAddress, tokenInAddress, tokenOutAddress, amountIn, slippagePercent = DEFAULT_SLIPPAGE, maxHops = DEFAULT_MAX_HOPS, deadline = DEFAULT_DEADLINE) {
29008
29076
  return await this.getUnsignedSwapTx(fromAddress, tokenInAddress, tokenOutAddress, ethers.BigNumber.from(amountIn), slippagePercent, maxHops, deadline, TradeType.EXACT_INPUT);
@@ -29011,14 +29079,14 @@ class Exchange {
29011
29079
  * Get the unsigned swap transaction given the amount to buy.
29012
29080
  * Includes quote details for the swap.
29013
29081
  *
29014
- * @param {string} fromAddress The public address that will sign and submit the transaction.
29015
- * @param {string} tokenInAddress Token address to sell.
29016
- * @param {string} tokenOutAddress Token address to buy.
29017
- * @param {ethers.BigNumberish} amountOut Amount to buy.
29018
- * @param {number} slippagePercent (optional) The percentage of slippage tolerance. Default = 0.1. Max = 50. Min = 0.
29019
- * @param {number} maxHops (optional) Maximum hops allowed in optimal route. Default is 2.
29020
- * @param {number} deadline (optional) Latest time swap can execute. Default is 15 minutes.
29021
- * @return {TransactionResponse} The result containing the unsigned transaction and details of the swap.
29082
+ * @param {string} fromAddress The public address that will sign and submit the transaction
29083
+ * @param {string} tokenInAddress ERC20 contract address or 'native' to sell
29084
+ * @param {string} tokenOutAddress ERC20 contract address or 'native' to buy
29085
+ * @param {ethers.BigNumberish} amountOut Amount to buy in the smallest unit of the token-out
29086
+ * @param {number} slippagePercent (optional) The percentage of slippage tolerance. Default = 0.1. Max = 50. Min = 0
29087
+ * @param {number} maxHops (optional) Maximum hops allowed in optimal route. Default is 2
29088
+ * @param {number} deadline (optional) Latest time swap can execute. Default is 15 minutes
29089
+ * @return {TransactionResponse} The result containing the unsigned transaction and details of the swap
29022
29090
  */
29023
29091
  async getUnsignedSwapTxFromAmountOut(fromAddress, tokenInAddress, tokenOutAddress, amountOut, slippagePercent = DEFAULT_SLIPPAGE, maxHops = DEFAULT_MAX_HOPS, deadline = DEFAULT_DEADLINE) {
29024
29092
  return await this.getUnsignedSwapTx(fromAddress, tokenInAddress, tokenOutAddress, ethers.BigNumber.from(amountOut), slippagePercent, maxHops, deadline, TradeType.EXACT_OUTPUT);
@@ -29262,6 +29330,14 @@ const $d85ad1457a3f1a83$export$fc55ed5a42b458ba = {
29262
29330
  [($0472f23319457bfb$export$c06e1e7429de6283).IMTBL_ZKEVM_MAINNET]: {
29263
29331
  url: "https://explorer.mainnet.immutable.com",
29264
29332
  nativeToken: $d85ad1457a3f1a83$export$6f24f3cef7d501c4.get(($0472f23319457bfb$export$c06e1e7429de6283).IMTBL_ZKEVM_MAINNET).nativeCurrency
29333
+ },
29334
+ [($0472f23319457bfb$export$c06e1e7429de6283).SEPOLIA]: {
29335
+ url: "https://eth-sepolia.blockscout.com",
29336
+ nativeToken: $d85ad1457a3f1a83$export$3e81fc0987227f10.get(($0472f23319457bfb$export$c06e1e7429de6283).SEPOLIA).nativeCurrency
29337
+ },
29338
+ [($0472f23319457bfb$export$c06e1e7429de6283).ETHEREUM]: {
29339
+ url: "https://eth.blockscout.com/",
29340
+ nativeToken: $d85ad1457a3f1a83$export$6f24f3cef7d501c4.get(($0472f23319457bfb$export$c06e1e7429de6283).ETHEREUM).nativeCurrency
29265
29341
  }
29266
29342
  };
29267
29343
  const $d85ad1457a3f1a83$export$db5daa1b5156ccfe = [
@@ -29861,6 +29937,7 @@ const $efe60cea83bfc4e8$export$473cec51305fdae8 = async (config, { type: type =
29861
29937
 
29862
29938
 
29863
29939
 
29940
+
29864
29941
  const $fd8a8472dcc3ec2b$var$CACHE_DATA_TTL = 60; // seconds
29865
29942
  class $fd8a8472dcc3ec2b$export$ef140a6b05dfc786 {
29866
29943
  url;
@@ -30033,18 +30110,23 @@ async function $1564e43dde50bb61$export$60e0fe116a0e6ed0(web3Provider, walletAdd
30033
30110
  type: ($a8bc256d81a5e2c1$export$e3dc0620abde7f5a).GET_ERC20_BALANCE_ERROR
30034
30111
  });
30035
30112
  }
30036
- // Blockscout client singleton
30037
- let $1564e43dde50bb61$var$blockscoutClient;
30038
- const $1564e43dde50bb61$export$8c978679845804d4 = async (walletAddress, chainId, rename)=>{
30113
+ // Blockscout client singleton per chain id
30114
+ const $1564e43dde50bb61$var$blockscoutClientMap = new Map();
30115
+ const $1564e43dde50bb61$export$8c978679845804d4 = async (walletAddress, chainId, filterTokens)=>{
30039
30116
  // Shuffle the mapping of the tokens configuration so it is a hashmap
30040
30117
  // for faster access to tokens config objects.
30041
- const mapRename = Object.assign({}, ...rename.map((t)=>({
30118
+ const shouldFilter = filterTokens.length > 0;
30119
+ const mapFilterTokens = Object.assign({}, ...filterTokens.map((t)=>({
30042
30120
  [t.address || ""]: t
30043
30121
  })));
30044
- // Ensure singleton is present and match the selected chain
30045
- if (!$1564e43dde50bb61$var$blockscoutClient || $1564e43dde50bb61$var$blockscoutClient.chainId !== chainId) $1564e43dde50bb61$var$blockscoutClient = new ($fd8a8472dcc3ec2b$export$ef140a6b05dfc786)({
30046
- chainId: chainId
30047
- });
30122
+ // Get blockscout client for the given chain
30123
+ let blockscoutClient = $1564e43dde50bb61$var$blockscoutClientMap.get(chainId);
30124
+ if (!blockscoutClient) {
30125
+ blockscoutClient = new ($fd8a8472dcc3ec2b$export$ef140a6b05dfc786)({
30126
+ chainId: chainId
30127
+ });
30128
+ $1564e43dde50bb61$var$blockscoutClientMap.set(chainId, blockscoutClient);
30129
+ }
30048
30130
  // Hold the items in an array for post-fetching processing
30049
30131
  const items = [];
30050
30132
  const tokenType = ($887a00f8f72d61f0$export$5bd1ea2b3d18210).ERC20;
@@ -30054,7 +30136,7 @@ const $1564e43dde50bb61$export$8c978679845804d4 = async (walletAddress, chainId,
30054
30136
  try {
30055
30137
  do {
30056
30138
  // eslint-disable-next-line no-await-in-loop
30057
- resp = await $1564e43dde50bb61$var$blockscoutClient.getTokensByWalletAddress({
30139
+ resp = await blockscoutClient.getTokensByWalletAddress({
30058
30140
  walletAddress: walletAddress,
30059
30141
  tokenType: tokenType,
30060
30142
  nextPage: resp?.next_page_params
@@ -30072,7 +30154,7 @@ const $1564e43dde50bb61$export$8c978679845804d4 = async (walletAddress, chainId,
30072
30154
  if (err?.code !== (HttpStatusCode$2).NotFound) throw new ($a8bc256d81a5e2c1$export$b722478a3cbfa3bc)(err.message || "InternalServerError | getTokensByWalletAddress", ($a8bc256d81a5e2c1$export$e3dc0620abde7f5a).GET_INDEXER_BALANCE_ERROR, err);
30073
30155
  }
30074
30156
  try {
30075
- const respNative = await $1564e43dde50bb61$var$blockscoutClient.getNativeTokenByWalletAddress({
30157
+ const respNative = await blockscoutClient.getNativeTokenByWalletAddress({
30076
30158
  walletAddress: walletAddress
30077
30159
  });
30078
30160
  items.push(respNative);
@@ -30086,24 +30168,26 @@ const $1564e43dde50bb61$export$8c978679845804d4 = async (walletAddress, chainId,
30086
30168
  // or simply an incorrect wallet address was provided.
30087
30169
  if (err?.code !== (HttpStatusCode$2).NotFound) throw new ($a8bc256d81a5e2c1$export$b722478a3cbfa3bc)(err.message || "InternalServerError | getNativeTokenByWalletAddress", ($a8bc256d81a5e2c1$export$e3dc0620abde7f5a).GET_INDEXER_BALANCE_ERROR, err);
30088
30170
  }
30171
+ const balances = [];
30172
+ items.forEach((item)=>{
30173
+ if (shouldFilter && !mapFilterTokens[item.token.address]) return;
30174
+ const tokenData = item.token || {};
30175
+ const balance = (BigNumber$1).from(item.value);
30176
+ let decimals = parseInt(tokenData.decimals, 10);
30177
+ if (Number.isNaN(decimals)) decimals = ($d85ad1457a3f1a83$export$903389470ba9433c);
30178
+ const token = {
30179
+ ...tokenData,
30180
+ decimals: decimals
30181
+ };
30182
+ const formattedBalance = (utils$1).formatUnits(item.value, token.decimals);
30183
+ balances.push({
30184
+ balance: balance,
30185
+ formattedBalance: formattedBalance,
30186
+ token: token
30187
+ });
30188
+ });
30089
30189
  return {
30090
- balances: items.map((item)=>{
30091
- const tokenData = item.token || {};
30092
- const balance = (BigNumber$1).from(item.value);
30093
- const renamed = mapRename[tokenData.address] || {};
30094
- const token = {
30095
- ...tokenData,
30096
- name: renamed.name ?? tokenData.name,
30097
- symbol: renamed.symbol ?? tokenData.symbol,
30098
- decimals: parseInt(tokenData.decimals, 10)
30099
- };
30100
- const formattedBalance = (utils$1).formatUnits(item.value, token.decimals);
30101
- return {
30102
- balance: balance,
30103
- formattedBalance: formattedBalance,
30104
- token: token
30105
- };
30106
- })
30190
+ balances: balances
30107
30191
  };
30108
30192
  };
30109
30193
  const $1564e43dde50bb61$export$a3238cee431627c6 = async (config, web3Provider, walletAddress, tokens)=>{
@@ -30134,7 +30218,15 @@ const $1564e43dde50bb61$export$fee49741664a4d7e = async (config, web3Provider, w
30134
30218
  // eslint-disable-next-line no-console
30135
30219
  console.error(err);
30136
30220
  }
30137
- if (flag && ($fd8a8472dcc3ec2b$export$ef140a6b05dfc786).isChainSupported(chainId)) return await $1564e43dde50bb61$export$8c978679845804d4(walletAddress, chainId, tokens);
30221
+ if (flag && ($fd8a8472dcc3ec2b$export$ef140a6b05dfc786).isChainSupported(chainId)) {
30222
+ // This is a hack because the widgets are still using the tokens symbol
30223
+ // to drive the conversions. If we remove all the token symbols from e.g. zkevm
30224
+ // then we would not have fiat conversions.
30225
+ // Please remove this hack once https://immutable.atlassian.net/browse/WT-1710
30226
+ // is done.
30227
+ const isL1Chain = ($4013c5c91bb535f6$export$9b794d067cdd1af6)(config) === chainId;
30228
+ return await $1564e43dde50bb61$export$8c978679845804d4(walletAddress, chainId, isL1Chain ? tokens : []);
30229
+ }
30138
30230
  // This fallback to use ERC20s calls which is a best effort solution
30139
30231
  // Fails in fetching data from the RCP calls might result in some
30140
30232
  // missing data.
@@ -33108,7 +33200,7 @@ class $a8cb37a3fc8eb863$export$1f60ba4ec72508a0 {
33108
33200
  const tokenList = await $efe60cea83bfc4e8$export$473cec51305fdae8(this.config, {
33109
33201
  type: ($08d5ddc39acd6833$export$fd9b17d87f4121d2).ONRAMP
33110
33202
  });
33111
- const token = tokenList.tokens.find((t)=>t.address?.toLowerCase() === params.tokenAddress?.toLowerCase());
33203
+ const token = tokenList.tokens?.find((t)=>t.address?.toLowerCase() === params.tokenAddress?.toLowerCase());
33112
33204
  if (token) {
33113
33205
  tokenAmount = params.tokenAmount;
33114
33206
  tokenSymbol = token.symbol;
@@ -33181,7 +33273,7 @@ var $045213b18e9f1f94$export$75be0f6af9650f2c;
33181
33273
  })($045213b18e9f1f94$export$75be0f6af9650f2c || ($045213b18e9f1f94$export$75be0f6af9650f2c = {}));
33182
33274
 
33183
33275
 
33184
- const $d663162fd5a0853f$export$38a083d9fb5551ca = "0.27.9";
33276
+ const $d663162fd5a0853f$export$38a083d9fb5551ca = "0.27.11";
33185
33277
  const $d663162fd5a0853f$export$83bf90b30cdfd29f = ()=>false;
33186
33278
  const $d663162fd5a0853f$export$1169f5475725171b = ()=>$d663162fd5a0853f$export$38a083d9fb5551ca;
33187
33279
 
@@ -33315,7 +33407,7 @@ var $207ed853f11d19d5$export$5a0ace85cae72d45;
33315
33407
  IMTBLWidgetEvents["IMTBL_SWAP_WIDGET_EVENT"] = "imtbl-swap-widget";
33316
33408
  IMTBLWidgetEvents["IMTBL_BRIDGE_WIDGET_EVENT"] = "imtbl-bridge-widget";
33317
33409
  IMTBLWidgetEvents["IMTBL_ONRAMP_WIDGET_EVENT"] = "imtbl-onramp-widget";
33318
- IMTBLWidgetEvents["IMTBL_PRIMARY_REVENUE_WIDGET_EVENT"] = "imtbl-sale-widget";
33410
+ IMTBLWidgetEvents["IMTBL_SALE_WIDGET_EVENT"] = "imtbl-sale-widget";
33319
33411
  })($207ed853f11d19d5$export$5a0ace85cae72d45 || ($207ed853f11d19d5$export$5a0ace85cae72d45 = {}));
33320
33412
 
33321
33413