@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.cjs CHANGED
@@ -19,7 +19,7 @@ var seaportJs = require('@opensea/seaport-js');
19
19
  var units = require('@ethersproject/units');
20
20
  var bignumber = require('@ethersproject/bignumber');
21
21
  var detectEthereumProvider = require('@metamask/detect-provider');
22
- var sdkCore = require('@uniswap/sdk-core');
22
+ var Uniswap = require('@uniswap/sdk-core');
23
23
  var assert = require('assert');
24
24
  var v3Sdk = require('@uniswap/v3-sdk');
25
25
  var solidity = require('@ethersproject/solidity');
@@ -46,6 +46,7 @@ function _interopNamespaceDefault(e) {
46
46
 
47
47
  var crypto__namespace = /*#__PURE__*/_interopNamespaceDefault(crypto);
48
48
  var encUtils__namespace = /*#__PURE__*/_interopNamespaceDefault(encUtils);
49
+ var Uniswap__namespace = /*#__PURE__*/_interopNamespaceDefault(Uniswap);
49
50
 
50
51
  var Environment$1;
51
52
  (function (Environment) {
@@ -3631,7 +3632,7 @@ class MultiRollupApiClients {
3631
3632
  }
3632
3633
 
3633
3634
  // eslint-disable-next-line @typescript-eslint/naming-convention
3634
- const defaultHeaders$1 = { 'x-sdk-version': 'ts-immutable-sdk-0.27.9' };
3635
+ const defaultHeaders$1 = { 'x-sdk-version': 'ts-immutable-sdk-0.27.11' };
3635
3636
  const createConfig = ({ basePath, headers, }) => {
3636
3637
  if (!basePath.trim()) {
3637
3638
  throw Error('basePath can not be empty');
@@ -3691,7 +3692,7 @@ class APIError extends Error {
3691
3692
 
3692
3693
  /* eslint-disable implicit-arrow-linebreak */
3693
3694
  const defaultHeaders = {
3694
- sdkVersion: 'ts-immutable-sdk-multi-rollup-api-client-0.27.9',
3695
+ sdkVersion: 'ts-immutable-sdk-multi-rollup-api-client-0.27.11',
3695
3696
  };
3696
3697
  /**
3697
3698
  * createAPIConfiguration to create a custom Configuration
@@ -4102,7 +4103,7 @@ const createImmutableXConfiguration = ({ basePath, chainID, coreContractAddress,
4102
4103
  chainID,
4103
4104
  coreContractAddress,
4104
4105
  registrationContractAddress,
4105
- sdkVersion: 'ts-immutable-sdk-0.27.9',
4106
+ sdkVersion: 'ts-immutable-sdk-0.27.11',
4106
4107
  });
4107
4108
  /**
4108
4109
  * Sets `sdkVersion` at the time of build
@@ -8582,6 +8583,7 @@ var PassportErrorType;
8582
8583
  PassportErrorType["SILENT_LOGIN_ERROR"] = "SILENT_LOGIN_ERROR";
8583
8584
  PassportErrorType["REFRESH_TOKEN_ERROR"] = "REFRESH_TOKEN_ERROR";
8584
8585
  PassportErrorType["USER_REGISTRATION_ERROR"] = "USER_REGISTRATION_ERROR";
8586
+ PassportErrorType["USER_NOT_REGISTERED_ERROR"] = "USER_NOT_REGISTERED_ERROR";
8585
8587
  PassportErrorType["LOGOUT_ERROR"] = "LOGOUT_ERROR";
8586
8588
  PassportErrorType["TRANSFER_ERROR"] = "TRANSFER_ERROR";
8587
8589
  PassportErrorType["CREATE_ORDER_ERROR"] = "CREATE_ORDER_ERROR";
@@ -8731,6 +8733,10 @@ class AuthManager {
8731
8733
  config;
8732
8734
  deviceCredentialsManager;
8733
8735
  logoutMode;
8736
+ /**
8737
+ * Promise that is used to prevent multiple concurrent calls to the refresh token endpoint.
8738
+ */
8739
+ refreshingPromise = null;
8734
8740
  constructor(config) {
8735
8741
  this.config = config;
8736
8742
  this.userManager = new oidcClientTs.UserManager(getAuthConfiguration(config));
@@ -8975,32 +8981,52 @@ class AuthManager {
8975
8981
  * @param forceRefresh If set to true, force an HTTP call to the OIDC server's authorization endpoint. This call will
8976
8982
  * throw an error if there's no refresh token.
8977
8983
  */
8978
- async getWebUser({ forceRefresh = false }) {
8984
+ async getAuthenticatedUser({ forceRefresh = false }) {
8979
8985
  if (forceRefresh) {
8980
- const newOidcUser = await this.userManager.signinSilent();
8981
- return newOidcUser ? AuthManager.mapOidcUserToDomainModel(newOidcUser) : null;
8986
+ return this.refreshTokenAndUpdatePromise();
8982
8987
  }
8983
8988
  const oidcUser = await this.userManager.getUser();
8984
8989
  if (!oidcUser)
8985
8990
  return null;
8986
- const tokenExpired = isTokenExpired(oidcUser);
8987
- if (!tokenExpired) {
8991
+ if (!isTokenExpired(oidcUser)) {
8988
8992
  return AuthManager.mapOidcUserToDomainModel(oidcUser);
8989
8993
  }
8990
8994
  if (oidcUser.refresh_token) {
8991
- const newOidcUser = await this.userManager.signinSilent();
8992
- if (newOidcUser) {
8993
- return AuthManager.mapOidcUserToDomainModel(newOidcUser);
8994
- }
8995
+ return this.refreshTokenAndUpdatePromise();
8995
8996
  }
8996
8997
  return null;
8997
8998
  }
8999
+ /**
9000
+ * Refreshes the token and returns the user.
9001
+ * If the token is already being refreshed, returns the existing promise.
9002
+ */
9003
+ async refreshTokenAndUpdatePromise() {
9004
+ if (this.refreshingPromise)
9005
+ return this.refreshingPromise;
9006
+ // eslint-disable-next-line no-async-promise-executor
9007
+ this.refreshingPromise = new Promise(async (resolve, reject) => {
9008
+ try {
9009
+ const newOidcUser = await this.userManager.signinSilent();
9010
+ if (newOidcUser) {
9011
+ resolve(AuthManager.mapOidcUserToDomainModel(newOidcUser));
9012
+ return;
9013
+ }
9014
+ resolve(null);
9015
+ }
9016
+ catch (err) {
9017
+ reject(err);
9018
+ }
9019
+ finally {
9020
+ this.refreshingPromise = null; // Reset the promise after completion
9021
+ }
9022
+ });
9023
+ return this.refreshingPromise;
9024
+ }
8998
9025
  async getUser({ forceRefresh } = { forceRefresh: false }) {
8999
9026
  return withPassportError(async () => {
9000
- const user = await this.getWebUser({ forceRefresh });
9001
- if (user) {
9027
+ const user = await this.getAuthenticatedUser({ forceRefresh });
9028
+ if (user)
9002
9029
  return user;
9003
- }
9004
9030
  const deviceToken = this.deviceCredentialsManager.getCredentials();
9005
9031
  if (deviceToken) {
9006
9032
  return AuthManager.mapDeviceTokenResponseToDomainUserModel(deviceToken);
@@ -9027,14 +9053,16 @@ class MagicAdapter {
9027
9053
  magicClient;
9028
9054
  constructor(config) {
9029
9055
  this.config = config;
9030
- this.magicClient = new magicSdk.Magic(this.config.magicPublishableApiKey, {
9031
- extensions: [new oidc.OpenIdExtension()],
9032
- network: config.network,
9033
- });
9034
- this.magicClient.preload();
9056
+ if (window) {
9057
+ this.magicClient = this.initMagicClient();
9058
+ this.magicClient.preload();
9059
+ }
9035
9060
  }
9036
9061
  async login(idToken) {
9037
9062
  return withPassportError(async () => {
9063
+ if (!this.magicClient) {
9064
+ this.magicClient = this.initMagicClient();
9065
+ }
9038
9066
  await this.magicClient.openid.loginWithOIDC({
9039
9067
  jwt: idToken,
9040
9068
  providerId: this.config.magicProviderId,
@@ -9043,10 +9071,16 @@ class MagicAdapter {
9043
9071
  }, PassportErrorType.WALLET_CONNECTION_ERROR);
9044
9072
  }
9045
9073
  async logout() {
9046
- if (this.magicClient.user) {
9074
+ if (this.magicClient?.user) {
9047
9075
  await this.magicClient.user.logout();
9048
9076
  }
9049
9077
  }
9078
+ initMagicClient() {
9079
+ return new magicSdk.Magic(this.config.magicPublishableApiKey, {
9080
+ extensions: [new oidc.OpenIdExtension()],
9081
+ network: this.config.network,
9082
+ });
9083
+ }
9050
9084
  }
9051
9085
 
9052
9086
  const getStarkSigner = async (signer) => withPassportError(async () => {
@@ -9133,16 +9167,13 @@ class GuardianClient {
9133
9167
  transactionAPI;
9134
9168
  messageAPI;
9135
9169
  confirmationScreen;
9136
- // TODO: ID-977, make this rollup agnostic
9137
- imxEtherAddress;
9138
9170
  crossSdkBridgeEnabled;
9139
- constructor({ accessToken, confirmationScreen, imxEtherAddress, config, }) {
9140
- const guardianConfiguration = new Configuration({ accessToken, basePath: config.imxPublicApiDomain });
9171
+ constructor({ confirmationScreen, config }) {
9172
+ const guardianConfiguration = new Configuration({ basePath: config.imxPublicApiDomain });
9141
9173
  this.confirmationScreen = confirmationScreen;
9142
- this.transactionAPI = new TransactionsApi(new Configuration(guardianConfiguration));
9143
- this.imxEtherAddress = imxEtherAddress;
9144
9174
  this.crossSdkBridgeEnabled = config.crossSdkBridgeEnabled;
9145
9175
  this.messageAPI = new MessagesApi(guardianConfiguration);
9176
+ this.transactionAPI = new TransactionsApi(guardianConfiguration);
9146
9177
  }
9147
9178
  /**
9148
9179
  * Open confirmation screen and close it automatically if the
@@ -9166,29 +9197,30 @@ class GuardianClient {
9166
9197
  withDefaultConfirmationScreenTask(task) {
9167
9198
  return this.withConfirmationScreenTask()(task);
9168
9199
  }
9169
- async validate({ payloadHash }) {
9200
+ async evaluateImxTransaction({ payloadHash, user }) {
9170
9201
  const finallyFn = () => {
9171
9202
  this.confirmationScreen.closeWindow();
9172
9203
  };
9204
+ const headers = { Authorization: `Bearer ${user.accessToken}` };
9173
9205
  const transactionRes = await retryWithDelay(async () => this.transactionAPI.getTransactionByID({
9174
9206
  transactionID: payloadHash,
9175
9207
  chainType: 'starkex',
9176
- }), { finallyFn });
9208
+ }, { headers }), { finallyFn });
9177
9209
  if (!transactionRes.data.id) {
9178
9210
  throw new Error("Transaction doesn't exists");
9179
9211
  }
9180
- const evaluateStarkexRes = await this.transactionAPI.evaluateTransaction({
9212
+ const evaluateImxRes = await this.transactionAPI.evaluateTransaction({
9181
9213
  id: payloadHash,
9182
9214
  transactionEvaluationRequest: {
9183
9215
  chainType: 'starkex',
9184
9216
  },
9185
- });
9186
- const { confirmationRequired } = evaluateStarkexRes.data;
9217
+ }, { headers });
9218
+ const { confirmationRequired } = evaluateImxRes.data;
9187
9219
  if (confirmationRequired) {
9188
9220
  if (this.crossSdkBridgeEnabled) {
9189
9221
  throw new Error(transactionRejectedCrossSdkBridgeError);
9190
9222
  }
9191
- const confirmationResult = await this.confirmationScreen.requestConfirmation(payloadHash, this.imxEtherAddress, TransactionApprovalRequestChainTypeEnum.Starkex);
9223
+ const confirmationResult = await this.confirmationScreen.requestConfirmation(payloadHash, user.imx.ethAddress, TransactionApprovalRequestChainTypeEnum.Starkex);
9192
9224
  if (!confirmationResult.confirmed) {
9193
9225
  throw new Error('Transaction rejected by user');
9194
9226
  }
@@ -9232,7 +9264,7 @@ class GuardianClient {
9232
9264
  throw new JsonRpcError(RpcErrorCode.TRANSACTION_REJECTED, transactionRejectedCrossSdkBridgeError);
9233
9265
  }
9234
9266
  if (confirmationRequired && !!transactionId) {
9235
- const confirmationResult = await this.confirmationScreen.requestConfirmation(transactionId, this.imxEtherAddress, TransactionApprovalRequestChainTypeEnum.Evm, chainId);
9267
+ const confirmationResult = await this.confirmationScreen.requestConfirmation(transactionId, user.zkEvm.ethAddress, TransactionApprovalRequestChainTypeEnum.Evm, chainId);
9236
9268
  if (!confirmationResult.confirmed) {
9237
9269
  throw new JsonRpcError(RpcErrorCode.TRANSACTION_REJECTED, 'Transaction rejected by user');
9238
9270
  }
@@ -9328,10 +9360,7 @@ async function createOrder$1({ starkSigner, user, request, ordersApi, guardianCl
9328
9360
  const { ethAddress } = user.imx;
9329
9361
  const amountSell = request.sell.type === ERC721$1 ? '1' : request.sell.amount;
9330
9362
  const amountBuy = request.buy.type === ERC721$1 ? '1' : request.buy.amount;
9331
- const headers = {
9332
- // eslint-disable-next-line @typescript-eslint/naming-convention
9333
- Authorization: `Bearer ${user.accessToken}`,
9334
- };
9363
+ const headers = { Authorization: `Bearer ${user.accessToken}` };
9335
9364
  const getSignableOrderRequestV3 = {
9336
9365
  user: ethAddress,
9337
9366
  amount_buy: amountBuy,
@@ -9345,7 +9374,8 @@ async function createOrder$1({ starkSigner, user, request, ordersApi, guardianCl
9345
9374
  const getSignableOrderResponse = await ordersApi.getSignableOrder({
9346
9375
  getSignableOrderRequestV3,
9347
9376
  }, { headers });
9348
- await guardianClient.validate({
9377
+ await guardianClient.evaluateImxTransaction({
9378
+ user,
9349
9379
  payloadHash: getSignableOrderResponse.data.payload_hash,
9350
9380
  });
9351
9381
  const { payload_hash: payloadHash } = getSignableOrderResponse.data;
@@ -9387,7 +9417,8 @@ async function cancelOrder$1({ user, starkSigner, request, ordersApi, guardianCl
9387
9417
  const getSignableCancelOrderResponse = await ordersApi.getSignableCancelOrderV3({
9388
9418
  getSignableCancelOrderRequest,
9389
9419
  }, { headers });
9390
- await guardianClient.validate({
9420
+ await guardianClient.evaluateImxTransaction({
9421
+ user,
9391
9422
  payloadHash: getSignableCancelOrderResponse.data.payload_hash,
9392
9423
  });
9393
9424
  const { payload_hash: payloadHash } = getSignableCancelOrderResponse.data;
@@ -9450,7 +9481,8 @@ async function createTrade$1({ request, tradesApi, user, starkSigner, guardianCl
9450
9481
  const getSignableTradeResponse = await tradesApi.getSignableTrade({
9451
9482
  getSignableTradeRequest,
9452
9483
  }, { headers });
9453
- await guardianClient.validate({
9484
+ await guardianClient.evaluateImxTransaction({
9485
+ user,
9454
9486
  payloadHash: getSignableTradeResponse.data.payload_hash,
9455
9487
  });
9456
9488
  const { payload_hash: payloadHash } = getSignableTradeResponse.data;
@@ -9497,7 +9529,8 @@ async function transfer$1({ request, transfersApi, starkSigner, user, guardianCl
9497
9529
  const signableResult = await transfersApi.getSignableTransferV1({
9498
9530
  getSignableTransferRequest,
9499
9531
  }, { headers });
9500
- await guardianClient.validate({
9532
+ await guardianClient.evaluateImxTransaction({
9533
+ user,
9501
9534
  payloadHash: signableResult.data.payload_hash,
9502
9535
  });
9503
9536
  const signableResultData = signableResult.data;
@@ -9544,14 +9577,12 @@ async function batchNftTransfer({ user, starkSigner, request, transfersApi, guar
9544
9577
  sender_ether_key: ethAddress,
9545
9578
  signable_requests: signableRequests,
9546
9579
  };
9547
- const headers = {
9548
- // eslint-disable-next-line @typescript-eslint/naming-convention
9549
- Authorization: `Bearer ${user.accessToken}`,
9550
- };
9580
+ const headers = { Authorization: `Bearer ${user.accessToken}` };
9551
9581
  const signableResult = await transfersApi.getSignableTransfer({
9552
9582
  getSignableTransferRequestV2,
9553
9583
  }, { headers });
9554
- await guardianClient.validate({
9584
+ await guardianClient.evaluateImxTransaction({
9585
+ user,
9555
9586
  payloadHash: signableResult.data.signable_responses[0]?.payload_hash,
9556
9587
  });
9557
9588
  const requests = await Promise.all(signableResult.data.signable_responses.map(async (resp) => {
@@ -9581,39 +9612,40 @@ async function batchNftTransfer({ user, starkSigner, request, transfersApi, guar
9581
9612
  }
9582
9613
 
9583
9614
  class PassportImxProvider {
9584
- user;
9615
+ authManager;
9585
9616
  starkSigner;
9586
9617
  immutableXClient;
9587
- confirmationScreen;
9588
9618
  guardianClient;
9589
- constructor({ user, starkSigner, immutableXClient, confirmationScreen, config, passportEventEmitter, }) {
9590
- this.user = user;
9619
+ constructor({ authManager, starkSigner, immutableXClient, confirmationScreen, config, passportEventEmitter, }) {
9620
+ this.authManager = authManager;
9591
9621
  this.starkSigner = starkSigner;
9592
9622
  this.immutableXClient = immutableXClient;
9593
- this.confirmationScreen = confirmationScreen;
9594
9623
  this.guardianClient = new GuardianClient({
9595
- accessToken: user.accessToken,
9596
9624
  confirmationScreen,
9597
- imxEtherAddress: user.imx.ethAddress,
9598
9625
  config,
9599
9626
  });
9600
9627
  passportEventEmitter.on(PassportEvents.LOGGED_OUT, this.handleLogout);
9601
9628
  }
9602
9629
  handleLogout = () => {
9603
- this.user = undefined;
9604
9630
  this.starkSigner = undefined;
9605
9631
  };
9606
- checkIsLoggedIn() {
9607
- if (this.user === undefined || this.starkSigner === undefined) {
9632
+ async getAuthenticatedUserSigner() {
9633
+ const user = await this.authManager.getUser();
9634
+ if (!user || this.starkSigner === undefined) {
9608
9635
  throw new PassportError('User has been logged out', PassportErrorType.NOT_LOGGED_IN_ERROR);
9609
9636
  }
9637
+ const isUserImx = (oidcUser) => oidcUser?.imx !== undefined;
9638
+ if (!isUserImx(user)) {
9639
+ throw new PassportError('User has not been registered with StarkEx', PassportErrorType.USER_NOT_REGISTERED_ERROR);
9640
+ }
9641
+ return { user, starkSigner: this.starkSigner };
9610
9642
  }
9611
9643
  async transfer(request) {
9612
- this.checkIsLoggedIn();
9644
+ const { user, starkSigner } = await this.getAuthenticatedUserSigner();
9613
9645
  return transfer$1({
9614
9646
  request,
9615
- user: this.user,
9616
- starkSigner: this.starkSigner,
9647
+ user,
9648
+ starkSigner,
9617
9649
  transfersApi: this.immutableXClient.transfersApi,
9618
9650
  guardianClient: this.guardianClient,
9619
9651
  });
@@ -9628,52 +9660,52 @@ class PassportImxProvider {
9628
9660
  isRegisteredOnchain() {
9629
9661
  throw new PassportError('Operation not supported', PassportErrorType.OPERATION_NOT_SUPPORTED_ERROR);
9630
9662
  }
9631
- createOrder(request) {
9632
- this.checkIsLoggedIn();
9663
+ async createOrder(request) {
9664
+ const { user, starkSigner } = await this.getAuthenticatedUserSigner();
9633
9665
  return createOrder$1({
9634
9666
  request,
9635
- user: this.user,
9636
- starkSigner: this.starkSigner,
9667
+ user,
9668
+ starkSigner,
9637
9669
  ordersApi: this.immutableXClient.ordersApi,
9638
9670
  guardianClient: this.guardianClient,
9639
9671
  });
9640
9672
  }
9641
- cancelOrder(request) {
9642
- this.checkIsLoggedIn();
9673
+ async cancelOrder(request) {
9674
+ const { user, starkSigner } = await this.getAuthenticatedUserSigner();
9643
9675
  return cancelOrder$1({
9644
9676
  request,
9645
- user: this.user,
9646
- starkSigner: this.starkSigner,
9677
+ user,
9678
+ starkSigner,
9647
9679
  ordersApi: this.immutableXClient.ordersApi,
9648
9680
  guardianClient: this.guardianClient,
9649
9681
  });
9650
9682
  }
9651
- createTrade(request) {
9652
- this.checkIsLoggedIn();
9683
+ async createTrade(request) {
9684
+ const { user, starkSigner } = await this.getAuthenticatedUserSigner();
9653
9685
  return createTrade$1({
9654
9686
  request,
9655
- user: this.user,
9656
- starkSigner: this.starkSigner,
9687
+ user,
9688
+ starkSigner,
9657
9689
  tradesApi: this.immutableXClient.tradesApi,
9658
9690
  guardianClient: this.guardianClient,
9659
9691
  });
9660
9692
  }
9661
- batchNftTransfer(request) {
9662
- this.checkIsLoggedIn();
9693
+ async batchNftTransfer(request) {
9694
+ const { user, starkSigner } = await this.getAuthenticatedUserSigner();
9663
9695
  return batchNftTransfer({
9664
9696
  request,
9665
- user: this.user,
9666
- starkSigner: this.starkSigner,
9697
+ user,
9698
+ starkSigner,
9667
9699
  transfersApi: this.immutableXClient.transfersApi,
9668
9700
  guardianClient: this.guardianClient,
9669
9701
  });
9670
9702
  }
9671
- exchangeTransfer(request) {
9672
- this.checkIsLoggedIn();
9703
+ async exchangeTransfer(request) {
9704
+ const { user, starkSigner } = await this.getAuthenticatedUserSigner();
9673
9705
  return exchangeTransfer$1({
9674
9706
  request,
9675
- user: this.user,
9676
- starkSigner: this.starkSigner,
9707
+ user,
9708
+ starkSigner,
9677
9709
  exchangesApi: this.immutableXClient.exchangeApi,
9678
9710
  });
9679
9711
  }
@@ -9696,9 +9728,9 @@ class PassportImxProvider {
9696
9728
  token) {
9697
9729
  throw new PassportError('Operation not supported', PassportErrorType.OPERATION_NOT_SUPPORTED_ERROR);
9698
9730
  }
9699
- getAddress() {
9700
- this.checkIsLoggedIn();
9701
- return Promise.resolve(this.user.imx.ethAddress);
9731
+ async getAddress() {
9732
+ const { user } = await this.getAuthenticatedUserSigner();
9733
+ return Promise.resolve(user.imx.ethAddress);
9702
9734
  }
9703
9735
  }
9704
9736
 
@@ -9752,9 +9784,9 @@ class PassportImxProviderFactory {
9752
9784
  const ethSigner = web3Provider.getSigner();
9753
9785
  const starkSigner = await getStarkSigner(ethSigner);
9754
9786
  if (!user.imx?.ethAddress) {
9755
- const userImx = await this.registerStarkEx(ethSigner, starkSigner, user.accessToken);
9787
+ await this.registerStarkEx(ethSigner, starkSigner, user.accessToken);
9756
9788
  return new PassportImxProvider({
9757
- user: userImx,
9789
+ authManager: this.authManager,
9758
9790
  starkSigner,
9759
9791
  immutableXClient: this.immutableXClient,
9760
9792
  confirmationScreen: this.confirmationScreen,
@@ -9763,7 +9795,7 @@ class PassportImxProviderFactory {
9763
9795
  });
9764
9796
  }
9765
9797
  return new PassportImxProvider({
9766
- user: user,
9798
+ authManager: this.authManager,
9767
9799
  starkSigner,
9768
9800
  immutableXClient: this.immutableXClient,
9769
9801
  confirmationScreen: this.confirmationScreen,
@@ -10508,9 +10540,7 @@ class ZkEvmProvider {
10508
10540
  user: this.user,
10509
10541
  });
10510
10542
  this.guardianClient = new GuardianClient({
10511
- accessToken: this.user.accessToken,
10512
10543
  confirmationScreen: this.confirmationScreen,
10513
- imxEtherAddress: this.user.zkEvm.ethAddress,
10514
10544
  config: this.config,
10515
10545
  });
10516
10546
  this.eventEmitter.emit(ProviderEvent.ACCOUNTS_CHANGED, [this.user.zkEvm.ethAddress]);
@@ -28000,13 +28030,14 @@ const quoteReturnMapping = {
28000
28030
  * @param poolB the other pool
28001
28031
  */
28002
28032
  function poolEquals(poolA, poolB) {
28003
- return (poolA === poolB
28004
- || (poolA.token0.equals(poolB.token0)
28005
- && poolA.token1.equals(poolB.token1)
28006
- && poolA.fee === poolB.fee));
28033
+ return (poolA === poolB ||
28034
+ (poolA.token0.equals(poolB.token0) && poolA.token1.equals(poolB.token1) && poolA.fee === poolB.fee));
28007
28035
  }
28008
- async function getERC20Decimals(tokenAddress, provider) {
28009
- const decimalsFunctionSig = ethers.ethers.utils.id('decimals()').substring(0, 10);
28036
+ const decimalsFunctionSig = ethers.ethers.utils.id('decimals()').substring(0, 10);
28037
+ async function getTokenDecimals(tokenAddress, provider, nativeToken) {
28038
+ if (tokenAddress === 'native') {
28039
+ return nativeToken.decimals;
28040
+ }
28010
28041
  try {
28011
28042
  const decimalsResult = await provider.call({
28012
28043
  to: tokenAddress,
@@ -28034,9 +28065,10 @@ function isValidNonZeroAddress(address) {
28034
28065
  return false;
28035
28066
  }
28036
28067
  }
28068
+ const isValidTokenLiteral = (address) => address === 'native' ? true : isValidNonZeroAddress(address);
28037
28069
  const erc20ToUniswapToken = (token) =>
28038
28070
  // eslint-disable-next-line implicit-arrow-linebreak
28039
- new sdkCore.Token(token.chainId, token.address, token.decimals, token.symbol, token.name);
28071
+ new Uniswap__namespace.Token(token.chainId, token.address, token.decimals, token.symbol, token.name);
28040
28072
  const uniswapTokenToERC20 = (token) => ({
28041
28073
  chainId: token.chainId,
28042
28074
  address: token.address,
@@ -28047,7 +28079,7 @@ const uniswapTokenToERC20 = (token) => ({
28047
28079
  });
28048
28080
  const toCurrencyAmount = (amount) => {
28049
28081
  const token = erc20ToUniswapToken(amount.token);
28050
- return sdkCore.CurrencyAmount.fromRawAmount(token, amount.value.toString());
28082
+ return Uniswap__namespace.CurrencyAmount.fromRawAmount(token, amount.value.toString());
28051
28083
  };
28052
28084
  const newAmount = (amount, token) => ({
28053
28085
  value: amount,
@@ -28093,6 +28125,28 @@ const subtractAmount = (a, b) => {
28093
28125
  }
28094
28126
  throw new Error('Token mismatch: token types must be the same');
28095
28127
  };
28128
+ /**
28129
+ * Converts our internal token type which could be ERC20 or Native
28130
+ * into a format consumable by Checkout. They require an address to be
28131
+ * present. We populate the address with empty string if it's Native.
28132
+ * If it's ERC20, we don't need to change it.
28133
+ */
28134
+ const toPublicTokenType = (token) => {
28135
+ if (token.type === 'native') {
28136
+ return {
28137
+ address: '',
28138
+ chainId: token.chainId,
28139
+ decimals: token.decimals,
28140
+ symbol: token.symbol,
28141
+ name: token.name,
28142
+ };
28143
+ }
28144
+ return token;
28145
+ };
28146
+ const toPublicAmount = (amount) => ({
28147
+ token: toPublicTokenType(amount.token),
28148
+ value: amount.value,
28149
+ });
28096
28150
 
28097
28151
  const amountIndex = 0;
28098
28152
  const gasEstimateIndex = 3;
@@ -28134,8 +28188,8 @@ async function getQuotesForRoutes(multicallContract, quoterContractAddress, rout
28134
28188
  const output = uniswapTokenToERC20(routes[i].output);
28135
28189
  decodedQuoteResults.push({
28136
28190
  route: routes[i],
28137
- amountIn: tradeType === sdkCore.TradeType.EXACT_INPUT ? amountSpecified : newAmount(quoteAmount, input),
28138
- amountOut: tradeType === sdkCore.TradeType.EXACT_INPUT ? newAmount(quoteAmount, output) : amountSpecified,
28191
+ amountIn: tradeType === Uniswap.TradeType.EXACT_INPUT ? amountSpecified : newAmount(quoteAmount, input),
28192
+ amountOut: tradeType === Uniswap.TradeType.EXACT_INPUT ? newAmount(quoteAmount, output) : amountSpecified,
28139
28193
  gasEstimate: ethers.ethers.BigNumber.from(decodedQuoteResult[gasEstimateIndex]),
28140
28194
  tradeType,
28141
28195
  });
@@ -28308,11 +28362,11 @@ class Router {
28308
28362
  throw new NoRoutesAvailableError();
28309
28363
  }
28310
28364
  // We want to maximise the amountOut for the EXACT_INPUT type
28311
- if (tradeType === sdkCore.TradeType.EXACT_INPUT) {
28365
+ if (tradeType === Uniswap.TradeType.EXACT_INPUT) {
28312
28366
  return this.bestQuoteForAmountIn(quotes);
28313
28367
  }
28314
28368
  // We want to minimise the amountIn for the EXACT_OUTPUT type
28315
- if (tradeType === sdkCore.TradeType.EXACT_OUTPUT) {
28369
+ if (tradeType === Uniswap.TradeType.EXACT_OUTPUT) {
28316
28370
  return this.bestQuoteForAmountOut(quotes);
28317
28371
  }
28318
28372
  throw new Error('Invalid trade type');
@@ -28340,7 +28394,7 @@ class Router {
28340
28394
  // eslint-disable-next-line class-methods-use-this
28341
28395
  determineERC20InAndERC20Out(tradeType, amountSpecified, otherToken) {
28342
28396
  // If the trade type is EXACT INPUT then we have specified the amount for the tokenIn
28343
- return tradeType === sdkCore.TradeType.EXACT_INPUT
28397
+ return tradeType === Uniswap.TradeType.EXACT_INPUT
28344
28398
  ? [amountSpecified.token, otherToken]
28345
28399
  : [otherToken, amountSpecified.token];
28346
28400
  }
@@ -28466,12 +28520,13 @@ const getUnsignedERC20ApproveTransaction = (ownerAddress, tokenAmount, spenderAd
28466
28520
  from: ownerAddress,
28467
28521
  };
28468
28522
  };
28469
- const prepareApproval = (tradeType, amountSpecified, amountWithSlippage, contracts, secondaryFees) => {
28470
- const amountOfTokenIn = tradeType === sdkCore.TradeType.EXACT_INPUT ? amountSpecified : amountWithSlippage;
28471
- const spender = secondaryFees.length === 0
28472
- ? contracts.routerAddress
28473
- : contracts.secondaryFeeAddress;
28474
- return { spender, amount: amountOfTokenIn };
28523
+ const prepareApproval = (tradeType, userSpecifiedAmount, quotedAmountWithSlippage, contracts, secondaryFees) => {
28524
+ const amountInToApprove = tradeType === Uniswap.TradeType.EXACT_INPUT ? userSpecifiedAmount : quotedAmountWithSlippage;
28525
+ if (!isERC20Amount(amountInToApprove)) {
28526
+ return null;
28527
+ }
28528
+ const spender = secondaryFees.length === 0 ? contracts.routerAddress : contracts.secondaryFeeAddress;
28529
+ return { spender, amount: amountInToApprove };
28475
28530
  };
28476
28531
  /**
28477
28532
  * Get an unsigned approval transaction if needed
@@ -28503,7 +28558,7 @@ async function getApproveGasEstimate(provider, ownerAddress, spenderAddress, tok
28503
28558
  from: ownerAddress,
28504
28559
  });
28505
28560
  }
28506
- const getApproval = async (provider, ownerAddress, preparedApproval, gasPrice, nativeTokenService) => {
28561
+ const getApproval = async (provider, ownerAddress, preparedApproval, gasPrice) => {
28507
28562
  const approveTransaction = await getApproveTransaction(provider, ownerAddress, preparedApproval.amount, preparedApproval.spender);
28508
28563
  if (!approveTransaction) {
28509
28564
  return null;
@@ -28512,18 +28567,49 @@ const getApproval = async (provider, ownerAddress, preparedApproval, gasPrice, n
28512
28567
  const gasFeeEstimate = gasPrice ? calculateGasFee(gasPrice, gasEstimate) : null;
28513
28568
  return {
28514
28569
  transaction: approveTransaction,
28515
- // TODO: TP-1649: Remove the wrapping here
28516
- gasFeeEstimate: gasFeeEstimate ? nativeTokenService.maybeWrapAmount(gasFeeEstimate) : null,
28570
+ gasFeeEstimate: gasFeeEstimate ? toPublicAmount(gasFeeEstimate) : null,
28517
28571
  };
28518
28572
  };
28519
28573
 
28574
+ const canUnwrapToken = (token) => token.type === 'native';
28575
+ class NativeTokenService {
28576
+ nativeToken;
28577
+ wrappedToken;
28578
+ constructor(nativeToken, wrappedToken) {
28579
+ this.nativeToken = nativeToken;
28580
+ this.wrappedToken = wrappedToken;
28581
+ }
28582
+ wrapAmount(amount) {
28583
+ if (!canUnwrapToken(amount.token)) {
28584
+ throw new Error(`cannot wrap non-native token: ${amount.token.address}`);
28585
+ }
28586
+ return newAmount(amount.value, this.wrappedToken);
28587
+ }
28588
+ unwrapAmount(amount) {
28589
+ const isWrappedToken = amount.token.address.toLowerCase() !== this.wrappedToken.address.toLowerCase();
28590
+ if (isWrappedToken) {
28591
+ throw new Error(`cannot unwrap non-wrapped token ${amount.token.address}`);
28592
+ }
28593
+ return newAmount(amount.value, this.nativeToken);
28594
+ }
28595
+ maybeWrapToken(token) {
28596
+ if (canUnwrapToken(token)) {
28597
+ return this.wrappedToken;
28598
+ }
28599
+ return token;
28600
+ }
28601
+ maybeWrapAmount(amount) {
28602
+ return newAmount(amount.value, this.maybeWrapToken(amount.token));
28603
+ }
28604
+ }
28605
+
28520
28606
  // slippageToPercent takes the slippage as a percentage (e.g. 0.1) and
28521
28607
  // converts it to the Uniswap equivalent type
28522
28608
  const slippageToFraction = (slippage) => {
28523
28609
  // If we receive a whole number, we can return slippage/100
28524
28610
  const noDecimals = slippage.toString().split('.').length === 1;
28525
28611
  if (noDecimals) {
28526
- return new sdkCore.Percent(slippage, 100);
28612
+ return new Uniswap.Percent(slippage, 100);
28527
28613
  }
28528
28614
  // Divide the slippage number by 100 to get the decimal
28529
28615
  const slippageDecimal = slippage / 100;
@@ -28533,41 +28619,37 @@ const slippageToFraction = (slippage) => {
28533
28619
  const numerator = parts[0] + parts[1];
28534
28620
  // Get the denominator by multiplying decimals^10
28535
28621
  const denominator = 10 ** parts[1].length;
28536
- return new sdkCore.Percent(numerator, denominator);
28622
+ return new Uniswap.Percent(numerator, denominator);
28537
28623
  };
28538
28624
 
28539
- function getQuoteAmountFromTradeType(tradeInfo) {
28540
- if (tradeInfo.tradeType === sdkCore.TradeType.EXACT_INPUT) {
28541
- return tradeInfo.amountOut;
28625
+ function getQuoteAmountFromTradeType(routerQuote) {
28626
+ if (routerQuote.tradeType === Uniswap.TradeType.EXACT_INPUT) {
28627
+ return routerQuote.amountOut;
28542
28628
  }
28543
- return tradeInfo.amountIn;
28629
+ return routerQuote.amountIn;
28544
28630
  }
28545
28631
  function applySlippage(tradeType, amount, slippage) {
28546
28632
  const slippageTolerance = slippageToFraction(slippage);
28547
28633
  const slippagePlusOne = slippageTolerance.add(1);
28548
- const maybeInverted = tradeType === sdkCore.TradeType.EXACT_INPUT ? slippagePlusOne.invert() : slippagePlusOne;
28634
+ const maybeInverted = tradeType === Uniswap.TradeType.EXACT_INPUT ? slippagePlusOne.invert() : slippagePlusOne;
28549
28635
  const amountWithSlippage = maybeInverted.multiply(amount.toString()).quotient;
28550
28636
  return ethers.ethers.BigNumber.from(amountWithSlippage.toString());
28551
28637
  }
28552
- function prepareUserQuote(otherToken, tradeInfo, slippage, fees, nativeTokenService) {
28553
- const quote = getQuoteAmountFromTradeType(tradeInfo);
28554
- const amountWithSlippage = applySlippage(tradeInfo.tradeType, quote.value, slippage);
28638
+ const prepareUserQuote = (nativeTokenService, routerQuote, slippage, tokenOfQuotedAmount) => {
28639
+ const erc20QuoteAmount = getQuoteAmountFromTradeType(routerQuote);
28640
+ // If the quote amount is the native token, we need to unwrap it if the user originally specified the native token
28641
+ const quotedAmount = canUnwrapToken(tokenOfQuotedAmount)
28642
+ ? nativeTokenService.unwrapAmount(erc20QuoteAmount)
28643
+ : erc20QuoteAmount;
28644
+ const quotedAmountWithMaxSlippage = newAmount(applySlippage(routerQuote.tradeType, quotedAmount.value, slippage), tokenOfQuotedAmount);
28555
28645
  return {
28556
- amount: quote,
28557
- amountWithMaxSlippage: {
28558
- token: otherToken,
28559
- value: amountWithSlippage,
28560
- },
28561
- slippage,
28562
- fees: fees.withAmounts().map((fee) => ({
28563
- ...fee,
28564
- amount: nativeTokenService.maybeWrapAmount(fee.amount),
28565
- })),
28646
+ quotedAmount,
28647
+ quotedAmountWithMaxSlippage,
28566
28648
  };
28567
- }
28649
+ };
28568
28650
  function getOurQuoteReqAmount(amountSpecified, // the amount specified by the user, either exactIn or exactOut
28569
28651
  fees, tradeType, nativeTokenService) {
28570
- if (tradeType === sdkCore.TradeType.EXACT_OUTPUT) {
28652
+ if (tradeType === Uniswap.TradeType.EXACT_OUTPUT) {
28571
28653
  // For an exact output swap, we do not need to subtract fees from the given amount
28572
28654
  return nativeTokenService.maybeWrapAmount(amountSpecified);
28573
28655
  }
@@ -28632,46 +28714,8 @@ class Fees {
28632
28714
  }
28633
28715
  }
28634
28716
 
28635
- class NativeTokenService {
28636
- nativeToken;
28637
- wrappedToken;
28638
- constructor(nativeToken, wrappedToken) {
28639
- this.nativeToken = nativeToken;
28640
- this.wrappedToken = wrappedToken;
28641
- }
28642
- wrapAmount(amount) {
28643
- return newAmount(amount.value, this.wrappedToken);
28644
- }
28645
- unwrapAmount(amount) {
28646
- if (amount.token !== this.wrappedToken) {
28647
- throw new Error(`token ${amount.token.address} is not wrapped`);
28648
- }
28649
- return newAmount(amount.value, this.nativeToken);
28650
- }
28651
- maybeWrapToken(token) {
28652
- if (this.isNativeToken(token)) {
28653
- return this.wrappedToken;
28654
- }
28655
- return token;
28656
- }
28657
- maybeWrapAmount(amount) {
28658
- return newAmount(amount.value, this.maybeWrapToken(amount.token));
28659
- }
28660
- isNativeToken(token) {
28661
- return token === this.nativeToken;
28662
- }
28663
- }
28664
-
28665
28717
  const IMMUTABLE_TESTNET_RPC_URL = 'https://rpc.testnet.immutable.com';
28666
28718
  const IMMUTABLE_TESTNET_CHAIN_ID = 13472;
28667
-
28668
- const NATIVE_IMX_IMMUTABLE_TESTNET = {
28669
- chainId: IMMUTABLE_TESTNET_CHAIN_ID,
28670
- decimals: 18,
28671
- symbol: 'tIMX',
28672
- name: 'Immutable Testnet Token',
28673
- type: 'native',
28674
- };
28675
28719
  const TIMX_IMMUTABLE_TESTNET = {
28676
28720
  chainId: IMMUTABLE_TESTNET_CHAIN_ID,
28677
28721
  address: '0x0000000000000000000000000000000000001010',
@@ -28700,8 +28744,10 @@ function buildSwapParametersForSinglePoolSwap(fromAddress, trade, route, amountI
28700
28744
  feeBasisPoints: fee.basisPoints,
28701
28745
  recipient: fee.recipient,
28702
28746
  }));
28703
- if (trade.tradeType === sdkCore.TradeType.EXACT_INPUT) {
28704
- return secondaryFeeContract.encodeFunctionData('exactInputSingleWithSecondaryFee', [secondaryFeeValues, {
28747
+ if (trade.tradeType === Uniswap.TradeType.EXACT_INPUT) {
28748
+ return secondaryFeeContract.encodeFunctionData('exactInputSingleWithSecondaryFee', [
28749
+ secondaryFeeValues,
28750
+ {
28705
28751
  tokenIn: route.tokenPath[0].address,
28706
28752
  tokenOut: route.tokenPath[1].address,
28707
28753
  fee: route.pools[0].fee,
@@ -28709,9 +28755,12 @@ function buildSwapParametersForSinglePoolSwap(fromAddress, trade, route, amountI
28709
28755
  amountIn,
28710
28756
  amountOutMinimum: amountOut,
28711
28757
  sqrtPriceLimitX96: 0,
28712
- }]);
28758
+ },
28759
+ ]);
28713
28760
  }
28714
- return secondaryFeeContract.encodeFunctionData('exactOutputSingleWithSecondaryFee', [secondaryFeeValues, {
28761
+ return secondaryFeeContract.encodeFunctionData('exactOutputSingleWithSecondaryFee', [
28762
+ secondaryFeeValues,
28763
+ {
28715
28764
  tokenIn: route.tokenPath[0].address,
28716
28765
  tokenOut: route.tokenPath[1].address,
28717
28766
  fee: route.pools[0].fee,
@@ -28719,28 +28768,35 @@ function buildSwapParametersForSinglePoolSwap(fromAddress, trade, route, amountI
28719
28768
  amountInMaximum: amountIn,
28720
28769
  amountOut,
28721
28770
  sqrtPriceLimitX96: 0,
28722
- }]);
28771
+ },
28772
+ ]);
28723
28773
  }
28724
28774
  function buildSwapParametersForMultiPoolSwap(fromAddress, trade, route, amountIn, amountOut, secondaryFees, secondaryFeeContract) {
28725
- const path = v3Sdk.encodeRouteToPath(route, trade.tradeType === sdkCore.TradeType.EXACT_OUTPUT);
28775
+ const path = v3Sdk.encodeRouteToPath(route, trade.tradeType === Uniswap.TradeType.EXACT_OUTPUT);
28726
28776
  const secondaryFeeValues = secondaryFees.map((fee) => ({
28727
28777
  feeBasisPoints: fee.basisPoints,
28728
28778
  recipient: fee.recipient,
28729
28779
  }));
28730
- if (trade.tradeType === sdkCore.TradeType.EXACT_INPUT) {
28731
- return secondaryFeeContract.encodeFunctionData('exactInputWithSecondaryFee', [secondaryFeeValues, {
28780
+ if (trade.tradeType === Uniswap.TradeType.EXACT_INPUT) {
28781
+ return secondaryFeeContract.encodeFunctionData('exactInputWithSecondaryFee', [
28782
+ secondaryFeeValues,
28783
+ {
28732
28784
  path,
28733
28785
  recipient: fromAddress,
28734
28786
  amountIn,
28735
28787
  amountOutMinimum: amountOut,
28736
- }]);
28788
+ },
28789
+ ]);
28737
28790
  }
28738
- return secondaryFeeContract.encodeFunctionData('exactOutputWithSecondaryFee', [secondaryFeeValues, {
28791
+ return secondaryFeeContract.encodeFunctionData('exactOutputWithSecondaryFee', [
28792
+ secondaryFeeValues,
28793
+ {
28739
28794
  path,
28740
28795
  recipient: fromAddress,
28741
28796
  amountInMaximum: amountIn,
28742
28797
  amountOut,
28743
- }]);
28798
+ },
28799
+ ]);
28744
28800
  }
28745
28801
  /**
28746
28802
  * Builds swap parameters
@@ -28765,7 +28821,10 @@ function buildSwapParameters(fromAddress, trade, options, secondaryFees, seconda
28765
28821
  function createSwapCallParametersWithFees(trade, fromAddress, swapOptions, secondaryFees) {
28766
28822
  const secondaryFeeContract = SecondaryFee__factory.createInterface();
28767
28823
  const swapWithFeesCalldata = buildSwapParameters(fromAddress, trade, swapOptions, secondaryFees, secondaryFeeContract);
28768
- return secondaryFeeContract.encodeFunctionData(multicallWithDeadlineFunctionSignature, [swapOptions.deadlineOrPreviousBlockhash, [swapWithFeesCalldata]]);
28824
+ return secondaryFeeContract.encodeFunctionData(multicallWithDeadlineFunctionSignature, [
28825
+ swapOptions.deadlineOrPreviousBlockhash,
28826
+ [swapWithFeesCalldata],
28827
+ ]);
28769
28828
  }
28770
28829
  function createSwapParameters(adjustedQuote, fromAddress, slippage, deadline, secondaryFees) {
28771
28830
  // Create an unchecked trade to be used in generating swap parameters.
@@ -28803,9 +28862,9 @@ function getSwap(adjustedQuote, fromAddress, slippage, deadline, peripheryRouter
28803
28862
  };
28804
28863
  }
28805
28864
  const adjustAmountIn = (ourQuote, amountSpecified, fees, nativeTokenService) => {
28806
- if (ourQuote.tradeType === sdkCore.TradeType.EXACT_OUTPUT) {
28865
+ if (ourQuote.tradeType === Uniswap.TradeType.EXACT_OUTPUT) {
28807
28866
  // when doing exact output, calculate the fees based on the amountIn
28808
- const amountToAdd = nativeTokenService.isNativeToken(fees.token)
28867
+ const amountToAdd = canUnwrapToken(fees.token)
28809
28868
  ? nativeTokenService.unwrapAmount(ourQuote.amountIn)
28810
28869
  : ourQuote.amountIn;
28811
28870
  fees.addAmount(amountToAdd);
@@ -28849,7 +28908,7 @@ const SUPPORTED_SANDBOX_CHAINS = {
28849
28908
  rpcUrl: IMMUTABLE_TESTNET_RPC_URL,
28850
28909
  contracts: CONTRACTS_FOR_CHAIN_ID[IMMUTABLE_TESTNET_CHAIN_ID],
28851
28910
  commonRoutingTokens: IMMUTABLE_TESTNET_COMMON_ROUTING_TOKENS,
28852
- nativeToken: NATIVE_IMX_IMMUTABLE_TESTNET,
28911
+ nativeToken: TIMX_IMMUTABLE_TESTNET,
28853
28912
  wrappedNativeToken: TIMX_IMMUTABLE_TESTNET, // TODO: TP-1649: Change to WIMX when ready.
28854
28913
  },
28855
28914
  };
@@ -28921,6 +28980,15 @@ class ExchangeConfiguration {
28921
28980
  }
28922
28981
  }
28923
28982
 
28983
+ const toPublicQuote = (amount, amountWithMaxSlippage, slippage, fees) => ({
28984
+ amount: toPublicAmount(amount),
28985
+ amountWithMaxSlippage: toPublicAmount(amountWithMaxSlippage),
28986
+ slippage,
28987
+ fees: fees.withAmounts().map((fee) => ({
28988
+ ...fee,
28989
+ amount: toPublicAmount(fee.amount),
28990
+ })),
28991
+ });
28924
28992
  class Exchange {
28925
28993
  provider;
28926
28994
  router;
@@ -28949,8 +29017,8 @@ class Exchange {
28949
29017
  }
28950
29018
  static validate(tokenInAddress, tokenOutAddress, maxHops, slippagePercent, fromAddress) {
28951
29019
  assert(isValidNonZeroAddress(fromAddress), new InvalidAddressError('invalid from address'));
28952
- assert(isValidNonZeroAddress(tokenInAddress), new InvalidAddressError('invalid token in address'));
28953
- assert(isValidNonZeroAddress(tokenOutAddress), new InvalidAddressError('invalid token out address'));
29020
+ assert(isValidTokenLiteral(tokenInAddress), new InvalidAddressError('invalid token in address'));
29021
+ assert(isValidTokenLiteral(tokenOutAddress), new InvalidAddressError('invalid token out address'));
28954
29022
  assert(tokenInAddress.toLocaleLowerCase() !== tokenOutAddress.toLocaleLowerCase(), new DuplicateAddressesError());
28955
29023
  assert(maxHops <= MAX_MAX_HOPS, new InvalidMaxHopsError('max hops must be less than or equal to 10'));
28956
29024
  assert(maxHops >= MIN_MAX_HOPS, new InvalidMaxHopsError('max hops must be greater than or equal to 1'));
@@ -28968,82 +29036,82 @@ class Exchange {
28968
29036
  }
28969
29037
  return this.secondaryFees;
28970
29038
  }
28971
- async getUnsignedSwapTx(fromAddress, tokenInAddress, tokenOutAddress, amount, slippagePercent, maxHops, deadline, tradeType) {
28972
- Exchange.validate(tokenInAddress, tokenOutAddress, maxHops, slippagePercent, fromAddress);
29039
+ parseTokenLiteral(tokenLiteral, decimals) {
29040
+ if (tokenLiteral === 'native') {
29041
+ return this.nativeToken;
29042
+ }
29043
+ return {
29044
+ type: 'erc20',
29045
+ address: tokenLiteral,
29046
+ chainId: this.chainId,
29047
+ decimals,
29048
+ };
29049
+ }
29050
+ async getUnsignedSwapTx(fromAddress, tokenInLiteral, tokenOutLiteral, amount, slippagePercent, maxHops, deadline, tradeType) {
29051
+ Exchange.validate(tokenInLiteral, tokenOutLiteral, maxHops, slippagePercent, fromAddress);
28973
29052
  // get the decimals of the tokens that will be swapped
28974
29053
  const [tokenInDecimals, tokenOutDecimals, secondaryFees] = await Promise.all([
28975
- getERC20Decimals(tokenInAddress, this.provider),
28976
- getERC20Decimals(tokenOutAddress, this.provider),
29054
+ getTokenDecimals(tokenInLiteral, this.provider, this.nativeToken),
29055
+ getTokenDecimals(tokenOutLiteral, this.provider, this.nativeToken),
28977
29056
  this.getSecondaryFees(),
28978
29057
  ]);
28979
- const tokenIn = {
28980
- type: 'erc20',
28981
- address: tokenInAddress,
28982
- chainId: this.chainId,
28983
- decimals: tokenInDecimals,
28984
- };
28985
- const tokenOut = {
28986
- type: 'erc20',
28987
- address: tokenOutAddress,
28988
- chainId: this.chainId,
28989
- decimals: tokenOutDecimals,
28990
- };
29058
+ const tokenIn = this.parseTokenLiteral(tokenInLiteral, tokenInDecimals);
29059
+ const tokenOut = this.parseTokenLiteral(tokenOutLiteral, tokenOutDecimals);
28991
29060
  // determine which amount was specified for the swap from the TradeType
28992
- const [tokenSpecified, otherToken] = tradeType === sdkCore.TradeType.EXACT_INPUT ? [tokenIn, tokenOut] : [tokenOut, tokenIn];
29061
+ const [tokenSpecified, otherToken] = tradeType === Uniswap.TradeType.EXACT_INPUT ? [tokenIn, tokenOut] : [tokenOut, tokenIn];
28993
29062
  const amountSpecified = newAmount(amount, tokenSpecified);
28994
29063
  const fees = new Fees(secondaryFees, tokenIn);
28995
29064
  const ourQuoteReqAmount = getOurQuoteReqAmount(amountSpecified, fees, tradeType, this.nativeTokenService);
28996
- // get quote and gas details
29065
+ // Quotes will always use ERC20s. If the user-specified token is Native, we use the Wrapped Native Token pool
28997
29066
  const [ourQuote, gasPrice] = await Promise.all([
28998
- this.router.findOptimalRoute(ourQuoteReqAmount, otherToken, tradeType, maxHops),
29067
+ this.router.findOptimalRoute(ourQuoteReqAmount, this.nativeTokenService.maybeWrapToken(otherToken), tradeType, maxHops),
28999
29068
  fetchGasPrice(this.provider, this.nativeToken),
29000
29069
  ]);
29001
29070
  const adjustedQuote = adjustQuoteWithFees(ourQuote, amountSpecified, fees, this.nativeTokenService);
29002
29071
  const swap = getSwap(adjustedQuote, fromAddress, slippagePercent, deadline, this.routerContractAddress, this.secondaryFeeContractAddress, gasPrice, secondaryFees, this.nativeTokenService);
29003
- const userQuote = prepareUserQuote(otherToken, adjustedQuote, slippagePercent, fees, this.nativeTokenService);
29004
- const preparedApproval = prepareApproval(tradeType, amountSpecified, userQuote.amountWithMaxSlippage, {
29072
+ const { quotedAmount, quotedAmountWithMaxSlippage } = prepareUserQuote(this.nativeTokenService, adjustedQuote, slippagePercent, otherToken);
29073
+ const preparedApproval = prepareApproval(tradeType, amountSpecified, quotedAmountWithMaxSlippage, {
29005
29074
  routerAddress: this.routerContractAddress,
29006
29075
  secondaryFeeAddress: this.secondaryFeeContractAddress,
29007
29076
  }, secondaryFees);
29008
29077
  // preparedApproval always uses the tokenIn address because we are always selling the tokenIn
29009
- const approval = await getApproval(this.provider, fromAddress, preparedApproval, gasPrice, this.nativeTokenService);
29010
- return {
29011
- approval,
29012
- swap,
29013
- quote: userQuote,
29014
- };
29078
+ const approval = preparedApproval
29079
+ ? await getApproval(this.provider, fromAddress, preparedApproval, gasPrice)
29080
+ : null;
29081
+ const quote = toPublicQuote(quotedAmount, quotedAmountWithMaxSlippage, slippagePercent, fees);
29082
+ return { quote, approval, swap };
29015
29083
  }
29016
29084
  /**
29017
29085
  * Get the unsigned swap transaction given the amount to sell.
29018
29086
  * Includes quote details for the swap.
29019
29087
  *
29020
- * @param {string} fromAddress The public address that will sign and submit the transaction.
29021
- * @param {string} tokenInAddress Token address to sell.
29022
- * @param {string} tokenOutAddress Token address to buy.
29023
- * @param {ethers.BigNumberish} amountIn Amount to sell.
29024
- * @param {number} slippagePercent (optional) The percentage of slippage tolerance. Default = 0.1. Max = 50. Min = 0.
29025
- * @param {number} maxHops (optional) Maximum hops allowed in optimal route. Default is 2.
29026
- * @param {number} deadline (optional) Latest time swap can execute. Default is 15 minutes.
29027
- * @return {TransactionResponse} The result containing the unsigned transaction and details of the swap.
29088
+ * @param {string} fromAddress The public address that will sign and submit the transaction
29089
+ * @param {string} tokenInAddress Token address or 'native' to sell
29090
+ * @param {string} tokenOutAddress Token address or 'native' to buy
29091
+ * @param {ethers.BigNumberish} amountIn Amount to sell in the smallest unit of the token-in
29092
+ * @param {number} slippagePercent (optional) The percentage of slippage tolerance. Default = 0.1. Max = 50. Min = 0
29093
+ * @param {number} maxHops (optional) Maximum hops allowed in optimal route. Default is 2
29094
+ * @param {number} deadline (optional) Latest time swap can execute. Default is 15 minutes
29095
+ * @return {TransactionResponse} The result containing the unsigned transaction and details of the swap
29028
29096
  */
29029
29097
  async getUnsignedSwapTxFromAmountIn(fromAddress, tokenInAddress, tokenOutAddress, amountIn, slippagePercent = DEFAULT_SLIPPAGE, maxHops = DEFAULT_MAX_HOPS, deadline = DEFAULT_DEADLINE) {
29030
- return await this.getUnsignedSwapTx(fromAddress, tokenInAddress, tokenOutAddress, ethers.ethers.BigNumber.from(amountIn), slippagePercent, maxHops, deadline, sdkCore.TradeType.EXACT_INPUT);
29098
+ return await this.getUnsignedSwapTx(fromAddress, tokenInAddress, tokenOutAddress, ethers.ethers.BigNumber.from(amountIn), slippagePercent, maxHops, deadline, Uniswap.TradeType.EXACT_INPUT);
29031
29099
  }
29032
29100
  /**
29033
29101
  * Get the unsigned swap transaction given the amount to buy.
29034
29102
  * Includes quote details for the swap.
29035
29103
  *
29036
- * @param {string} fromAddress The public address that will sign and submit the transaction.
29037
- * @param {string} tokenInAddress Token address to sell.
29038
- * @param {string} tokenOutAddress Token address to buy.
29039
- * @param {ethers.BigNumberish} amountOut Amount to buy.
29040
- * @param {number} slippagePercent (optional) The percentage of slippage tolerance. Default = 0.1. Max = 50. Min = 0.
29041
- * @param {number} maxHops (optional) Maximum hops allowed in optimal route. Default is 2.
29042
- * @param {number} deadline (optional) Latest time swap can execute. Default is 15 minutes.
29043
- * @return {TransactionResponse} The result containing the unsigned transaction and details of the swap.
29104
+ * @param {string} fromAddress The public address that will sign and submit the transaction
29105
+ * @param {string} tokenInAddress ERC20 contract address or 'native' to sell
29106
+ * @param {string} tokenOutAddress ERC20 contract address or 'native' to buy
29107
+ * @param {ethers.BigNumberish} amountOut Amount to buy in the smallest unit of the token-out
29108
+ * @param {number} slippagePercent (optional) The percentage of slippage tolerance. Default = 0.1. Max = 50. Min = 0
29109
+ * @param {number} maxHops (optional) Maximum hops allowed in optimal route. Default is 2
29110
+ * @param {number} deadline (optional) Latest time swap can execute. Default is 15 minutes
29111
+ * @return {TransactionResponse} The result containing the unsigned transaction and details of the swap
29044
29112
  */
29045
29113
  async getUnsignedSwapTxFromAmountOut(fromAddress, tokenInAddress, tokenOutAddress, amountOut, slippagePercent = DEFAULT_SLIPPAGE, maxHops = DEFAULT_MAX_HOPS, deadline = DEFAULT_DEADLINE) {
29046
- return await this.getUnsignedSwapTx(fromAddress, tokenInAddress, tokenOutAddress, ethers.ethers.BigNumber.from(amountOut), slippagePercent, maxHops, deadline, sdkCore.TradeType.EXACT_OUTPUT);
29114
+ return await this.getUnsignedSwapTx(fromAddress, tokenInAddress, tokenOutAddress, ethers.ethers.BigNumber.from(amountOut), slippagePercent, maxHops, deadline, Uniswap.TradeType.EXACT_OUTPUT);
29047
29115
  }
29048
29116
  }
29049
29117
 
@@ -29284,6 +29352,14 @@ const $d85ad1457a3f1a83$export$fc55ed5a42b458ba = {
29284
29352
  [($0472f23319457bfb$export$c06e1e7429de6283).IMTBL_ZKEVM_MAINNET]: {
29285
29353
  url: "https://explorer.mainnet.immutable.com",
29286
29354
  nativeToken: $d85ad1457a3f1a83$export$6f24f3cef7d501c4.get(($0472f23319457bfb$export$c06e1e7429de6283).IMTBL_ZKEVM_MAINNET).nativeCurrency
29355
+ },
29356
+ [($0472f23319457bfb$export$c06e1e7429de6283).SEPOLIA]: {
29357
+ url: "https://eth-sepolia.blockscout.com",
29358
+ nativeToken: $d85ad1457a3f1a83$export$3e81fc0987227f10.get(($0472f23319457bfb$export$c06e1e7429de6283).SEPOLIA).nativeCurrency
29359
+ },
29360
+ [($0472f23319457bfb$export$c06e1e7429de6283).ETHEREUM]: {
29361
+ url: "https://eth.blockscout.com/",
29362
+ nativeToken: $d85ad1457a3f1a83$export$6f24f3cef7d501c4.get(($0472f23319457bfb$export$c06e1e7429de6283).ETHEREUM).nativeCurrency
29287
29363
  }
29288
29364
  };
29289
29365
  const $d85ad1457a3f1a83$export$db5daa1b5156ccfe = [
@@ -29883,6 +29959,7 @@ const $efe60cea83bfc4e8$export$473cec51305fdae8 = async (config, { type: type =
29883
29959
 
29884
29960
 
29885
29961
 
29962
+
29886
29963
  const $fd8a8472dcc3ec2b$var$CACHE_DATA_TTL = 60; // seconds
29887
29964
  class $fd8a8472dcc3ec2b$export$ef140a6b05dfc786 {
29888
29965
  url;
@@ -30055,18 +30132,23 @@ async function $1564e43dde50bb61$export$60e0fe116a0e6ed0(web3Provider, walletAdd
30055
30132
  type: ($a8bc256d81a5e2c1$export$e3dc0620abde7f5a).GET_ERC20_BALANCE_ERROR
30056
30133
  });
30057
30134
  }
30058
- // Blockscout client singleton
30059
- let $1564e43dde50bb61$var$blockscoutClient;
30060
- const $1564e43dde50bb61$export$8c978679845804d4 = async (walletAddress, chainId, rename)=>{
30135
+ // Blockscout client singleton per chain id
30136
+ const $1564e43dde50bb61$var$blockscoutClientMap = new Map();
30137
+ const $1564e43dde50bb61$export$8c978679845804d4 = async (walletAddress, chainId, filterTokens)=>{
30061
30138
  // Shuffle the mapping of the tokens configuration so it is a hashmap
30062
30139
  // for faster access to tokens config objects.
30063
- const mapRename = Object.assign({}, ...rename.map((t)=>({
30140
+ const shouldFilter = filterTokens.length > 0;
30141
+ const mapFilterTokens = Object.assign({}, ...filterTokens.map((t)=>({
30064
30142
  [t.address || ""]: t
30065
30143
  })));
30066
- // Ensure singleton is present and match the selected chain
30067
- if (!$1564e43dde50bb61$var$blockscoutClient || $1564e43dde50bb61$var$blockscoutClient.chainId !== chainId) $1564e43dde50bb61$var$blockscoutClient = new ($fd8a8472dcc3ec2b$export$ef140a6b05dfc786)({
30068
- chainId: chainId
30069
- });
30144
+ // Get blockscout client for the given chain
30145
+ let blockscoutClient = $1564e43dde50bb61$var$blockscoutClientMap.get(chainId);
30146
+ if (!blockscoutClient) {
30147
+ blockscoutClient = new ($fd8a8472dcc3ec2b$export$ef140a6b05dfc786)({
30148
+ chainId: chainId
30149
+ });
30150
+ $1564e43dde50bb61$var$blockscoutClientMap.set(chainId, blockscoutClient);
30151
+ }
30070
30152
  // Hold the items in an array for post-fetching processing
30071
30153
  const items = [];
30072
30154
  const tokenType = ($887a00f8f72d61f0$export$5bd1ea2b3d18210).ERC20;
@@ -30076,7 +30158,7 @@ const $1564e43dde50bb61$export$8c978679845804d4 = async (walletAddress, chainId,
30076
30158
  try {
30077
30159
  do {
30078
30160
  // eslint-disable-next-line no-await-in-loop
30079
- resp = await $1564e43dde50bb61$var$blockscoutClient.getTokensByWalletAddress({
30161
+ resp = await blockscoutClient.getTokensByWalletAddress({
30080
30162
  walletAddress: walletAddress,
30081
30163
  tokenType: tokenType,
30082
30164
  nextPage: resp?.next_page_params
@@ -30094,7 +30176,7 @@ const $1564e43dde50bb61$export$8c978679845804d4 = async (walletAddress, chainId,
30094
30176
  if (err?.code !== (globalAxios$1.HttpStatusCode).NotFound) throw new ($a8bc256d81a5e2c1$export$b722478a3cbfa3bc)(err.message || "InternalServerError | getTokensByWalletAddress", ($a8bc256d81a5e2c1$export$e3dc0620abde7f5a).GET_INDEXER_BALANCE_ERROR, err);
30095
30177
  }
30096
30178
  try {
30097
- const respNative = await $1564e43dde50bb61$var$blockscoutClient.getNativeTokenByWalletAddress({
30179
+ const respNative = await blockscoutClient.getNativeTokenByWalletAddress({
30098
30180
  walletAddress: walletAddress
30099
30181
  });
30100
30182
  items.push(respNative);
@@ -30108,24 +30190,26 @@ const $1564e43dde50bb61$export$8c978679845804d4 = async (walletAddress, chainId,
30108
30190
  // or simply an incorrect wallet address was provided.
30109
30191
  if (err?.code !== (globalAxios$1.HttpStatusCode).NotFound) throw new ($a8bc256d81a5e2c1$export$b722478a3cbfa3bc)(err.message || "InternalServerError | getNativeTokenByWalletAddress", ($a8bc256d81a5e2c1$export$e3dc0620abde7f5a).GET_INDEXER_BALANCE_ERROR, err);
30110
30192
  }
30193
+ const balances = [];
30194
+ items.forEach((item)=>{
30195
+ if (shouldFilter && !mapFilterTokens[item.token.address]) return;
30196
+ const tokenData = item.token || {};
30197
+ const balance = (ethers.BigNumber).from(item.value);
30198
+ let decimals = parseInt(tokenData.decimals, 10);
30199
+ if (Number.isNaN(decimals)) decimals = ($d85ad1457a3f1a83$export$903389470ba9433c);
30200
+ const token = {
30201
+ ...tokenData,
30202
+ decimals: decimals
30203
+ };
30204
+ const formattedBalance = (ethers.utils).formatUnits(item.value, token.decimals);
30205
+ balances.push({
30206
+ balance: balance,
30207
+ formattedBalance: formattedBalance,
30208
+ token: token
30209
+ });
30210
+ });
30111
30211
  return {
30112
- balances: items.map((item)=>{
30113
- const tokenData = item.token || {};
30114
- const balance = (ethers.BigNumber).from(item.value);
30115
- const renamed = mapRename[tokenData.address] || {};
30116
- const token = {
30117
- ...tokenData,
30118
- name: renamed.name ?? tokenData.name,
30119
- symbol: renamed.symbol ?? tokenData.symbol,
30120
- decimals: parseInt(tokenData.decimals, 10)
30121
- };
30122
- const formattedBalance = (ethers.utils).formatUnits(item.value, token.decimals);
30123
- return {
30124
- balance: balance,
30125
- formattedBalance: formattedBalance,
30126
- token: token
30127
- };
30128
- })
30212
+ balances: balances
30129
30213
  };
30130
30214
  };
30131
30215
  const $1564e43dde50bb61$export$a3238cee431627c6 = async (config, web3Provider, walletAddress, tokens)=>{
@@ -30156,7 +30240,15 @@ const $1564e43dde50bb61$export$fee49741664a4d7e = async (config, web3Provider, w
30156
30240
  // eslint-disable-next-line no-console
30157
30241
  console.error(err);
30158
30242
  }
30159
- if (flag && ($fd8a8472dcc3ec2b$export$ef140a6b05dfc786).isChainSupported(chainId)) return await $1564e43dde50bb61$export$8c978679845804d4(walletAddress, chainId, tokens);
30243
+ if (flag && ($fd8a8472dcc3ec2b$export$ef140a6b05dfc786).isChainSupported(chainId)) {
30244
+ // This is a hack because the widgets are still using the tokens symbol
30245
+ // to drive the conversions. If we remove all the token symbols from e.g. zkevm
30246
+ // then we would not have fiat conversions.
30247
+ // Please remove this hack once https://immutable.atlassian.net/browse/WT-1710
30248
+ // is done.
30249
+ const isL1Chain = ($4013c5c91bb535f6$export$9b794d067cdd1af6)(config) === chainId;
30250
+ return await $1564e43dde50bb61$export$8c978679845804d4(walletAddress, chainId, isL1Chain ? tokens : []);
30251
+ }
30160
30252
  // This fallback to use ERC20s calls which is a best effort solution
30161
30253
  // Fails in fetching data from the RCP calls might result in some
30162
30254
  // missing data.
@@ -33130,7 +33222,7 @@ class $a8cb37a3fc8eb863$export$1f60ba4ec72508a0 {
33130
33222
  const tokenList = await $efe60cea83bfc4e8$export$473cec51305fdae8(this.config, {
33131
33223
  type: ($08d5ddc39acd6833$export$fd9b17d87f4121d2).ONRAMP
33132
33224
  });
33133
- const token = tokenList.tokens.find((t)=>t.address?.toLowerCase() === params.tokenAddress?.toLowerCase());
33225
+ const token = tokenList.tokens?.find((t)=>t.address?.toLowerCase() === params.tokenAddress?.toLowerCase());
33134
33226
  if (token) {
33135
33227
  tokenAmount = params.tokenAmount;
33136
33228
  tokenSymbol = token.symbol;
@@ -33203,7 +33295,7 @@ var $045213b18e9f1f94$export$75be0f6af9650f2c;
33203
33295
  })($045213b18e9f1f94$export$75be0f6af9650f2c || ($045213b18e9f1f94$export$75be0f6af9650f2c = {}));
33204
33296
 
33205
33297
 
33206
- const $d663162fd5a0853f$export$38a083d9fb5551ca = "0.27.9";
33298
+ const $d663162fd5a0853f$export$38a083d9fb5551ca = "0.27.11";
33207
33299
  const $d663162fd5a0853f$export$83bf90b30cdfd29f = ()=>false;
33208
33300
  const $d663162fd5a0853f$export$1169f5475725171b = ()=>$d663162fd5a0853f$export$38a083d9fb5551ca;
33209
33301
 
@@ -33337,7 +33429,7 @@ var $207ed853f11d19d5$export$5a0ace85cae72d45;
33337
33429
  IMTBLWidgetEvents["IMTBL_SWAP_WIDGET_EVENT"] = "imtbl-swap-widget";
33338
33430
  IMTBLWidgetEvents["IMTBL_BRIDGE_WIDGET_EVENT"] = "imtbl-bridge-widget";
33339
33431
  IMTBLWidgetEvents["IMTBL_ONRAMP_WIDGET_EVENT"] = "imtbl-onramp-widget";
33340
- IMTBLWidgetEvents["IMTBL_PRIMARY_REVENUE_WIDGET_EVENT"] = "imtbl-sale-widget";
33432
+ IMTBLWidgetEvents["IMTBL_SALE_WIDGET_EVENT"] = "imtbl-sale-widget";
33341
33433
  })($207ed853f11d19d5$export$5a0ace85cae72d45 || ($207ed853f11d19d5$export$5a0ace85cae72d45 = {}));
33342
33434
 
33343
33435