@imtbl/sdk 0.44.4-alpha.1 → 0.45.0

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
@@ -1,5 +1,5 @@
1
- import globalAxios$1, { isAxiosError as isAxiosError$2, AxiosError as AxiosError$2, HttpStatusCode as HttpStatusCode$3 } from 'axios';
2
- import { ImmutableX, Config, IMXError, createStarkSigner, generateLegacyStarkPrivateKey, TransfersApi as TransfersApi$1, OrdersApi as OrdersApi$2, UsersApi as UsersApi$1, Contracts, TradesApi as TradesApi$1, ExchangesApi as ExchangesApi$1, WithdrawalsApi as WithdrawalsApi$1, MintsApi as MintsApi$1, DepositsApi as DepositsApi$1, EncodingApi as EncodingApi$1, TokensApi as TokensApi$2 } from '@imtbl/core-sdk';
1
+ import globalAxios$1, { isAxiosError as isAxiosError$2, HttpStatusCode as HttpStatusCode$3, AxiosError as AxiosError$2 } from 'axios';
2
+ import { ImmutableX, Config, generateLegacyStarkPrivateKey, createStarkSigner, TransfersApi as TransfersApi$1, OrdersApi as OrdersApi$2, UsersApi as UsersApi$1, Contracts, TradesApi as TradesApi$1, ExchangesApi as ExchangesApi$1, WithdrawalsApi as WithdrawalsApi$1, MintsApi as MintsApi$1, DepositsApi as DepositsApi$1, EncodingApi as EncodingApi$1, TokensApi as TokensApi$2, IMXError } from '@imtbl/core-sdk';
3
3
  import { UserManager, User, InMemoryWebStorage, WebStorageStateStore } from 'oidc-client-ts';
4
4
  import jwt_decode from 'jwt-decode';
5
5
  import * as crypto from 'crypto';
@@ -14,8 +14,6 @@ import { walletContracts } from '@0xsequence/abi';
14
14
  import { v1 } from '@0xsequence/core';
15
15
  import FormData$2 from 'form-data';
16
16
  import { Seaport as Seaport$1 } from '@opensea/seaport-js';
17
- import { parseUnits } from '@ethersproject/units';
18
- import { BigNumber as BigNumber$2 } from '@ethersproject/bignumber';
19
17
  import detectEthereumProvider from '@metamask/detect-provider';
20
18
  import * as Uniswap from '@uniswap/sdk-core';
21
19
  import { TradeType, Percent } from '@uniswap/sdk-core';
@@ -23,6 +21,8 @@ import assert from 'assert';
23
21
  import { FeeAmount, Route, SwapQuoter, Pool, Trade, toHex as toHex$1, encodeRouteToPath } from '@uniswap/v3-sdk';
24
22
  import { keccak256 as keccak256$1 } from '@ethersproject/solidity';
25
23
  import { SwapRouter, PaymentsExtended } from '@uniswap/router-sdk';
24
+ import { parseUnits } from '@ethersproject/units';
25
+ import { BigNumber as BigNumber$2 } from '@ethersproject/bignumber';
26
26
 
27
27
  var Environment$1;
