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