@imtbl/sdk 0.27.8 → 0.27.10

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.8' };
3613
+ const defaultHeaders$1 = { 'x-sdk-version': 'ts-immutable-sdk-0.27.10' };
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.8',
3673
+ sdkVersion: 'ts-immutable-sdk-multi-rollup-api-client-0.27.10',
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.8',
4084
+ sdkVersion: 'ts-immutable-sdk-0.27.10',
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,10 +28008,8 @@ 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
28014
  async function getERC20Decimals(tokenAddress, provider) {
27987
28015
  const decimalsFunctionSig = ethers.utils.id('decimals()').substring(0, 10);
@@ -28014,7 +28042,7 @@ function isValidNonZeroAddress(address) {
28014
28042
  }
28015
28043
  const erc20ToUniswapToken = (token) =>
28016
28044
  // eslint-disable-next-line implicit-arrow-linebreak
28017
- new Token(token.chainId, token.address, token.decimals, token.symbol, token.name);
28045
+ new Uniswap.Token(token.chainId, token.address, token.decimals, token.symbol, token.name);
28018
28046
  const uniswapTokenToERC20 = (token) => ({
28019
28047
  chainId: token.chainId,
28020
28048
  address: token.address,
@@ -28025,25 +28053,74 @@ const uniswapTokenToERC20 = (token) => ({
28025
28053
  });
28026
28054
  const toCurrencyAmount = (amount) => {
28027
28055
  const token = erc20ToUniswapToken(amount.token);
28028
- return CurrencyAmount.fromRawAmount(token, amount.value.toString());
28056
+ return Uniswap.CurrencyAmount.fromRawAmount(token, amount.value.toString());
28029
28057
  };
28030
28058
  const newAmount = (amount, token) => ({
28031
28059
  value: amount,
28032
28060
  token,
28033
28061
  });
28034
28062
  const isERC20Amount = (amount) => amount.token.type === 'erc20';
28063
+ const isNativeAmount = (amount) => amount.token.type === 'native';
28035
28064
  const addERC20Amount = (a, b) => {
28036
28065
  // Make sure the ERC20s have the same address
28037
28066
  if (a.token.address !== b.token.address)
28038
28067
  throw new Error('Token mismatch: token addresses must be the same');
28039
28068
  return { value: a.value.add(b.value), token: a.token };
28040
28069
  };
28070
+ const addNativeAmount = (a, b) => ({
28071
+ value: a.value.add(b.value),
28072
+ token: a.token,
28073
+ });
28074
+ const addAmount = (a, b) => {
28075
+ if (isERC20Amount(a) && isERC20Amount(b)) {
28076
+ return addERC20Amount(a, b);
28077
+ }
28078
+ if (isNativeAmount(a) && isNativeAmount(b)) {
28079
+ return addNativeAmount(a, b);
28080
+ }
28081
+ throw new Error('Token mismatch: token types must be the same');
28082
+ };
28041
28083
  const subtractERC20Amount = (a, b) => {
28042
28084
  // Make sure the ERC20s have the same address
28043
28085
  if (a.token.address !== b.token.address)
28044
28086
  throw new Error('Token mismatch: token addresses must be the same');
28045
28087
  return { value: a.value.sub(b.value), token: a.token };
28046
28088
  };
28089
+ const subtractNativeAmount = (a, b) => ({
28090
+ value: a.value.sub(b.value),
28091
+ token: a.token,
28092
+ });
28093
+ const subtractAmount = (a, b) => {
28094
+ if (isERC20Amount(a) && isERC20Amount(b)) {
28095
+ return subtractERC20Amount(a, b);
28096
+ }
28097
+ if (isNativeAmount(a) && isNativeAmount(b)) {
28098
+ return subtractNativeAmount(a, b);
28099
+ }
28100
+ throw new Error('Token mismatch: token types must be the same');
28101
+ };
28102
+ /**
28103
+ * Converts our internal token type which could be ERC20 or Native
28104
+ * into a format consumable by Checkout. They require an address to be
28105
+ * present. We populate the address with empty string if it's Native.
28106
+ * If it's ERC20, we don't need to change it.
28107
+ */
28108
+ const toPublicTokenType = (token) => {
28109
+ if (token.type === 'native') {
28110
+ return {
28111
+ address: '',
28112
+ chainId: token.chainId,
28113
+ decimals: token.decimals,
28114
+ symbol: token.symbol,
28115
+ name: token.name,
28116
+ };
28117
+ }
28118
+ return token;
28119
+ };
28120
+ const toPublicAmount = (amount) => ({
28121
+ token: toPublicTokenType(amount.token),
28122
+ value: amount.value,
28123
+ });
28047
28124
 
28048
28125
  const amountIndex = 0;
28049
28126
  const gasEstimateIndex = 3;
@@ -28417,11 +28494,11 @@ const getUnsignedERC20ApproveTransaction = (ownerAddress, tokenAmount, spenderAd
28417
28494
  from: ownerAddress,
28418
28495
  };
28419
28496
  };
28420
- const prepareApproval = (tradeType, amountSpecified, amountWithSlippage, routingContracts, secondaryFees) => {
28497
+ const prepareApproval = (tradeType, amountSpecified, amountWithSlippage, contracts, secondaryFees) => {
28421
28498
  const amountOfTokenIn = tradeType === TradeType.EXACT_INPUT ? amountSpecified : amountWithSlippage;
28422
28499
  const spender = secondaryFees.length === 0
28423
- ? routingContracts.peripheryRouterAddress
28424
- : routingContracts.secondaryFeeAddress;
28500
+ ? contracts.routerAddress
28501
+ : contracts.secondaryFeeAddress;
28425
28502
  return { spender, amount: amountOfTokenIn };
28426
28503
  };
28427
28504
  /**
@@ -28454,7 +28531,7 @@ async function getApproveGasEstimate(provider, ownerAddress, spenderAddress, tok
28454
28531
  from: ownerAddress,
28455
28532
  });
28456
28533
  }
28457
- const getApproval = async (provider, ownerAddress, preparedApproval, gasPrice, nativeTokenService) => {
28534
+ const getApproval = async (provider, ownerAddress, preparedApproval, gasPrice) => {
28458
28535
  const approveTransaction = await getApproveTransaction(provider, ownerAddress, preparedApproval.amount, preparedApproval.spender);
28459
28536
  if (!approveTransaction) {
28460
28537
  return null;
@@ -28463,8 +28540,7 @@ const getApproval = async (provider, ownerAddress, preparedApproval, gasPrice, n
28463
28540
  const gasFeeEstimate = gasPrice ? calculateGasFee(gasPrice, gasEstimate) : null;
28464
28541
  return {
28465
28542
  transaction: approveTransaction,
28466
- // TODO: TP-1649: Remove the wrapping here
28467
- gasFeeEstimate: gasFeeEstimate ? nativeTokenService.maybeWrapAmount(gasFeeEstimate) : null,
28543
+ gasFeeEstimate: gasFeeEstimate ? toPublicAmount(gasFeeEstimate) : null,
28468
28544
  };
28469
28545
  };
28470
28546
 
@@ -28500,25 +28576,8 @@ function applySlippage(tradeType, amount, slippage) {
28500
28576
  const amountWithSlippage = maybeInverted.multiply(amount.toString()).quotient;
28501
28577
  return ethers.BigNumber.from(amountWithSlippage.toString());
28502
28578
  }
28503
- function prepareUserQuote(otherToken, tradeInfo, slippage, fees) {
28504
- const quote = getQuoteAmountFromTradeType(tradeInfo);
28505
- const amountWithSlippage = applySlippage(tradeInfo.tradeType, quote.value, slippage);
28506
- return {
28507
- amount: quote,
28508
- amountWithMaxSlippage: {
28509
- token: otherToken,
28510
- value: amountWithSlippage,
28511
- },
28512
- slippage,
28513
- fees: fees.withAmounts(),
28514
- };
28515
- }
28516
28579
  function getOurQuoteReqAmount(amountSpecified, // the amount specified by the user, either exactIn or exactOut
28517
28580
  fees, tradeType, nativeTokenService) {
28518
- // TODO: TP-1649: Remove this when we support Native
28519
- if (!isERC20Amount(amountSpecified)) {
28520
- throw new Error('Not implemented yet!');
28521
- }
28522
28581
  if (tradeType === TradeType.EXACT_OUTPUT) {
28523
28582
  // For an exact output swap, we do not need to subtract fees from the given amount
28524
28583
  return nativeTokenService.maybeWrapAmount(amountSpecified);
@@ -28549,14 +28608,17 @@ class Fees {
28549
28608
  this.secondaryFees = secondaryFees;
28550
28609
  this.amount = newAmount(BigNumber$1.from(0), token);
28551
28610
  }
28611
+ get token() {
28612
+ return this.amount.token;
28613
+ }
28552
28614
  addAmount(amount) {
28553
- this.amount = addERC20Amount(this.amount, amount);
28615
+ this.amount = addAmount(this.amount, amount);
28554
28616
  }
28555
28617
  amountWithFeesApplied() {
28556
- return addERC20Amount(this.amount, this.total());
28618
+ return addAmount(this.amount, this.total());
28557
28619
  }
28558
28620
  amountLessFees() {
28559
- return subtractERC20Amount(this.amount, this.total());
28621
+ return subtractAmount(this.amount, this.total());
28560
28622
  }
28561
28623
  withAmounts() {
28562
28624
  return this.secondaryFees.map((fee) => {
@@ -28575,7 +28637,7 @@ class Fees {
28575
28637
  const feeAmount = this.amount.value
28576
28638
  .mul(fee.basisPoints)
28577
28639
  .div(BASIS_POINT_PRECISION);
28578
- totalFees = addERC20Amount(totalFees, newAmount(feeAmount, this.amount.token));
28640
+ totalFees = addAmount(totalFees, newAmount(feeAmount, this.amount.token));
28579
28641
  }
28580
28642
  return totalFees;
28581
28643
  }
@@ -28589,11 +28651,14 @@ class NativeTokenService {
28589
28651
  this.wrappedToken = wrappedToken;
28590
28652
  }
28591
28653
  wrapAmount(amount) {
28654
+ if (!this.isNativeToken(amount.token)) {
28655
+ throw new Error(`cannot wrap non-native token: ${amount.token.address}`);
28656
+ }
28592
28657
  return newAmount(amount.value, this.wrappedToken);
28593
28658
  }
28594
28659
  unwrapAmount(amount) {
28595
28660
  if (amount.token !== this.wrappedToken) {
28596
- throw new Error(`token ${amount.token.address} is not wrapped`);
28661
+ throw new Error(`cannot unwrap non-wrapped token ${amount.token.address}`);
28597
28662
  }
28598
28663
  return newAmount(amount.value, this.nativeToken);
28599
28664
  }
@@ -28613,14 +28678,6 @@ class NativeTokenService {
28613
28678
 
28614
28679
  const IMMUTABLE_TESTNET_RPC_URL = 'https://rpc.testnet.immutable.com';
28615
28680
  const IMMUTABLE_TESTNET_CHAIN_ID = 13472;
28616
-
28617
- const NATIVE_IMX_IMMUTABLE_TESTNET = {
28618
- chainId: IMMUTABLE_TESTNET_CHAIN_ID,
28619
- decimals: 18,
28620
- symbol: 'tIMX',
28621
- name: 'Immutable Testnet Token',
28622
- type: 'native',
28623
- };
28624
28681
  const TIMX_IMMUTABLE_TESTNET = {
28625
28682
  chainId: IMMUTABLE_TESTNET_CHAIN_ID,
28626
28683
  address: '0x0000000000000000000000000000000000001010',
@@ -28751,21 +28808,33 @@ function getSwap(adjustedQuote, fromAddress, slippage, deadline, peripheryRouter
28751
28808
  gasFeeEstimate: gasFeeEstimate ? nativeTokenService.maybeWrapAmount(gasFeeEstimate) : null,
28752
28809
  };
28753
28810
  }
28754
- function prepareSwap(ourQuote, amountSpecified, fees) {
28811
+ const adjustAmountIn = (ourQuote, amountSpecified, fees, nativeTokenService) => {
28755
28812
  if (ourQuote.tradeType === TradeType.EXACT_OUTPUT) {
28756
- fees.addAmount(ourQuote.amountIn);
28757
- return {
28758
- gasEstimate: ourQuote.gasEstimate,
28759
- route: ourQuote.route,
28760
- amountIn: fees.amountWithFeesApplied(),
28761
- amountOut: amountSpecified,
28762
- tradeType: ourQuote.tradeType,
28763
- };
28813
+ // when doing exact output, calculate the fees based on the amountIn
28814
+ const amountToAdd = nativeTokenService.isNativeToken(fees.token)
28815
+ ? nativeTokenService.unwrapAmount(ourQuote.amountIn)
28816
+ : ourQuote.amountIn;
28817
+ fees.addAmount(amountToAdd);
28818
+ return nativeTokenService.maybeWrapAmount(fees.amountWithFeesApplied());
28764
28819
  }
28820
+ return nativeTokenService.maybeWrapAmount(amountSpecified);
28821
+ };
28822
+ /**
28823
+ * adjustQuoteWithFees adjusts the amountIn of the quote to account for fees
28824
+ * EXACT_OUTPUT swaps will have the fees added to the amountIn if there are fees specified
28825
+ * EXACT_INPUT swaps will have amountIn set to the user-specified amount
28826
+ * @param ourQuote The quote from calling the Quoter contract
28827
+ * @param amountSpecified The user-specified amount for the swap (EXACT...)
28828
+ * @param fees The fees applied to the swap
28829
+ * @param tokenWrapper Helper class for the native token and associated ERC20
28830
+ * @returns {QuoteResult} The adjusted quote
28831
+ */
28832
+ function adjustQuoteWithFees(ourQuote, amountSpecified, fees, nativeTokenService) {
28833
+ const adjustedAmountIn = adjustAmountIn(ourQuote, amountSpecified, fees, nativeTokenService);
28765
28834
  return {
28766
28835
  gasEstimate: ourQuote.gasEstimate,
28767
28836
  route: ourQuote.route,
28768
- amountIn: amountSpecified,
28837
+ amountIn: adjustedAmountIn,
28769
28838
  amountOut: ourQuote.amountOut,
28770
28839
  tradeType: ourQuote.tradeType,
28771
28840
  };
@@ -28786,7 +28855,7 @@ const SUPPORTED_SANDBOX_CHAINS = {
28786
28855
  rpcUrl: IMMUTABLE_TESTNET_RPC_URL,
28787
28856
  contracts: CONTRACTS_FOR_CHAIN_ID[IMMUTABLE_TESTNET_CHAIN_ID],
28788
28857
  commonRoutingTokens: IMMUTABLE_TESTNET_COMMON_ROUTING_TOKENS,
28789
- nativeToken: NATIVE_IMX_IMMUTABLE_TESTNET,
28858
+ nativeToken: TIMX_IMMUTABLE_TESTNET,
28790
28859
  wrappedNativeToken: TIMX_IMMUTABLE_TESTNET, // TODO: TP-1649: Change to WIMX when ready.
28791
28860
  },
28792
28861
  };
@@ -28858,6 +28927,15 @@ class ExchangeConfiguration {
28858
28927
  }
28859
28928
  }
28860
28929
 
28930
+ const toPublicQuote = (amount, amountWithMaxSlippage, slippage, fees) => ({
28931
+ amount,
28932
+ amountWithMaxSlippage,
28933
+ slippage,
28934
+ fees: fees.withAmounts().map((fee) => ({
28935
+ ...fee,
28936
+ amount: toPublicAmount(fee.amount),
28937
+ })),
28938
+ });
28861
28939
  class Exchange {
28862
28940
  provider;
28863
28941
  router;
@@ -28866,6 +28944,8 @@ class Exchange {
28866
28944
  wrappedNativeToken;
28867
28945
  secondaryFees;
28868
28946
  nativeTokenService;
28947
+ secondaryFeeContractAddress;
28948
+ routerContractAddress;
28869
28949
  constructor(configuration) {
28870
28950
  const config = new ExchangeConfiguration(configuration);
28871
28951
  this.chainId = config.chain.chainId;
@@ -28873,13 +28953,13 @@ class Exchange {
28873
28953
  this.wrappedNativeToken = config.chain.wrappedNativeToken;
28874
28954
  this.nativeTokenService = new NativeTokenService(this.nativeToken, this.wrappedNativeToken);
28875
28955
  this.secondaryFees = config.secondaryFees;
28956
+ this.routerContractAddress = config.chain.contracts.peripheryRouter;
28957
+ this.secondaryFeeContractAddress = config.chain.contracts.secondaryFee;
28876
28958
  this.provider = new ethers.providers.JsonRpcProvider(config.chain.rpcUrl);
28877
28959
  this.router = new Router(this.provider, config.chain.commonRoutingTokens, {
28878
28960
  multicallAddress: config.chain.contracts.multicall,
28879
28961
  factoryAddress: config.chain.contracts.coreFactory,
28880
28962
  quoterAddress: config.chain.contracts.quoterV2,
28881
- peripheryRouterAddress: config.chain.contracts.peripheryRouter,
28882
- secondaryFeeAddress: config.chain.contracts.secondaryFee,
28883
28963
  });
28884
28964
  }
28885
28965
  static validate(tokenInAddress, tokenOutAddress, maxHops, slippagePercent, fromAddress) {
@@ -28896,7 +28976,7 @@ class Exchange {
28896
28976
  if (this.secondaryFees.length === 0) {
28897
28977
  return [];
28898
28978
  }
28899
- const secondaryFeeContract = SecondaryFee__factory.connect(this.router.routingContracts.secondaryFeeAddress, this.provider);
28979
+ const secondaryFeeContract = SecondaryFee__factory.connect(this.secondaryFeeContractAddress, this.provider);
28900
28980
  if (await secondaryFeeContract.paused()) {
28901
28981
  // Do not use secondary fees if the contract is paused
28902
28982
  return [];
@@ -28924,8 +29004,7 @@ class Exchange {
28924
29004
  decimals: tokenOutDecimals,
28925
29005
  };
28926
29006
  // determine which amount was specified for the swap from the TradeType
28927
- const [tokenSpecified, otherToken] = tradeType === TradeType.EXACT_INPUT
28928
- ? [tokenIn, tokenOut] : [tokenOut, tokenIn];
29007
+ const [tokenSpecified, otherToken] = tradeType === TradeType.EXACT_INPUT ? [tokenIn, tokenOut] : [tokenOut, tokenIn];
28929
29008
  const amountSpecified = newAmount(amount, tokenSpecified);
28930
29009
  const fees = new Fees(secondaryFees, tokenIn);
28931
29010
  const ourQuoteReqAmount = getOurQuoteReqAmount(amountSpecified, fees, tradeType, this.nativeTokenService);
@@ -28934,17 +29013,18 @@ class Exchange {
28934
29013
  this.router.findOptimalRoute(ourQuoteReqAmount, otherToken, tradeType, maxHops),
28935
29014
  fetchGasPrice(this.provider, this.nativeToken),
28936
29015
  ]);
28937
- const adjustedQuote = prepareSwap(ourQuote, amountSpecified, fees);
28938
- const swap = getSwap(adjustedQuote, fromAddress, slippagePercent, deadline, this.router.routingContracts.peripheryRouterAddress, this.router.routingContracts.secondaryFeeAddress, gasPrice, secondaryFees, this.nativeTokenService);
28939
- const userQuote = prepareUserQuote(otherToken, adjustedQuote, slippagePercent, fees);
28940
- const preparedApproval = prepareApproval(tradeType, amountSpecified, userQuote.amountWithMaxSlippage, this.router.routingContracts, secondaryFees);
29016
+ const adjustedQuote = adjustQuoteWithFees(ourQuote, amountSpecified, fees, this.nativeTokenService);
29017
+ const swap = getSwap(adjustedQuote, fromAddress, slippagePercent, deadline, this.routerContractAddress, this.secondaryFeeContractAddress, gasPrice, secondaryFees, this.nativeTokenService);
29018
+ const quotedAmount = getQuoteAmountFromTradeType(adjustedQuote);
29019
+ const amountWithMaxSlippage = newAmount(applySlippage(adjustedQuote.tradeType, quotedAmount.value, slippagePercent), otherToken);
29020
+ const preparedApproval = prepareApproval(tradeType, amountSpecified, amountWithMaxSlippage, {
29021
+ routerAddress: this.routerContractAddress,
29022
+ secondaryFeeAddress: this.secondaryFeeContractAddress,
29023
+ }, secondaryFees);
28941
29024
  // preparedApproval always uses the tokenIn address because we are always selling the tokenIn
28942
- const approval = await getApproval(this.provider, fromAddress, preparedApproval, gasPrice, this.nativeTokenService);
28943
- return {
28944
- approval,
28945
- swap,
28946
- quote: userQuote,
28947
- };
29025
+ const approval = await getApproval(this.provider, fromAddress, preparedApproval, gasPrice);
29026
+ const quote = toPublicQuote(quotedAmount, amountWithMaxSlippage, slippagePercent, fees);
29027
+ return { quote, approval, swap };
28948
29028
  }
28949
29029
  /**
28950
29030
  * Get the unsigned swap transaction given the amount to sell.
@@ -33136,7 +33216,7 @@ var $045213b18e9f1f94$export$75be0f6af9650f2c;
33136
33216
  })($045213b18e9f1f94$export$75be0f6af9650f2c || ($045213b18e9f1f94$export$75be0f6af9650f2c = {}));
33137
33217
 
33138
33218
 
33139
- const $d663162fd5a0853f$export$38a083d9fb5551ca = "0.27.8";
33219
+ const $d663162fd5a0853f$export$38a083d9fb5551ca = "0.27.10";
33140
33220
  const $d663162fd5a0853f$export$83bf90b30cdfd29f = ()=>false;
33141
33221
  const $d663162fd5a0853f$export$1169f5475725171b = ()=>$d663162fd5a0853f$export$38a083d9fb5551ca;
33142
33222