28
28
  (function (Environment) {
@@ -10619,7 +10619,7 @@ class MultiRollupApiClients {
10619
10619
  }
10620
10620
 
10621
10621
  // eslint-disable-next-line @typescript-eslint/naming-convention
10622
- const defaultHeaders$1 = { 'x-sdk-version': 'ts-immutable-sdk-0.44.4-alpha.1' };
10622
+ const defaultHeaders$1 = { 'x-sdk-version': 'ts-immutable-sdk-0.45.0' };
10623
10623
  const createConfig = ({ basePath, headers, }) => {
10624
10624
  if (!basePath.trim()) {
10625
10625
  throw Error('basePath can not be empty');
@@ -10691,7 +10691,7 @@ class APIError extends Error {
10691
10691
 
10692
10692
  /* eslint-disable implicit-arrow-linebreak */
10693
10693
  const defaultHeaders = {
10694
- sdkVersion: 'ts-immutable-sdk-multi-rollup-api-client-0.44.4-alpha.1',
10694
+ sdkVersion: 'ts-immutable-sdk-multi-rollup-api-client-0.45.0',
10695
10695
  };
10696
10696
  /**
10697
10697
  * createAPIConfiguration to create a custom Configuration
@@ -11130,7 +11130,7 @@ const createImmutableXConfiguration = ({ basePath, chainID, coreContractAddress,
11130
11130
  chainID,
11131
11131
  coreContractAddress,
11132
11132
  registrationContractAddress,
11133
- sdkVersion: 'ts-immutable-sdk-0.44.4-alpha.1',
11133
+ sdkVersion: 'ts-immutable-sdk-0.45.0',
11134
11134
  });
11135
11135
  /**
11136
11136
  * Sets `sdkVersion` at the time of build
@@ -11176,7 +11176,7 @@ class ImxConfiguration {
11176
11176
  }
11177
11177
  }
11178
11178
 
11179
- class ImmutableXClient {
11179
+ class IMXClient {
11180
11180
  immutableX;
11181
11181
  depositsApi;
11182
11182
  mintsApi;
@@ -11633,14 +11633,6 @@ class ImmutableXClient {
11633
11633
  }
11634
11634
  }
11635
11635
 
11636
- var immutablex_client = /*#__PURE__*/Object.freeze({
11637
- __proto__: null,
11638
- IMXError: IMXError,
11639
- ImmutableXClient: ImmutableXClient,
11640
- imxClientCreateStarkSigner: createStarkSigner,
11641
- imxClientGenerateLegacyStarkPrivateKey: generateLegacyStarkPrivateKey
11642
- });
11643
-
11644
11636
  function bind$1(fn, thisArg) {
11645
11637
  return function wrap() {
11646
11638
  return fn.apply(thisArg, arguments);
@@ -17873,7 +17865,7 @@ class Passport {
17873
17865
  this.magicAdapter = new MagicAdapter(this.config);
17874
17866
  this.confirmationScreen = new ConfirmationScreen(this.config);
17875
17867
  this.immutableXClient = passportModuleConfiguration.overrides?.immutableXClient
17876
- || new ImmutableXClient({
17868
+ || new IMXClient({
17877
17869
  baseConfig: passportModuleConfiguration.baseConfig,
17878
17870
  });
17879
17871
  this.multiRollupApiClients = new MultiRollupApiClients(this.config.multiRollupConfig);
@@ -19623,1151 +19615,67 @@ var orderbook = /*#__PURE__*/Object.freeze({
19623
19615
  constants: constants
19624
19616
  });
19625
19617
 
19626
- function isChainValid(chainID, config) {
19627
- return chainID === config.ethConfiguration.chainID;
19628
- }
19629
- async function validateChain(signer, config) {
19630
- const chainID = await signer.getChainId();
19631
- if (!isChainValid(chainID, config)) {
19632
- throw new Error('The wallet used for this operation is not connected to the correct network.');
19633
- }
19618
+ function bind(fn, thisArg) {
19619
+ return function wrap() {
19620
+ return fn.apply(thisArg, arguments);
19621
+ };
19634
19622
  }
19635
19623
 
19636
- async function transfer({ signers: { ethSigner, starkSigner }, request, config, }) {
19637
- await validateChain(ethSigner, config.immutableXConfig);
19638
- const ethAddress = await ethSigner.getAddress();
19639
- const transfersApi = new TransfersApi$1(config.immutableXConfig.apiConfiguration);
19640
- const transferAmount = request.type === 'ERC721' ? '1' : request.amount;
19641
- const signableResult = await transfersApi.getSignableTransferV1({
19642
- getSignableTransferRequest: {
19643
- sender: ethAddress,
19644
- token: convertToSignableToken(request),
19645
- amount: transferAmount,
19646
- receiver: request.receiver,
19647
- },
19648
- });
19649
- const { signable_message: signableMessage, payload_hash: payloadHash } = signableResult.data;
19650
- const ethSignature = await signRaw(signableMessage, ethSigner);
19651
- const starkSignature = await starkSigner.signMessage(payloadHash);
19652
- const transferSigningParams = {
19653
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
19654
- sender_stark_key: signableResult.data.sender_stark_key,
19655
- sender_vault_id: signableResult.data.sender_vault_id,
19656
- receiver_stark_key: signableResult.data.receiver_stark_key,
19657
- receiver_vault_id: signableResult.data.receiver_vault_id,
19658
- asset_id: signableResult.data.asset_id,
19659
- amount: signableResult.data.amount,
19660
- nonce: signableResult.data.nonce,
19661
- expiration_timestamp: signableResult.data.expiration_timestamp,
19662
- stark_signature: starkSignature,
19663
- };
19664
- const response = await transfersApi.createTransferV1({
19665
- createTransferRequest: transferSigningParams,
19666
- xImxEthAddress: ethAddress,
19667
- xImxEthSignature: ethSignature,
19668
- });
19669
- return {
19670
- sent_signature: response?.data.sent_signature,
19671
- status: response?.data.status?.toString(),
19672
- time: response?.data.time,
19673
- transfer_id: response?.data.transfer_id,
19674
- };
19675
- }
19676
- async function batchTransfer({ signers: { ethSigner, starkSigner }, request, config, }) {
19677
- await validateChain(ethSigner, config.immutableXConfig);
19678
- const ethAddress = await ethSigner.getAddress();
19679
- const transfersApi = new TransfersApi$1(config.immutableXConfig.apiConfiguration);
19680
- const signableRequests = request.map((nftTransfer) => ({
19681
- amount: '1',
19682
- token: convertToSignableToken({
19683
- type: 'ERC721',
19684
- tokenId: nftTransfer.tokenId,
19685
- tokenAddress: nftTransfer.tokenAddress,
19686
- }),
19687
- receiver: nftTransfer.receiver,
19688
- }));
19689
- const signableResult = await transfersApi.getSignableTransfer({
19690
- getSignableTransferRequestV2: {
19691
- sender_ether_key: ethAddress,
19692
- signable_requests: signableRequests,
19693
- },
19694
- });
19695
- const signableMessage = signableResult.data.signable_message;
19696
- if (signableMessage === undefined) {
19697
- throw new Error('Invalid response from Signable registration offchain');
19698
- }
19699
- const ethSignature = await signRaw(signableMessage, ethSigner);
19700
- const requests = [];
19701
- for (const resp of signableResult.data.signable_responses) {
19702
- // TODO: remove once fixed
19703
- // eslint-disable-next-line no-await-in-loop
19704
- const starkSignature = await starkSigner.signMessage(resp.payload_hash);
19705
- const req = {
19706
- sender_vault_id: resp.sender_vault_id,
19707
- receiver_stark_key: resp.receiver_stark_key,
19708
- receiver_vault_id: resp.receiver_vault_id,
19709
- asset_id: resp.asset_id,
19710
- amount: resp.amount,
19711
- nonce: resp.nonce,
19712
- expiration_timestamp: resp.expiration_timestamp,
19713
- stark_signature: starkSignature,
19714
- };
19715
- requests.push(req);
19716
- }
19717
- // TODO: throw error on missing payload hash?
19718
- const transferSigningParams = {
19719
- sender_stark_key: signableResult.data.sender_stark_key,
19720
- requests,
19721
- };
19722
- const response = await transfersApi.createTransfer({
19723
- createTransferRequestV2: transferSigningParams,
19724
- xImxEthAddress: ethAddress,
19725
- xImxEthSignature: ethSignature,
19726
- });
19727
- return {
19728
- transfer_ids: response?.data.transfer_ids,
19729
- };
19730
- }
19624
+ // utils is a library of generic helper functions non-specific to axios
19731
19625
 
19732
- async function createOrder({ signers, request, config, }) {
19733
- await validateChain(signers.ethSigner, config.immutableXConfig);
19734
- const ethAddress = await signers.ethSigner.getAddress();
19735
- const ordersApi = new OrdersApi$2(config.immutableXConfig.apiConfiguration);
19736
- const amountSell = request.sell.type === 'ERC721' ? '1' : request.sell.amount;
19737
- const amountBuy = request.buy.type === 'ERC721' ? '1' : request.buy.amount;
19738
- const getSignableOrderRequest = {
19739
- user: ethAddress,
19740
- amount_buy: amountBuy,
19741
- token_buy: convertToSignableToken(request.buy),
19742
- amount_sell: amountSell,
19743
- token_sell: convertToSignableToken(request.sell),
19744
- fees: request.fees,
19745
- expiration_timestamp: request.expiration_timestamp,
19746
- };
19747
- const getSignableOrderResponse = await ordersApi.getSignableOrder({
19748
- getSignableOrderRequestV3: getSignableOrderRequest,
19749
- });
19750
- const { signable_message: signableMessage, payload_hash: payloadHash } = getSignableOrderResponse.data;
19751
- const ethSignature = await signRaw(signableMessage, signers.ethSigner);
19752
- const starkSignature = await signers.starkSigner.signMessage(payloadHash);
19753
- const resp = getSignableOrderResponse.data;
19754
- const orderParams = {
19755
- createOrderRequest: {
19756
- amount_buy: resp.amount_buy,
19757
- amount_sell: resp.amount_sell,
19758
- asset_id_buy: resp.asset_id_buy,
19759
- asset_id_sell: resp.asset_id_sell,
19760
- expiration_timestamp: resp.expiration_timestamp,
19761
- fees: request.fees,
19762
- nonce: resp.nonce,
19763
- stark_key: resp.stark_key,
19764
- stark_signature: starkSignature,
19765
- vault_id_buy: resp.vault_id_buy,
19766
- vault_id_sell: resp.vault_id_sell,
19767
- },
19768
- xImxEthAddress: ethAddress,
19769
- xImxEthSignature: ethSignature,
19770
- };
19771
- const createOrderResponse = await ordersApi.createOrderV3(orderParams);
19772
- return {
19773
- ...createOrderResponse.data,
19774
- };
19775
- }
19776
- async function cancelOrder({ signers, request, config, }) {
19777
- const ordersApi = new OrdersApi$2(config.immutableXConfig.apiConfiguration);
19778
- const getSignableCancelOrderResponse = await ordersApi.getSignableCancelOrderV3({
19779
- getSignableCancelOrderRequest: {
19780
- order_id: request.order_id,
19781
- },
19782
- });
19783
- const { signable_message: signableMessage, payload_hash: payloadHash } = getSignableCancelOrderResponse.data;
19784
- const ethSignature = await signRaw(signableMessage, signers.ethSigner);
19785
- const starkSignature = await signers.starkSigner.signMessage(payloadHash);
19786
- const ethAddress = await signers.ethSigner.getAddress();
19787
- const cancelOrderResponse = await ordersApi.cancelOrderV3({
19788
- id: request.order_id.toString(),
19789
- cancelOrderRequest: {
19790
- order_id: request.order_id,
19791
- stark_signature: starkSignature,
19792
- },
19793
- xImxEthAddress: ethAddress,
19794
- xImxEthSignature: ethSignature,
19795
- });
19796
- return {
19797
- order_id: cancelOrderResponse.data.order_id,
19798
- status: cancelOrderResponse.data.status,
19799
- };
19800
- }
19626
+ const {toString} = Object.prototype;
19627
+ const {getPrototypeOf} = Object;
19801
19628
 
19802
- async function registerOffchain(signers, config) {
19803
- await validateChain(signers.ethSigner, config.immutableXConfig);
19804
- const usersApi = new UsersApi$1(config.immutableXConfig.apiConfiguration);
19805
- const userAddress = await signers.ethSigner.getAddress();
19806
- const starkPublicKey = await signers.starkSigner.getAddress();
19807
- const signableResult = await usersApi.getSignableRegistrationOffchain({
19808
- getSignableRegistrationRequest: {
19809
- ether_key: userAddress,
19810
- stark_key: starkPublicKey,
19811
- },
19812
- });
19813
- const { signable_message: signableMessage, payload_hash: payloadHash } = signableResult.data;
19814
- const ethSignature = await signRaw(signableMessage, signers.ethSigner);
19815
- const starkSignature = await signers.starkSigner.signMessage(payloadHash);
19816
- const registeredUser = await usersApi.registerUser({
19817
- registerUserRequest: {
19818
- eth_signature: ethSignature,
19819
- ether_key: userAddress,
19820
- stark_signature: starkSignature,
19821
- stark_key: starkPublicKey,
19822
- },
19823
- });
19824
- return registeredUser.data;
19825
- }
19826
- async function isRegisteredOffchain(ethAddress, config) {
19827
- try {
19828
- const usersApi = new UsersApi$1(config.immutableXConfig.apiConfiguration);
19829
- const getUsersResult = await usersApi.getUsers({
19830
- user: ethAddress,
19831
- });
19832
- const { accounts } = getUsersResult.data;
19833
- return accounts?.length > 0;
19834
- }
19835
- catch (ex) {
19836
- if (ex instanceof AxiosError$2 && ex.response?.status === 404) {
19837
- return false;
19838
- }
19839
- throw ex;
19840
- }
19841
- }
19842
- async function isRegisteredOnChain(starkPublicKey, ethSigner, config) {
19843
- await validateChain(ethSigner, config.immutableXConfig);
19844
- const registrationContract = Contracts.Registration.connect(config.immutableXConfig.ethConfiguration.registrationContractAddress, ethSigner);
19845
- try {
19846
- return await registrationContract.isRegistered(starkPublicKey);
19847
- }
19848
- catch (ex) {
19849
- if (ex.reason === 'USER_UNREGISTERED') {
19850
- return false;
19851
- }
19852
- throw ex;
19853
- }
19854
- }
19855
- async function getSignableRegistrationOnchain(etherKey, starkPublicKey, usersApi) {
19856
- const response = await usersApi.getSignableRegistration({
19857
- getSignableRegistrationRequest: {
19858
- ether_key: etherKey,
19859
- stark_key: starkPublicKey,
19860
- },
19861
- });
19862
- return {
19863
- operator_signature: response.data.operator_signature,
19864
- payload_hash: response.data.payload_hash,
19865
- readable_transaction: response.data.readable_transaction,
19866
- verification_signature: response.data.verification_signature,
19867
- };
19868
- }
19629
+ const kindOf = (cache => thing => {
19630
+ const str = toString.call(thing);
19631
+ return cache[str] || (cache[str] = str.slice(8, -1).toLowerCase());
19632
+ })(Object.create(null));
19869
19633
 
19870
- const assertIsDefined = (value) => {
19871
- if (value !== undefined)
19872
- return value;
19873
- throw new Error('undefined field exception');
19634
+ const kindOfTest = (type) => {
19635
+ type = type.toLowerCase();
19636
+ return (thing) => kindOf(thing) === type
19874
19637
  };
19875
- async function prepareWithdrawalAction(params) {
19876
- const { signers: { ethSigner, starkSigner }, type, config, } = params;
19877
- await validateChain(ethSigner, params.config);
19878
- const withdrawalsApi = new WithdrawalsApi$1(config.apiConfiguration);
19879
- const withdrawalAmount = type === 'ERC721' ? '1' : params.amount;
19880
- const signableWithdrawalResult = await withdrawalsApi.getSignableWithdrawal({
19881
- getSignableWithdrawalRequest: {
19882
- user: await ethSigner.getAddress(),
19883
- token: convertToSignableToken(params),
19884
- amount: withdrawalAmount,
19885
- },
19886
- });
19887
- const { signable_message: signableMessage, payload_hash: payloadHash } = signableWithdrawalResult.data;
19888
- const starkSignature = await starkSigner.signMessage(payloadHash);
19889
- const { ethAddress, ethSignature } = await signMessage$1(signableMessage, ethSigner);
19890
- const prepareWithdrawalResponse = await withdrawalsApi.createWithdrawal({
19891
- createWithdrawalRequest: {
19892
- stark_key: assertIsDefined(signableWithdrawalResult.data.stark_key),
19893
- amount: withdrawalAmount,
19894
- asset_id: assertIsDefined(signableWithdrawalResult.data.asset_id),
19895
- vault_id: assertIsDefined(signableWithdrawalResult.data.vault_id),
19896
- nonce: assertIsDefined(signableWithdrawalResult.data.nonce),
19897
- stark_signature: starkSignature,
19898
- },
19899
- xImxEthAddress: ethAddress,
19900
- xImxEthSignature: ethSignature,
19901
- });
19902
- return prepareWithdrawalResponse.data;
19903
- }
19904
19638
 
19905
- async function getEncodeAssetInfo(assetType, tokenType, config, tokenData) {
19906
- const encodingApi = new EncodingApi$1(config.apiConfiguration);
19907
- const result = await encodingApi.encodeAsset({
19908
- assetType,
19909
- encodeAssetRequest: {
19910
- token: {
19911
- type: tokenType,
19912
- ...(tokenData && { data: tokenData }),
19913
- },
19914
- },
19915
- });
19916
- return result.data;
19917
- }
19639
+ const typeOfTest = type => thing => typeof thing === type;
19918
19640
 
19919
- async function executeRegisterAndWithdrawERC20({ ethSigner, assetType, starkPublicKey, config, }) {
19920
- const etherKey = await ethSigner.getAddress();
19921
- const imxConfig = config.immutableXConfig;
19922
- const usersApi = new UsersApi$1(imxConfig.apiConfiguration);
19923
- const signableResult = await getSignableRegistrationOnchain(etherKey, starkPublicKey, usersApi);
19924
- const contract = Contracts.Registration.connect(config.immutableXConfig.ethConfiguration.registrationContractAddress, ethSigner);
19925
- const populatedTransaction = await contract.populateTransaction.registerAndWithdraw(etherKey, starkPublicKey, signableResult.operator_signature, assetType);
19926
- return ethSigner.sendTransaction(populatedTransaction);
19927
- }
19928
- async function executeWithdrawERC20(ethSigner, assetType, starkPublicKey, config) {
19929
- const contract = Contracts.Core.connect(config.ethConfiguration.coreContractAddress, ethSigner);
19930
- const populatedTransaction = await contract.populateTransaction.withdraw(starkPublicKey, assetType);
19931
- return ethSigner.sendTransaction(populatedTransaction);
19932
- }
19933
- async function completeERC20WithdrawalAction({ ethSigner, starkPublicKey, token, config, }) {
19934
- await validateChain(ethSigner, config.immutableXConfig);
19935
- const imxConfig = config.immutableXConfig;
19936
- const assetType = await getEncodeAssetInfo('asset', 'ERC20', imxConfig, {
19937
- token_address: token.tokenAddress,
19938
- });
19939
- const isRegistered = await isRegisteredOnChain(starkPublicKey, ethSigner, config);
19940
- if (!isRegistered) {
19941
- return executeRegisterAndWithdrawERC20({
19942
- ethSigner,
19943
- assetType: assetType.asset_type,
19944
- starkPublicKey,
19945
- config,
19946
- });
19947
- }
19948
- return executeWithdrawERC20(ethSigner, assetType.asset_type, starkPublicKey, imxConfig);
19949
- }
19641
+ /**
19642
+ * Determine if a value is an Array
19643
+ *
19644
+ * @param {Object} val The value to test
19645
+ *
19646
+ * @returns {boolean} True if value is an Array, otherwise false
19647
+ */
19648
+ const {isArray} = Array;
19950
19649
 
19951
- async function executeWithdrawMintableERC721(ethSigner, assetType, starkPublicKey, mintingBlob, config) {
19952
- const contract = Contracts.Core.connect(config.ethConfiguration.coreContractAddress, ethSigner);
19953
- const populatedTransaction = await contract.populateTransaction.withdrawAndMint(starkPublicKey, assetType, mintingBlob);
19954
- return ethSigner.sendTransaction(populatedTransaction);
19955
- }
19956
- async function executeRegisterAndWithdrawMintableERC721(ethSigner, assetType, starkPublicKey, mintingBlob, config) {
19957
- const etherKey = await ethSigner.getAddress();
19958
- const usersApi = new UsersApi$1(config.apiConfiguration);
19959
- const signableResult = await getSignableRegistrationOnchain(etherKey, starkPublicKey, usersApi);
19960
- const contract = Contracts.Registration.connect(config.ethConfiguration.registrationContractAddress, ethSigner);
19961
- const populatedTransaction = await contract.populateTransaction.regsiterAndWithdrawAndMint(etherKey, starkPublicKey, signableResult.operator_signature, assetType, mintingBlob);
19962
- return ethSigner.sendTransaction(populatedTransaction);
19963
- }
19964
- function getMintingBlob(token) {
19965
- const { id } = token.data;
19966
- const blueprint = token.data.blueprint || '';
19967
- return encUtils.sanitizeHex(encUtils.utf8ToHex(`{${id}}:{${blueprint}}`));
19968
- }
19969
- async function completeMintableERC721Withdrawal(ethSigner, starkPublicKey, token, config) {
19970
- const imxConfig = config.immutableXConfig;
19971
- const assetType = await getEncodeAssetInfo('mintable-asset', 'ERC721', imxConfig, {
19972
- id: token.data.id,
19973
- token_address: token.data.tokenAddress,
19974
- ...(token.data.blueprint && { blueprint: token.data.blueprint }),
19975
- });
19976
- const mintingBlob = getMintingBlob(token);
19977
- const isRegistered = await isRegisteredOnChain(starkPublicKey, ethSigner, config);
19978
- if (!isRegistered) {
19979
- return executeRegisterAndWithdrawMintableERC721(ethSigner, assetType.asset_type, starkPublicKey, mintingBlob, imxConfig);
19980
- }
19981
- return executeWithdrawMintableERC721(ethSigner, assetType.asset_type, starkPublicKey, mintingBlob, imxConfig);
19982
- }
19983
- async function executeRegisterAndWithdrawERC721(ethSigner, assetType, starkPublicKey, tokenId, config) {
19984
- const etherKey = await ethSigner.getAddress();
19985
- const usersApi = new UsersApi$1(config.apiConfiguration);
19986
- const signableResult = await getSignableRegistrationOnchain(etherKey, starkPublicKey, usersApi);
19987
- const contract = Contracts.Registration.connect(config.ethConfiguration.registrationContractAddress, ethSigner);
19988
- const populatedTransaction = await contract.populateTransaction.registerAndWithdrawNft(etherKey, starkPublicKey, signableResult.operator_signature, assetType, tokenId);
19989
- return ethSigner.sendTransaction(populatedTransaction);
19990
- }
19991
- async function executeWithdrawERC721(ethSigner, assetType, starkPublicKey, tokenId, config) {
19992
- const contract = Contracts.Core.connect(config.ethConfiguration.coreContractAddress, ethSigner);
19993
- const populatedTransaction = await contract.populateTransaction.withdrawNft(starkPublicKey, assetType, tokenId);
19994
- return ethSigner.sendTransaction(populatedTransaction);
19995
- }
19996
- async function completeERC721Withdrawal(ethSigner, starkPublicKey, token, config) {
19997
- const imxConfig = config.immutableXConfig;
19998
- const assetType = await getEncodeAssetInfo('asset', 'ERC721', imxConfig, {
19999
- token_id: token.tokenId,
20000
- token_address: token.tokenAddress,
20001
- });
20002
- const isRegistered = await isRegisteredOnChain(starkPublicKey, ethSigner, config);
20003
- if (!isRegistered) {
20004
- return executeRegisterAndWithdrawERC721(ethSigner, assetType.asset_type, starkPublicKey, token.tokenId, imxConfig);
20005
- }
20006
- return executeWithdrawERC721(ethSigner, assetType.asset_type, starkPublicKey, token.tokenId, imxConfig);
20007
- }
20008
- async function completeERC721WithdrawalAction({ ethSigner, starkPublicKey, token, config, }) {
20009
- await validateChain(ethSigner, config.immutableXConfig);
20010
- const { tokenAddress } = token;
20011
- const { tokenId } = token;
20012
- const imxConfig = config.immutableXConfig;
20013
- const mintsApi = new MintsApi$1(imxConfig.apiConfiguration);
20014
- return await mintsApi
20015
- .getMintableTokenDetailsByClientTokenId({
20016
- tokenAddress,
20017
- tokenId,
20018
- })
20019
- .then((mintableToken) => completeMintableERC721Withdrawal(ethSigner, starkPublicKey, {
20020
- type: 'ERC721',
20021
- data: {
20022
- id: tokenId,
20023
- tokenAddress,
20024
- blueprint: mintableToken.data.blueprint,
20025
- },
20026
- }, config))
20027
- .catch((error) => {
20028
- if (error.response?.status === 404) {
20029
- // token is already minted on L1
20030
- return completeERC721Withdrawal(ethSigner, starkPublicKey, token, config);
20031
- }
20032
- throw error; // unable to recover from any other kind of error
20033
- });
20034
- }
19650
+ /**
19651
+ * Determine if a value is undefined
19652
+ *
19653
+ * @param {*} val The value to test
19654
+ *
19655
+ * @returns {boolean} True if the value is undefined, otherwise false
19656
+ */
19657
+ const isUndefined = typeOfTest('undefined');
20035
19658
 
20036
- async function executeRegisterAndWithdrawEth(ethSigner, assetType, starkPublicKey, config) {
20037
- const etherKey = await ethSigner.getAddress();
20038
- const usersApi = new UsersApi$1(config.apiConfiguration);
20039
- const signableResult = await getSignableRegistrationOnchain(etherKey, starkPublicKey, usersApi);
20040
- const contract = Contracts.Registration.connect(config.ethConfiguration.registrationContractAddress, ethSigner);
20041
- const populatedTransaction = await contract.populateTransaction.registerAndWithdraw(etherKey, starkPublicKey, signableResult.operator_signature, assetType);
20042
- return ethSigner.sendTransaction(populatedTransaction);
20043
- }
20044
- async function executeWithdrawEth(ethSigner, assetType, starkPublicKey, config) {
20045
- const contract = Contracts.Core.connect(config.ethConfiguration.coreContractAddress, ethSigner);
20046
- const populatedTransaction = await contract.populateTransaction.withdraw(starkPublicKey, assetType);
20047
- return ethSigner.sendTransaction(populatedTransaction);
20048
- }
20049
- async function completeEthWithdrawalAction({ ethSigner, starkPublicKey, config, }) {
20050
- await validateChain(ethSigner, config.immutableXConfig);
20051
- const imxConfig = config.immutableXConfig;
20052
- const assetType = await getEncodeAssetInfo('asset', 'ETH', imxConfig);
20053
- const isRegistered = await isRegisteredOnChain(starkPublicKey, ethSigner, config);
20054
- if (!isRegistered) {
20055
- return executeRegisterAndWithdrawEth(ethSigner, assetType.asset_type, starkPublicKey, imxConfig);
20056
- }
20057
- return executeWithdrawEth(ethSigner, assetType.asset_type, starkPublicKey, imxConfig);
19659
+ /**
19660
+ * Determine if a value is a Buffer
19661
+ *
19662
+ * @param {*} val The value to test
19663
+ *
19664
+ * @returns {boolean} True if value is a Buffer, otherwise false
19665
+ */
19666
+ function isBuffer(val) {
19667
+ return val !== null && !isUndefined(val) && val.constructor !== null && !isUndefined(val.constructor)
19668
+ && isFunction(val.constructor.isBuffer) && val.constructor.isBuffer(val);
20058
19669
  }
20059
19670
 
20060
- async function prepareWithdrawal({ signers, withdrawal, config, }) {
20061
- return prepareWithdrawalAction({
20062
- signers,
20063
- config: config.immutableXConfig,
20064
- ...withdrawal,
20065
- });
20066
- }
20067
- // TODO: remove once fixed
20068
- // eslint-disable-next-line consistent-return
20069
- async function completeWithdrawal({ signers: { ethSigner }, starkPublicKey, token, config, }) {
20070
- // TODO: please add a reasonable default here
20071
- // eslint-disable-next-line default-case
20072
- switch (token.type) {
20073
- case 'ETH':
20074
- return completeEthWithdrawalAction({ ethSigner, starkPublicKey, config });
20075
- case 'ERC20':
20076
- return completeERC20WithdrawalAction({
20077
- ethSigner,
20078
- starkPublicKey,
20079
- token,
20080
- config,
20081
- });
20082
- case 'ERC721':
20083
- return completeERC721WithdrawalAction({
20084
- ethSigner,
20085
- starkPublicKey,
20086
- token,
20087
- config,
20088
- });
20089
- }
20090
- }
20091
-
20092
- async function createTrade({ signers: { ethSigner, starkSigner }, request, config, }) {
20093
- await validateChain(ethSigner, config.immutableXConfig);
20094
- const ethAddress = await ethSigner.getAddress();
20095
- const tradesApi = new TradesApi$1(config.immutableXConfig.apiConfiguration);
20096
- const signableResult = await tradesApi.getSignableTrade({
20097
- getSignableTradeRequest: {
20098
- user: ethAddress,
20099
- order_id: request.order_id,
20100
- fees: request.fees,
20101
- },
20102
- });
20103
- const { signable_message: signableMessage, payload_hash: payloadHash } = signableResult.data;
20104
- const ethSignature = await signRaw(signableMessage, ethSigner);
20105
- const starkSignature = await starkSigner.signMessage(payloadHash);
20106
- const createTradeResponse = await tradesApi.createTradeV3({
20107
- createTradeRequest: {
20108
- amount_buy: signableResult.data.amount_buy,
20109
- amount_sell: signableResult.data.amount_sell,
20110
- asset_id_buy: signableResult.data.asset_id_buy,
20111
- asset_id_sell: signableResult.data.asset_id_sell,
20112
- expiration_timestamp: signableResult.data.expiration_timestamp,
20113
- fee_info: signableResult.data.fee_info,
20114
- fees: request.fees,
20115
- include_fees: true,
20116
- nonce: signableResult.data.nonce,
20117
- order_id: request.order_id,
20118
- stark_key: signableResult.data.stark_key,
20119
- vault_id_buy: signableResult.data.vault_id_buy,
20120
- vault_id_sell: signableResult.data.vault_id_sell,
20121
- stark_signature: starkSignature,
20122
- },
20123
- xImxEthAddress: ethAddress,
20124
- xImxEthSignature: ethSignature,
20125
- });
20126
- return createTradeResponse.data;
20127
- }
20128
-
20129
- async function executeRegisterAndDepositEth(ethSigner, amount, assetType, starkPublicKey, vaultId, config, usersApi) {
20130
- const etherKey = await ethSigner.getAddress();
20131
- const coreContract = Contracts.Core.connect(config.ethConfiguration.coreContractAddress, ethSigner);
20132
- const signableResult = await getSignableRegistrationOnchain(etherKey, starkPublicKey, usersApi);
20133
- const populatedTransaction = await coreContract.populateTransaction.registerAndDepositEth(etherKey, starkPublicKey, signableResult.operator_signature, assetType, vaultId);
20134
- return ethSigner.sendTransaction({ ...populatedTransaction, value: amount });
20135
- }
20136
- async function executeDepositEth(ethSigner, amount, assetType, starkPublicKey, vaultId, config) {
20137
- const coreContract = Contracts.Core.connect(config.ethConfiguration.coreContractAddress, ethSigner);
20138
- const populatedTransaction = await coreContract.populateTransaction['deposit(uint256,uint256,uint256)'](starkPublicKey, assetType, vaultId);
20139
- return ethSigner.sendTransaction({ ...populatedTransaction, value: amount });
20140
- }
20141
- async function depositEth({ signers: { ethSigner }, deposit, config, }) {
20142
- await validateChain(ethSigner, config.immutableXConfig);
20143
- const user = await ethSigner.getAddress();
20144
- const data = {
20145
- decimals: 18,
20146
- };
20147
- const amount = parseUnits(deposit.amount, 'wei');
20148
- const imxConfig = config.immutableXConfig;
20149
- const depositsApi = new DepositsApi$1(imxConfig.apiConfiguration);
20150
- const encodingApi = new EncodingApi$1(imxConfig.apiConfiguration);
20151
- const usersApi = new UsersApi$1(imxConfig.apiConfiguration);
20152
- const getSignableDepositRequest = {
20153
- user,
20154
- token: {
20155
- type: deposit.type,
20156
- data,
20157
- },
20158
- amount: amount.toString(),
20159
- };
20160
- const signableDepositResult = await depositsApi.getSignableDeposit({
20161
- getSignableDepositRequest,
20162
- });
20163
- const encodingResult = await encodingApi.encodeAsset({
20164
- assetType: 'asset',
20165
- encodeAssetRequest: {
20166
- token: {
20167
- type: deposit.type,
20168
- },
20169
- },
20170
- });
20171
- const assetType = encodingResult.data.asset_type;
20172
- const starkPublicKey = signableDepositResult.data.stark_key;
20173
- const vaultId = signableDepositResult.data.vault_id;
20174
- const isRegistered = await isRegisteredOnChain(starkPublicKey, ethSigner, config);
20175
- if (!isRegistered) {
20176
- return executeRegisterAndDepositEth(ethSigner, amount, assetType, starkPublicKey, vaultId, imxConfig, usersApi);
20177
- }
20178
- return executeDepositEth(ethSigner, amount, assetType, starkPublicKey, vaultId, imxConfig);
20179
- }
20180
-
20181
- async function executeRegisterAndDepositERC20(ethSigner, quantizedAmount, assetType, starkPublicKey, vaultId, config, usersApi) {
20182
- const etherKey = await ethSigner.getAddress();
20183
- const coreContract = Contracts.Core.connect(config.coreContractAddress, ethSigner);
20184
- const signableResult = await getSignableRegistrationOnchain(etherKey, starkPublicKey, usersApi);
20185
- const populatedTransaction = await coreContract.populateTransaction.registerAndDepositERC20(etherKey, starkPublicKey, signableResult.operator_signature, assetType, vaultId, quantizedAmount);
20186
- return ethSigner.sendTransaction(populatedTransaction);
20187
- }
20188
- async function executeDepositERC20(ethSigner, quantizedAmount, assetType, starkPublicKey, vaultId, config) {
20189
- const coreContract = Contracts.Core.connect(config.coreContractAddress, ethSigner);
20190
- const populatedTransaction = await coreContract.populateTransaction.depositERC20(starkPublicKey, assetType, vaultId, quantizedAmount);
20191
- return ethSigner.sendTransaction(populatedTransaction);
20192
- }
20193
- async function depositERC20({ signers: { ethSigner }, deposit, config, }) {
20194
- await validateChain(ethSigner, config.immutableXConfig);
20195
- const { apiConfiguration, ethConfiguration } = config.immutableXConfig;
20196
- const user = await ethSigner.getAddress();
20197
- const tokensApi = new TokensApi$2(apiConfiguration);
20198
- const depositsApi = new DepositsApi$1(apiConfiguration);
20199
- const encodingApi = new EncodingApi$1(apiConfiguration);
20200
- const usersApi = new UsersApi$1(apiConfiguration);
20201
- // Get decimals for this specific ERC20
20202
- const token = await tokensApi.getToken({ address: deposit.tokenAddress });
20203
- // TODO: remove once fixed
20204
- // eslint-disable-next-line radix
20205
- const decimals = parseInt(token.data.decimals);
20206
- const data = {
20207
- decimals,
20208
- token_address: deposit.tokenAddress,
20209
- };
20210
- const amount = parseUnits(deposit.amount, 0); // 0 to always use undecimalized value
20211
- // Approve whether an amount of token from an account can be spent by a third-party account
20212
- const tokenContract = Contracts.IERC20.connect(deposit.tokenAddress, ethSigner);
20213
- const approveTransaction = await tokenContract.populateTransaction.approve(ethConfiguration.coreContractAddress, amount);
20214
- await ethSigner.sendTransaction(approveTransaction);
20215
- const getSignableDepositRequest = {
20216
- user,
20217
- token: {
20218
- type: deposit.type,
20219
- data,
20220
- },
20221
- amount: amount.toString(),
20222
- };
20223
- const signableDepositResult = await depositsApi.getSignableDeposit({
20224
- getSignableDepositRequest,
20225
- });
20226
- // Perform encoding on asset details to get an assetType (required for stark contract request)
20227
- const encodingResult = await encodingApi.encodeAsset({
20228
- assetType: 'asset',
20229
- encodeAssetRequest: {
20230
- token: {
20231
- type: deposit.type,
20232
- data: {
20233
- token_address: deposit.tokenAddress,
20234
- },
20235
- },
20236
- },
20237
- });
20238
- const assetType = encodingResult.data.asset_type;
20239
- const starkPublicKey = signableDepositResult.data.stark_key;
20240
- const vaultId = signableDepositResult.data.vault_id;
20241
- const quantizedAmount = BigNumber$2.from(signableDepositResult.data.amount);
20242
- const isRegistered = await isRegisteredOnChain(starkPublicKey, ethSigner, config);
20243
- if (!isRegistered) {
20244
- return executeRegisterAndDepositERC20(ethSigner, quantizedAmount, assetType, starkPublicKey, vaultId, ethConfiguration, usersApi);
20245
- }
20246
- return executeDepositERC20(ethSigner, quantizedAmount, assetType, starkPublicKey, vaultId, ethConfiguration);
20247
- }
20248
-
20249
- async function executeDepositERC721(ethSigner, tokenId, assetType, starkPublicKey, vaultId, config) {
20250
- const coreContract = Contracts.Core.connect(config.ethConfiguration.coreContractAddress, ethSigner);
20251
- const populatedTransaction = await coreContract.populateTransaction.depositNft(starkPublicKey, assetType, vaultId, tokenId);
20252
- return ethSigner.sendTransaction(populatedTransaction);
20253
- }
20254
- async function depositERC721({ signers: { ethSigner }, deposit, config, }) {
20255
- await validateChain(ethSigner, config.immutableXConfig);
20256
- const user = await ethSigner.getAddress();
20257
- const { immutableXConfig } = config;
20258
- const depositsApi = new DepositsApi$1(immutableXConfig.apiConfiguration);
20259
- const encodingApi = new EncodingApi$1(immutableXConfig.apiConfiguration);
20260
- const usersApi = new UsersApi$1(immutableXConfig.apiConfiguration);
20261
- const data = {
20262
- token_address: deposit.tokenAddress,
20263
- token_id: deposit.tokenId,
20264
- };
20265
- const amount = '1';
20266
- const getSignableDepositRequest = {
20267
- user,
20268
- token: {
20269
- type: deposit.type,
20270
- data,
20271
- },
20272
- amount: amount.toString(),
20273
- };
20274
- const signableDepositResult = await depositsApi.getSignableDeposit({
20275
- getSignableDepositRequest,
20276
- });
20277
- // Perform encoding on asset details to get an assetType (required for stark contract request)
20278
- const encodingResult = await encodingApi.encodeAsset({
20279
- assetType: 'asset',
20280
- encodeAssetRequest: {
20281
- token: {
20282
- type: deposit.type,
20283
- data: {
20284
- token_address: deposit.tokenAddress,
20285
- token_id: deposit.tokenId,
20286
- },
20287
- },
20288
- },
20289
- });
20290
- const assetType = encodingResult.data.asset_type;
20291
- const starkPublicKey = signableDepositResult.data.stark_key;
20292
- const vaultId = signableDepositResult.data.vault_id;
20293
- const isRegistered = await isRegisteredOnChain(starkPublicKey, ethSigner, config);
20294
- // Approve whether an amount of token from an account can be spent by a third-party account
20295
- const tokenContract = Contracts.IERC721.connect(deposit.tokenAddress, ethSigner);
20296
- const operator = immutableXConfig.ethConfiguration.coreContractAddress;
20297
- const isApprovedForAll = await tokenContract.isApprovedForAll(user, operator);
20298
- if (!isApprovedForAll) {
20299
- await tokenContract.setApprovalForAll(operator, true);
20300
- }
20301
- if (!isRegistered) {
20302
- const signableResult = await getSignableRegistrationOnchain(user, starkPublicKey, usersApi);
20303
- const coreContract = Contracts.Core.connect(immutableXConfig.ethConfiguration.coreContractAddress, ethSigner);
20304
- // Note: proxy registration contract registerAndDepositNft method is not used as
20305
- // it currently fails erc721 transfer ownership check
20306
- await coreContract.registerUser(user, starkPublicKey, signableResult.operator_signature);
20307
- }
20308
- return executeDepositERC721(ethSigner, deposit.tokenId, assetType, starkPublicKey, vaultId, immutableXConfig);
20309
- }
20310
-
20311
- // TODO: remove once fixed deposit variable shadowing
20312
- // eslint-disable-next-line consistent-return, @typescript-eslint/no-shadow
20313
- async function deposit({ signers, deposit, config }) {
20314
- // TODO: please add a reasonable default here
20315
- // eslint-disable-next-line default-case
20316
- switch (deposit.type) {
20317
- case 'ETH':
20318
- return depositEth({ signers, deposit, config });
20319
- case 'ERC20':
20320
- return depositERC20({ signers, deposit, config });
20321
- case 'ERC721':
20322
- return depositERC721({ signers, deposit, config });
20323
- }
20324
- }
20325
-
20326
- async function exchangeTransfer({ signers, request, config, }) {
20327
- await validateChain(signers.ethSigner, config.immutableXConfig);
20328
- const exchangeApi = new ExchangesApi$1(config.immutableXConfig.apiConfiguration);
20329
- const ethAddress = await signers.ethSigner.getAddress();
20330
- const transferAmount = request.amount;
20331
- const signableResult = await exchangeApi.getExchangeSignableTransfer({
20332
- id: request.transactionID,
20333
- getSignableTransferRequest: {
20334
- sender: ethAddress,
20335
- token: convertToSignableToken(request),
20336
- amount: transferAmount,
20337
- receiver: request.receiver,
20338
- },
20339
- });
20340
- const { signable_message: signableMessage, payload_hash: payloadHash } = signableResult.data;
20341
- const ethSignature = await signRaw(signableMessage, signers.ethSigner);
20342
- const starkSignature = await signers.starkSigner.signMessage(payloadHash);
20343
- const transferSigningParams = {
20344
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
20345
- sender_stark_key: signableResult.data.sender_stark_key,
20346
- sender_vault_id: signableResult.data.sender_vault_id,
20347
- receiver_stark_key: signableResult.data.receiver_stark_key,
20348
- receiver_vault_id: signableResult.data.receiver_vault_id,
20349
- asset_id: signableResult.data.asset_id,
20350
- amount: signableResult.data.amount,
20351
- nonce: signableResult.data.nonce,
20352
- expiration_timestamp: signableResult.data.expiration_timestamp,
20353
- stark_signature: starkSignature,
20354
- };
20355
- const response = await exchangeApi.createExchangeTransfer({
20356
- id: request.transactionID,
20357
- createTransferRequest: transferSigningParams,
20358
- xImxEthAddress: ethAddress,
20359
- xImxEthSignature: ethSignature,
20360
- });
20361
- return {
20362
- sent_signature: response?.data.sent_signature,
20363
- status: response?.data.status?.toString(),
20364
- time: response?.data.time,
20365
- transfer_id: response?.data.transfer_id,
20366
- };
20367
- }
20368
-
20369
- class GenericIMXProvider {
20370
- config;
20371
- signers;
20372
- constructor(config, ethSigner, starkSigner) {
20373
- this.config = config;
20374
- this.signers = { ethSigner, starkSigner };
20375
- }
20376
- async getAddress() {
20377
- return this.signers.ethSigner.getAddress();
20378
- }
20379
- async isRegisteredOffchain() {
20380
- const ethAddress = await this.getAddress();
20381
- return isRegisteredOffchain(ethAddress, this.config);
20382
- }
20383
- registerOffchain() {
20384
- return registerOffchain(this.signers, this.config);
20385
- }
20386
- batchNftTransfer(request) {
20387
- return batchTransfer({
20388
- signers: this.signers,
20389
- request,
20390
- config: this.config,
20391
- });
20392
- }
20393
- cancelOrder(request) {
20394
- return cancelOrder({
20395
- signers: this.signers,
20396
- request,
20397
- config: this.config,
20398
- });
20399
- }
20400
- completeWithdrawal(starkPublicKey, token) {
20401
- return completeWithdrawal({
20402
- config: this.config,
20403
- signers: this.signers,
20404
- token,
20405
- starkPublicKey,
20406
- });
20407
- }
20408
- createOrder(request) {
20409
- return createOrder({
20410
- signers: this.signers,
20411
- request,
20412
- config: this.config,
20413
- });
20414
- }
20415
- createTrade(request) {
20416
- return createTrade({
20417
- signers: this.signers,
20418
- request,
20419
- config: this.config,
20420
- });
20421
- }
20422
- deposit(tokenAmount) {
20423
- return deposit({
20424
- signers: this.signers,
20425
- deposit: tokenAmount,
20426
- config: this.config,
20427
- });
20428
- }
20429
- exchangeTransfer(request) {
20430
- return exchangeTransfer({
20431
- signers: this.signers,
20432
- request,
20433
- config: this.config,
20434
- });
20435
- }
20436
- async isRegisteredOnchain() {
20437
- const starkPublicKey = await this.signers.starkSigner.getAddress();
20438
- return isRegisteredOnChain(starkPublicKey, this.signers.ethSigner, this.config);
20439
- }
20440
- prepareWithdrawal(request) {
20441
- return prepareWithdrawal({
20442
- signers: this.signers,
20443
- withdrawal: request,
20444
- config: this.config,
20445
- });
20446
- }
20447
- transfer(request) {
20448
- return transfer({
20449
- signers: this.signers,
20450
- request,
20451
- config: this.config,
20452
- });
20453
- }
20454
- }
20455
-
20456
- const WALLET_ACTION = {
20457
- // TODO: remove once fixed - consider using an enum
20458
- // eslint-disable-next-line @typescript-eslint/naming-convention
20459
- SWITCH_CHAIN: 'wallet_switchEthereumChain',
20460
- // eslint-disable-next-line @typescript-eslint/naming-convention
20461
- CONNECT: 'eth_requestAccounts',
20462
- };
20463
- function isRequestableProvider(provider) {
20464
- return !!provider?.request;
20465
- }
20466
- async function connectProvider(provider, chainID) {
20467
- await provider.request({ method: WALLET_ACTION.CONNECT });
20468
- if (chainID) {
20469
- await provider.request({
20470
- method: WALLET_ACTION.SWITCH_CHAIN,
20471
- params: [{ chainId: `0x${chainID.toString(16)}` }],
20472
- });
20473
- }
20474
- }
20475
-
20476
- const ERRORS = {
20477
- // TODO: remove once fixed - consider using something in line with the naming convention
20478
- // eslint-disable-next-line @typescript-eslint/naming-convention
20479
- PROVIDER_NOT_FOUND: 'The Metamask provider was not found',
20480
- };
20481
- async function connect$1({ chainID, }) {
20482
- const provider = (await detectEthereumProvider());
20483
- if (!isRequestableProvider(provider)) {
20484
- throw new Error(ERRORS.PROVIDER_NOT_FOUND);
20485
- }
20486
- await connectProvider(provider, chainID);
20487
- // NOTE: if we want to listen to Metamask events in the future, we can add a
20488
- // listener here.
20489
- return new ethers.providers.Web3Provider(provider);
20490
- }
20491
-
20492
- const COMMUNICATION_TYPE = 'message';
20493
- var RequestEventType;
20494
- (function (RequestEventType) {
20495
- RequestEventType["GET_CONNECTION_REQUEST"] = "GET_CONNECTION_REQUEST";
20496
- RequestEventType["CONNECT_WALLET_REQUEST"] = "CONNECT_WALLET_REQUEST";
20497
- RequestEventType["SIGN_MESSAGE_REQUEST"] = "SIGN_MESSAGE_REQUEST";
20498
- RequestEventType["DISCONNECT_WALLET_REQUEST"] = "DISCONNECT_WALLET_REQUEST";
20499
- })(RequestEventType || (RequestEventType = {}));
20500
- var ResponseEventType;
20501
- (function (ResponseEventType) {
20502
- ResponseEventType["CONNECT_WALLET_RESPONSE"] = "CONNECT_WALLET_RESPONSE";
20503
- ResponseEventType["SIGN_MESSAGE_RESPONSE"] = "SIGN_MESSAGE_RESPONSE";
20504
- ResponseEventType["GET_CONNECTION_RESPONSE"] = "GET_CONNECTION_RESPONSE";
20505
- ResponseEventType["DISCONNECT_WALLET_RESPONSE"] = "DISCONNECT_WALLET_RESPONSE";
20506
- })(ResponseEventType || (ResponseEventType = {}));
20507
-
20508
- function postRequestMessage(iframe, payload) {
20509
- if (iframe && iframe.contentWindow) {
20510
- iframe.contentWindow.postMessage(payload, new URL(iframe.src).origin);
20511
- }
20512
- }
20513
-
20514
- function messageResponseListener(iframe, event, eventType, callback) {
20515
- if (iframe && event.source !== iframe.contentWindow) {
20516
- return;
20517
- }
20518
- const l2WalletMessage = event.data;
20519
- if (l2WalletMessage.type !== eventType) {
20520
- return;
20521
- }
20522
- callback(l2WalletMessage.details);
20523
- }
20524
-
20525
- class ImxSigner {
20526
- publicAddress;
20527
- iframe;
20528
- constructor(publicAddress, iframe) {
20529
- this.publicAddress = publicAddress;
20530
- this.iframe = iframe;
20531
- }
20532
- getAddress() {
20533
- return this.publicAddress;
20534
- }
20535
- signMessage(rawMessage) {
20536
- return new Promise((resolve, reject) => {
20537
- const listener = (event) => {
20538
- messageResponseListener(this.iframe, event, ResponseEventType.SIGN_MESSAGE_RESPONSE, (messageDetails) => {
20539
- window.removeEventListener(COMMUNICATION_TYPE, listener);
20540
- if (!messageDetails.success) {
20541
- reject(new Error(messageDetails.error?.message));
20542
- }
20543
- resolve(messageDetails.data.signedMessage);
20544
- });
20545
- };
20546
- window.addEventListener(COMMUNICATION_TYPE, listener);
20547
- postRequestMessage(this.iframe, {
20548
- type: RequestEventType.SIGN_MESSAGE_REQUEST,
20549
- details: { starkPublicKey: this.publicAddress, message: rawMessage },
20550
- });
20551
- });
20552
- }
20553
- getIFrame() {
20554
- return this.iframe;
20555
- }
20556
- }
20557
-
20558
- const IMX_WALLET_IFRAME_ID = 'imx-wallet-app';
20559
- const IMX_WALLET_IFRAME_HOSTS = {
20560
- [Environment$1.SANDBOX]: 'https://wallets.sandbox.immutable.com',
20561
- [Environment$1.PRODUCTION]: 'https://wallets.immutable.com',
20562
- };
20563
- const IMX_WALLET_IFRAME_STYLE = 'display: none;';
20564
- function getIFrame() {
20565
- return document.querySelector(`iframe#${IMX_WALLET_IFRAME_ID}`);
20566
- }
20567
- async function setupIFrame(env) {
20568
- return new Promise((resolve) => {
20569
- const iframe = document.createElement('iframe');
20570
- iframe.setAttribute('id', IMX_WALLET_IFRAME_ID);
20571
- iframe.setAttribute('src', IMX_WALLET_IFRAME_HOSTS[env]);
20572
- iframe.setAttribute('style', IMX_WALLET_IFRAME_STYLE);
20573
- document.body.appendChild(iframe);
20574
- iframe.onload = () => resolve(iframe);
20575
- });
20576
- }
20577
- async function getOrSetupIFrame(env) {
20578
- const iframe = getIFrame();
20579
- if (iframe)
20580
- return iframe;
20581
- return await setupIFrame(env);
20582
- }
20583
-
20584
- const DEFAULT_CONNECTION_MESSAGE = 'Only sign this request if you’ve initiated an action with Immutable X.';
20585
- const CONNECTION_FAILED_ERROR = 'The L2 IMX Wallet connection has failed';
20586
- async function connect(l1Provider, env) {
20587
- const l1Signer = l1Provider.getSigner();
20588
- const address = await l1Signer.getAddress();
20589
- const signature = await l1Signer.signMessage(DEFAULT_CONNECTION_MESSAGE);
20590
- const iframe = await getOrSetupIFrame(env);
20591
- return new Promise((resolve, reject) => {
20592
- const listener = (event) => {
20593
- messageResponseListener(iframe, event, ResponseEventType.CONNECT_WALLET_RESPONSE, (messageDetails) => {
20594
- window.removeEventListener(COMMUNICATION_TYPE, listener);
20595
- if (!messageDetails.success) {
20596
- reject(new Error(CONNECTION_FAILED_ERROR));
20597
- }
20598
- resolve(new ImxSigner(messageDetails.data.starkPublicKey, iframe));
20599
- });
20600
- };
20601
- window.addEventListener(COMMUNICATION_TYPE, listener);
20602
- postRequestMessage(iframe, {
20603
- type: RequestEventType.CONNECT_WALLET_REQUEST,
20604
- details: { ethAddress: address, signature },
20605
- });
20606
- });
20607
- }
20608
- async function disconnect(imxSigner) {
20609
- const iframe = imxSigner.getIFrame();
20610
- return new Promise((resolve, reject) => {
20611
- const listener = (event) => {
20612
- messageResponseListener(iframe, event, ResponseEventType.DISCONNECT_WALLET_RESPONSE, (messageDetails) => {
20613
- window.removeEventListener(COMMUNICATION_TYPE, listener);
20614
- if (!messageDetails.success && messageDetails.error) {
20615
- reject(messageDetails.error);
20616
- }
20617
- iframe.remove();
20618
- resolve();
20619
- });
20620
- };
20621
- window.addEventListener(COMMUNICATION_TYPE, listener);
20622
- postRequestMessage(iframe, {
20623
- type: RequestEventType.DISCONNECT_WALLET_REQUEST,
20624
- details: { starkPublicKey: imxSigner.getAddress() },
20625
- });
20626
- });
20627
- }
20628
-
20629
- var ProviderErrorType;
20630
- (function (ProviderErrorType) {
20631
- ProviderErrorType["PROVIDER_CONNECTION_ERROR"] = "PROVIDER_CONNECTION_ERROR";
20632
- ProviderErrorType["WALLET_CONNECTION_ERROR"] = "WALLET_CONNECTION_ERROR";
20633
- })(ProviderErrorType || (ProviderErrorType = {}));
20634
- class ProviderError extends Error {
20635
- type;
20636
- constructor(message, type) {
20637
- super(message);
20638
- this.type = type;
20639
- }
20640
- }
20641
- const withProviderError = async (fn, customError) => {
20642
- try {
20643
- return await fn();
20644
- }
20645
- catch (error) {
20646
- const errorMessage = customError.message || `${error.message}` || 'UnknownError';
20647
- throw new ProviderError(errorMessage, customError.type);
20648
- }
20649
- };
20650
-
20651
- class MetaMaskIMXProvider extends GenericIMXProvider {
20652
- static imxSigner;
20653
- static async connect(config) {
20654
- return await withProviderError(async () => {
20655
- const metaMaskProvider = await connect$1({
20656
- chainID: config.immutableXConfig.ethConfiguration.chainID,
20657
- });
20658
- this.imxSigner = await connect(metaMaskProvider, config.baseConfig.environment);
20659
- return new MetaMaskIMXProvider(config, metaMaskProvider.getSigner(), this.imxSigner);
20660
- }, { type: ProviderErrorType.WALLET_CONNECTION_ERROR });
20661
- }
20662
- static async disconnect() {
20663
- if (!this.imxSigner) {
20664
- throw new ProviderError('Attempted to disconnect from the MetaMask IMX provider without an established connection', ProviderErrorType.PROVIDER_CONNECTION_ERROR);
20665
- }
20666
- return withProviderError(async () => {
20667
- await disconnect(this.imxSigner);
20668
- }, { type: ProviderErrorType.PROVIDER_CONNECTION_ERROR });
20669
- }
20670
- static async signMessage(message) {
20671
- if (!this.imxSigner) {
20672
- throw new ProviderError('Attempted to sign a message with the MetaMask IMX provider without an established connection', ProviderErrorType.PROVIDER_CONNECTION_ERROR);
20673
- }
20674
- return withProviderError(async () => await this.imxSigner.signMessage(message), { type: ProviderErrorType.PROVIDER_CONNECTION_ERROR });
20675
- }
20676
- }
20677
-
20678
- class ProviderConfiguration {
20679
- immutableXConfig;
20680
- baseConfig;
20681
- constructor({ baseConfig, overrides }) {
20682
- this.baseConfig = baseConfig;
20683
- if (overrides) {
20684
- this.immutableXConfig = overrides.immutableXConfig;
20685
- }
20686
- else {
20687
- // TODO: remove once a sensible default is chosen
20688
- // eslint-disable-next-line default-case
20689
- switch (baseConfig.environment) {
20690
- case Environment$1.SANDBOX: {
20691
- this.immutableXConfig = Config.SANDBOX;
20692
- break;
20693
- }
20694
- case Environment$1.PRODUCTION: {
20695
- this.immutableXConfig = Config.PRODUCTION;
20696
- break;
20697
- }
20698
- }
20699
- }
20700
- }
20701
- }
20702
-
20703
- var provider = /*#__PURE__*/Object.freeze({
20704
- __proto__: null,
20705
- GenericIMXProvider: GenericIMXProvider,
20706
- MetaMaskIMXProvider: MetaMaskIMXProvider,
20707
- ProviderConfiguration: ProviderConfiguration
20708
- });
20709
-
20710
- function bind(fn, thisArg) {
20711
- return function wrap() {
20712
- return fn.apply(thisArg, arguments);
20713
- };
20714
- }
20715
-
20716
- // utils is a library of generic helper functions non-specific to axios
20717
-
20718
- const {toString} = Object.prototype;
20719
- const {getPrototypeOf} = Object;
20720
-
20721
- const kindOf = (cache => thing => {
20722
- const str = toString.call(thing);
20723
- return cache[str] || (cache[str] = str.slice(8, -1).toLowerCase());
20724
- })(Object.create(null));
20725
-
20726
- const kindOfTest = (type) => {
20727
- type = type.toLowerCase();
20728
- return (thing) => kindOf(thing) === type
20729
- };
20730
-
20731
- const typeOfTest = type => thing => typeof thing === type;
20732
-
20733
- /**
20734
- * Determine if a value is an Array
20735
- *
20736
- * @param {Object} val The value to test
20737
- *
20738
- * @returns {boolean} True if value is an Array, otherwise false
20739
- */
20740
- const {isArray} = Array;
20741
-
20742
- /**
20743
- * Determine if a value is undefined
20744
- *
20745
- * @param {*} val The value to test
20746
- *
20747
- * @returns {boolean} True if the value is undefined, otherwise false
20748
- */
20749
- const isUndefined = typeOfTest('undefined');
20750
-
20751
- /**
20752
- * Determine if a value is a Buffer
20753
- *
20754
- * @param {*} val The value to test
20755
- *
20756
- * @returns {boolean} True if value is a Buffer, otherwise false
20757
- */
20758
- function isBuffer(val) {
20759
- return val !== null && !isUndefined(val) && val.constructor !== null && !isUndefined(val.constructor)
20760
- && isFunction(val.constructor.isBuffer) && val.constructor.isBuffer(val);
20761
- }
20762
-
20763
- /**
20764
- * Determine if a value is an ArrayBuffer
20765
- *
20766
- * @param {*} val The value to test
20767
- *
20768
- * @returns {boolean} True if value is an ArrayBuffer, otherwise false
20769
- */
20770
- const isArrayBuffer = kindOfTest('ArrayBuffer');
19671
+ /**
19672
+ * Determine if a value is an ArrayBuffer
19673
+ *
19674
+ * @param {*} val The value to test
19675
+ *
19676
+ * @returns {boolean} True if value is an ArrayBuffer, otherwise false
19677
+ */
19678
+ const isArrayBuffer = kindOfTest('ArrayBuffer');
20771
19679
 
20772
19680
 
20773
19681
  /**
@@ -41979,7 +40887,7 @@ const GAS_OVERRIDES = {
41979
40887
  maxPriorityFeePerGas: BigNumber$1.from(101e9),
41980
40888
  };
41981
40889
 
41982
- const SDK_VERSION_MARKER = '0.44.4-alpha.1';
40890
+ const SDK_VERSION_MARKER = '0.45.0';
41983
40891
  // This SDK version is replaced by the `yarn build` command ran on the root level
41984
40892
  const globalPackageVersion = () => SDK_VERSION_MARKER;
41985
40893
 
@@ -42473,7 +41381,7 @@ const getBalances = async (config, web3Provider, walletAddress, tokens) => {
42473
41381
  });
42474
41382
  return { balances };
42475
41383
  };
42476
- const getAllBalances = async (config, web3Provider, walletAddress, chainId) => {
41384
+ const getAllBalances = async (config, web3Provider, walletAddress, chainId, forceFetch = false) => {
42477
41385
  if (!walletAddress && !web3Provider) {
42478
41386
  throw new CheckoutError('both walletAddress and provider are missing. At least one must be provided.', CheckoutErrorType.MISSING_PARAMS);
42479
41387
  }
@@ -42495,6 +41403,9 @@ const getAllBalances = async (config, web3Provider, walletAddress, chainId) => {
42495
41403
  // eslint-disable-next-line no-console
42496
41404
  console.error(err);
42497
41405
  }
41406
+ if (forceFetch) {
41407
+ resetBlockscoutClientMap();
41408
+ }
42498
41409
  let address = walletAddress;
42499
41410
  if (flag && Blockscout.isChainSupported(chainId)) {
42500
41411
  // This is a hack because the widgets are still using the tokens symbol
@@ -43371,7 +42282,7 @@ const getTokenBalanceRequirement = (itemRequirement, balances) => {
43371
42282
  /**
43372
42283
  * Gets the balances for all NATIVE and ERC20 balance requirements.
43373
42284
  */
43374
- const getTokenBalances = async (config, provider, ownerAddress, itemRequirements) => {
42285
+ const getTokenBalances = async (config, provider, ownerAddress, itemRequirements, forceFetch = false) => {
43375
42286
  try {
43376
42287
  const tokenMap = new Map();
43377
42288
  getTokensFromRequirements(itemRequirements).forEach((item) => {
@@ -43379,7 +42290,7 @@ const getTokenBalances = async (config, provider, ownerAddress, itemRequirements
43379
42290
  return;
43380
42291
  tokenMap.set(item.address.toLocaleLowerCase(), item);
43381
42292
  });
43382
- const { balances } = await getAllBalances(config, provider, ownerAddress, getL2ChainId(config));
42293
+ const { balances } = await getAllBalances(config, provider, ownerAddress, getL2ChainId(config), forceFetch);
43383
42294
  return balances.filter((balance) => tokenMap.get((balance.token.address || NATIVE).toLocaleLowerCase()));
43384
42295
  }
43385
42296
  catch (err) {
@@ -43429,7 +42340,7 @@ const getERC721Balances = async (provider, ownerAddress, itemRequirements) => {
43429
42340
  /**
43430
42341
  * Checks the item requirements against the owner balances.
43431
42342
  */
43432
- const balanceCheck = async (config, provider, ownerAddress, itemRequirements) => {
42343
+ const balanceCheck = async (config, provider, ownerAddress, itemRequirements, forceFetch = false) => {
43433
42344
  const aggregatedItems = balanceAggregator(itemRequirements);
43434
42345
  const requiredToken = [];
43435
42346
  const requiredERC721 = [];
@@ -43450,7 +42361,7 @@ const balanceCheck = async (config, provider, ownerAddress, itemRequirements) =>
43450
42361
  // Get all ERC20 and NATIVE balances
43451
42362
  const balancePromises = [];
43452
42363
  if (requiredToken.length > 0) {
43453
- balancePromises.push(getTokenBalances(config, provider, ownerAddress, aggregatedItems));
42364
+ balancePromises.push(getTokenBalances(config, provider, ownerAddress, aggregatedItems, forceFetch));
43454
42365
  }
43455
42366
  // Get all ERC721 balances
43456
42367
  if (requiredERC721.length > 0) {
@@ -44813,7 +43724,7 @@ const smartCheckout = async (config, provider, itemRequirements, transactionOrGa
44813
43724
  aggregatedItems.push(gasItem);
44814
43725
  aggregatedItems = itemAggregator(aggregatedItems);
44815
43726
  }
44816
- const balanceCheckResult = await measureAsyncExecution(config, 'Time to run balance checks', balanceCheck(config, provider, ownerAddress, aggregatedItems));
43727
+ const balanceCheckResult = await measureAsyncExecution(config, 'Time to run balance checks', balanceCheck(config, provider, ownerAddress, aggregatedItems, true));
44817
43728
  const { sufficient } = balanceCheckResult;
44818
43729
  const transactionRequirements = balanceCheckResult.balanceRequirements;
44819
43730
  if (sufficient) {
@@ -44869,1093 +43780,2181 @@ const signFulfillmentTransactions = async (provider, fulfillmentTransactions) =>
44869
43780
  receipts = await Promise.all(response.map((transaction) => transaction.transactionResponse.wait()));
44870
43781
  }
44871
43782
  catch (err) {
44872
- throw new CheckoutError('An error occurred while executing the fulfillment transaction', CheckoutErrorType.EXECUTE_FULFILLMENT_TRANSACTION_ERROR, { error: err });
43783
+ throw new CheckoutError('An error occurred while executing the fulfillment transaction', CheckoutErrorType.EXECUTE_FULFILLMENT_TRANSACTION_ERROR, { error: err });
43784
+ }
43785
+ for (const receipt of receipts) {
43786
+ if (receipt.status === 0) {
43787
+ return {
43788
+ type: SignTransactionStatusType.FAILED,
43789
+ transactionHash: receipt.transactionHash,
43790
+ reason: 'Fulfillment transaction failed and was reverted',
43791
+ };
43792
+ }
43793
+ }
43794
+ return {
43795
+ type: SignTransactionStatusType.SUCCESS,
43796
+ };
43797
+ };
43798
+ const signMessage = async (provider, unsignedMessage) => {
43799
+ try {
43800
+ // eslint-disable-next-line no-underscore-dangle
43801
+ const signedMessage = await provider.getSigner()._signTypedData(unsignedMessage.unsignedMessage.domain, unsignedMessage.unsignedMessage.types, unsignedMessage.unsignedMessage.value);
43802
+ return {
43803
+ orderComponents: unsignedMessage.orderComponents,
43804
+ orderHash: unsignedMessage.orderHash,
43805
+ signedMessage,
43806
+ };
43807
+ }
43808
+ catch (err) {
43809
+ throw new CheckoutError('An error occurred while signing the message', CheckoutErrorType.SIGN_MESSAGE_ERROR, { error: err });
43810
+ }
43811
+ };
43812
+
43813
+ const getUnsignedERC721Transactions = async (actions) => {
43814
+ let approvalTransactions = [];
43815
+ let fulfillmentTransactions = [];
43816
+ const approvalPromises = [];
43817
+ const fulfillmentPromises = [];
43818
+ for (const action of actions) {
43819
+ if (action.type !== ActionType.TRANSACTION)
43820
+ continue;
43821
+ if (action.purpose === TransactionPurpose.APPROVAL) {
43822
+ approvalPromises.push(action.buildTransaction());
43823
+ }
43824
+ if (action.purpose === TransactionPurpose.FULFILL_ORDER) {
43825
+ fulfillmentPromises.push(action.buildTransaction());
43826
+ }
43827
+ }
43828
+ approvalTransactions = await Promise.all(approvalPromises);
43829
+ fulfillmentTransactions = await Promise.all(fulfillmentPromises);
43830
+ return {
43831
+ approvalTransactions,
43832
+ fulfillmentTransactions,
43833
+ };
43834
+ };
43835
+ const getUnsignedERC20ApprovalTransactions = async (actions) => {
43836
+ let approvalTransactions = [];
43837
+ const approvalPromises = [];
43838
+ for (const action of actions) {
43839
+ if (action.type !== ActionType.TRANSACTION)
43840
+ continue;
43841
+ if (action.purpose === TransactionPurpose.APPROVAL) {
43842
+ approvalPromises.push(action.buildTransaction());
43843
+ }
43844
+ }
43845
+ approvalTransactions = await Promise.all(approvalPromises);
43846
+ return approvalTransactions;
43847
+ };
43848
+ const getUnsignedFulfillmentTransactions = async (actions) => {
43849
+ let fulfillmentTransactions = [];
43850
+ const fulfillmentPromises = [];
43851
+ for (const action of actions) {
43852
+ if (action.type !== ActionType.TRANSACTION)
43853
+ continue;
43854
+ if (action.purpose === TransactionPurpose.FULFILL_ORDER) {
43855
+ fulfillmentPromises.push(action.buildTransaction());
43856
+ }
43857
+ }
43858
+ fulfillmentTransactions = await Promise.all(fulfillmentPromises);
43859
+ return fulfillmentTransactions;
43860
+ };
43861
+ const getUnsignedMessage = (orderHash, orderComponents, actions) => {
43862
+ let unsignedMessage;
43863
+ for (const action of actions) {
43864
+ if (action.type !== ActionType.SIGNABLE)
43865
+ continue;
43866
+ if (action.purpose === SignablePurpose.CREATE_LISTING) {
43867
+ unsignedMessage = {
43868
+ domain: action.message.domain,
43869
+ types: action.message.types,
43870
+ value: action.message.value,
43871
+ };
43872
+ }
43873
+ }
43874
+ if (!unsignedMessage)
43875
+ return undefined;
43876
+ return {
43877
+ orderHash,
43878
+ orderComponents,
43879
+ unsignedMessage,
43880
+ };
43881
+ };
43882
+
43883
+ const MAX_FEE_PERCENTAGE_DECIMAL = 1; // 100%
43884
+ const MAX_FEE_DECIMAL_PLACES = 6; // will allow 0.000001 (0.0001%) as the minimum value
43885
+ const calculateFeesPercent = (orderFee, amountBn) => {
43886
+ const feePercentage = orderFee.amount;
43887
+ // note: multiply in and out of the maximum decimal places to the power of ten to do the math in big number integers
43888
+ const feePercentageMultiplier = Math.round(feePercentage.percentageDecimal * (10 ** MAX_FEE_DECIMAL_PLACES));
43889
+ const bnFeeAmount = amountBn
43890
+ .mul(BigNumber$1.from(feePercentageMultiplier))
43891
+ .div(10 ** MAX_FEE_DECIMAL_PLACES);
43892
+ return bnFeeAmount;
43893
+ };
43894
+ const calculateFeesToken = (orderFee, decimals) => {
43895
+ const feeToken = orderFee.amount;
43896
+ const bnFeeAmount = utils$3.parseUnits(feeToken.token, decimals);
43897
+ return bnFeeAmount;
43898
+ };
43899
+ const calculateFees = (orderFees, weiAmount, decimals = 18) => {
43900
+ let totalTokenFees = BigNumber$1.from(0);
43901
+ const amountBn = BigNumber$1.from(weiAmount);
43902
+ // note: multiply in and out of the maximum decimal places to the power of ten to do the math in big number integers
43903
+ const totalAllowableFees = amountBn
43904
+ .mul(MAX_FEE_PERCENTAGE_DECIMAL * (10 ** MAX_FEE_DECIMAL_PLACES))
43905
+ .div(10 ** MAX_FEE_DECIMAL_PLACES);
43906
+ const calculateFeesResult = [];
43907
+ for (const orderFee of orderFees) {
43908
+ let currentFeeBn = BigNumber$1.from(0);
43909
+ if (Object.hasOwn(orderFee.amount, 'percentageDecimal')) {
43910
+ currentFeeBn = calculateFeesPercent(orderFee, amountBn);
43911
+ totalTokenFees = totalTokenFees.add(currentFeeBn);
43912
+ }
43913
+ else if (Object.hasOwn(orderFee.amount, 'token')) {
43914
+ currentFeeBn = calculateFeesToken(orderFee, decimals);
43915
+ totalTokenFees = totalTokenFees.add(currentFeeBn);
43916
+ }
43917
+ else {
43918
+ throw new CheckoutError('Unknown fee type parsed, must be percentageDecimal or token', CheckoutErrorType.ORDER_FEE_ERROR);
43919
+ }
43920
+ if (totalTokenFees.gt(totalAllowableFees)) {
43921
+ throw new CheckoutError(`The combined fees are above the allowed maximum of ${MAX_FEE_PERCENTAGE_DECIMAL * 100}%`, CheckoutErrorType.ORDER_FEE_ERROR);
43922
+ }
43923
+ if (currentFeeBn.gt(0)) {
43924
+ calculateFeesResult.push({
43925
+ amount: currentFeeBn.toString(),
43926
+ recipientAddress: orderFee.recipient,
43927
+ });
43928
+ }
43929
+ } // for
43930
+ return calculateFeesResult;
43931
+ };
43932
+
43933
+ const getItemRequirement = (type, tokenAddress, amount, spenderAddress) => {
43934
+ switch (type) {
43935
+ case ItemType.ERC20:
43936
+ return {
43937
+ type,
43938
+ amount,
43939
+ tokenAddress,
43940
+ spenderAddress,
43941
+ };
43942
+ case ItemType.NATIVE:
43943
+ default:
43944
+ return {
43945
+ type: ItemType.NATIVE,
43946
+ amount,
43947
+ };
43948
+ }
43949
+ };
43950
+ const getTransactionOrGas = (gasLimit, fulfillmentTransactions) => {
43951
+ if (fulfillmentTransactions.length > 0) {
43952
+ return {
43953
+ type: TransactionOrGasType.TRANSACTION,
43954
+ transaction: fulfillmentTransactions[0],
43955
+ };
43956
+ }
43957
+ return {
43958
+ type: TransactionOrGasType.GAS,
43959
+ gasToken: {
43960
+ type: GasTokenType.NATIVE,
43961
+ limit: BigNumber$1.from(gasLimit),
43962
+ },
43963
+ };
43964
+ };
43965
+ const buy = async (config, provider, orders, overrides = {
43966
+ waitFulfillmentSettlements: true,
43967
+ }) => {
43968
+ if (orders.length === 0) {
43969
+ throw new CheckoutError('No orders were provided to the orders array. Please provide at least one order.', CheckoutErrorType.FULFILL_ORDER_LISTING_ERROR);
43970
+ }
43971
+ let order;
43972
+ let spenderAddress = '';
43973
+ let decimals = 18;
43974
+ const gasLimit = constants.estimatedFulfillmentGasGwei;
43975
+ const orderbook = createOrderbookInstance(config);
43976
+ const blockchainClient = createBlockchainDataInstance(config);
43977
+ const fulfillerAddress = await measureAsyncExecution(config, 'Time to get the address from the provider', provider.getSigner().getAddress());
43978
+ // Prefetch balances and store them in memory
43979
+ resetBlockscoutClientMap();
43980
+ getAllBalances(config, provider, fulfillerAddress, getL1ChainId(config));
43981
+ getAllBalances(config, provider, fulfillerAddress, getL2ChainId(config));
43982
+ const { id, takerFees } = orders[0];
43983
+ let orderChainName;
43984
+ try {
43985
+ order = await measureAsyncExecution(config, 'Time to fetch the listing from the orderbook', orderbook.getListing(id));
43986
+ const { seaportContractAddress, chainName } = orderbook.config();
43987
+ orderChainName = chainName;
43988
+ spenderAddress = seaportContractAddress;
43989
+ }
43990
+ catch (err) {
43991
+ throw new CheckoutError('An error occurred while getting the order listing', CheckoutErrorType.GET_ORDER_LISTING_ERROR, {
43992
+ error: err,
43993
+ orderId: id,
43994
+ });
43995
+ }
43996
+ if (order.result.buy.length === 0) {
43997
+ throw new CheckoutError('An error occurred with the get order listing', CheckoutErrorType.GET_ORDER_LISTING_ERROR, {
43998
+ orderId: id,
43999
+ message: 'No buy side tokens found on order',
44000
+ });
44001
+ }
44002
+ const buyToken = order.result.buy[0];
44003
+ if (buyToken.type === 'ERC20') {
44004
+ const token = await measureAsyncExecution(config, 'Time to get decimals of token contract for the buy token', blockchainClient.getToken({ contractAddress: buyToken.contractAddress, chainName: orderChainName }));
44005
+ if (token.result.decimals)
44006
+ decimals = token.result.decimals;
44007
+ }
44008
+ let fees = [];
44009
+ if (takerFees && takerFees.length > 0) {
44010
+ fees = calculateFees(takerFees, buyToken.amount, decimals);
44011
+ }
44012
+ let unsignedApprovalTransactions = [];
44013
+ let unsignedFulfillmentTransactions = [];
44014
+ let orderActions = [];
44015
+ const fulfillOrderStartTime = performance.now();
44016
+ try {
44017
+ const { actions } = await measureAsyncExecution(config, 'Time to call fulfillOrder from the orderbook', orderbook.fulfillOrder(id, fulfillerAddress, fees));
44018
+ orderActions = actions;
44019
+ unsignedApprovalTransactions = await measureAsyncExecution(config, 'Time to construct the unsigned approval transactions', getUnsignedERC20ApprovalTransactions(actions));
44020
+ }
44021
+ catch (err) {
44022
+ const elapsedTimeInSeconds = (performance.now() - fulfillOrderStartTime) / 1000;
44023
+ debugLogger(config, 'Time to call fulfillOrder from the orderbook', elapsedTimeInSeconds);
44024
+ if (err.message.includes(OrderStatusName.EXPIRED)) {
44025
+ throw new CheckoutError('Order is expired', CheckoutErrorType.ORDER_EXPIRED_ERROR, { orderId: id });
44026
+ }
44027
+ // The balances error will be handled by bulk order fulfillment but for now we
44028
+ // need to assert on this string to check that the error is not a balances error
44029
+ if (!err.message.includes('The fulfiller does not have the balances needed to fulfill')) {
44030
+ throw new CheckoutError('Error occurred while trying to fulfill the order', CheckoutErrorType.FULFILL_ORDER_LISTING_ERROR, {
44031
+ orderId: id,
44032
+ error: err,
44033
+ });
44034
+ }
44035
+ }
44036
+ try {
44037
+ unsignedFulfillmentTransactions = await measureAsyncExecution(config, 'Time to construct the unsigned fulfillment transactions', getUnsignedFulfillmentTransactions(orderActions));
44038
+ }
44039
+ catch {
44040
+ // if cannot estimate gas then silently continue and use gas limit in smartCheckout
44041
+ // but get the fulfillment transactions after they have approved the spending
44042
+ }
44043
+ let amount = BigNumber$1.from('0');
44044
+ let type = ItemType.NATIVE;
44045
+ let contractAddress = '';
44046
+ const buyArray = order.result.buy;
44047
+ if (buyArray.length > 0) {
44048
+ switch (buyArray[0].type) {
44049
+ case 'NATIVE':
44050
+ type = ItemType.NATIVE;
44051
+ break;
44052
+ case 'ERC20':
44053
+ type = ItemType.ERC20;
44054
+ contractAddress = buyArray[0].contractAddress;
44055
+ break;
44056
+ default:
44057
+ throw new CheckoutError('Purchasing token type is unsupported', CheckoutErrorType.UNSUPPORTED_TOKEN_TYPE_ERROR, {
44058
+ orderId: id,
44059
+ });
44060
+ }
44061
+ }
44062
+ buyArray.forEach((item) => {
44063
+ if (item.type !== ItemType.ERC721) {
44064
+ amount = amount.add(BigNumber$1.from(item.amount));
44065
+ }
44066
+ });
44067
+ const feeArray = order.result.fees;
44068
+ feeArray.forEach((item) => {
44069
+ amount = amount.add(BigNumber$1.from(item.amount));
44070
+ });
44071
+ const itemRequirements = [
44072
+ getItemRequirement(type, contractAddress, amount, spenderAddress),
44073
+ ];
44074
+ const smartCheckoutResult = await measureAsyncExecution(config, 'Total time running smart checkout', smartCheckout(config, provider, itemRequirements, getTransactionOrGas(gasLimit, unsignedFulfillmentTransactions)));
44075
+ if (smartCheckoutResult.sufficient) {
44076
+ const approvalResult = await signApprovalTransactions(provider, unsignedApprovalTransactions);
44077
+ if (approvalResult.type === SignTransactionStatusType.FAILED) {
44078
+ return {
44079
+ status: CheckoutStatus.FAILED,
44080
+ transactionHash: approvalResult.transactionHash,
44081
+ reason: approvalResult.reason,
44082
+ smartCheckoutResult,
44083
+ };
44084
+ }
44085
+ try {
44086
+ if (unsignedFulfillmentTransactions.length === 0) {
44087
+ unsignedFulfillmentTransactions = await getUnsignedFulfillmentTransactions(orderActions);
44088
+ }
44089
+ }
44090
+ catch (err) {
44091
+ throw new CheckoutError('Error fetching fulfillment transaction', CheckoutErrorType.FULFILL_ORDER_LISTING_ERROR, { error: err });
44092
+ }
44093
+ if (overrides.waitFulfillmentSettlements) {
44094
+ const fulfillmentResult = await signFulfillmentTransactions(provider, unsignedFulfillmentTransactions);
44095
+ if (fulfillmentResult.type === SignTransactionStatusType.FAILED) {
44096
+ return {
44097
+ status: CheckoutStatus.FAILED,
44098
+ transactionHash: fulfillmentResult.transactionHash,
44099
+ reason: fulfillmentResult.reason,
44100
+ smartCheckoutResult,
44101
+ };
44102
+ }
44103
+ return {
44104
+ status: CheckoutStatus.SUCCESS,
44105
+ smartCheckoutResult,
44106
+ };
44107
+ }
44108
+ let transactions;
44109
+ try {
44110
+ const response = await Promise.all(unsignedFulfillmentTransactions.map((transaction) => sendTransaction(provider, transaction)));
44111
+ transactions = response.map((result) => result.transactionResponse);
44112
+ }
44113
+ catch (err) {
44114
+ throw new CheckoutError('An error occurred while executing the fulfillment transaction', CheckoutErrorType.EXECUTE_FULFILLMENT_TRANSACTION_ERROR, {
44115
+ message: err.message,
44116
+ });
44117
+ }
44118
+ return {
44119
+ status: CheckoutStatus.FULFILLMENTS_UNSETTLED,
44120
+ smartCheckoutResult,
44121
+ transactions,
44122
+ };
44123
+ }
44124
+ return {
44125
+ status: CheckoutStatus.INSUFFICIENT_FUNDS,
44126
+ smartCheckoutResult,
44127
+ };
44128
+ };
44129
+
44130
+ const cancel = async (config, provider, orderIds, overrides = {
44131
+ waitFulfillmentSettlements: true,
44132
+ }) => {
44133
+ let unsignedCancelOrderTransaction;
44134
+ if (orderIds.length === 0) {
44135
+ throw new CheckoutError('No orderIds were provided to the orderIds array. Please provide at least one orderId.', CheckoutErrorType.CANCEL_ORDER_LISTING_ERROR);
44136
+ }
44137
+ // Update this when bulk cancel is supported
44138
+ const orderId = orderIds[0];
44139
+ try {
44140
+ const offererAddress = await measureAsyncExecution(config, 'Time to get the address from the provider', provider.getSigner().getAddress());
44141
+ const orderbook = createOrderbookInstance(config);
44142
+ const cancelOrderResponse = await measureAsyncExecution(config, 'Time to get the cancel order from the orderbook', orderbook.cancelOrdersOnChain([orderId], offererAddress));
44143
+ unsignedCancelOrderTransaction = await cancelOrderResponse.cancellationAction.buildTransaction();
44144
+ }
44145
+ catch (err) {
44146
+ throw new CheckoutError('An error occurred while cancelling the order listing', CheckoutErrorType.CANCEL_ORDER_LISTING_ERROR, {
44147
+ orderId,
44148
+ error: err,
44149
+ });
44150
+ }
44151
+ if (overrides.waitFulfillmentSettlements) {
44152
+ const result = await signFulfillmentTransactions(provider, [unsignedCancelOrderTransaction]);
44153
+ if (result.type === SignTransactionStatusType.FAILED) {
44154
+ return {
44155
+ status: CheckoutStatus.FAILED,
44156
+ transactionHash: result.transactionHash,
44157
+ reason: result.reason,
44158
+ };
44159
+ }
44160
+ return {
44161
+ status: CheckoutStatus.SUCCESS,
44162
+ };
44163
+ }
44164
+ let transactions;
44165
+ try {
44166
+ const response = await Promise.all([unsignedCancelOrderTransaction].map((transaction) => sendTransaction(provider, transaction)));
44167
+ transactions = response.map((result) => result.transactionResponse);
44168
+ }
44169
+ catch (err) {
44170
+ throw new CheckoutError('An error occurred while executing the fulfillment transaction', CheckoutErrorType.EXECUTE_FULFILLMENT_TRANSACTION_ERROR, {
44171
+ message: err.message,
44172
+ });
44173
+ }
44174
+ return {
44175
+ status: CheckoutStatus.FULFILLMENTS_UNSETTLED,
44176
+ transactions,
44177
+ };
44178
+ };
44179
+
44180
+ const getERC721Requirement = (id, contractAddress, spenderAddress) => ({
44181
+ type: ItemType.ERC721,
44182
+ id,
44183
+ contractAddress,
44184
+ spenderAddress,
44185
+ });
44186
+ const getBuyToken = (buyToken, decimals = 18) => {
44187
+ const bnAmount = utils$3.parseUnits(buyToken.amount, decimals);
44188
+ if (buyToken.type === ItemType.NATIVE) {
44189
+ return {
44190
+ type: ItemType.NATIVE,
44191
+ amount: bnAmount.toString(),
44192
+ };
44193
+ }
44194
+ return {
44195
+ type: ItemType.ERC20,
44196
+ amount: bnAmount.toString(),
44197
+ contractAddress: buyToken.tokenAddress,
44198
+ };
44199
+ };
44200
+ const sell = async (config, provider, orders) => {
44201
+ let orderbook;
44202
+ let listing;
44203
+ let spenderAddress = '';
44204
+ if (orders.length === 0) {
44205
+ throw new CheckoutError('No orders were provided to the orders array. Please provide at least one order.', CheckoutErrorType.PREPARE_ORDER_LISTING_ERROR);
44206
+ }
44207
+ const { buyToken, sellToken, makerFees, orderExpiry, } = orders[0];
44208
+ let decimals = 18;
44209
+ if (buyToken.type === ItemType.ERC20) {
44210
+ // get this from the allowed list
44211
+ const buyTokenContract = new Contract$1(buyToken.tokenAddress, JSON.stringify(ERC20ABI), provider);
44212
+ decimals = await measureAsyncExecution(config, 'Time to get decimals of token contract for the buy token', buyTokenContract.decimals());
44213
+ }
44214
+ const buyTokenOrNative = getBuyToken(buyToken, decimals);
44215
+ try {
44216
+ const walletAddress = await measureAsyncExecution(config, 'Time to get the address from the provider', provider.getSigner().getAddress());
44217
+ orderbook = createOrderbookInstance(config);
44218
+ const { seaportContractAddress } = orderbook.config();
44219
+ spenderAddress = seaportContractAddress;
44220
+ listing = await measureAsyncExecution(config, 'Time to prepare the listing from the orderbook', orderbook.prepareListing({
44221
+ makerAddress: walletAddress,
44222
+ buy: buyTokenOrNative,
44223
+ sell: {
44224
+ type: ItemType.ERC721,
44225
+ contractAddress: sellToken.collectionAddress,
44226
+ tokenId: sellToken.id,
44227
+ },
44228
+ orderExpiry,
44229
+ }));
44230
+ }
44231
+ catch (err) {
44232
+ throw new CheckoutError('An error occurred while preparing the listing', CheckoutErrorType.PREPARE_ORDER_LISTING_ERROR, {
44233
+ error: err,
44234
+ id: sellToken.id,
44235
+ collectionAddress: sellToken.collectionAddress,
44236
+ });
44873
44237
  }
44874
- for (const receipt of receipts) {
44875
- if (receipt.status === 0) {
44238
+ const itemRequirements = [
44239
+ getERC721Requirement(sellToken.id, sellToken.collectionAddress, spenderAddress),
44240
+ ];
44241
+ const smartCheckoutResult = await measureAsyncExecution(config, 'Total time running smart checkout', smartCheckout(config, provider, itemRequirements, {
44242
+ type: TransactionOrGasType.GAS,
44243
+ gasToken: {
44244
+ type: GasTokenType.NATIVE,
44245
+ limit: BigNumber$1.from(constants.estimatedFulfillmentGasGwei),
44246
+ },
44247
+ }));
44248
+ if (smartCheckoutResult.sufficient) {
44249
+ const unsignedTransactions = await getUnsignedERC721Transactions(listing.actions);
44250
+ const approvalResult = await signApprovalTransactions(provider, unsignedTransactions.approvalTransactions);
44251
+ if (approvalResult.type === SignTransactionStatusType.FAILED) {
44876
44252
  return {
44877
- type: SignTransactionStatusType.FAILED,
44878
- transactionHash: receipt.transactionHash,
44879
- reason: 'Fulfillment transaction failed and was reverted',
44253
+ status: CheckoutStatus.FAILED,
44254
+ transactionHash: approvalResult.transactionHash,
44255
+ reason: approvalResult.reason,
44256
+ smartCheckoutResult,
44880
44257
  };
44881
44258
  }
44882
- }
44883
- return {
44884
- type: SignTransactionStatusType.SUCCESS,
44885
- };
44886
- };
44887
- const signMessage = async (provider, unsignedMessage) => {
44888
- try {
44889
- // eslint-disable-next-line no-underscore-dangle
44890
- const signedMessage = await provider.getSigner()._signTypedData(unsignedMessage.unsignedMessage.domain, unsignedMessage.unsignedMessage.types, unsignedMessage.unsignedMessage.value);
44891
- return {
44892
- orderComponents: unsignedMessage.orderComponents,
44893
- orderHash: unsignedMessage.orderHash,
44894
- signedMessage,
44259
+ const unsignedMessage = getUnsignedMessage(listing.orderHash, listing.orderComponents, listing.actions);
44260
+ if (!unsignedMessage) {
44261
+ // For sell it is expected the orderbook will always return an unsigned message
44262
+ // If for some reason it is missing then we cannot proceed with the create listing
44263
+ throw new CheckoutError('The unsigned message is missing after preparing the listing', CheckoutErrorType.SIGN_MESSAGE_ERROR, {
44264
+ id: sellToken.id,
44265
+ collectionAddress: sellToken.collectionAddress,
44266
+ });
44267
+ }
44268
+ const signedMessage = await signMessage(provider, unsignedMessage);
44269
+ let orderId = '';
44270
+ const createListingParams = {
44271
+ orderComponents: signedMessage.orderComponents,
44272
+ orderHash: signedMessage.orderHash,
44273
+ orderSignature: signedMessage.signedMessage,
44274
+ makerFees: [],
44895
44275
  };
44896
- }
44897
- catch (err) {
44898
- throw new CheckoutError('An error occurred while signing the message', CheckoutErrorType.SIGN_MESSAGE_ERROR, { error: err });
44899
- }
44900
- };
44901
-
44902
- const getUnsignedERC721Transactions = async (actions) => {
44903
- let approvalTransactions = [];
44904
- let fulfillmentTransactions = [];
44905
- const approvalPromises = [];
44906
- const fulfillmentPromises = [];
44907
- for (const action of actions) {
44908
- if (action.type !== ActionType.TRANSACTION)
44909
- continue;
44910
- if (action.purpose === TransactionPurpose.APPROVAL) {
44911
- approvalPromises.push(action.buildTransaction());
44276
+ if (makerFees !== undefined) {
44277
+ const orderBookFees = calculateFees(makerFees, buyTokenOrNative.amount, decimals);
44278
+ if (orderBookFees.length !== makerFees.length) {
44279
+ throw new CheckoutError('One of the fees is too small, must be greater than 0.000001', CheckoutErrorType.CREATE_ORDER_LISTING_ERROR);
44280
+ }
44281
+ createListingParams.makerFees = orderBookFees;
44912
44282
  }
44913
- if (action.purpose === TransactionPurpose.FULFILL_ORDER) {
44914
- fulfillmentPromises.push(action.buildTransaction());
44283
+ try {
44284
+ const order = await orderbook.createListing(createListingParams);
44285
+ orderId = order.result.id;
44286
+ }
44287
+ catch (err) {
44288
+ throw new CheckoutError('An error occurred while creating the listing', CheckoutErrorType.CREATE_ORDER_LISTING_ERROR, {
44289
+ error: err,
44290
+ collectionId: sellToken.id,
44291
+ collectionAddress: sellToken.collectionAddress,
44292
+ });
44915
44293
  }
44294
+ return {
44295
+ status: CheckoutStatus.SUCCESS,
44296
+ orderIds: [orderId],
44297
+ smartCheckoutResult,
44298
+ };
44916
44299
  }
44917
- approvalTransactions = await Promise.all(approvalPromises);
44918
- fulfillmentTransactions = await Promise.all(fulfillmentPromises);
44919
44300
  return {
44920
- approvalTransactions,
44921
- fulfillmentTransactions,
44301
+ status: CheckoutStatus.INSUFFICIENT_FUNDS,
44302
+ smartCheckoutResult,
44922
44303
  };
44923
44304
  };
44924
- const getUnsignedERC20ApprovalTransactions = async (actions) => {
44925
- let approvalTransactions = [];
44926
- const approvalPromises = [];
44927
- for (const action of actions) {
44928
- if (action.type !== ActionType.TRANSACTION)
44929
- continue;
44930
- if (action.purpose === TransactionPurpose.APPROVAL) {
44931
- approvalPromises.push(action.buildTransaction());
44932
- }
44305
+
44306
+ class FiatRampService {
44307
+ config;
44308
+ /**
44309
+ * Constructs a new instance of the FiatRampService class.
44310
+ * @param {CheckoutConfiguration} config - The config required for the FiatRampService.
44311
+ */
44312
+ constructor(config) {
44313
+ this.config = config;
44933
44314
  }
44934
- approvalTransactions = await Promise.all(approvalPromises);
44935
- return approvalTransactions;
44936
- };
44937
- const getUnsignedFulfillmentTransactions = async (actions) => {
44938
- let fulfillmentTransactions = [];
44939
- const fulfillmentPromises = [];
44940
- for (const action of actions) {
44941
- if (action.type !== ActionType.TRANSACTION)
44942
- continue;
44943
- if (action.purpose === TransactionPurpose.FULFILL_ORDER) {
44944
- fulfillmentPromises.push(action.buildTransaction());
44945
- }
44315
+ async feeEstimate() {
44316
+ const config = (await this.config.remote.getConfig('onramp'));
44317
+ return config[OnRampProvider.TRANSAK]?.fees;
44946
44318
  }
44947
- fulfillmentTransactions = await Promise.all(fulfillmentPromises);
44948
- return fulfillmentTransactions;
44949
- };
44950
- const getUnsignedMessage = (orderHash, orderComponents, actions) => {
44951
- let unsignedMessage;
44952
- for (const action of actions) {
44953
- if (action.type !== ActionType.SIGNABLE)
44954
- continue;
44955
- if (action.purpose === SignablePurpose.CREATE_LISTING) {
44956
- unsignedMessage = {
44957
- domain: action.message.domain,
44958
- types: action.message.types,
44959
- value: action.message.value,
44960
- };
44961
- }
44319
+ async createWidgetUrl(params) {
44320
+ return (await this.getTransakWidgetUrl(params));
44962
44321
  }
44963
- if (!unsignedMessage)
44964
- return undefined;
44965
- return {
44966
- orderHash,
44967
- orderComponents,
44968
- unsignedMessage,
44969
- };
44970
- };
44971
-
44972
- const MAX_FEE_PERCENTAGE_DECIMAL = 1; // 100%
44973
- const MAX_FEE_DECIMAL_PLACES = 6; // will allow 0.000001 (0.0001%) as the minimum value
44974
- const calculateFeesPercent = (orderFee, amountBn) => {
44975
- const feePercentage = orderFee.amount;
44976
- // note: multiply in and out of the maximum decimal places to the power of ten to do the math in big number integers
44977
- const feePercentageMultiplier = Math.round(feePercentage.percentageDecimal * (10 ** MAX_FEE_DECIMAL_PLACES));
44978
- const bnFeeAmount = amountBn
44979
- .mul(BigNumber$1.from(feePercentageMultiplier))
44980
- .div(10 ** MAX_FEE_DECIMAL_PLACES);
44981
- return bnFeeAmount;
44982
- };
44983
- const calculateFeesToken = (orderFee, decimals) => {
44984
- const feeToken = orderFee.amount;
44985
- const bnFeeAmount = utils$3.parseUnits(feeToken.token, decimals);
44986
- return bnFeeAmount;
44987
- };
44988
- const calculateFees = (orderFees, weiAmount, decimals = 18) => {
44989
- let totalTokenFees = BigNumber$1.from(0);
44990
- const amountBn = BigNumber$1.from(weiAmount);
44991
- // note: multiply in and out of the maximum decimal places to the power of ten to do the math in big number integers
44992
- const totalAllowableFees = amountBn
44993
- .mul(MAX_FEE_PERCENTAGE_DECIMAL * (10 ** MAX_FEE_DECIMAL_PLACES))
44994
- .div(10 ** MAX_FEE_DECIMAL_PLACES);
44995
- const calculateFeesResult = [];
44996
- for (const orderFee of orderFees) {
44997
- let currentFeeBn = BigNumber$1.from(0);
44998
- if (Object.hasOwn(orderFee.amount, 'percentageDecimal')) {
44999
- currentFeeBn = calculateFeesPercent(orderFee, amountBn);
45000
- totalTokenFees = totalTokenFees.add(currentFeeBn);
44322
+ async getTransakWidgetUrl(params) {
44323
+ let widgetUrl = `${TRANSAK_API_BASE_URL[this.config.environment]}?`;
44324
+ const onRampConfig = (await this.config.remote.getConfig('onramp'));
44325
+ const apiKey = onRampConfig[OnRampProvider.TRANSAK].publishableApiKey;
44326
+ const transakPublishableKey = `apiKey=${apiKey}`;
44327
+ const zkevmNetwork = 'network=immutablezkevm';
44328
+ const defaultPaymentMethod = 'defaultPaymentMethod=credit_debit_card';
44329
+ const disableBankTransfer = 'disablePaymentMethods=sepa_bank_transfer,gbp_bank_transfer,'
44330
+ + 'pm_cash_app,pm_jwire,pm_paymaya,pm_bpi,pm_ubp,pm_grabpay,pm_shopeepay,pm_gcash,pm_pix,'
44331
+ + 'pm_astropay,pm_pse,inr_bank_transfer';
44332
+ const productsAvailed = 'productsAvailed=buy';
44333
+ const exchangeScreenTitle = 'exchangeScreenTitle=Buy';
44334
+ const themeColor = 'themeColor=0D0D0D';
44335
+ widgetUrl += `${transakPublishableKey}&`
44336
+ + `${zkevmNetwork}&`
44337
+ + `${defaultPaymentMethod}&`
44338
+ + `${disableBankTransfer}&`
44339
+ + `${productsAvailed}&`
44340
+ + `${exchangeScreenTitle}&`
44341
+ + `${themeColor}`;
44342
+ if (params.isPassport && params.email) {
44343
+ const encodedEmail = encodeURIComponent(params.email);
44344
+ widgetUrl += `&email=${encodedEmail}&isAutoFillUserData=true&disableWalletAddressForm=true`;
45001
44345
  }
45002
- else if (Object.hasOwn(orderFee.amount, 'token')) {
45003
- currentFeeBn = calculateFeesToken(orderFee, decimals);
45004
- totalTokenFees = totalTokenFees.add(currentFeeBn);
44346
+ if (params.tokenAmount && params.tokenSymbol) {
44347
+ widgetUrl += `&defaultCryptoAmount=${params.tokenAmount}&cryptoCurrencyCode=${params.tokenSymbol}`;
45005
44348
  }
45006
44349
  else {
45007
- throw new CheckoutError('Unknown fee type parsed, must be percentageDecimal or token', CheckoutErrorType.ORDER_FEE_ERROR);
45008
- }
45009
- if (totalTokenFees.gt(totalAllowableFees)) {
45010
- throw new CheckoutError(`The combined fees are above the allowed maximum of ${MAX_FEE_PERCENTAGE_DECIMAL * 100}%`, CheckoutErrorType.ORDER_FEE_ERROR);
44350
+ widgetUrl += '&defaultCryptoCurrency=IMX';
45011
44351
  }
45012
- if (currentFeeBn.gt(0)) {
45013
- calculateFeesResult.push({
45014
- amount: currentFeeBn.toString(),
45015
- recipientAddress: orderFee.recipient,
45016
- });
44352
+ if (params.walletAddress) {
44353
+ widgetUrl += `&walletAddress=${params.walletAddress}`;
45017
44354
  }
45018
- } // for
45019
- return calculateFeesResult;
45020
- };
44355
+ return widgetUrl;
44356
+ }
44357
+ }
45021
44358
 
45022
- const getItemRequirement = (type, tokenAddress, amount, spenderAddress) => {
45023
- switch (type) {
45024
- case ItemType.ERC20:
44359
+ async function getItemRequirementsFromRequirements(provider, requirements) {
44360
+ // Get all decimal values by calling contracts for each ERC20
44361
+ const decimalPromises = [];
44362
+ requirements.forEach((itemRequirementParam) => {
44363
+ if (itemRequirementParam.type === ItemType.ERC20) {
44364
+ const { tokenAddress } = itemRequirementParam;
44365
+ decimalPromises.push(getTokenContract(tokenAddress, ERC20ABI, provider).decimals());
44366
+ }
44367
+ });
44368
+ const decimals = await Promise.all(decimalPromises);
44369
+ // Map ItemRequirementsParam objects to ItemRequirement by parsing amounts from formatted string to BigNumebrs
44370
+ const itemRequirements = requirements.map((itemRequirementParam, index) => {
44371
+ if (itemRequirementParam.type === ItemType.NATIVE) {
45025
44372
  return {
45026
- type,
45027
- amount,
45028
- tokenAddress,
45029
- spenderAddress,
44373
+ ...itemRequirementParam,
44374
+ amount: utils$3.parseUnits(itemRequirementParam.amount, 18),
45030
44375
  };
45031
- case ItemType.NATIVE:
45032
- default:
44376
+ }
44377
+ if (itemRequirementParam.type === ItemType.ERC20) {
45033
44378
  return {
45034
- type: ItemType.NATIVE,
45035
- amount,
44379
+ ...itemRequirementParam,
44380
+ amount: utils$3.parseUnits(itemRequirementParam.amount, decimals[index]),
45036
44381
  };
44382
+ }
44383
+ return itemRequirementParam;
44384
+ });
44385
+ return itemRequirements;
44386
+ }
44387
+
44388
+ /**
44389
+ * Validates and builds a version string based on the given SemanticVersion object.
44390
+ * If the version is undefined or has an invalid major version, it returns the default checkout version.
44391
+ * If the version is all zeros, it also returns the default checkout version.
44392
+ * Otherwise, it constructs a validated version string based on the major, minor, patch, and build numbers.
44393
+ */
44394
+ function validateAndBuildVersion(version) {
44395
+ const defaultPackageVersion = globalPackageVersion();
44396
+ if (version === undefined || version.major === undefined)
44397
+ return defaultPackageVersion;
44398
+ if (!Number.isInteger(version.major) || version.major < 0)
44399
+ return defaultPackageVersion;
44400
+ if (version.minor !== undefined && version.minor < 0)
44401
+ return defaultPackageVersion;
44402
+ if (version.patch !== undefined && version.patch < 0)
44403
+ return defaultPackageVersion;
44404
+ if (version.major === 0 && version.minor === undefined)
44405
+ return defaultPackageVersion;
44406
+ if (version.major === 0 && version.minor === 0 && version.patch === undefined)
44407
+ return defaultPackageVersion;
44408
+ if (version.major === 0 && version.minor === undefined && version.patch === undefined)
44409
+ return defaultPackageVersion;
44410
+ if (version.major === 0 && version.minor === 0 && version.patch === 0)
44411
+ return defaultPackageVersion;
44412
+ let validatedVersion = version.major.toString();
44413
+ if (version.minor === undefined)
44414
+ return validatedVersion;
44415
+ if (Number.isInteger(version.minor)) {
44416
+ validatedVersion += `.${version.minor.toString()}`;
45037
44417
  }
45038
- };
45039
- const getTransactionOrGas = (gasLimit, fulfillmentTransactions) => {
45040
- if (fulfillmentTransactions.length > 0) {
45041
- return {
45042
- type: TransactionOrGasType.TRANSACTION,
45043
- transaction: fulfillmentTransactions[0],
44418
+ if (version.patch === undefined)
44419
+ return validatedVersion;
44420
+ if (Number.isInteger(version.patch)) {
44421
+ validatedVersion += `.${version.patch.toString()}`;
44422
+ }
44423
+ if (version.prerelease === undefined || version.prerelease !== 'alpha')
44424
+ return validatedVersion;
44425
+ if (version.prerelease === 'alpha') {
44426
+ validatedVersion += `-${version.prerelease}`;
44427
+ }
44428
+ if (version.build === undefined)
44429
+ return validatedVersion;
44430
+ if (Number.isInteger(version.build) && version.build >= 0) {
44431
+ validatedVersion += `.${version.build.toString()}`;
44432
+ }
44433
+ return validatedVersion;
44434
+ }
44435
+
44436
+ function loadUnresolved(version) {
44437
+ if (window === undefined) {
44438
+ throw new Error('missing window object: please run Checkout client side');
44439
+ }
44440
+ if (document === undefined) {
44441
+ throw new Error('missing document object: please run Checkout client side');
44442
+ }
44443
+ const scriptId = 'immutable-checkout-widgets-bundle';
44444
+ const validVersion = validateAndBuildVersion(version);
44445
+ // Prevent the script to be loaded more than once
44446
+ // by checking the presence of the script and its version.
44447
+ const initScript = document.getElementById(scriptId);
44448
+ if (initScript)
44449
+ return { loaded: true, element: initScript };
44450
+ const tag = document.createElement('script');
44451
+ let cdnUrl = `https://cdn.jsdelivr.net/npm/@imtbl/sdk@${validVersion}/dist/browser/checkout/widgets.js`;
44452
+ tag.setAttribute('id', scriptId);
44453
+ tag.setAttribute('data-version', validVersion);
44454
+ tag.setAttribute('src', cdnUrl);
44455
+ document.head.appendChild(tag);
44456
+ return { loaded: false, element: tag };
44457
+ }
44458
+
44459
+ const PUBLISHABLE_KEY_PREFIX = 'pk_imapik-';
44460
+ const publishableKeyDomainAllowlist = [
44461
+ 'https://checkout-api.dev.immutable.com',
44462
+ 'https://checkout-api.sandbox.immutable.com',
44463
+ 'https://checkout-api.immutable.com',
44464
+ ];
44465
+ class HttpClient {
44466
+ config;
44467
+ axiosInstance;
44468
+ constructor(config) {
44469
+ this.config = config;
44470
+ this.axiosInstance = globalAxios$1.create();
44471
+ this.setupInterceptors();
44472
+ }
44473
+ // eslint-disable-next-line class-methods-use-this
44474
+ shouldAddPublishableKey(url) {
44475
+ // Check if the request is going to a whitelisted domain
44476
+ return publishableKeyDomainAllowlist.some((domain) => url.startsWith(domain));
44477
+ }
44478
+ setupInterceptors() {
44479
+ this.axiosInstance.interceptors.request.use((config) => {
44480
+ const publishableKey = this.config?.baseConfig?.publishableKey;
44481
+ if (publishableKey && this.shouldAddPublishableKey(config.url || '')) {
44482
+ if (!publishableKey.startsWith(PUBLISHABLE_KEY_PREFIX)) {
44483
+ throw new Error('Invalid Publishable key. Create your Publishable key in Immutable developer hub.'
44484
+ + ' https://hub.immutable.com');
44485
+ }
44486
+ // Add publishable key header for whitelisted domains
44487
+ // eslint-disable-next-line no-param-reassign
44488
+ config.headers['x-immutable-publishable-key'] = publishableKey;
44489
+ }
44490
+ return config;
44491
+ }, (error) => Promise.reject(error));
44492
+ }
44493
+ async request(config) {
44494
+ return await this.axiosInstance.request(config);
44495
+ }
44496
+ async get(url, config) {
44497
+ const requestConfig = {
44498
+ ...config,
44499
+ url,
45044
44500
  };
44501
+ return await this.request(requestConfig);
45045
44502
  }
45046
- return {
45047
- type: TransactionOrGasType.GAS,
45048
- gasToken: {
45049
- type: GasTokenType.NATIVE,
45050
- limit: BigNumber$1.from(gasLimit),
45051
- },
45052
- };
44503
+ async post(url, data, config) {
44504
+ const requestConfig = {
44505
+ ...config,
44506
+ data,
44507
+ url,
44508
+ };
44509
+ return await this.request(requestConfig);
44510
+ }
44511
+ async put(url, data, config) {
44512
+ const requestConfig = {
44513
+ ...config,
44514
+ data,
44515
+ url,
44516
+ };
44517
+ return await this.request(requestConfig);
44518
+ }
44519
+ async delete(url, data, config) {
44520
+ const requestConfig = {
44521
+ ...config,
44522
+ data,
44523
+ url,
44524
+ };
44525
+ return await this.request(requestConfig);
44526
+ }
44527
+ }
44528
+
44529
+ const SANDBOX_CONFIGURATION = {
44530
+ baseConfig: {
44531
+ environment: Environment$1.SANDBOX,
44532
+ },
44533
+ passport: undefined,
45053
44534
  };
45054
- const buy = async (config, provider, orders, overrides = {
45055
- waitFulfillmentSettlements: true,
45056
- }) => {
45057
- if (orders.length === 0) {
45058
- throw new CheckoutError('No orders were provided to the orders array. Please provide at least one order.', CheckoutErrorType.FULFILL_ORDER_LISTING_ERROR);
44535
+ const WIDGETS_SCRIPT_TIMEOUT = 100;
44536
+ // Checkout SDK
44537
+ class Checkout {
44538
+ readOnlyProviders;
44539
+ httpClient;
44540
+ config;
44541
+ fiatRampService;
44542
+ availability;
44543
+ passport;
44544
+ /**
44545
+ * Constructs a new instance of the CheckoutModule class.
44546
+ * @param {CheckoutModuleConfiguration} [config=SANDBOX_CONFIGURATION] - The configuration object for the CheckoutModule.
44547
+ */
44548
+ constructor(config = SANDBOX_CONFIGURATION) {
44549
+ this.httpClient = new HttpClient(config);
44550
+ this.config = new CheckoutConfiguration(config, this.httpClient);
44551
+ this.fiatRampService = new FiatRampService(this.config);
44552
+ this.readOnlyProviders = new Map();
44553
+ this.availability = availabilityService(this.config.isDevelopment, this.config.isProduction);
44554
+ this.passport = config.passport;
44555
+ }
44556
+ /**
44557
+ * Loads the widgets bundle and initiate the widgets factory.
44558
+ * @param {WidgetsInit} init - The initialisation parameters for loading the widgets bundle and applying configuration
44559
+ */
44560
+ async widgets(init) {
44561
+ const checkout = this;
44562
+ // Preload the configurations
44563
+ await checkout.config.remote.getConfig();
44564
+ const factory = new Promise((resolve, reject) => {
44565
+ function checkForWidgetsBundleLoaded() {
44566
+ if (typeof ImmutableCheckoutWidgets !== 'undefined') {
44567
+ resolve(new ImmutableCheckoutWidgets.WidgetsFactory(checkout, init.config));
44568
+ }
44569
+ else {
44570
+ // If ImmutableCheckoutWidgets is not defined, wait for set amount of time.
44571
+ // When time has elapsed, check again if ImmutableCheckoutWidgets is defined.
44572
+ // Once it's defined, the promise will resolve and setTimeout won't be called again.
44573
+ setTimeout(checkForWidgetsBundleLoaded, WIDGETS_SCRIPT_TIMEOUT);
44574
+ }
44575
+ }
44576
+ try {
44577
+ const script = loadUnresolved(init.version);
44578
+ if (script.loaded && typeof ImmutableCheckoutWidgets !== 'undefined') {
44579
+ resolve(new ImmutableCheckoutWidgets.WidgetsFactory(checkout, init.config));
44580
+ }
44581
+ else {
44582
+ checkForWidgetsBundleLoaded();
44583
+ }
44584
+ }
44585
+ catch (err) {
44586
+ reject(new CheckoutError('Failed to load widgets script', CheckoutErrorType.WIDGETS_SCRIPT_LOAD_ERROR, { error: err }));
44587
+ }
44588
+ });
44589
+ return factory;
44590
+ }
44591
+ /**
44592
+ * Creates a provider using the given parameters.
44593
+ * @param {CreateProviderParams} params - The parameters for creating the provider.
44594
+ * @returns {Promise<CreateProviderResult>} A promise that resolves to the created provider.
44595
+ */
44596
+ async createProvider(params) {
44597
+ return await createProvider(params.walletProviderName, this.passport);
44598
+ }
44599
+ /**
44600
+ * Checks if a wallet is connected to the specified provider.
44601
+ * @param {CheckConnectionParams} params - The parameters for checking the wallet connection.
44602
+ * @returns {Promise<CheckConnectionResult>} - A promise that resolves to the result of the check.
44603
+ */
44604
+ async checkIsWalletConnected(params) {
44605
+ const web3Provider = await validateProvider(this.config, params.provider, { allowUnsupportedProvider: true });
44606
+ return checkIsWalletConnected(web3Provider);
45059
44607
  }
45060
- let order;
45061
- let spenderAddress = '';
45062
- let decimals = 18;
45063
- const gasLimit = constants.estimatedFulfillmentGasGwei;
45064
- const orderbook = createOrderbookInstance(config);
45065
- const blockchainClient = createBlockchainDataInstance(config);
45066
- const fulfillerAddress = await measureAsyncExecution(config, 'Time to get the address from the provider', provider.getSigner().getAddress());
45067
- // Prefetch balances and store them in memory
45068
- resetBlockscoutClientMap();
45069
- getAllBalances(config, provider, fulfillerAddress, getL1ChainId(config));
45070
- getAllBalances(config, provider, fulfillerAddress, getL2ChainId(config));
45071
- const { id, takerFees } = orders[0];
45072
- let orderChainName;
45073
- try {
45074
- order = await measureAsyncExecution(config, 'Time to fetch the listing from the orderbook', orderbook.getListing(id));
45075
- const { seaportContractAddress, chainName } = orderbook.config();
45076
- orderChainName = chainName;
45077
- spenderAddress = seaportContractAddress;
44608
+ /**
44609
+ * Connects to a blockchain network using the specified provider.
44610
+ * @param {ConnectParams} params - The parameters for connecting to the network.
44611
+ * @returns {Promise<ConnectResult>} A promise that resolves to an object containing the provider and network information.
44612
+ * @throws {Error} If the provider is not valid or if there is an error connecting to the network.
44613
+ */
44614
+ async connect(params) {
44615
+ const web3Provider = await validateProvider(this.config, params.provider, { allowUnsupportedProvider: true });
44616
+ await connectSite(web3Provider);
44617
+ return { provider: web3Provider };
45078
44618
  }
45079
- catch (err) {
45080
- throw new CheckoutError('An error occurred while getting the order listing', CheckoutErrorType.GET_ORDER_LISTING_ERROR, {
45081
- error: err,
45082
- orderId: id,
44619
+ /**
44620
+ * Switches the network for the current wallet provider.
44621
+ * @param {SwitchNetworkParams} params - The parameters for switching the network.
44622
+ * @returns {Promise<SwitchNetworkResult>} - A promise that resolves to the result of switching the network.
44623
+ */
44624
+ async switchNetwork(params) {
44625
+ const web3Provider = await validateProvider(this.config, params.provider, {
44626
+ allowUnsupportedProvider: true,
44627
+ allowMistmatchedChainId: true,
45083
44628
  });
44629
+ const switchNetworkRes = await switchWalletNetwork(this.config, web3Provider, params.chainId);
44630
+ return switchNetworkRes;
45084
44631
  }
45085
- if (order.result.buy.length === 0) {
45086
- throw new CheckoutError('An error occurred with the get order listing', CheckoutErrorType.GET_ORDER_LISTING_ERROR, {
45087
- orderId: id,
45088
- message: 'No buy side tokens found on order',
45089
- });
44632
+ /**
44633
+ * Retrieves the token information given the token address. This function makes RPC calls to
44634
+ * ERC20 contracts to fetch the main contract information (e.g. symbol).
44635
+ * @param {GetTokenInfoParams} params - The parameters for retrieving the token information.
44636
+ * @returns {Promise<TokenInfo>} - A promise that resolves to the token info request.
44637
+ */
44638
+ async getTokenInfo(params) {
44639
+ return await getERC20TokenInfo(params.provider, params.tokenAddress);
45090
44640
  }
45091
- const buyToken = order.result.buy[0];
45092
- if (buyToken.type === 'ERC20') {
45093
- const token = await measureAsyncExecution(config, 'Time to get decimals of token contract for the buy token', blockchainClient.getToken({ contractAddress: buyToken.contractAddress, chainName: orderChainName }));
45094
- if (token.result.decimals)
45095
- decimals = token.result.decimals;
44641
+ /**
44642
+ * Retrieves the balance of a wallet address.
44643
+ * @param {GetBalanceParams} params - The parameters for retrieving the balance.
44644
+ * @returns {Promise<GetBalanceResult>} - A promise that resolves to the balance result.
44645
+ */
44646
+ async getBalance(params) {
44647
+ const web3Provider = await validateProvider(this.config, params.provider);
44648
+ if (!params.tokenAddress || params.tokenAddress === '') {
44649
+ return await getBalance(this.config, web3Provider, params.walletAddress);
44650
+ }
44651
+ return await getERC20Balance(web3Provider, params.walletAddress, params.tokenAddress);
45096
44652
  }
45097
- let fees = [];
45098
- if (takerFees && takerFees.length > 0) {
45099
- fees = calculateFees(takerFees, buyToken.amount, decimals);
44653
+ /**
44654
+ * Retrieves the balances of all tokens for a given wallet address on a specific chain.
44655
+ * @param {GetAllBalancesParams} params - The parameters for retrieving the balances.
44656
+ * @returns {Promise<GetAllBalancesResult>} - A promise that resolves to the result of retrieving the balances.
44657
+ */
44658
+ async getAllBalances(params) {
44659
+ return getAllBalances(this.config, params.provider, params.walletAddress, params.chainId);
45100
44660
  }
45101
- let unsignedApprovalTransactions = [];
45102
- let unsignedFulfillmentTransactions = [];
45103
- let orderActions = [];
45104
- const fulfillOrderStartTime = performance.now();
45105
- try {
45106
- const { actions } = await measureAsyncExecution(config, 'Time to call fulfillOrder from the orderbook', orderbook.fulfillOrder(id, fulfillerAddress, fees));
45107
- orderActions = actions;
45108
- unsignedApprovalTransactions = await measureAsyncExecution(config, 'Time to construct the unsigned approval transactions', getUnsignedERC20ApprovalTransactions(actions));
44661
+ /**
44662
+ * Retrieves the supported networks based on the provided parameters.
44663
+ * @param {GetNetworkAllowListParams} params - The parameters for retrieving the network allow list.
44664
+ * @returns {Promise<GetNetworkAllowListResult>} - A promise that resolves to the network allow list result.
44665
+ */
44666
+ async getNetworkAllowList(params) {
44667
+ return await getNetworkAllowList(this.config, params);
45109
44668
  }
45110
- catch (err) {
45111
- const elapsedTimeInSeconds = (performance.now() - fulfillOrderStartTime) / 1000;
45112
- debugLogger(config, 'Time to call fulfillOrder from the orderbook', elapsedTimeInSeconds);
45113
- if (err.message.includes(OrderStatusName.EXPIRED)) {
45114
- throw new CheckoutError('Order is expired', CheckoutErrorType.ORDER_EXPIRED_ERROR, { orderId: id });
45115
- }
45116
- // The balances error will be handled by bulk order fulfillment but for now we
45117
- // need to assert on this string to check that the error is not a balances error
45118
- if (!err.message.includes('The fulfiller does not have the balances needed to fulfill')) {
45119
- throw new CheckoutError('Error occurred while trying to fulfill the order', CheckoutErrorType.FULFILL_ORDER_LISTING_ERROR, {
45120
- orderId: id,
45121
- error: err,
45122
- });
45123
- }
44669
+ /**
44670
+ * Retrieves the supported tokens based on the provided parameters.
44671
+ * @param {GetTokenAllowListParams} params - The parameters for retrieving the token allow list.
44672
+ * @returns {Promise<GetTokenAllowListResult>} - A promise that resolves to the token allow list result.
44673
+ */
44674
+ async getTokenAllowList(params) {
44675
+ return await getTokenAllowList(this.config, params);
45124
44676
  }
45125
- try {
45126
- unsignedFulfillmentTransactions = await measureAsyncExecution(config, 'Time to construct the unsigned fulfillment transactions', getUnsignedFulfillmentTransactions(orderActions));
44677
+ /**
44678
+ * Retrieves the default supported wallets based on the provided parameters.
44679
+ * @param {GetWalletAllowListParams} params - The parameters for retrieving the wallet allow list.
44680
+ * @returns {Promise<GetWalletAllowListResult>} - A promise that resolves to the wallet allow list result.
44681
+ */
44682
+ async getWalletAllowList(params) {
44683
+ return await getWalletAllowList(params);
45127
44684
  }
45128
- catch {
45129
- // if cannot estimate gas then silently continue and use gas limit in smartCheckout
45130
- // but get the fulfillment transactions after they have approved the spending
44685
+ /**
44686
+ * Sends a transaction using the specified provider and transaction parameters.
44687
+ * @param {SendTransactionParams} params - The parameters for sending the transaction.
44688
+ * @returns {Promise<SendTransactionResult>} A promise that resolves to the result of the transaction.
44689
+ */
44690
+ async sendTransaction(params) {
44691
+ const web3Provider = await validateProvider(this.config, params.provider);
44692
+ return await sendTransaction(web3Provider, params.transaction);
45131
44693
  }
45132
- let amount = BigNumber$1.from('0');
45133
- let type = ItemType.NATIVE;
45134
- let contractAddress = '';
45135
- const buyArray = order.result.buy;
45136
- if (buyArray.length > 0) {
45137
- switch (buyArray[0].type) {
45138
- case 'NATIVE':
45139
- type = ItemType.NATIVE;
45140
- break;
45141
- case 'ERC20':
45142
- type = ItemType.ERC20;
45143
- contractAddress = buyArray[0].contractAddress;
45144
- break;
45145
- default:
45146
- throw new CheckoutError('Purchasing token type is unsupported', CheckoutErrorType.UNSUPPORTED_TOKEN_TYPE_ERROR, {
45147
- orderId: id,
45148
- });
45149
- }
44694
+ /**
44695
+ * Retrieves network information using the specified provider.
44696
+ * @param {GetNetworkParams} params - The parameters for retrieving network information.
44697
+ * @returns {Promise<NetworkInfo>} A promise that resolves to the network information.
44698
+ */
44699
+ async getNetworkInfo(params) {
44700
+ const web3Provider = await validateProvider(this.config, params.provider, {
44701
+ allowUnsupportedProvider: true,
44702
+ allowMistmatchedChainId: true,
44703
+ });
44704
+ return await getNetworkInfo(this.config, web3Provider);
45150
44705
  }
45151
- buyArray.forEach((item) => {
45152
- if (item.type !== ItemType.ERC721) {
45153
- amount = amount.add(BigNumber$1.from(item.amount));
44706
+ /**
44707
+ * Determines the requirements for performing a buy.
44708
+ * @param {BuyParams} params - The parameters for the buy.
44709
+ */
44710
+ async buy(params) {
44711
+ if (params.orders.length > 1) {
44712
+ // eslint-disable-next-line no-console
44713
+ console.warn('This endpoint currently only processes the first order in the array.');
45154
44714
  }
45155
- });
45156
- const feeArray = order.result.fees;
45157
- feeArray.forEach((item) => {
45158
- amount = amount.add(BigNumber$1.from(item.amount));
45159
- });
45160
- const itemRequirements = [
45161
- getItemRequirement(type, contractAddress, amount, spenderAddress),
45162
- ];
45163
- const smartCheckoutResult = await measureAsyncExecution(config, 'Total time running smart checkout', smartCheckout(config, provider, itemRequirements, getTransactionOrGas(gasLimit, unsignedFulfillmentTransactions)));
45164
- if (smartCheckoutResult.sufficient) {
45165
- const approvalResult = await signApprovalTransactions(provider, unsignedApprovalTransactions);
45166
- if (approvalResult.type === SignTransactionStatusType.FAILED) {
45167
- return {
45168
- status: CheckoutStatus.FAILED,
45169
- transactionHash: approvalResult.transactionHash,
45170
- reason: approvalResult.reason,
45171
- smartCheckoutResult,
45172
- };
44715
+ const web3Provider = await validateProvider(this.config, params.provider);
44716
+ return await buy(this.config, web3Provider, params.orders, params.overrides);
44717
+ }
44718
+ /**
44719
+ * Determines the requirements for performing a sell.
44720
+ * @param {SellParams} params - The parameters for the sell.
44721
+ * Only currently actions the first order in the array until we support batch processing.
44722
+ * Only currently actions the first fee in the fees array of each order until we support multiple fees.
44723
+ */
44724
+ async sell(params) {
44725
+ if (params.orders.length > 1) {
44726
+ // eslint-disable-next-line no-console
44727
+ console.warn('This endpoint currently only processes the first order in the array.');
45173
44728
  }
44729
+ const web3Provider = await validateProvider(this.config, params.provider);
44730
+ return await sell(this.config, web3Provider, params.orders);
44731
+ }
44732
+ /**
44733
+ * Cancels a sell.
44734
+ * @param {CancelParams} params - The parameters for the cancel.
44735
+ */
44736
+ async cancel(params) {
44737
+ // eslint-disable-next-line no-console
44738
+ console.warn('This endpoint currently only processes the first order in the array.');
44739
+ const web3Provider = await validateProvider(this.config, params.provider);
44740
+ return await cancel(this.config, web3Provider, params.orderIds, params.overrides);
44741
+ }
44742
+ /**
44743
+ * Determines the transaction requirements to complete a purchase.
44744
+ * @params {SmartCheckoutParams} params - The parameters for smart checkout.
44745
+ */
44746
+ async smartCheckout(params) {
44747
+ const web3Provider = await validateProvider(this.config, params.provider);
44748
+ let itemRequirements = [];
45174
44749
  try {
45175
- if (unsignedFulfillmentTransactions.length === 0) {
45176
- unsignedFulfillmentTransactions = await getUnsignedFulfillmentTransactions(orderActions);
45177
- }
44750
+ itemRequirements = await getItemRequirementsFromRequirements(web3Provider, params.itemRequirements);
45178
44751
  }
45179
44752
  catch (err) {
45180
- throw new CheckoutError('Error fetching fulfillment transaction', CheckoutErrorType.FULFILL_ORDER_LISTING_ERROR, { error: err });
45181
- }
45182
- if (overrides.waitFulfillmentSettlements) {
45183
- const fulfillmentResult = await signFulfillmentTransactions(provider, unsignedFulfillmentTransactions);
45184
- if (fulfillmentResult.type === SignTransactionStatusType.FAILED) {
45185
- return {
45186
- status: CheckoutStatus.FAILED,
45187
- transactionHash: fulfillmentResult.transactionHash,
45188
- reason: fulfillmentResult.reason,
45189
- smartCheckoutResult,
45190
- };
45191
- }
45192
- return {
45193
- status: CheckoutStatus.SUCCESS,
45194
- smartCheckoutResult,
45195
- };
44753
+ throw new CheckoutError('Failed to map item requirements', CheckoutErrorType.ITEM_REQUIREMENTS_ERROR, { error: err });
45196
44754
  }
45197
- let transactions;
45198
- try {
45199
- const response = await Promise.all(unsignedFulfillmentTransactions.map((transaction) => sendTransaction(provider, transaction)));
45200
- transactions = response.map((result) => result.transactionResponse);
44755
+ return await smartCheckout(this.config, web3Provider, itemRequirements, params.transactionOrGasAmount);
44756
+ }
44757
+ /**
44758
+ * Checks if the given object is a Web3 provider.
44759
+ * @param {Web3Provider} web3Provider - The object to check.
44760
+ * @returns {boolean} - True if the object is a Web3 provider, false otherwise.
44761
+ */
44762
+ static isWeb3Provider(web3Provider) {
44763
+ return isWeb3Provider(web3Provider);
44764
+ }
44765
+ /**
44766
+ * Estimates the gas required for a swap or bridge transaction.
44767
+ * @param {GasEstimateParams} params - The parameters for the gas estimation.
44768
+ * @returns {Promise<GasEstimateSwapResult | GasEstimateBridgeToL2Result>} - A promise that resolves to the gas estimation result.
44769
+ */
44770
+ async gasEstimate(params) {
44771
+ this.readOnlyProviders = await createReadOnlyProviders(this.config, this.readOnlyProviders);
44772
+ return await gasEstimator(params, this.readOnlyProviders, this.config);
44773
+ }
44774
+ /**
44775
+ * Creates and returns a URL for the fiat ramp widget.
44776
+ * @param {FiatRampParams} params - The parameters for creating the url.
44777
+ * @returns {Promise<string>} - A promise that resolves to a string url.
44778
+ */
44779
+ async createFiatRampUrl(params) {
44780
+ let tokenAmount;
44781
+ let tokenSymbol = 'IMX';
44782
+ let email;
44783
+ const walletAddress = await params.web3Provider.getSigner().getAddress();
44784
+ const isPassport = params.web3Provider.provider?.isPassport || false;
44785
+ if (isPassport && params.passport) {
44786
+ const userInfo = await params.passport.getUserInfo();
44787
+ email = userInfo?.email;
45201
44788
  }
45202
- catch (err) {
45203
- throw new CheckoutError('An error occurred while executing the fulfillment transaction', CheckoutErrorType.EXECUTE_FULFILLMENT_TRANSACTION_ERROR, {
45204
- message: err.message,
45205
- });
44789
+ const tokenList = await getTokenAllowList(this.config, { type: TokenFilterTypes.ONRAMP });
44790
+ const token = tokenList.tokens?.find((t) => isMatchingAddress(t.address, params.tokenAddress));
44791
+ if (token) {
44792
+ tokenAmount = params.tokenAmount;
44793
+ tokenSymbol = token.symbol;
45206
44794
  }
45207
- return {
45208
- status: CheckoutStatus.FULFILLMENTS_UNSETTLED,
45209
- smartCheckoutResult,
45210
- transactions,
44795
+ return await this.fiatRampService.createWidgetUrl({
44796
+ exchangeType: params.exchangeType,
44797
+ isPassport,
44798
+ walletAddress,
44799
+ tokenAmount,
44800
+ tokenSymbol,
44801
+ email,
44802
+ });
44803
+ }
44804
+ /**
44805
+ * Fetches fiat ramp fee estimations.
44806
+ * @returns {Promise<OnRampProviderFees>} - A promise that resolves to OnRampProviderFees.
44807
+ */
44808
+ async getExchangeFeeEstimate() {
44809
+ return await this.fiatRampService.feeEstimate();
44810
+ }
44811
+ /**
44812
+ * Fetches Swap widget availability.
44813
+ * @returns {Promise<boolean>} - A promise that resolves to a boolean.
44814
+ */
44815
+ async isSwapAvailable() {
44816
+ return this.availability.checkDexAvailability();
44817
+ }
44818
+ }
44819
+
44820
+ class BlockExplorerService {
44821
+ /**
44822
+ * getTransationLink returns the link to the transaction on blockscout
44823
+ * @param hash transaction hash
44824
+ * @returns link to the transaction on blockscout
44825
+ */
44826
+ static getTransactionLink(chainId, hash) {
44827
+ const url = BLOCKSCOUT_CHAIN_URL_MAP?.[chainId]?.url;
44828
+ if (!url || !hash)
44829
+ return undefined;
44830
+ return `${url}/tx/${hash}`;
44831
+ }
44832
+ }
44833
+
44834
+ var checkout = /*#__PURE__*/Object.freeze({
44835
+ __proto__: null,
44836
+ BlockExplorerService: BlockExplorerService,
44837
+ get BridgeEventType () { return BridgeEventType; },
44838
+ get ChainId () { return ChainId; },
44839
+ get ChainName () { return ChainName; },
44840
+ get ChainSlug () { return ChainSlug; },
44841
+ Checkout: Checkout,
44842
+ CheckoutConfiguration: CheckoutConfiguration,
44843
+ get CheckoutErrorType () { return CheckoutErrorType; },
44844
+ get CheckoutStatus () { return CheckoutStatus; },
44845
+ get ConnectEventType () { return ConnectEventType; },
44846
+ get ConnectTargetLayer () { return ConnectTargetLayer; },
44847
+ get ExchangeType () { return ExchangeType; },
44848
+ get FeeType () { return FeeType; },
44849
+ get FundingStepType () { return FundingStepType; },
44850
+ get GasEstimateType () { return GasEstimateType; },
44851
+ get GasTokenType () { return GasTokenType; },
44852
+ IMMUTABLE_API_BASE_URL: IMMUTABLE_API_BASE_URL,
44853
+ get IMTBLWidgetEvents () { return IMTBLWidgetEvents; },
44854
+ get ItemType () { return ItemType; },
44855
+ get NetworkFilterTypes () { return NetworkFilterTypes; },
44856
+ get OnRampEventType () { return OnRampEventType; },
44857
+ get OrchestrationEventType () { return OrchestrationEventType; },
44858
+ get ProviderEventType () { return ProviderEventType; },
44859
+ get RoutingOutcomeType () { return RoutingOutcomeType; },
44860
+ get SaleEventType () { return SaleEventType; },
44861
+ get SalePaymentTypes () { return SalePaymentTypes; },
44862
+ get SwapEventType () { return SwapEventType; },
44863
+ get TokenFilterTypes () { return TokenFilterTypes; },
44864
+ get TransactionOrGasType () { return TransactionOrGasType; },
44865
+ get WalletEventType () { return WalletEventType; },
44866
+ get WalletFilterTypes () { return WalletFilterTypes; },
44867
+ get WalletProviderName () { return WalletProviderName; },
44868
+ get WidgetTheme () { return WidgetTheme; },
44869
+ get WidgetType () { return WidgetType; }
44870
+ });
44871
+
44872
+ function isChainValid(chainID, config) {
44873
+ return chainID === config.ethConfiguration.chainID;
44874
+ }
44875
+ async function validateChain(signer, config) {
44876
+ const chainID = await signer.getChainId();
44877
+ if (!isChainValid(chainID, config)) {
44878
+ throw new Error('The wallet used for this operation is not connected to the correct network.');
44879
+ }
44880
+ }
44881
+
44882
+ async function transfer({ signers: { ethSigner, starkSigner }, request, config, }) {
44883
+ await validateChain(ethSigner, config.immutableXConfig);
44884
+ const ethAddress = await ethSigner.getAddress();
44885
+ const transfersApi = new TransfersApi$1(config.immutableXConfig.apiConfiguration);
44886
+ const transferAmount = request.type === 'ERC721' ? '1' : request.amount;
44887
+ const signableResult = await transfersApi.getSignableTransferV1({
44888
+ getSignableTransferRequest: {
44889
+ sender: ethAddress,
44890
+ token: convertToSignableToken(request),
44891
+ amount: transferAmount,
44892
+ receiver: request.receiver,
44893
+ },
44894
+ });
44895
+ const { signable_message: signableMessage, payload_hash: payloadHash } = signableResult.data;
44896
+ const ethSignature = await signRaw(signableMessage, ethSigner);
44897
+ const starkSignature = await starkSigner.signMessage(payloadHash);
44898
+ const transferSigningParams = {
44899
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
44900
+ sender_stark_key: signableResult.data.sender_stark_key,
44901
+ sender_vault_id: signableResult.data.sender_vault_id,
44902
+ receiver_stark_key: signableResult.data.receiver_stark_key,
44903
+ receiver_vault_id: signableResult.data.receiver_vault_id,
44904
+ asset_id: signableResult.data.asset_id,
44905
+ amount: signableResult.data.amount,
44906
+ nonce: signableResult.data.nonce,
44907
+ expiration_timestamp: signableResult.data.expiration_timestamp,
44908
+ stark_signature: starkSignature,
44909
+ };
44910
+ const response = await transfersApi.createTransferV1({
44911
+ createTransferRequest: transferSigningParams,
44912
+ xImxEthAddress: ethAddress,
44913
+ xImxEthSignature: ethSignature,
44914
+ });
44915
+ return {
44916
+ sent_signature: response?.data.sent_signature,
44917
+ status: response?.data.status?.toString(),
44918
+ time: response?.data.time,
44919
+ transfer_id: response?.data.transfer_id,
44920
+ };
44921
+ }
44922
+ async function batchTransfer({ signers: { ethSigner, starkSigner }, request, config, }) {
44923
+ await validateChain(ethSigner, config.immutableXConfig);
44924
+ const ethAddress = await ethSigner.getAddress();
44925
+ const transfersApi = new TransfersApi$1(config.immutableXConfig.apiConfiguration);
44926
+ const signableRequests = request.map((nftTransfer) => ({
44927
+ amount: '1',
44928
+ token: convertToSignableToken({
44929
+ type: 'ERC721',
44930
+ tokenId: nftTransfer.tokenId,
44931
+ tokenAddress: nftTransfer.tokenAddress,
44932
+ }),
44933
+ receiver: nftTransfer.receiver,
44934
+ }));
44935
+ const signableResult = await transfersApi.getSignableTransfer({
44936
+ getSignableTransferRequestV2: {
44937
+ sender_ether_key: ethAddress,
44938
+ signable_requests: signableRequests,
44939
+ },
44940
+ });
44941
+ const signableMessage = signableResult.data.signable_message;
44942
+ if (signableMessage === undefined) {
44943
+ throw new Error('Invalid response from Signable registration offchain');
44944
+ }
44945
+ const ethSignature = await signRaw(signableMessage, ethSigner);
44946
+ const requests = [];
44947
+ for (const resp of signableResult.data.signable_responses) {
44948
+ // TODO: remove once fixed
44949
+ // eslint-disable-next-line no-await-in-loop
44950
+ const starkSignature = await starkSigner.signMessage(resp.payload_hash);
44951
+ const req = {
44952
+ sender_vault_id: resp.sender_vault_id,
44953
+ receiver_stark_key: resp.receiver_stark_key,
44954
+ receiver_vault_id: resp.receiver_vault_id,
44955
+ asset_id: resp.asset_id,
44956
+ amount: resp.amount,
44957
+ nonce: resp.nonce,
44958
+ expiration_timestamp: resp.expiration_timestamp,
44959
+ stark_signature: starkSignature,
45211
44960
  };
44961
+ requests.push(req);
45212
44962
  }
44963
+ // TODO: throw error on missing payload hash?
44964
+ const transferSigningParams = {
44965
+ sender_stark_key: signableResult.data.sender_stark_key,
44966
+ requests,
44967
+ };
44968
+ const response = await transfersApi.createTransfer({
44969
+ createTransferRequestV2: transferSigningParams,
44970
+ xImxEthAddress: ethAddress,
44971
+ xImxEthSignature: ethSignature,
44972
+ });
44973
+ return {
44974
+ transfer_ids: response?.data.transfer_ids,
44975
+ };
44976
+ }
44977
+
44978
+ async function createOrder({ signers, request, config, }) {
44979
+ await validateChain(signers.ethSigner, config.immutableXConfig);
44980
+ const ethAddress = await signers.ethSigner.getAddress();
44981
+ const ordersApi = new OrdersApi$2(config.immutableXConfig.apiConfiguration);
44982
+ const amountSell = request.sell.type === 'ERC721' ? '1' : request.sell.amount;
44983
+ const amountBuy = request.buy.type === 'ERC721' ? '1' : request.buy.amount;
44984
+ const getSignableOrderRequest = {
44985
+ user: ethAddress,
44986
+ amount_buy: amountBuy,
44987
+ token_buy: convertToSignableToken(request.buy),
44988
+ amount_sell: amountSell,
44989
+ token_sell: convertToSignableToken(request.sell),
44990
+ fees: request.fees,
44991
+ expiration_timestamp: request.expiration_timestamp,
44992
+ };
44993
+ const getSignableOrderResponse = await ordersApi.getSignableOrder({
44994
+ getSignableOrderRequestV3: getSignableOrderRequest,
44995
+ });
44996
+ const { signable_message: signableMessage, payload_hash: payloadHash } = getSignableOrderResponse.data;
44997
+ const ethSignature = await signRaw(signableMessage, signers.ethSigner);
44998
+ const starkSignature = await signers.starkSigner.signMessage(payloadHash);
44999
+ const resp = getSignableOrderResponse.data;
45000
+ const orderParams = {
45001
+ createOrderRequest: {
45002
+ amount_buy: resp.amount_buy,
45003
+ amount_sell: resp.amount_sell,
45004
+ asset_id_buy: resp.asset_id_buy,
45005
+ asset_id_sell: resp.asset_id_sell,
45006
+ expiration_timestamp: resp.expiration_timestamp,
45007
+ fees: request.fees,
45008
+ nonce: resp.nonce,
45009
+ stark_key: resp.stark_key,
45010
+ stark_signature: starkSignature,
45011
+ vault_id_buy: resp.vault_id_buy,
45012
+ vault_id_sell: resp.vault_id_sell,
45013
+ },
45014
+ xImxEthAddress: ethAddress,
45015
+ xImxEthSignature: ethSignature,
45016
+ };
45017
+ const createOrderResponse = await ordersApi.createOrderV3(orderParams);
45213
45018
  return {
45214
- status: CheckoutStatus.INSUFFICIENT_FUNDS,
45215
- smartCheckoutResult,
45019
+ ...createOrderResponse.data,
45216
45020
  };
45217
- };
45021
+ }
45022
+ async function cancelOrder({ signers, request, config, }) {
45023
+ const ordersApi = new OrdersApi$2(config.immutableXConfig.apiConfiguration);
45024
+ const getSignableCancelOrderResponse = await ordersApi.getSignableCancelOrderV3({
45025
+ getSignableCancelOrderRequest: {
45026
+ order_id: request.order_id,
45027
+ },
45028
+ });
45029
+ const { signable_message: signableMessage, payload_hash: payloadHash } = getSignableCancelOrderResponse.data;
45030
+ const ethSignature = await signRaw(signableMessage, signers.ethSigner);
45031
+ const starkSignature = await signers.starkSigner.signMessage(payloadHash);
45032
+ const ethAddress = await signers.ethSigner.getAddress();
45033
+ const cancelOrderResponse = await ordersApi.cancelOrderV3({
45034
+ id: request.order_id.toString(),
45035
+ cancelOrderRequest: {
45036
+ order_id: request.order_id,
45037
+ stark_signature: starkSignature,
45038
+ },
45039
+ xImxEthAddress: ethAddress,
45040
+ xImxEthSignature: ethSignature,
45041
+ });
45042
+ return {
45043
+ order_id: cancelOrderResponse.data.order_id,
45044
+ status: cancelOrderResponse.data.status,
45045
+ };
45046
+ }
45218
45047
 
45219
- const cancel = async (config, provider, orderIds, overrides = {
45220
- waitFulfillmentSettlements: true,
45221
- }) => {
45222
- let unsignedCancelOrderTransaction;
45223
- if (orderIds.length === 0) {
45224
- throw new CheckoutError('No orderIds were provided to the orderIds array. Please provide at least one orderId.', CheckoutErrorType.CANCEL_ORDER_LISTING_ERROR);
45225
- }
45226
- // Update this when bulk cancel is supported
45227
- const orderId = orderIds[0];
45048
+ async function registerOffchain(signers, config) {
45049
+ await validateChain(signers.ethSigner, config.immutableXConfig);
45050
+ const usersApi = new UsersApi$1(config.immutableXConfig.apiConfiguration);
45051
+ const userAddress = await signers.ethSigner.getAddress();
45052
+ const starkPublicKey = await signers.starkSigner.getAddress();
45053
+ const signableResult = await usersApi.getSignableRegistrationOffchain({
45054
+ getSignableRegistrationRequest: {
45055
+ ether_key: userAddress,
45056
+ stark_key: starkPublicKey,
45057
+ },
45058
+ });
45059
+ const { signable_message: signableMessage, payload_hash: payloadHash } = signableResult.data;
45060
+ const ethSignature = await signRaw(signableMessage, signers.ethSigner);
45061
+ const starkSignature = await signers.starkSigner.signMessage(payloadHash);
45062
+ const registeredUser = await usersApi.registerUser({
45063
+ registerUserRequest: {
45064
+ eth_signature: ethSignature,
45065
+ ether_key: userAddress,
45066
+ stark_signature: starkSignature,
45067
+ stark_key: starkPublicKey,
45068
+ },
45069
+ });
45070
+ return registeredUser.data;
45071
+ }
45072
+ async function isRegisteredOffchain(ethAddress, config) {
45228
45073
  try {
45229
- const offererAddress = await measureAsyncExecution(config, 'Time to get the address from the provider', provider.getSigner().getAddress());
45230
- const orderbook = createOrderbookInstance(config);
45231
- const cancelOrderResponse = await measureAsyncExecution(config, 'Time to get the cancel order from the orderbook', orderbook.cancelOrdersOnChain([orderId], offererAddress));
45232
- unsignedCancelOrderTransaction = await cancelOrderResponse.cancellationAction.buildTransaction();
45233
- }
45234
- catch (err) {
45235
- throw new CheckoutError('An error occurred while cancelling the order listing', CheckoutErrorType.CANCEL_ORDER_LISTING_ERROR, {
45236
- orderId,
45237
- error: err,
45074
+ const usersApi = new UsersApi$1(config.immutableXConfig.apiConfiguration);
45075
+ const getUsersResult = await usersApi.getUsers({
45076
+ user: ethAddress,
45238
45077
  });
45078
+ const { accounts } = getUsersResult.data;
45079
+ return accounts?.length > 0;
45239
45080
  }
45240
- if (overrides.waitFulfillmentSettlements) {
45241
- const result = await signFulfillmentTransactions(provider, [unsignedCancelOrderTransaction]);
45242
- if (result.type === SignTransactionStatusType.FAILED) {
45243
- return {
45244
- status: CheckoutStatus.FAILED,
45245
- transactionHash: result.transactionHash,
45246
- reason: result.reason,
45247
- };
45081
+ catch (ex) {
45082
+ if (ex instanceof AxiosError$2 && ex.response?.status === 404) {
45083
+ return false;
45248
45084
  }
45249
- return {
45250
- status: CheckoutStatus.SUCCESS,
45251
- };
45085
+ throw ex;
45252
45086
  }
45253
- let transactions;
45087
+ }
45088
+ async function isRegisteredOnChain(starkPublicKey, ethSigner, config) {
45089
+ await validateChain(ethSigner, config.immutableXConfig);
45090
+ const registrationContract = Contracts.Registration.connect(config.immutableXConfig.ethConfiguration.registrationContractAddress, ethSigner);
45254
45091
  try {
45255
- const response = await Promise.all([unsignedCancelOrderTransaction].map((transaction) => sendTransaction(provider, transaction)));
45256
- transactions = response.map((result) => result.transactionResponse);
45092
+ return await registrationContract.isRegistered(starkPublicKey);
45257
45093
  }
45258
- catch (err) {
45259
- throw new CheckoutError('An error occurred while executing the fulfillment transaction', CheckoutErrorType.EXECUTE_FULFILLMENT_TRANSACTION_ERROR, {
45260
- message: err.message,
45261
- });
45094
+ catch (ex) {
45095
+ if (ex.reason === 'USER_UNREGISTERED') {
45096
+ return false;
45097
+ }
45098
+ throw ex;
45262
45099
  }
45100
+ }
45101
+ async function getSignableRegistrationOnchain(etherKey, starkPublicKey, usersApi) {
45102
+ const response = await usersApi.getSignableRegistration({
45103
+ getSignableRegistrationRequest: {
45104
+ ether_key: etherKey,
45105
+ stark_key: starkPublicKey,
45106
+ },
45107
+ });
45263
45108
  return {
45264
- status: CheckoutStatus.FULFILLMENTS_UNSETTLED,
45265
- transactions,
45109
+ operator_signature: response.data.operator_signature,
45110
+ payload_hash: response.data.payload_hash,
45111
+ readable_transaction: response.data.readable_transaction,
45112
+ verification_signature: response.data.verification_signature,
45266
45113
  };
45267
- };
45114
+ }
45268
45115
 
45269
- const getERC721Requirement = (id, contractAddress, spenderAddress) => ({
45270
- type: ItemType.ERC721,
45271
- id,
45272
- contractAddress,
45273
- spenderAddress,
45274
- });
45275
- const getBuyToken = (buyToken, decimals = 18) => {
45276
- const bnAmount = utils$3.parseUnits(buyToken.amount, decimals);
45277
- if (buyToken.type === ItemType.NATIVE) {
45278
- return {
45279
- type: ItemType.NATIVE,
45280
- amount: bnAmount.toString(),
45281
- };
45282
- }
45283
- return {
45284
- type: ItemType.ERC20,
45285
- amount: bnAmount.toString(),
45286
- contractAddress: buyToken.tokenAddress,
45287
- };
45116
+ const assertIsDefined = (value) => {
45117
+ if (value !== undefined)
45118
+ return value;
45119
+ throw new Error('undefined field exception');
45288
45120
  };
45289
- const sell = async (config, provider, orders) => {
45290
- let orderbook;
45291
- let listing;
45292
- let spenderAddress = '';
45293
- if (orders.length === 0) {
45294
- throw new CheckoutError('No orders were provided to the orders array. Please provide at least one order.', CheckoutErrorType.PREPARE_ORDER_LISTING_ERROR);
45295
- }
45296
- const { buyToken, sellToken, makerFees, orderExpiry, } = orders[0];
45297
- let decimals = 18;
45298
- if (buyToken.type === ItemType.ERC20) {
45299
- // get this from the allowed list
45300
- const buyTokenContract = new Contract$1(buyToken.tokenAddress, JSON.stringify(ERC20ABI), provider);
45301
- decimals = await measureAsyncExecution(config, 'Time to get decimals of token contract for the buy token', buyTokenContract.decimals());
45302
- }
45303
- const buyTokenOrNative = getBuyToken(buyToken, decimals);
45304
- try {
45305
- const walletAddress = await measureAsyncExecution(config, 'Time to get the address from the provider', provider.getSigner().getAddress());
45306
- orderbook = createOrderbookInstance(config);
45307
- const { seaportContractAddress } = orderbook.config();
45308
- spenderAddress = seaportContractAddress;
45309
- listing = await measureAsyncExecution(config, 'Time to prepare the listing from the orderbook', orderbook.prepareListing({
45310
- makerAddress: walletAddress,
45311
- buy: buyTokenOrNative,
45312
- sell: {
45313
- type: ItemType.ERC721,
45314
- contractAddress: sellToken.collectionAddress,
45315
- tokenId: sellToken.id,
45121
+ async function prepareWithdrawalAction(params) {
45122
+ const { signers: { ethSigner, starkSigner }, type, config, } = params;
45123
+ await validateChain(ethSigner, params.config);
45124
+ const withdrawalsApi = new WithdrawalsApi$1(config.apiConfiguration);
45125
+ const withdrawalAmount = type === 'ERC721' ? '1' : params.amount;
45126
+ const signableWithdrawalResult = await withdrawalsApi.getSignableWithdrawal({
45127
+ getSignableWithdrawalRequest: {
45128
+ user: await ethSigner.getAddress(),
45129
+ token: convertToSignableToken(params),
45130
+ amount: withdrawalAmount,
45131
+ },
45132
+ });
45133
+ const { signable_message: signableMessage, payload_hash: payloadHash } = signableWithdrawalResult.data;
45134
+ const starkSignature = await starkSigner.signMessage(payloadHash);
45135
+ const { ethAddress, ethSignature } = await signMessage$1(signableMessage, ethSigner);
45136
+ const prepareWithdrawalResponse = await withdrawalsApi.createWithdrawal({
45137
+ createWithdrawalRequest: {
45138
+ stark_key: assertIsDefined(signableWithdrawalResult.data.stark_key),
45139
+ amount: withdrawalAmount,
45140
+ asset_id: assertIsDefined(signableWithdrawalResult.data.asset_id),
45141
+ vault_id: assertIsDefined(signableWithdrawalResult.data.vault_id),
45142
+ nonce: assertIsDefined(signableWithdrawalResult.data.nonce),
45143
+ stark_signature: starkSignature,
45144
+ },
45145
+ xImxEthAddress: ethAddress,
45146
+ xImxEthSignature: ethSignature,
45147
+ });
45148
+ return prepareWithdrawalResponse.data;
45149
+ }
45150
+
45151
+ async function getEncodeAssetInfo(assetType, tokenType, config, tokenData) {
45152
+ const encodingApi = new EncodingApi$1(config.apiConfiguration);
45153
+ const result = await encodingApi.encodeAsset({
45154
+ assetType,
45155
+ encodeAssetRequest: {
45156
+ token: {
45157
+ type: tokenType,
45158
+ ...(tokenData && { data: tokenData }),
45316
45159
  },
45317
- orderExpiry,
45318
- }));
45319
- }
45320
- catch (err) {
45321
- throw new CheckoutError('An error occurred while preparing the listing', CheckoutErrorType.PREPARE_ORDER_LISTING_ERROR, {
45322
- error: err,
45323
- id: sellToken.id,
45324
- collectionAddress: sellToken.collectionAddress,
45325
- });
45326
- }
45327
- const itemRequirements = [
45328
- getERC721Requirement(sellToken.id, sellToken.collectionAddress, spenderAddress),
45329
- ];
45330
- const smartCheckoutResult = await measureAsyncExecution(config, 'Total time running smart checkout', smartCheckout(config, provider, itemRequirements, {
45331
- type: TransactionOrGasType.GAS,
45332
- gasToken: {
45333
- type: GasTokenType.NATIVE,
45334
- limit: BigNumber$1.from(constants.estimatedFulfillmentGasGwei),
45335
45160
  },
45336
- }));
45337
- if (smartCheckoutResult.sufficient) {
45338
- const unsignedTransactions = await getUnsignedERC721Transactions(listing.actions);
45339
- const approvalResult = await signApprovalTransactions(provider, unsignedTransactions.approvalTransactions);
45340
- if (approvalResult.type === SignTransactionStatusType.FAILED) {
45341
- return {
45342
- status: CheckoutStatus.FAILED,
45343
- transactionHash: approvalResult.transactionHash,
45344
- reason: approvalResult.reason,
45345
- smartCheckoutResult,
45346
- };
45347
- }
45348
- const unsignedMessage = getUnsignedMessage(listing.orderHash, listing.orderComponents, listing.actions);
45349
- if (!unsignedMessage) {
45350
- // For sell it is expected the orderbook will always return an unsigned message
45351
- // If for some reason it is missing then we cannot proceed with the create listing
45352
- throw new CheckoutError('The unsigned message is missing after preparing the listing', CheckoutErrorType.SIGN_MESSAGE_ERROR, {
45353
- id: sellToken.id,
45354
- collectionAddress: sellToken.collectionAddress,
45355
- });
45356
- }
45357
- const signedMessage = await signMessage(provider, unsignedMessage);
45358
- let orderId = '';
45359
- const createListingParams = {
45360
- orderComponents: signedMessage.orderComponents,
45361
- orderHash: signedMessage.orderHash,
45362
- orderSignature: signedMessage.signedMessage,
45363
- makerFees: [],
45364
- };
45365
- if (makerFees !== undefined) {
45366
- const orderBookFees = calculateFees(makerFees, buyTokenOrNative.amount, decimals);
45367
- if (orderBookFees.length !== makerFees.length) {
45368
- throw new CheckoutError('One of the fees is too small, must be greater than 0.000001', CheckoutErrorType.CREATE_ORDER_LISTING_ERROR);
45369
- }
45370
- createListingParams.makerFees = orderBookFees;
45371
- }
45372
- try {
45373
- const order = await orderbook.createListing(createListingParams);
45374
- orderId = order.result.id;
45375
- }
45376
- catch (err) {
45377
- throw new CheckoutError('An error occurred while creating the listing', CheckoutErrorType.CREATE_ORDER_LISTING_ERROR, {
45378
- error: err,
45379
- collectionId: sellToken.id,
45380
- collectionAddress: sellToken.collectionAddress,
45381
- });
45382
- }
45383
- return {
45384
- status: CheckoutStatus.SUCCESS,
45385
- orderIds: [orderId],
45386
- smartCheckoutResult,
45387
- };
45388
- }
45389
- return {
45390
- status: CheckoutStatus.INSUFFICIENT_FUNDS,
45391
- smartCheckoutResult,
45392
- };
45393
- };
45161
+ });
45162
+ return result.data;
45163
+ }
45394
45164
 
45395
- class FiatRampService {
45396
- config;
45397
- /**
45398
- * Constructs a new instance of the FiatRampService class.
45399
- * @param {CheckoutConfiguration} config - The config required for the FiatRampService.
45400
- */
45401
- constructor(config) {
45402
- this.config = config;
45165
+ async function executeRegisterAndWithdrawERC20({ ethSigner, assetType, starkPublicKey, config, }) {
45166
+ const etherKey = await ethSigner.getAddress();
45167
+ const imxConfig = config.immutableXConfig;
45168
+ const usersApi = new UsersApi$1(imxConfig.apiConfiguration);
45169
+ const signableResult = await getSignableRegistrationOnchain(etherKey, starkPublicKey, usersApi);
45170
+ const contract = Contracts.Registration.connect(config.immutableXConfig.ethConfiguration.registrationContractAddress, ethSigner);
45171
+ const populatedTransaction = await contract.populateTransaction.registerAndWithdraw(etherKey, starkPublicKey, signableResult.operator_signature, assetType);
45172
+ return ethSigner.sendTransaction(populatedTransaction);
45173
+ }
45174
+ async function executeWithdrawERC20(ethSigner, assetType, starkPublicKey, config) {
45175
+ const contract = Contracts.Core.connect(config.ethConfiguration.coreContractAddress, ethSigner);
45176
+ const populatedTransaction = await contract.populateTransaction.withdraw(starkPublicKey, assetType);
45177
+ return ethSigner.sendTransaction(populatedTransaction);
45178
+ }
45179
+ async function completeERC20WithdrawalAction({ ethSigner, starkPublicKey, token, config, }) {
45180
+ await validateChain(ethSigner, config.immutableXConfig);
45181
+ const imxConfig = config.immutableXConfig;
45182
+ const assetType = await getEncodeAssetInfo('asset', 'ERC20', imxConfig, {
45183
+ token_address: token.tokenAddress,
45184
+ });
45185
+ const isRegistered = await isRegisteredOnChain(starkPublicKey, ethSigner, config);
45186
+ if (!isRegistered) {
45187
+ return executeRegisterAndWithdrawERC20({
45188
+ ethSigner,
45189
+ assetType: assetType.asset_type,
45190
+ starkPublicKey,
45191
+ config,
45192
+ });
45403
45193
  }
45404
- async feeEstimate() {
45405
- const config = (await this.config.remote.getConfig('onramp'));
45406
- return config[OnRampProvider.TRANSAK]?.fees;
45194
+ return executeWithdrawERC20(ethSigner, assetType.asset_type, starkPublicKey, imxConfig);
45195
+ }
45196
+
45197
+ async function executeWithdrawMintableERC721(ethSigner, assetType, starkPublicKey, mintingBlob, config) {
45198
+ const contract = Contracts.Core.connect(config.ethConfiguration.coreContractAddress, ethSigner);
45199
+ const populatedTransaction = await contract.populateTransaction.withdrawAndMint(starkPublicKey, assetType, mintingBlob);
45200
+ return ethSigner.sendTransaction(populatedTransaction);
45201
+ }
45202
+ async function executeRegisterAndWithdrawMintableERC721(ethSigner, assetType, starkPublicKey, mintingBlob, config) {
45203
+ const etherKey = await ethSigner.getAddress();
45204
+ const usersApi = new UsersApi$1(config.apiConfiguration);
45205
+ const signableResult = await getSignableRegistrationOnchain(etherKey, starkPublicKey, usersApi);
45206
+ const contract = Contracts.Registration.connect(config.ethConfiguration.registrationContractAddress, ethSigner);
45207
+ const populatedTransaction = await contract.populateTransaction.regsiterAndWithdrawAndMint(etherKey, starkPublicKey, signableResult.operator_signature, assetType, mintingBlob);
45208
+ return ethSigner.sendTransaction(populatedTransaction);
45209
+ }
45210
+ function getMintingBlob(token) {
45211
+ const { id } = token.data;
45212
+ const blueprint = token.data.blueprint || '';
45213
+ return encUtils.sanitizeHex(encUtils.utf8ToHex(`{${id}}:{${blueprint}}`));
45214
+ }
45215
+ async function completeMintableERC721Withdrawal(ethSigner, starkPublicKey, token, config) {
45216
+ const imxConfig = config.immutableXConfig;
45217
+ const assetType = await getEncodeAssetInfo('mintable-asset', 'ERC721', imxConfig, {
45218
+ id: token.data.id,
45219
+ token_address: token.data.tokenAddress,
45220
+ ...(token.data.blueprint && { blueprint: token.data.blueprint }),
45221
+ });
45222
+ const mintingBlob = getMintingBlob(token);
45223
+ const isRegistered = await isRegisteredOnChain(starkPublicKey, ethSigner, config);
45224
+ if (!isRegistered) {
45225
+ return executeRegisterAndWithdrawMintableERC721(ethSigner, assetType.asset_type, starkPublicKey, mintingBlob, imxConfig);
45407
45226
  }
45408
- async createWidgetUrl(params) {
45409
- return (await this.getTransakWidgetUrl(params));
45227
+ return executeWithdrawMintableERC721(ethSigner, assetType.asset_type, starkPublicKey, mintingBlob, imxConfig);
45228
+ }
45229
+ async function executeRegisterAndWithdrawERC721(ethSigner, assetType, starkPublicKey, tokenId, config) {
45230
+ const etherKey = await ethSigner.getAddress();
45231
+ const usersApi = new UsersApi$1(config.apiConfiguration);
45232
+ const signableResult = await getSignableRegistrationOnchain(etherKey, starkPublicKey, usersApi);
45233
+ const contract = Contracts.Registration.connect(config.ethConfiguration.registrationContractAddress, ethSigner);
45234
+ const populatedTransaction = await contract.populateTransaction.registerAndWithdrawNft(etherKey, starkPublicKey, signableResult.operator_signature, assetType, tokenId);
45235
+ return ethSigner.sendTransaction(populatedTransaction);
45236
+ }
45237
+ async function executeWithdrawERC721(ethSigner, assetType, starkPublicKey, tokenId, config) {
45238
+ const contract = Contracts.Core.connect(config.ethConfiguration.coreContractAddress, ethSigner);
45239
+ const populatedTransaction = await contract.populateTransaction.withdrawNft(starkPublicKey, assetType, tokenId);
45240
+ return ethSigner.sendTransaction(populatedTransaction);
45241
+ }
45242
+ async function completeERC721Withdrawal(ethSigner, starkPublicKey, token, config) {
45243
+ const imxConfig = config.immutableXConfig;
45244
+ const assetType = await getEncodeAssetInfo('asset', 'ERC721', imxConfig, {
45245
+ token_id: token.tokenId,
45246
+ token_address: token.tokenAddress,
45247
+ });
45248
+ const isRegistered = await isRegisteredOnChain(starkPublicKey, ethSigner, config);
45249
+ if (!isRegistered) {
45250
+ return executeRegisterAndWithdrawERC721(ethSigner, assetType.asset_type, starkPublicKey, token.tokenId, imxConfig);
45410
45251
  }
45411
- async getTransakWidgetUrl(params) {
45412
- let widgetUrl = `${TRANSAK_API_BASE_URL[this.config.environment]}?`;
45413
- const onRampConfig = (await this.config.remote.getConfig('onramp'));
45414
- const apiKey = onRampConfig[OnRampProvider.TRANSAK].publishableApiKey;
45415
- const transakPublishableKey = `apiKey=${apiKey}`;
45416
- const zkevmNetwork = 'network=immutablezkevm';
45417
- const defaultPaymentMethod = 'defaultPaymentMethod=credit_debit_card';
45418
- const disableBankTransfer = 'disablePaymentMethods=sepa_bank_transfer,gbp_bank_transfer,'
45419
- + 'pm_cash_app,pm_jwire,pm_paymaya,pm_bpi,pm_ubp,pm_grabpay,pm_shopeepay,pm_gcash,pm_pix,'
45420
- + 'pm_astropay,pm_pse,inr_bank_transfer';
45421
- const productsAvailed = 'productsAvailed=buy';
45422
- const exchangeScreenTitle = 'exchangeScreenTitle=Buy';
45423
- const themeColor = 'themeColor=0D0D0D';
45424
- widgetUrl += `${transakPublishableKey}&`
45425
- + `${zkevmNetwork}&`
45426
- + `${defaultPaymentMethod}&`
45427
- + `${disableBankTransfer}&`
45428
- + `${productsAvailed}&`
45429
- + `${exchangeScreenTitle}&`
45430
- + `${themeColor}`;
45431
- if (params.isPassport && params.email) {
45432
- const encodedEmail = encodeURIComponent(params.email);
45433
- widgetUrl += `&email=${encodedEmail}&isAutoFillUserData=true&disableWalletAddressForm=true`;
45434
- }
45435
- if (params.tokenAmount && params.tokenSymbol) {
45436
- widgetUrl += `&defaultCryptoAmount=${params.tokenAmount}&cryptoCurrencyCode=${params.tokenSymbol}`;
45437
- }
45438
- else {
45439
- widgetUrl += '&defaultCryptoCurrency=IMX';
45440
- }
45441
- if (params.walletAddress) {
45442
- widgetUrl += `&walletAddress=${params.walletAddress}`;
45252
+ return executeWithdrawERC721(ethSigner, assetType.asset_type, starkPublicKey, token.tokenId, imxConfig);
45253
+ }
45254
+ async function completeERC721WithdrawalAction({ ethSigner, starkPublicKey, token, config, }) {
45255
+ await validateChain(ethSigner, config.immutableXConfig);
45256
+ const { tokenAddress } = token;
45257
+ const { tokenId } = token;
45258
+ const imxConfig = config.immutableXConfig;
45259
+ const mintsApi = new MintsApi$1(imxConfig.apiConfiguration);
45260
+ return await mintsApi
45261
+ .getMintableTokenDetailsByClientTokenId({
45262
+ tokenAddress,
45263
+ tokenId,
45264
+ })
45265
+ .then((mintableToken) => completeMintableERC721Withdrawal(ethSigner, starkPublicKey, {
45266
+ type: 'ERC721',
45267
+ data: {
45268
+ id: tokenId,
45269
+ tokenAddress,
45270
+ blueprint: mintableToken.data.blueprint,
45271
+ },
45272
+ }, config))
45273
+ .catch((error) => {
45274
+ if (error.response?.status === 404) {
45275
+ // token is already minted on L1
45276
+ return completeERC721Withdrawal(ethSigner, starkPublicKey, token, config);
45443
45277
  }
45444
- return widgetUrl;
45278
+ throw error; // unable to recover from any other kind of error
45279
+ });
45280
+ }
45281
+
45282
+ async function executeRegisterAndWithdrawEth(ethSigner, assetType, starkPublicKey, config) {
45283
+ const etherKey = await ethSigner.getAddress();
45284
+ const usersApi = new UsersApi$1(config.apiConfiguration);
45285
+ const signableResult = await getSignableRegistrationOnchain(etherKey, starkPublicKey, usersApi);
45286
+ const contract = Contracts.Registration.connect(config.ethConfiguration.registrationContractAddress, ethSigner);
45287
+ const populatedTransaction = await contract.populateTransaction.registerAndWithdraw(etherKey, starkPublicKey, signableResult.operator_signature, assetType);
45288
+ return ethSigner.sendTransaction(populatedTransaction);
45289
+ }
45290
+ async function executeWithdrawEth(ethSigner, assetType, starkPublicKey, config) {
45291
+ const contract = Contracts.Core.connect(config.ethConfiguration.coreContractAddress, ethSigner);
45292
+ const populatedTransaction = await contract.populateTransaction.withdraw(starkPublicKey, assetType);
45293
+ return ethSigner.sendTransaction(populatedTransaction);
45294
+ }
45295
+ async function completeEthWithdrawalAction({ ethSigner, starkPublicKey, config, }) {
45296
+ await validateChain(ethSigner, config.immutableXConfig);
45297
+ const imxConfig = config.immutableXConfig;
45298
+ const assetType = await getEncodeAssetInfo('asset', 'ETH', imxConfig);
45299
+ const isRegistered = await isRegisteredOnChain(starkPublicKey, ethSigner, config);
45300
+ if (!isRegistered) {
45301
+ return executeRegisterAndWithdrawEth(ethSigner, assetType.asset_type, starkPublicKey, imxConfig);
45302
+ }
45303
+ return executeWithdrawEth(ethSigner, assetType.asset_type, starkPublicKey, imxConfig);
45304
+ }
45305
+
45306
+ async function prepareWithdrawal({ signers, withdrawal, config, }) {
45307
+ return prepareWithdrawalAction({
45308
+ signers,
45309
+ config: config.immutableXConfig,
45310
+ ...withdrawal,
45311
+ });
45312
+ }
45313
+ // TODO: remove once fixed
45314
+ // eslint-disable-next-line consistent-return
45315
+ async function completeWithdrawal({ signers: { ethSigner }, starkPublicKey, token, config, }) {
45316
+ // TODO: please add a reasonable default here
45317
+ // eslint-disable-next-line default-case
45318
+ switch (token.type) {
45319
+ case 'ETH':
45320
+ return completeEthWithdrawalAction({ ethSigner, starkPublicKey, config });
45321
+ case 'ERC20':
45322
+ return completeERC20WithdrawalAction({
45323
+ ethSigner,
45324
+ starkPublicKey,
45325
+ token,
45326
+ config,
45327
+ });
45328
+ case 'ERC721':
45329
+ return completeERC721WithdrawalAction({
45330
+ ethSigner,
45331
+ starkPublicKey,
45332
+ token,
45333
+ config,
45334
+ });
45445
45335
  }
45446
45336
  }
45447
45337
 
45448
- async function getItemRequirementsFromRequirements(provider, requirements) {
45449
- // Get all decimal values by calling contracts for each ERC20
45450
- const decimalPromises = [];
45451
- requirements.forEach((itemRequirementParam) => {
45452
- if (itemRequirementParam.type === ItemType.ERC20) {
45453
- const { tokenAddress } = itemRequirementParam;
45454
- decimalPromises.push(getTokenContract(tokenAddress, ERC20ABI, provider).decimals());
45455
- }
45338
+ async function createTrade({ signers: { ethSigner, starkSigner }, request, config, }) {
45339
+ await validateChain(ethSigner, config.immutableXConfig);
45340
+ const ethAddress = await ethSigner.getAddress();
45341
+ const tradesApi = new TradesApi$1(config.immutableXConfig.apiConfiguration);
45342
+ const signableResult = await tradesApi.getSignableTrade({
45343
+ getSignableTradeRequest: {
45344
+ user: ethAddress,
45345
+ order_id: request.order_id,
45346
+ fees: request.fees,
45347
+ },
45456
45348
  });
45457
- const decimals = await Promise.all(decimalPromises);
45458
- // Map ItemRequirementsParam objects to ItemRequirement by parsing amounts from formatted string to BigNumebrs
45459
- const itemRequirements = requirements.map((itemRequirementParam, index) => {
45460
- if (itemRequirementParam.type === ItemType.NATIVE) {
45461
- return {
45462
- ...itemRequirementParam,
45463
- amount: utils$3.parseUnits(itemRequirementParam.amount, 18),
45464
- };
45465
- }
45466
- if (itemRequirementParam.type === ItemType.ERC20) {
45467
- return {
45468
- ...itemRequirementParam,
45469
- amount: utils$3.parseUnits(itemRequirementParam.amount, decimals[index]),
45470
- };
45471
- }
45472
- return itemRequirementParam;
45349
+ const { signable_message: signableMessage, payload_hash: payloadHash } = signableResult.data;
45350
+ const ethSignature = await signRaw(signableMessage, ethSigner);
45351
+ const starkSignature = await starkSigner.signMessage(payloadHash);
45352
+ const createTradeResponse = await tradesApi.createTradeV3({
45353
+ createTradeRequest: {
45354
+ amount_buy: signableResult.data.amount_buy,
45355
+ amount_sell: signableResult.data.amount_sell,
45356
+ asset_id_buy: signableResult.data.asset_id_buy,
45357
+ asset_id_sell: signableResult.data.asset_id_sell,
45358
+ expiration_timestamp: signableResult.data.expiration_timestamp,
45359
+ fee_info: signableResult.data.fee_info,
45360
+ fees: request.fees,
45361
+ include_fees: true,
45362
+ nonce: signableResult.data.nonce,
45363
+ order_id: request.order_id,
45364
+ stark_key: signableResult.data.stark_key,
45365
+ vault_id_buy: signableResult.data.vault_id_buy,
45366
+ vault_id_sell: signableResult.data.vault_id_sell,
45367
+ stark_signature: starkSignature,
45368
+ },
45369
+ xImxEthAddress: ethAddress,
45370
+ xImxEthSignature: ethSignature,
45473
45371
  });
45474
- return itemRequirements;
45372
+ return createTradeResponse.data;
45475
45373
  }
45476
45374
 
45477
- /**
45478
- * Validates and builds a version string based on the given SemanticVersion object.
45479
- * If the version is undefined or has an invalid major version, it returns the default checkout version.
45480
- * If the version is all zeros, it also returns the default checkout version.
45481
- * Otherwise, it constructs a validated version string based on the major, minor, patch, and build numbers.
45482
- */
45483
- function validateAndBuildVersion(version) {
45484
- const defaultPackageVersion = globalPackageVersion();
45485
- if (version === undefined || version.major === undefined)
45486
- return defaultPackageVersion;
45487
- if (!Number.isInteger(version.major) || version.major < 0)
45488
- return defaultPackageVersion;
45489
- if (version.minor !== undefined && version.minor < 0)
45490
- return defaultPackageVersion;
45491
- if (version.patch !== undefined && version.patch < 0)
45492
- return defaultPackageVersion;
45493
- if (version.major === 0 && version.minor === undefined)
45494
- return defaultPackageVersion;
45495
- if (version.major === 0 && version.minor === 0 && version.patch === undefined)
45496
- return defaultPackageVersion;
45497
- if (version.major === 0 && version.minor === undefined && version.patch === undefined)
45498
- return defaultPackageVersion;
45499
- if (version.major === 0 && version.minor === 0 && version.patch === 0)
45500
- return defaultPackageVersion;
45501
- let validatedVersion = version.major.toString();
45502
- if (version.minor === undefined)
45503
- return validatedVersion;
45504
- if (Number.isInteger(version.minor)) {
45505
- validatedVersion += `.${version.minor.toString()}`;
45375
+ async function executeRegisterAndDepositEth(ethSigner, amount, assetType, starkPublicKey, vaultId, config, usersApi) {
45376
+ const etherKey = await ethSigner.getAddress();
45377
+ const coreContract = Contracts.Core.connect(config.ethConfiguration.coreContractAddress, ethSigner);
45378
+ const signableResult = await getSignableRegistrationOnchain(etherKey, starkPublicKey, usersApi);
45379
+ const populatedTransaction = await coreContract.populateTransaction.registerAndDepositEth(etherKey, starkPublicKey, signableResult.operator_signature, assetType, vaultId);
45380
+ return ethSigner.sendTransaction({ ...populatedTransaction, value: amount });
45381
+ }
45382
+ async function executeDepositEth(ethSigner, amount, assetType, starkPublicKey, vaultId, config) {
45383
+ const coreContract = Contracts.Core.connect(config.ethConfiguration.coreContractAddress, ethSigner);
45384
+ const populatedTransaction = await coreContract.populateTransaction['deposit(uint256,uint256,uint256)'](starkPublicKey, assetType, vaultId);
45385
+ return ethSigner.sendTransaction({ ...populatedTransaction, value: amount });
45386
+ }
45387
+ async function depositEth({ signers: { ethSigner }, deposit, config, }) {
45388
+ await validateChain(ethSigner, config.immutableXConfig);
45389
+ const user = await ethSigner.getAddress();
45390
+ const data = {
45391
+ decimals: 18,
45392
+ };
45393
+ const amount = parseUnits(deposit.amount, 'wei');
45394
+ const imxConfig = config.immutableXConfig;
45395
+ const depositsApi = new DepositsApi$1(imxConfig.apiConfiguration);
45396
+ const encodingApi = new EncodingApi$1(imxConfig.apiConfiguration);
45397
+ const usersApi = new UsersApi$1(imxConfig.apiConfiguration);
45398
+ const getSignableDepositRequest = {
45399
+ user,
45400
+ token: {
45401
+ type: deposit.type,
45402
+ data,
45403
+ },
45404
+ amount: amount.toString(),
45405
+ };
45406
+ const signableDepositResult = await depositsApi.getSignableDeposit({
45407
+ getSignableDepositRequest,
45408
+ });
45409
+ const encodingResult = await encodingApi.encodeAsset({
45410
+ assetType: 'asset',
45411
+ encodeAssetRequest: {
45412
+ token: {
45413
+ type: deposit.type,
45414
+ },
45415
+ },
45416
+ });
45417
+ const assetType = encodingResult.data.asset_type;
45418
+ const starkPublicKey = signableDepositResult.data.stark_key;
45419
+ const vaultId = signableDepositResult.data.vault_id;
45420
+ const isRegistered = await isRegisteredOnChain(starkPublicKey, ethSigner, config);
45421
+ if (!isRegistered) {
45422
+ return executeRegisterAndDepositEth(ethSigner, amount, assetType, starkPublicKey, vaultId, imxConfig, usersApi);
45506
45423
  }
45507
- if (version.patch === undefined)
45508
- return validatedVersion;
45509
- if (Number.isInteger(version.patch)) {
45510
- validatedVersion += `.${version.patch.toString()}`;
45424
+ return executeDepositEth(ethSigner, amount, assetType, starkPublicKey, vaultId, imxConfig);
45425
+ }
45426
+
45427
+ async function executeRegisterAndDepositERC20(ethSigner, quantizedAmount, assetType, starkPublicKey, vaultId, config, usersApi) {
45428
+ const etherKey = await ethSigner.getAddress();
45429
+ const coreContract = Contracts.Core.connect(config.coreContractAddress, ethSigner);
45430
+ const signableResult = await getSignableRegistrationOnchain(etherKey, starkPublicKey, usersApi);
45431
+ const populatedTransaction = await coreContract.populateTransaction.registerAndDepositERC20(etherKey, starkPublicKey, signableResult.operator_signature, assetType, vaultId, quantizedAmount);
45432
+ return ethSigner.sendTransaction(populatedTransaction);
45433
+ }
45434
+ async function executeDepositERC20(ethSigner, quantizedAmount, assetType, starkPublicKey, vaultId, config) {
45435
+ const coreContract = Contracts.Core.connect(config.coreContractAddress, ethSigner);
45436
+ const populatedTransaction = await coreContract.populateTransaction.depositERC20(starkPublicKey, assetType, vaultId, quantizedAmount);
45437
+ return ethSigner.sendTransaction(populatedTransaction);
45438
+ }
45439
+ async function depositERC20({ signers: { ethSigner }, deposit, config, }) {
45440
+ await validateChain(ethSigner, config.immutableXConfig);
45441
+ const { apiConfiguration, ethConfiguration } = config.immutableXConfig;
45442
+ const user = await ethSigner.getAddress();
45443
+ const tokensApi = new TokensApi$2(apiConfiguration);
45444
+ const depositsApi = new DepositsApi$1(apiConfiguration);
45445
+ const encodingApi = new EncodingApi$1(apiConfiguration);
45446
+ const usersApi = new UsersApi$1(apiConfiguration);
45447
+ // Get decimals for this specific ERC20
45448
+ const token = await tokensApi.getToken({ address: deposit.tokenAddress });
45449
+ // TODO: remove once fixed
45450
+ // eslint-disable-next-line radix
45451
+ const decimals = parseInt(token.data.decimals);
45452
+ const data = {
45453
+ decimals,
45454
+ token_address: deposit.tokenAddress,
45455
+ };
45456
+ const amount = parseUnits(deposit.amount, 0); // 0 to always use undecimalized value
45457
+ // Approve whether an amount of token from an account can be spent by a third-party account
45458
+ const tokenContract = Contracts.IERC20.connect(deposit.tokenAddress, ethSigner);
45459
+ const approveTransaction = await tokenContract.populateTransaction.approve(ethConfiguration.coreContractAddress, amount);
45460
+ await ethSigner.sendTransaction(approveTransaction);
45461
+ const getSignableDepositRequest = {
45462
+ user,
45463
+ token: {
45464
+ type: deposit.type,
45465
+ data,
45466
+ },
45467
+ amount: amount.toString(),
45468
+ };
45469
+ const signableDepositResult = await depositsApi.getSignableDeposit({
45470
+ getSignableDepositRequest,
45471
+ });
45472
+ // Perform encoding on asset details to get an assetType (required for stark contract request)
45473
+ const encodingResult = await encodingApi.encodeAsset({
45474
+ assetType: 'asset',
45475
+ encodeAssetRequest: {
45476
+ token: {
45477
+ type: deposit.type,
45478
+ data: {
45479
+ token_address: deposit.tokenAddress,
45480
+ },
45481
+ },
45482
+ },
45483
+ });
45484
+ const assetType = encodingResult.data.asset_type;
45485
+ const starkPublicKey = signableDepositResult.data.stark_key;
45486
+ const vaultId = signableDepositResult.data.vault_id;
45487
+ const quantizedAmount = BigNumber$2.from(signableDepositResult.data.amount);
45488
+ const isRegistered = await isRegisteredOnChain(starkPublicKey, ethSigner, config);
45489
+ if (!isRegistered) {
45490
+ return executeRegisterAndDepositERC20(ethSigner, quantizedAmount, assetType, starkPublicKey, vaultId, ethConfiguration, usersApi);
45511
45491
  }
45512
- if (version.prerelease === undefined || version.prerelease !== 'alpha')
45513
- return validatedVersion;
45514
- if (version.prerelease === 'alpha') {
45515
- validatedVersion += `-${version.prerelease}`;
45492
+ return executeDepositERC20(ethSigner, quantizedAmount, assetType, starkPublicKey, vaultId, ethConfiguration);
45493
+ }
45494
+
45495
+ async function executeDepositERC721(ethSigner, tokenId, assetType, starkPublicKey, vaultId, config) {
45496
+ const coreContract = Contracts.Core.connect(config.ethConfiguration.coreContractAddress, ethSigner);
45497
+ const populatedTransaction = await coreContract.populateTransaction.depositNft(starkPublicKey, assetType, vaultId, tokenId);
45498
+ return ethSigner.sendTransaction(populatedTransaction);
45499
+ }
45500
+ async function depositERC721({ signers: { ethSigner }, deposit, config, }) {
45501
+ await validateChain(ethSigner, config.immutableXConfig);
45502
+ const user = await ethSigner.getAddress();
45503
+ const { immutableXConfig } = config;
45504
+ const depositsApi = new DepositsApi$1(immutableXConfig.apiConfiguration);
45505
+ const encodingApi = new EncodingApi$1(immutableXConfig.apiConfiguration);
45506
+ const usersApi = new UsersApi$1(immutableXConfig.apiConfiguration);
45507
+ const data = {
45508
+ token_address: deposit.tokenAddress,
45509
+ token_id: deposit.tokenId,
45510
+ };
45511
+ const amount = '1';
45512
+ const getSignableDepositRequest = {
45513
+ user,
45514
+ token: {
45515
+ type: deposit.type,
45516
+ data,
45517
+ },
45518
+ amount: amount.toString(),
45519
+ };
45520
+ const signableDepositResult = await depositsApi.getSignableDeposit({
45521
+ getSignableDepositRequest,
45522
+ });
45523
+ // Perform encoding on asset details to get an assetType (required for stark contract request)
45524
+ const encodingResult = await encodingApi.encodeAsset({
45525
+ assetType: 'asset',
45526
+ encodeAssetRequest: {
45527
+ token: {
45528
+ type: deposit.type,
45529
+ data: {
45530
+ token_address: deposit.tokenAddress,
45531
+ token_id: deposit.tokenId,
45532
+ },
45533
+ },
45534
+ },
45535
+ });
45536
+ const assetType = encodingResult.data.asset_type;
45537
+ const starkPublicKey = signableDepositResult.data.stark_key;
45538
+ const vaultId = signableDepositResult.data.vault_id;
45539
+ const isRegistered = await isRegisteredOnChain(starkPublicKey, ethSigner, config);
45540
+ // Approve whether an amount of token from an account can be spent by a third-party account
45541
+ const tokenContract = Contracts.IERC721.connect(deposit.tokenAddress, ethSigner);
45542
+ const operator = immutableXConfig.ethConfiguration.coreContractAddress;
45543
+ const isApprovedForAll = await tokenContract.isApprovedForAll(user, operator);
45544
+ if (!isApprovedForAll) {
45545
+ await tokenContract.setApprovalForAll(operator, true);
45516
45546
  }
45517
- if (version.build === undefined)
45518
- return validatedVersion;
45519
- if (Number.isInteger(version.build) && version.build >= 0) {
45520
- validatedVersion += `.${version.build.toString()}`;
45547
+ if (!isRegistered) {
45548
+ const signableResult = await getSignableRegistrationOnchain(user, starkPublicKey, usersApi);
45549
+ const coreContract = Contracts.Core.connect(immutableXConfig.ethConfiguration.coreContractAddress, ethSigner);
45550
+ // Note: proxy registration contract registerAndDepositNft method is not used as
45551
+ // it currently fails erc721 transfer ownership check
45552
+ await coreContract.registerUser(user, starkPublicKey, signableResult.operator_signature);
45521
45553
  }
45522
- return validatedVersion;
45554
+ return executeDepositERC721(ethSigner, deposit.tokenId, assetType, starkPublicKey, vaultId, immutableXConfig);
45523
45555
  }
45524
45556
 
45525
- function loadUnresolved(version) {
45526
- if (window === undefined) {
45527
- throw new Error('missing window object: please run Checkout client side');
45528
- }
45529
- if (document === undefined) {
45530
- throw new Error('missing document object: please run Checkout client side');
45557
+ // TODO: remove once fixed deposit variable shadowing
45558
+ // eslint-disable-next-line consistent-return, @typescript-eslint/no-shadow
45559
+ async function deposit({ signers, deposit, config }) {
45560
+ // TODO: please add a reasonable default here
45561
+ // eslint-disable-next-line default-case
45562
+ switch (deposit.type) {
45563
+ case 'ETH':
45564
+ return depositEth({ signers, deposit, config });
45565
+ case 'ERC20':
45566
+ return depositERC20({ signers, deposit, config });
45567
+ case 'ERC721':
45568
+ return depositERC721({ signers, deposit, config });
45531
45569
  }
45532
- const scriptId = 'immutable-checkout-widgets-bundle';
45533
- const validVersion = validateAndBuildVersion(version);
45534
- // Prevent the script to be loaded more than once
45535
- // by checking the presence of the script and its version.
45536
- const initScript = document.getElementById(scriptId);
45537
- if (initScript)
45538
- return { loaded: true, element: initScript };
45539
- const tag = document.createElement('script');
45540
- let cdnUrl = `https://cdn.jsdelivr.net/npm/@imtbl/sdk@${validVersion}/dist/browser/checkout/widgets.js`;
45541
- tag.setAttribute('id', scriptId);
45542
- tag.setAttribute('data-version', validVersion);
45543
- tag.setAttribute('src', cdnUrl);
45544
- document.head.appendChild(tag);
45545
- return { loaded: false, element: tag };
45546
45570
  }
45547
45571
 
45548
- const PUBLISHABLE_KEY_PREFIX = 'pk_imapik-';
45549
- const publishableKeyDomainAllowlist = [
45550
- 'https://checkout-api.dev.immutable.com',
45551
- 'https://checkout-api.sandbox.immutable.com',
45552
- 'https://checkout-api.immutable.com',
45553
- ];
45554
- class HttpClient {
45572
+ async function exchangeTransfer({ signers, request, config, }) {
45573
+ await validateChain(signers.ethSigner, config.immutableXConfig);
45574
+ const exchangeApi = new ExchangesApi$1(config.immutableXConfig.apiConfiguration);
45575
+ const ethAddress = await signers.ethSigner.getAddress();
45576
+ const transferAmount = request.amount;
45577
+ const signableResult = await exchangeApi.getExchangeSignableTransfer({
45578
+ id: request.transactionID,
45579
+ getSignableTransferRequest: {
45580
+ sender: ethAddress,
45581
+ token: convertToSignableToken(request),
45582
+ amount: transferAmount,
45583
+ receiver: request.receiver,
45584
+ },
45585
+ });
45586
+ const { signable_message: signableMessage, payload_hash: payloadHash } = signableResult.data;
45587
+ const ethSignature = await signRaw(signableMessage, signers.ethSigner);
45588
+ const starkSignature = await signers.starkSigner.signMessage(payloadHash);
45589
+ const transferSigningParams = {
45590
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
45591
+ sender_stark_key: signableResult.data.sender_stark_key,
45592
+ sender_vault_id: signableResult.data.sender_vault_id,
45593
+ receiver_stark_key: signableResult.data.receiver_stark_key,
45594
+ receiver_vault_id: signableResult.data.receiver_vault_id,
45595
+ asset_id: signableResult.data.asset_id,
45596
+ amount: signableResult.data.amount,
45597
+ nonce: signableResult.data.nonce,
45598
+ expiration_timestamp: signableResult.data.expiration_timestamp,
45599
+ stark_signature: starkSignature,
45600
+ };
45601
+ const response = await exchangeApi.createExchangeTransfer({
45602
+ id: request.transactionID,
45603
+ createTransferRequest: transferSigningParams,
45604
+ xImxEthAddress: ethAddress,
45605
+ xImxEthSignature: ethSignature,
45606
+ });
45607
+ return {
45608
+ sent_signature: response?.data.sent_signature,
45609
+ status: response?.data.status?.toString(),
45610
+ time: response?.data.time,
45611
+ transfer_id: response?.data.transfer_id,
45612
+ };
45613
+ }
45614
+
45615
+ class GenericIMXProvider {
45555
45616
  config;
45556
- axiosInstance;
45557
- constructor(config) {
45617
+ signers;
45618
+ constructor(config, ethSigner, starkSigner) {
45558
45619
  this.config = config;
45559
- this.axiosInstance = globalAxios$1.create();
45560
- this.setupInterceptors();
45561
- }
45562
- // eslint-disable-next-line class-methods-use-this
45563
- shouldAddPublishableKey(url) {
45564
- // Check if the request is going to a whitelisted domain
45565
- return publishableKeyDomainAllowlist.some((domain) => url.startsWith(domain));
45620
+ this.signers = { ethSigner, starkSigner };
45566
45621
  }
45567
- setupInterceptors() {
45568
- this.axiosInstance.interceptors.request.use((config) => {
45569
- const publishableKey = this.config?.baseConfig?.publishableKey;
45570
- if (publishableKey && this.shouldAddPublishableKey(config.url || '')) {
45571
- if (!publishableKey.startsWith(PUBLISHABLE_KEY_PREFIX)) {
45572
- throw new Error('Invalid Publishable key. Create your Publishable key in Immutable developer hub.'
45573
- + ' https://hub.immutable.com');
45574
- }
45575
- // Add publishable key header for whitelisted domains
45576
- // eslint-disable-next-line no-param-reassign
45577
- config.headers['x-immutable-publishable-key'] = publishableKey;
45578
- }
45579
- return config;
45580
- }, (error) => Promise.reject(error));
45622
+ async getAddress() {
45623
+ return this.signers.ethSigner.getAddress();
45581
45624
  }
45582
- async request(config) {
45583
- return await this.axiosInstance.request(config);
45625
+ async isRegisteredOffchain() {
45626
+ const ethAddress = await this.getAddress();
45627
+ return isRegisteredOffchain(ethAddress, this.config);
45584
45628
  }
45585
- async get(url, config) {
45586
- const requestConfig = {
45587
- ...config,
45588
- url,
45589
- };
45590
- return await this.request(requestConfig);
45629
+ registerOffchain() {
45630
+ return registerOffchain(this.signers, this.config);
45591
45631
  }
45592
- async post(url, data, config) {
45593
- const requestConfig = {
45594
- ...config,
45595
- data,
45596
- url,
45597
- };
45598
- return await this.request(requestConfig);
45632
+ batchNftTransfer(request) {
45633
+ return batchTransfer({
45634
+ signers: this.signers,
45635
+ request,
45636
+ config: this.config,
45637
+ });
45599
45638
  }
45600
- async put(url, data, config) {
45601
- const requestConfig = {
45602
- ...config,
45603
- data,
45604
- url,
45605
- };
45606
- return await this.request(requestConfig);
45639
+ cancelOrder(request) {
45640
+ return cancelOrder({
45641
+ signers: this.signers,
45642
+ request,
45643
+ config: this.config,
45644
+ });
45607
45645
  }
45608
- async delete(url, data, config) {
45609
- const requestConfig = {
45610
- ...config,
45611
- data,
45612
- url,
45613
- };
45614
- return await this.request(requestConfig);
45646
+ completeWithdrawal(starkPublicKey, token) {
45647
+ return completeWithdrawal({
45648
+ config: this.config,
45649
+ signers: this.signers,
45650
+ token,
45651
+ starkPublicKey,
45652
+ });
45615
45653
  }
45616
- }
45617
-
45618
- const SANDBOX_CONFIGURATION = {
45619
- baseConfig: {
45620
- environment: Environment$1.SANDBOX,
45621
- },
45622
- passport: undefined,
45623
- };
45624
- const WIDGETS_SCRIPT_TIMEOUT = 100;
45625
- // Checkout SDK
45626
- class Checkout {
45627
- readOnlyProviders;
45628
- httpClient;
45629
- config;
45630
- fiatRampService;
45631
- availability;
45632
- passport;
45633
- /**
45634
- * Constructs a new instance of the CheckoutModule class.
45635
- * @param {CheckoutModuleConfiguration} [config=SANDBOX_CONFIGURATION] - The configuration object for the CheckoutModule.
45636
- */
45637
- constructor(config = SANDBOX_CONFIGURATION) {
45638
- this.httpClient = new HttpClient(config);
45639
- this.config = new CheckoutConfiguration(config, this.httpClient);
45640
- this.fiatRampService = new FiatRampService(this.config);
45641
- this.readOnlyProviders = new Map();
45642
- this.availability = availabilityService(this.config.isDevelopment, this.config.isProduction);
45643
- this.passport = config.passport;
45654
+ createOrder(request) {
45655
+ return createOrder({
45656
+ signers: this.signers,
45657
+ request,
45658
+ config: this.config,
45659
+ });
45644
45660
  }
45645
- /**
45646
- * Loads the widgets bundle and initiate the widgets factory.
45647
- * @param {WidgetsInit} init - The initialisation parameters for loading the widgets bundle and applying configuration
45648
- */
45649
- async widgets(init) {
45650
- const checkout = this;
45651
- // Preload the configurations
45652
- await checkout.config.remote.getConfig();
45653
- const factory = new Promise((resolve, reject) => {
45654
- function checkForWidgetsBundleLoaded() {
45655
- if (typeof ImmutableCheckoutWidgets !== 'undefined') {
45656
- resolve(new ImmutableCheckoutWidgets.WidgetsFactory(checkout, init.config));
45657
- }
45658
- else {
45659
- // If ImmutableCheckoutWidgets is not defined, wait for set amount of time.
45660
- // When time has elapsed, check again if ImmutableCheckoutWidgets is defined.
45661
- // Once it's defined, the promise will resolve and setTimeout won't be called again.
45662
- setTimeout(checkForWidgetsBundleLoaded, WIDGETS_SCRIPT_TIMEOUT);
45663
- }
45664
- }
45665
- try {
45666
- const script = loadUnresolved(init.version);
45667
- if (script.loaded && typeof ImmutableCheckoutWidgets !== 'undefined') {
45668
- resolve(new ImmutableCheckoutWidgets.WidgetsFactory(checkout, init.config));
45669
- }
45670
- else {
45671
- checkForWidgetsBundleLoaded();
45672
- }
45673
- }
45674
- catch (err) {
45675
- reject(new CheckoutError('Failed to load widgets script', CheckoutErrorType.WIDGETS_SCRIPT_LOAD_ERROR, { error: err }));
45676
- }
45661
+ createTrade(request) {
45662
+ return createTrade({
45663
+ signers: this.signers,
45664
+ request,
45665
+ config: this.config,
45677
45666
  });
45678
- return factory;
45679
45667
  }
45680
- /**
45681
- * Creates a provider using the given parameters.
45682
- * @param {CreateProviderParams} params - The parameters for creating the provider.
45683
- * @returns {Promise<CreateProviderResult>} A promise that resolves to the created provider.
45684
- */
45685
- async createProvider(params) {
45686
- return await createProvider(params.walletProviderName, this.passport);
45668
+ deposit(tokenAmount) {
45669
+ return deposit({
45670
+ signers: this.signers,
45671
+ deposit: tokenAmount,
45672
+ config: this.config,
45673
+ });
45687
45674
  }
45688
- /**
45689
- * Checks if a wallet is connected to the specified provider.
45690
- * @param {CheckConnectionParams} params - The parameters for checking the wallet connection.
45691
- * @returns {Promise<CheckConnectionResult>} - A promise that resolves to the result of the check.
45692
- */
45693
- async checkIsWalletConnected(params) {
45694
- const web3Provider = await validateProvider(this.config, params.provider, { allowUnsupportedProvider: true });
45695
- return checkIsWalletConnected(web3Provider);
45675
+ exchangeTransfer(request) {
45676
+ return exchangeTransfer({
45677
+ signers: this.signers,
45678
+ request,
45679
+ config: this.config,
45680
+ });
45696
45681
  }
45697
- /**
45698
- * Connects to a blockchain network using the specified provider.
45699
- * @param {ConnectParams} params - The parameters for connecting to the network.
45700
- * @returns {Promise<ConnectResult>} A promise that resolves to an object containing the provider and network information.
45701
- * @throws {Error} If the provider is not valid or if there is an error connecting to the network.
45702
- */
45703
- async connect(params) {
45704
- const web3Provider = await validateProvider(this.config, params.provider, { allowUnsupportedProvider: true });
45705
- await connectSite(web3Provider);
45706
- return { provider: web3Provider };
45682
+ async isRegisteredOnchain() {
45683
+ const starkPublicKey = await this.signers.starkSigner.getAddress();
45684
+ return isRegisteredOnChain(starkPublicKey, this.signers.ethSigner, this.config);
45707
45685
  }
45708
- /**
45709
- * Switches the network for the current wallet provider.
45710
- * @param {SwitchNetworkParams} params - The parameters for switching the network.
45711
- * @returns {Promise<SwitchNetworkResult>} - A promise that resolves to the result of switching the network.
45712
- */
45713
- async switchNetwork(params) {
45714
- const web3Provider = await validateProvider(this.config, params.provider, {
45715
- allowUnsupportedProvider: true,
45716
- allowMistmatchedChainId: true,
45686
+ prepareWithdrawal(request) {
45687
+ return prepareWithdrawal({
45688
+ signers: this.signers,
45689
+ withdrawal: request,
45690
+ config: this.config,
45717
45691
  });
45718
- const switchNetworkRes = await switchWalletNetwork(this.config, web3Provider, params.chainId);
45719
- return switchNetworkRes;
45720
45692
  }
45721
- /**
45722
- * Retrieves the token information given the token address. This function makes RPC calls to
45723
- * ERC20 contracts to fetch the main contract information (e.g. symbol).
45724
- * @param {GetTokenInfoParams} params - The parameters for retrieving the token information.
45725
- * @returns {Promise<TokenInfo>} - A promise that resolves to the token info request.
45726
- */
45727
- async getTokenInfo(params) {
45728
- return await getERC20TokenInfo(params.provider, params.tokenAddress);
45693
+ transfer(request) {
45694
+ return transfer({
45695
+ signers: this.signers,
45696
+ request,
45697
+ config: this.config,
45698
+ });
45729
45699
  }
45730
- /**
45731
- * Retrieves the balance of a wallet address.
45732
- * @param {GetBalanceParams} params - The parameters for retrieving the balance.
45733
- * @returns {Promise<GetBalanceResult>} - A promise that resolves to the balance result.
45734
- */
45735
- async getBalance(params) {
45736
- const web3Provider = await validateProvider(this.config, params.provider);
45737
- if (!params.tokenAddress || params.tokenAddress === '') {
45738
- return await getBalance(this.config, web3Provider, params.walletAddress);
45739
- }
45740
- return await getERC20Balance(web3Provider, params.walletAddress, params.tokenAddress);
45700
+ }
45701
+
45702
+ const WALLET_ACTION = {
45703
+ // TODO: remove once fixed - consider using an enum
45704
+ // eslint-disable-next-line @typescript-eslint/naming-convention
45705
+ SWITCH_CHAIN: 'wallet_switchEthereumChain',
45706
+ // eslint-disable-next-line @typescript-eslint/naming-convention
45707
+ CONNECT: 'eth_requestAccounts',
45708
+ };
45709
+ function isRequestableProvider(provider) {
45710
+ return !!provider?.request;
45711
+ }
45712
+ async function connectProvider(provider, chainID) {
45713
+ await provider.request({ method: WALLET_ACTION.CONNECT });
45714
+ if (chainID) {
45715
+ await provider.request({
45716
+ method: WALLET_ACTION.SWITCH_CHAIN,
45717
+ params: [{ chainId: `0x${chainID.toString(16)}` }],
45718
+ });
45741
45719
  }
45742
- /**
45743
- * Retrieves the balances of all tokens for a given wallet address on a specific chain.
45744
- * @param {GetAllBalancesParams} params - The parameters for retrieving the balances.
45745
- * @returns {Promise<GetAllBalancesResult>} - A promise that resolves to the result of retrieving the balances.
45746
- */
45747
- async getAllBalances(params) {
45748
- return getAllBalances(this.config, params.provider, params.walletAddress, params.chainId);
45720
+ }
45721
+
45722
+ const ERRORS = {
45723
+ // TODO: remove once fixed - consider using something in line with the naming convention
45724
+ // eslint-disable-next-line @typescript-eslint/naming-convention
45725
+ PROVIDER_NOT_FOUND: 'The Metamask provider was not found',
45726
+ };
45727
+ async function connect$1({ chainID, }) {
45728
+ const provider = (await detectEthereumProvider());
45729
+ if (!isRequestableProvider(provider)) {
45730
+ throw new Error(ERRORS.PROVIDER_NOT_FOUND);
45749
45731
  }
45750
- /**
45751
- * Retrieves the supported networks based on the provided parameters.
45752
- * @param {GetNetworkAllowListParams} params - The parameters for retrieving the network allow list.
45753
- * @returns {Promise<GetNetworkAllowListResult>} - A promise that resolves to the network allow list result.
45754
- */
45755
- async getNetworkAllowList(params) {
45756
- return await getNetworkAllowList(this.config, params);
45732
+ await connectProvider(provider, chainID);
45733
+ // NOTE: if we want to listen to Metamask events in the future, we can add a
45734
+ // listener here.
45735
+ return new ethers.providers.Web3Provider(provider);
45736
+ }
45737
+
45738
+ const COMMUNICATION_TYPE = 'message';
45739
+ var RequestEventType;
45740
+ (function (RequestEventType) {
45741
+ RequestEventType["GET_CONNECTION_REQUEST"] = "GET_CONNECTION_REQUEST";
45742
+ RequestEventType["CONNECT_WALLET_REQUEST"] = "CONNECT_WALLET_REQUEST";
45743
+ RequestEventType["SIGN_MESSAGE_REQUEST"] = "SIGN_MESSAGE_REQUEST";
45744
+ RequestEventType["DISCONNECT_WALLET_REQUEST"] = "DISCONNECT_WALLET_REQUEST";
45745
+ })(RequestEventType || (RequestEventType = {}));
45746
+ var ResponseEventType;
45747
+ (function (ResponseEventType) {
45748
+ ResponseEventType["CONNECT_WALLET_RESPONSE"] = "CONNECT_WALLET_RESPONSE";
45749
+ ResponseEventType["SIGN_MESSAGE_RESPONSE"] = "SIGN_MESSAGE_RESPONSE";
45750
+ ResponseEventType["GET_CONNECTION_RESPONSE"] = "GET_CONNECTION_RESPONSE";
45751
+ ResponseEventType["DISCONNECT_WALLET_RESPONSE"] = "DISCONNECT_WALLET_RESPONSE";
45752
+ })(ResponseEventType || (ResponseEventType = {}));
45753
+
45754
+ function postRequestMessage(iframe, payload) {
45755
+ if (iframe && iframe.contentWindow) {
45756
+ iframe.contentWindow.postMessage(payload, new URL(iframe.src).origin);
45757
45757
  }
45758
- /**
45759
- * Retrieves the supported tokens based on the provided parameters.
45760
- * @param {GetTokenAllowListParams} params - The parameters for retrieving the token allow list.
45761
- * @returns {Promise<GetTokenAllowListResult>} - A promise that resolves to the token allow list result.
45762
- */
45763
- async getTokenAllowList(params) {
45764
- return await getTokenAllowList(this.config, params);
45758
+ }
45759
+
45760
+ function messageResponseListener(iframe, event, eventType, callback) {
45761
+ if (iframe && event.source !== iframe.contentWindow) {
45762
+ return;
45765
45763
  }
45766
- /**
45767
- * Retrieves the default supported wallets based on the provided parameters.
45768
- * @param {GetWalletAllowListParams} params - The parameters for retrieving the wallet allow list.
45769
- * @returns {Promise<GetWalletAllowListResult>} - A promise that resolves to the wallet allow list result.
45770
- */
45771
- async getWalletAllowList(params) {
45772
- return await getWalletAllowList(params);
45764
+ const l2WalletMessage = event.data;
45765
+ if (l2WalletMessage.type !== eventType) {
45766
+ return;
45773
45767
  }
45774
- /**
45775
- * Sends a transaction using the specified provider and transaction parameters.
45776
- * @param {SendTransactionParams} params - The parameters for sending the transaction.
45777
- * @returns {Promise<SendTransactionResult>} A promise that resolves to the result of the transaction.
45778
- */
45779
- async sendTransaction(params) {
45780
- const web3Provider = await validateProvider(this.config, params.provider);
45781
- return await sendTransaction(web3Provider, params.transaction);
45768
+ callback(l2WalletMessage.details);
45769
+ }
45770
+
45771
+ class ImxSigner {
45772
+ publicAddress;
45773
+ iframe;
45774
+ constructor(publicAddress, iframe) {
45775
+ this.publicAddress = publicAddress;
45776
+ this.iframe = iframe;
45782
45777
  }
45783
- /**
45784
- * Retrieves network information using the specified provider.
45785
- * @param {GetNetworkParams} params - The parameters for retrieving network information.
45786
- * @returns {Promise<NetworkInfo>} A promise that resolves to the network information.
45787
- */
45788
- async getNetworkInfo(params) {
45789
- const web3Provider = await validateProvider(this.config, params.provider, {
45790
- allowUnsupportedProvider: true,
45791
- allowMistmatchedChainId: true,
45792
- });
45793
- return await getNetworkInfo(this.config, web3Provider);
45778
+ getAddress() {
45779
+ return this.publicAddress;
45794
45780
  }
45795
- /**
45796
- * Determines the requirements for performing a buy.
45797
- * @param {BuyParams} params - The parameters for the buy.
45798
- */
45799
- async buy(params) {
45800
- if (params.orders.length > 1) {
45801
- // eslint-disable-next-line no-console
45802
- console.warn('This endpoint currently only processes the first order in the array.');
45803
- }
45804
- const web3Provider = await validateProvider(this.config, params.provider);
45805
- return await buy(this.config, web3Provider, params.orders, params.overrides);
45781
+ signMessage(rawMessage) {
45782
+ return new Promise((resolve, reject) => {
45783
+ const listener = (event) => {
45784
+ messageResponseListener(this.iframe, event, ResponseEventType.SIGN_MESSAGE_RESPONSE, (messageDetails) => {
45785
+ window.removeEventListener(COMMUNICATION_TYPE, listener);
45786
+ if (!messageDetails.success) {
45787
+ reject(new Error(messageDetails.error?.message));
45788
+ }
45789
+ resolve(messageDetails.data.signedMessage);
45790
+ });
45791
+ };
45792
+ window.addEventListener(COMMUNICATION_TYPE, listener);
45793
+ postRequestMessage(this.iframe, {
45794
+ type: RequestEventType.SIGN_MESSAGE_REQUEST,
45795
+ details: { starkPublicKey: this.publicAddress, message: rawMessage },
45796
+ });
45797
+ });
45806
45798
  }
45807
- /**
45808
- * Determines the requirements for performing a sell.
45809
- * @param {SellParams} params - The parameters for the sell.
45810
- * Only currently actions the first order in the array until we support batch processing.
45811
- * Only currently actions the first fee in the fees array of each order until we support multiple fees.
45812
- */
45813
- async sell(params) {
45814
- if (params.orders.length > 1) {
45815
- // eslint-disable-next-line no-console
45816
- console.warn('This endpoint currently only processes the first order in the array.');
45817
- }
45818
- const web3Provider = await validateProvider(this.config, params.provider);
45819
- return await sell(this.config, web3Provider, params.orders);
45799
+ getIFrame() {
45800
+ return this.iframe;
45820
45801
  }
45821
- /**
45822
- * Cancels a sell.
45823
- * @param {CancelParams} params - The parameters for the cancel.
45824
- */
45825
- async cancel(params) {
45826
- // eslint-disable-next-line no-console
45827
- console.warn('This endpoint currently only processes the first order in the array.');
45828
- const web3Provider = await validateProvider(this.config, params.provider);
45829
- return await cancel(this.config, web3Provider, params.orderIds, params.overrides);
45802
+ }
45803
+
45804
+ const IMX_WALLET_IFRAME_ID = 'imx-wallet-app';
45805
+ const IMX_WALLET_IFRAME_HOSTS = {
45806
+ [Environment$1.SANDBOX]: 'https://wallets.sandbox.immutable.com',
45807
+ [Environment$1.PRODUCTION]: 'https://wallets.immutable.com',
45808
+ };
45809
+ const IMX_WALLET_IFRAME_STYLE = 'display: none;';
45810
+ function getIFrame() {
45811
+ return document.querySelector(`iframe#${IMX_WALLET_IFRAME_ID}`);
45812
+ }
45813
+ async function setupIFrame(env) {
45814
+ return new Promise((resolve) => {
45815
+ const iframe = document.createElement('iframe');
45816
+ iframe.setAttribute('id', IMX_WALLET_IFRAME_ID);
45817
+ iframe.setAttribute('src', IMX_WALLET_IFRAME_HOSTS[env]);
45818
+ iframe.setAttribute('style', IMX_WALLET_IFRAME_STYLE);
45819
+ document.body.appendChild(iframe);
45820
+ iframe.onload = () => resolve(iframe);
45821
+ });
45822
+ }
45823
+ async function getOrSetupIFrame(env) {
45824
+ const iframe = getIFrame();
45825
+ if (iframe)
45826
+ return iframe;
45827
+ return await setupIFrame(env);
45828
+ }
45829
+
45830
+ const DEFAULT_CONNECTION_MESSAGE = 'Only sign this request if you’ve initiated an action with Immutable X.';
45831
+ const CONNECTION_FAILED_ERROR = 'The L2 IMX Wallet connection has failed';
45832
+ async function connect(l1Provider, env) {
45833
+ const l1Signer = l1Provider.getSigner();
45834
+ const address = await l1Signer.getAddress();
45835
+ const signature = await l1Signer.signMessage(DEFAULT_CONNECTION_MESSAGE);
45836
+ const iframe = await getOrSetupIFrame(env);
45837
+ return new Promise((resolve, reject) => {
45838
+ const listener = (event) => {
45839
+ messageResponseListener(iframe, event, ResponseEventType.CONNECT_WALLET_RESPONSE, (messageDetails) => {
45840
+ window.removeEventListener(COMMUNICATION_TYPE, listener);
45841
+ if (!messageDetails.success) {
45842
+ reject(new Error(CONNECTION_FAILED_ERROR));
45843
+ }
45844
+ resolve(new ImxSigner(messageDetails.data.starkPublicKey, iframe));
45845
+ });
45846
+ };
45847
+ window.addEventListener(COMMUNICATION_TYPE, listener);
45848
+ postRequestMessage(iframe, {
45849
+ type: RequestEventType.CONNECT_WALLET_REQUEST,
45850
+ details: { ethAddress: address, signature },
45851
+ });
45852
+ });
45853
+ }
45854
+ async function disconnect(imxSigner) {
45855
+ const iframe = imxSigner.getIFrame();
45856
+ return new Promise((resolve, reject) => {
45857
+ const listener = (event) => {
45858
+ messageResponseListener(iframe, event, ResponseEventType.DISCONNECT_WALLET_RESPONSE, (messageDetails) => {
45859
+ window.removeEventListener(COMMUNICATION_TYPE, listener);
45860
+ if (!messageDetails.success && messageDetails.error) {
45861
+ reject(messageDetails.error);
45862
+ }
45863
+ iframe.remove();
45864
+ resolve();
45865
+ });
45866
+ };
45867
+ window.addEventListener(COMMUNICATION_TYPE, listener);
45868
+ postRequestMessage(iframe, {
45869
+ type: RequestEventType.DISCONNECT_WALLET_REQUEST,
45870
+ details: { starkPublicKey: imxSigner.getAddress() },
45871
+ });
45872
+ });
45873
+ }
45874
+
45875
+ var ProviderErrorType;
45876
+ (function (ProviderErrorType) {
45877
+ ProviderErrorType["PROVIDER_CONNECTION_ERROR"] = "PROVIDER_CONNECTION_ERROR";
45878
+ ProviderErrorType["WALLET_CONNECTION_ERROR"] = "WALLET_CONNECTION_ERROR";
45879
+ })(ProviderErrorType || (ProviderErrorType = {}));
45880
+ class ProviderError extends Error {
45881
+ type;
45882
+ constructor(message, type) {
45883
+ super(message);
45884
+ this.type = type;
45830
45885
  }
45831
- /**
45832
- * Determines the transaction requirements to complete a purchase.
45833
- * @params {SmartCheckoutParams} params - The parameters for smart checkout.
45834
- */
45835
- async smartCheckout(params) {
45836
- const web3Provider = await validateProvider(this.config, params.provider);
45837
- let itemRequirements = [];
45838
- try {
45839
- itemRequirements = await getItemRequirementsFromRequirements(web3Provider, params.itemRequirements);
45840
- }
45841
- catch (err) {
45842
- throw new CheckoutError('Failed to map item requirements', CheckoutErrorType.ITEM_REQUIREMENTS_ERROR, { error: err });
45843
- }
45844
- return await smartCheckout(this.config, web3Provider, itemRequirements, params.transactionOrGasAmount);
45886
+ }
45887
+ const withProviderError = async (fn, customError) => {
45888
+ try {
45889
+ return await fn();
45845
45890
  }
45846
- /**
45847
- * Checks if the given object is a Web3 provider.
45848
- * @param {Web3Provider} web3Provider - The object to check.
45849
- * @returns {boolean} - True if the object is a Web3 provider, false otherwise.
45850
- */
45851
- static isWeb3Provider(web3Provider) {
45852
- return isWeb3Provider(web3Provider);
45891
+ catch (error) {
45892
+ const errorMessage = customError.message || `${error.message}` || 'UnknownError';
45893
+ throw new ProviderError(errorMessage, customError.type);
45853
45894
  }
45854
- /**
45855
- * Estimates the gas required for a swap or bridge transaction.
45856
- * @param {GasEstimateParams} params - The parameters for the gas estimation.
45857
- * @returns {Promise<GasEstimateSwapResult | GasEstimateBridgeToL2Result>} - A promise that resolves to the gas estimation result.
45858
- */
45859
- async gasEstimate(params) {
45860
- this.readOnlyProviders = await createReadOnlyProviders(this.config, this.readOnlyProviders);
45861
- return await gasEstimator(params, this.readOnlyProviders, this.config);
45895
+ };
45896
+
45897
+ class MetaMaskIMXProvider extends GenericIMXProvider {
45898
+ static imxSigner;
45899
+ static async connect(config) {
45900
+ return await withProviderError(async () => {
45901
+ const metaMaskProvider = await connect$1({
45902
+ chainID: config.immutableXConfig.ethConfiguration.chainID,
45903
+ });
45904
+ this.imxSigner = await connect(metaMaskProvider, config.baseConfig.environment);
45905
+ return new MetaMaskIMXProvider(config, metaMaskProvider.getSigner(), this.imxSigner);
45906
+ }, { type: ProviderErrorType.WALLET_CONNECTION_ERROR });
45862
45907
  }
45863
- /**
45864
- * Creates and returns a URL for the fiat ramp widget.
45865
- * @param {FiatRampParams} params - The parameters for creating the url.
45866
- * @returns {Promise<string>} - A promise that resolves to a string url.
45867
- */
45868
- async createFiatRampUrl(params) {
45869
- let tokenAmount;
45870
- let tokenSymbol = 'IMX';
45871
- let email;
45872
- const walletAddress = await params.web3Provider.getSigner().getAddress();
45873
- const isPassport = params.web3Provider.provider?.isPassport || false;
45874
- if (isPassport && params.passport) {
45875
- const userInfo = await params.passport.getUserInfo();
45876
- email = userInfo?.email;
45877
- }
45878
- const tokenList = await getTokenAllowList(this.config, { type: TokenFilterTypes.ONRAMP });
45879
- const token = tokenList.tokens?.find((t) => isMatchingAddress(t.address, params.tokenAddress));
45880
- if (token) {
45881
- tokenAmount = params.tokenAmount;
45882
- tokenSymbol = token.symbol;
45908
+ static async disconnect() {
45909
+ if (!this.imxSigner) {
45910
+ throw new ProviderError('Attempted to disconnect from the MetaMask IMX provider without an established connection', ProviderErrorType.PROVIDER_CONNECTION_ERROR);
45883
45911
  }
45884
- return await this.fiatRampService.createWidgetUrl({
45885
- exchangeType: params.exchangeType,
45886
- isPassport,
45887
- walletAddress,
45888
- tokenAmount,
45889
- tokenSymbol,
45890
- email,
45891
- });
45892
- }
45893
- /**
45894
- * Fetches fiat ramp fee estimations.
45895
- * @returns {Promise<OnRampProviderFees>} - A promise that resolves to OnRampProviderFees.
45896
- */
45897
- async getExchangeFeeEstimate() {
45898
- return await this.fiatRampService.feeEstimate();
45912
+ return withProviderError(async () => {
45913
+ await disconnect(this.imxSigner);
45914
+ }, { type: ProviderErrorType.PROVIDER_CONNECTION_ERROR });
45899
45915
  }
45900
- /**
45901
- * Fetches Swap widget availability.
45902
- * @returns {Promise<boolean>} - A promise that resolves to a boolean.
45903
- */
45904
- async isSwapAvailable() {
45905
- return this.availability.checkDexAvailability();
45916
+ static async signMessage(message) {
45917
+ if (!this.imxSigner) {
45918
+ throw new ProviderError('Attempted to sign a message with the MetaMask IMX provider without an established connection', ProviderErrorType.PROVIDER_CONNECTION_ERROR);
45919
+ }
45920
+ return withProviderError(async () => await this.imxSigner.signMessage(message), { type: ProviderErrorType.PROVIDER_CONNECTION_ERROR });
45906
45921
  }
45907
45922
  }
45908
45923
 
45909
- class BlockExplorerService {
45910
- /**
45911
- * getTransationLink returns the link to the transaction on blockscout
45912
- * @param hash transaction hash
45913
- * @returns link to the transaction on blockscout
45914
- */
45915
- static getTransactionLink(chainId, hash) {
45916
- const url = BLOCKSCOUT_CHAIN_URL_MAP?.[chainId]?.url;
45917
- if (!url || !hash)
45918
- return undefined;
45919
- return `${url}/tx/${hash}`;
45924
+ class ProviderConfiguration {
45925
+ immutableXConfig;
45926
+ baseConfig;
45927
+ constructor({ baseConfig, overrides }) {
45928
+ this.baseConfig = baseConfig;
45929
+ if (overrides) {
45930
+ this.immutableXConfig = overrides.immutableXConfig;
45931
+ }
45932
+ else {
45933
+ // TODO: remove once a sensible default is chosen
45934
+ // eslint-disable-next-line default-case
45935
+ switch (baseConfig.environment) {
45936
+ case Environment$1.SANDBOX: {
45937
+ this.immutableXConfig = Config.SANDBOX;
45938
+ break;
45939
+ }
45940
+ case Environment$1.PRODUCTION: {
45941
+ this.immutableXConfig = Config.PRODUCTION;
45942
+ break;
45943
+ }
45944
+ }
45945
+ }
45920
45946
  }
45921
45947
  }
45922
45948
 
45923
- var checkout = /*#__PURE__*/Object.freeze({
45949
+ var x = /*#__PURE__*/Object.freeze({
45924
45950
  __proto__: null,
45925
- BlockExplorerService: BlockExplorerService,
45926
- get BridgeEventType () { return BridgeEventType; },
45927
- get ChainId () { return ChainId; },
45928
- get ChainName () { return ChainName; },
45929
- get ChainSlug () { return ChainSlug; },
45930
- Checkout: Checkout,
45931
- CheckoutConfiguration: CheckoutConfiguration,
45932
- get CheckoutErrorType () { return CheckoutErrorType; },
45933
- get CheckoutStatus () { return CheckoutStatus; },
45934
- get ConnectEventType () { return ConnectEventType; },
45935
- get ConnectTargetLayer () { return ConnectTargetLayer; },
45936
- get ExchangeType () { return ExchangeType; },
45937
- get FeeType () { return FeeType; },
45938
- get FundingStepType () { return FundingStepType; },
45939
- get GasEstimateType () { return GasEstimateType; },
45940
- get GasTokenType () { return GasTokenType; },
45941
- IMMUTABLE_API_BASE_URL: IMMUTABLE_API_BASE_URL,
45942
- get IMTBLWidgetEvents () { return IMTBLWidgetEvents; },
45943
- get ItemType () { return ItemType; },
45944
- get NetworkFilterTypes () { return NetworkFilterTypes; },
45945
- get OnRampEventType () { return OnRampEventType; },
45946
- get OrchestrationEventType () { return OrchestrationEventType; },
45947
- get ProviderEventType () { return ProviderEventType; },
45948
- get RoutingOutcomeType () { return RoutingOutcomeType; },
45949
- get SaleEventType () { return SaleEventType; },
45950
- get SalePaymentTypes () { return SalePaymentTypes; },
45951
- get SwapEventType () { return SwapEventType; },
45952
- get TokenFilterTypes () { return TokenFilterTypes; },
45953
- get TransactionOrGasType () { return TransactionOrGasType; },
45954
- get WalletEventType () { return WalletEventType; },
45955
- get WalletFilterTypes () { return WalletFilterTypes; },
45956
- get WalletProviderName () { return WalletProviderName; },
45957
- get WidgetTheme () { return WidgetTheme; },
45958
- get WidgetType () { return WidgetType; }
45951
+ GenericIMXProvider: GenericIMXProvider,
45952
+ IMXClient: IMXClient,
45953
+ IMXError: IMXError,
45954
+ MetaMaskIMXProvider: MetaMaskIMXProvider,
45955
+ ProviderConfiguration: ProviderConfiguration,
45956
+ imxClientCreateStarkSigner: createStarkSigner,
45957
+ imxClientGenerateLegacyStarkPrivateKey: generateLegacyStarkPrivateKey
45959
45958
  });
45960
45959
 
45961
- export { blockchain_data as blockchainData, checkout, config, immutablex_client as immutablexClient, orderbook, passport, provider };
45960
+ export { blockchain_data as blockchainData, checkout, config, orderbook, passport, x };