@imtbl/sdk 0.44.4 → 0.45.1

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' };
10644
+ const defaultHeaders$1 = { 'x-sdk-version': 'ts-immutable-sdk-0.45.1' };
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',
10716
+ sdkVersion: 'ts-immutable-sdk-multi-rollup-api-client-0.45.1',
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',
11155
+ sdkVersion: 'ts-immutable-sdk-0.45.1',
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
  /**
@@ -41995,13 +40903,13 @@ const ERC721ABI = [
41995
40903
  },
41996
40904
  ];
41997
40905
  // Gas overrides -- Anti-spam mechanism for when the baseFee drops low
41998
- // https://github.com/immutable/imx-docs/blob/main/docs/main/zkEVM/overview/gas-configuration.md
41999
- const GAS_OVERRIDES = {
42000
- maxFeePerGas: ethers.BigNumber.from(102e9),
42001
- maxPriorityFeePerGas: ethers.BigNumber.from(101e9),
40906
+ // https://docs.immutable.com/docs/zkEVM/architecture/gas-config
40907
+ const IMMUTABLE_ZKVEM_GAS_OVERRIDES = {
40908
+ maxFeePerGas: ethers.BigNumber.from(15e9),
40909
+ maxPriorityFeePerGas: ethers.BigNumber.from(10e9),
42002
40910
  };
42003
40911
 
42004
- const SDK_VERSION_MARKER = '0.44.4';
40912
+ const SDK_VERSION_MARKER = '0.45.1';
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
 
@@ -42149,6 +41057,9 @@ class CheckoutConfiguration {
42149
41057
  }
42150
41058
 
42151
41059
  const isMatchingAddress = (addressA = '', addressB = '') => (addressA.toLowerCase() === addressB.toLowerCase());
41060
+ const isZkEvmChainId = (chainId) => chainId === ChainId.IMTBL_ZKEVM_DEVNET
41061
+ || chainId === ChainId.IMTBL_ZKEVM_TESTNET
41062
+ || chainId === ChainId.IMTBL_ZKEVM_MAINNET;
42152
41063
 
42153
41064
  const getTokenAllowList = async (config, { type = TokenFilterTypes.ALL, chainId, exclude, }) => {
42154
41065
  let tokens = [];
@@ -42495,7 +41406,7 @@ const getBalances = async (config, web3Provider, walletAddress, tokens) => {
42495
41406
  });
42496
41407
  return { balances };
42497
41408
  };
42498
- const getAllBalances = async (config, web3Provider, walletAddress, chainId) => {
41409
+ const getAllBalances = async (config, web3Provider, walletAddress, chainId, forceFetch = false) => {
42499
41410
  if (!walletAddress && !web3Provider) {
42500
41411
  throw new CheckoutError('both walletAddress and provider are missing. At least one must be provided.', CheckoutErrorType.MISSING_PARAMS);
42501
41412
  }
@@ -42517,6 +41428,9 @@ const getAllBalances = async (config, web3Provider, walletAddress, chainId) => {
42517
41428
  // eslint-disable-next-line no-console
42518
41429
  console.error(err);
42519
41430
  }
41431
+ if (forceFetch) {
41432
+ resetBlockscoutClientMap();
41433
+ }
42520
41434
  let address = walletAddress;
42521
41435
  if (flag && Blockscout.isChainSupported(chainId)) {
42522
41436
  // This is a hack because the widgets are still using the tokens symbol
@@ -42682,16 +41596,19 @@ async function getWalletAllowList(params) {
42682
41596
  };
42683
41597
  }
42684
41598
 
42685
- const setTransactionGasLimits = (transaction) => {
41599
+ const setTransactionGasLimits = async (web3Provider, transaction) => {
42686
41600
  const rawTx = transaction;
42687
- rawTx.maxFeePerGas = GAS_OVERRIDES.maxFeePerGas;
42688
- rawTx.maxPriorityFeePerGas = GAS_OVERRIDES.maxPriorityFeePerGas;
41601
+ const { chainId } = await web3Provider.getNetwork();
41602
+ if (!isZkEvmChainId(chainId))
41603
+ return rawTx;
41604
+ rawTx.maxFeePerGas = IMMUTABLE_ZKVEM_GAS_OVERRIDES.maxFeePerGas;
41605
+ rawTx.maxPriorityFeePerGas = IMMUTABLE_ZKVEM_GAS_OVERRIDES.maxPriorityFeePerGas;
42689
41606
  return rawTx;
42690
41607
  };
42691
41608
  const sendTransaction = async (web3Provider, transaction) => {
42692
41609
  try {
42693
41610
  const signer = web3Provider.getSigner();
42694
- const rawTx = setTransactionGasLimits(transaction);
41611
+ const rawTx = await setTransactionGasLimits(web3Provider, transaction);
42695
41612
  const transactionResponse = await signer.sendTransaction(rawTx);
42696
41613
  return {
42697
41614
  transactionResponse,
@@ -43393,7 +42310,7 @@ const getTokenBalanceRequirement = (itemRequirement, balances) => {
43393
42310
  /**
43394
42311
  * Gets the balances for all NATIVE and ERC20 balance requirements.
43395
42312
  */
43396
- const getTokenBalances = async (config, provider, ownerAddress, itemRequirements) => {
42313
+ const getTokenBalances = async (config, provider, ownerAddress, itemRequirements, forceFetch = false) => {
43397
42314
  try {
43398
42315
  const tokenMap = new Map();
43399
42316
  getTokensFromRequirements(itemRequirements).forEach((item) => {
@@ -43401,7 +42318,7 @@ const getTokenBalances = async (config, provider, ownerAddress, itemRequirements
43401
42318
  return;
43402
42319
  tokenMap.set(item.address.toLocaleLowerCase(), item);
43403
42320
  });
43404
- const { balances } = await getAllBalances(config, provider, ownerAddress, getL2ChainId(config));
42321
+ const { balances } = await getAllBalances(config, provider, ownerAddress, getL2ChainId(config), forceFetch);
43405
42322
  return balances.filter((balance) => tokenMap.get((balance.token.address || NATIVE).toLocaleLowerCase()));
43406
42323
  }
43407
42324
  catch (err) {
@@ -43451,7 +42368,7 @@ const getERC721Balances = async (provider, ownerAddress, itemRequirements) => {
43451
42368
  /**
43452
42369
  * Checks the item requirements against the owner balances.
43453
42370
  */
43454
- const balanceCheck = async (config, provider, ownerAddress, itemRequirements) => {
42371
+ const balanceCheck = async (config, provider, ownerAddress, itemRequirements, forceFetch = false) => {
43455
42372
  const aggregatedItems = balanceAggregator(itemRequirements);
43456
42373
  const requiredToken = [];
43457
42374
  const requiredERC721 = [];
@@ -43472,7 +42389,7 @@ const balanceCheck = async (config, provider, ownerAddress, itemRequirements) =>
43472
42389
  // Get all ERC20 and NATIVE balances
43473
42390
  const balancePromises = [];
43474
42391
  if (requiredToken.length > 0) {
43475
- balancePromises.push(getTokenBalances(config, provider, ownerAddress, aggregatedItems));
42392
+ balancePromises.push(getTokenBalances(config, provider, ownerAddress, aggregatedItems, forceFetch));
43476
42393
  }
43477
42394
  // Get all ERC721 balances
43478
42395
  if (requiredERC721.length > 0) {
@@ -44835,7 +43752,7 @@ const smartCheckout = async (config, provider, itemRequirements, transactionOrGa
44835
43752
  aggregatedItems.push(gasItem);
44836
43753
  aggregatedItems = itemAggregator(aggregatedItems);
44837
43754
  }
44838
- const balanceCheckResult = await measureAsyncExecution(config, 'Time to run balance checks', balanceCheck(config, provider, ownerAddress, aggregatedItems));
43755
+ const balanceCheckResult = await measureAsyncExecution(config, 'Time to run balance checks', balanceCheck(config, provider, ownerAddress, aggregatedItems, true));
44839
43756
  const { sufficient } = balanceCheckResult;
44840
43757
  const transactionRequirements = balanceCheckResult.balanceRequirements;
44841
43758
  if (sufficient) {
@@ -44891,1099 +43808,2186 @@ const signFulfillmentTransactions = async (provider, fulfillmentTransactions) =>
44891
43808
  receipts = await Promise.all(response.map((transaction) => transaction.transactionResponse.wait()));
44892
43809
  }
44893
43810
  catch (err) {
44894
- throw new CheckoutError('An error occurred while executing the fulfillment transaction', CheckoutErrorType.EXECUTE_FULFILLMENT_TRANSACTION_ERROR, { error: err });
43811
+ throw new CheckoutError('An error occurred while executing the fulfillment transaction', CheckoutErrorType.EXECUTE_FULFILLMENT_TRANSACTION_ERROR, { error: err });
43812
+ }
43813
+ for (const receipt of receipts) {
43814
+ if (receipt.status === 0) {
43815
+ return {
43816
+ type: SignTransactionStatusType.FAILED,
43817
+ transactionHash: receipt.transactionHash,
43818
+ reason: 'Fulfillment transaction failed and was reverted',
43819
+ };
43820
+ }
43821
+ }
43822
+ return {
43823
+ type: SignTransactionStatusType.SUCCESS,
43824
+ };
43825
+ };
43826
+ const signMessage = async (provider, unsignedMessage) => {
43827
+ try {
43828
+ // eslint-disable-next-line no-underscore-dangle
43829
+ const signedMessage = await provider.getSigner()._signTypedData(unsignedMessage.unsignedMessage.domain, unsignedMessage.unsignedMessage.types, unsignedMessage.unsignedMessage.value);
43830
+ return {
43831
+ orderComponents: unsignedMessage.orderComponents,
43832
+ orderHash: unsignedMessage.orderHash,
43833
+ signedMessage,
43834
+ };
43835
+ }
43836
+ catch (err) {
43837
+ throw new CheckoutError('An error occurred while signing the message', CheckoutErrorType.SIGN_MESSAGE_ERROR, { error: err });
43838
+ }
43839
+ };
43840
+
43841
+ const getUnsignedERC721Transactions = async (actions) => {
43842
+ let approvalTransactions = [];
43843
+ let fulfillmentTransactions = [];
43844
+ const approvalPromises = [];
43845
+ const fulfillmentPromises = [];
43846
+ for (const action of actions) {
43847
+ if (action.type !== ActionType.TRANSACTION)
43848
+ continue;
43849
+ if (action.purpose === TransactionPurpose.APPROVAL) {
43850
+ approvalPromises.push(action.buildTransaction());
43851
+ }
43852
+ if (action.purpose === TransactionPurpose.FULFILL_ORDER) {
43853
+ fulfillmentPromises.push(action.buildTransaction());
43854
+ }
43855
+ }
43856
+ approvalTransactions = await Promise.all(approvalPromises);
43857
+ fulfillmentTransactions = await Promise.all(fulfillmentPromises);
43858
+ return {
43859
+ approvalTransactions,
43860
+ fulfillmentTransactions,
43861
+ };
43862
+ };
43863
+ const getUnsignedERC20ApprovalTransactions = async (actions) => {
43864
+ let approvalTransactions = [];
43865
+ const approvalPromises = [];
43866
+ for (const action of actions) {
43867
+ if (action.type !== ActionType.TRANSACTION)
43868
+ continue;
43869
+ if (action.purpose === TransactionPurpose.APPROVAL) {
43870
+ approvalPromises.push(action.buildTransaction());
43871
+ }
43872
+ }
43873
+ approvalTransactions = await Promise.all(approvalPromises);
43874
+ return approvalTransactions;
43875
+ };
43876
+ const getUnsignedFulfillmentTransactions = async (actions) => {
43877
+ let fulfillmentTransactions = [];
43878
+ const fulfillmentPromises = [];
43879
+ for (const action of actions) {
43880
+ if (action.type !== ActionType.TRANSACTION)
43881
+ continue;
43882
+ if (action.purpose === TransactionPurpose.FULFILL_ORDER) {
43883
+ fulfillmentPromises.push(action.buildTransaction());
43884
+ }
43885
+ }
43886
+ fulfillmentTransactions = await Promise.all(fulfillmentPromises);
43887
+ return fulfillmentTransactions;
43888
+ };
43889
+ const getUnsignedMessage = (orderHash, orderComponents, actions) => {
43890
+ let unsignedMessage;
43891
+ for (const action of actions) {
43892
+ if (action.type !== ActionType.SIGNABLE)
43893
+ continue;
43894
+ if (action.purpose === SignablePurpose.CREATE_LISTING) {
43895
+ unsignedMessage = {
43896
+ domain: action.message.domain,
43897
+ types: action.message.types,
43898
+ value: action.message.value,
43899
+ };
43900
+ }
43901
+ }
43902
+ if (!unsignedMessage)
43903
+ return undefined;
43904
+ return {
43905
+ orderHash,
43906
+ orderComponents,
43907
+ unsignedMessage,
43908
+ };
43909
+ };
43910
+
43911
+ const MAX_FEE_PERCENTAGE_DECIMAL = 1; // 100%
43912
+ const MAX_FEE_DECIMAL_PLACES = 6; // will allow 0.000001 (0.0001%) as the minimum value
43913
+ const calculateFeesPercent = (orderFee, amountBn) => {
43914
+ const feePercentage = orderFee.amount;
43915
+ // note: multiply in and out of the maximum decimal places to the power of ten to do the math in big number integers
43916
+ const feePercentageMultiplier = Math.round(feePercentage.percentageDecimal * (10 ** MAX_FEE_DECIMAL_PLACES));
43917
+ const bnFeeAmount = amountBn
43918
+ .mul(ethers.BigNumber.from(feePercentageMultiplier))
43919
+ .div(10 ** MAX_FEE_DECIMAL_PLACES);
43920
+ return bnFeeAmount;
43921
+ };
43922
+ const calculateFeesToken = (orderFee, decimals) => {
43923
+ const feeToken = orderFee.amount;
43924
+ const bnFeeAmount = ethers.utils.parseUnits(feeToken.token, decimals);
43925
+ return bnFeeAmount;
43926
+ };
43927
+ const calculateFees = (orderFees, weiAmount, decimals = 18) => {
43928
+ let totalTokenFees = ethers.BigNumber.from(0);
43929
+ const amountBn = ethers.BigNumber.from(weiAmount);
43930
+ // note: multiply in and out of the maximum decimal places to the power of ten to do the math in big number integers
43931
+ const totalAllowableFees = amountBn
43932
+ .mul(MAX_FEE_PERCENTAGE_DECIMAL * (10 ** MAX_FEE_DECIMAL_PLACES))
43933
+ .div(10 ** MAX_FEE_DECIMAL_PLACES);
43934
+ const calculateFeesResult = [];
43935
+ for (const orderFee of orderFees) {
43936
+ let currentFeeBn = ethers.BigNumber.from(0);
43937
+ if (Object.hasOwn(orderFee.amount, 'percentageDecimal')) {
43938
+ currentFeeBn = calculateFeesPercent(orderFee, amountBn);
43939
+ totalTokenFees = totalTokenFees.add(currentFeeBn);
43940
+ }
43941
+ else if (Object.hasOwn(orderFee.amount, 'token')) {
43942
+ currentFeeBn = calculateFeesToken(orderFee, decimals);
43943
+ totalTokenFees = totalTokenFees.add(currentFeeBn);
43944
+ }
43945
+ else {
43946
+ throw new CheckoutError('Unknown fee type parsed, must be percentageDecimal or token', CheckoutErrorType.ORDER_FEE_ERROR);
43947
+ }
43948
+ if (totalTokenFees.gt(totalAllowableFees)) {
43949
+ throw new CheckoutError(`The combined fees are above the allowed maximum of ${MAX_FEE_PERCENTAGE_DECIMAL * 100}%`, CheckoutErrorType.ORDER_FEE_ERROR);
43950
+ }
43951
+ if (currentFeeBn.gt(0)) {
43952
+ calculateFeesResult.push({
43953
+ amount: currentFeeBn.toString(),
43954
+ recipientAddress: orderFee.recipient,
43955
+ });
43956
+ }
43957
+ } // for
43958
+ return calculateFeesResult;
43959
+ };
43960
+
43961
+ const getItemRequirement = (type, tokenAddress, amount, spenderAddress) => {
43962
+ switch (type) {
43963
+ case ItemType.ERC20:
43964
+ return {
43965
+ type,
43966
+ amount,
43967
+ tokenAddress,
43968
+ spenderAddress,
43969
+ };
43970
+ case ItemType.NATIVE:
43971
+ default:
43972
+ return {
43973
+ type: ItemType.NATIVE,
43974
+ amount,
43975
+ };
43976
+ }
43977
+ };
43978
+ const getTransactionOrGas = (gasLimit, fulfillmentTransactions) => {
43979
+ if (fulfillmentTransactions.length > 0) {
43980
+ return {
43981
+ type: TransactionOrGasType.TRANSACTION,
43982
+ transaction: fulfillmentTransactions[0],
43983
+ };
43984
+ }
43985
+ return {
43986
+ type: TransactionOrGasType.GAS,
43987
+ gasToken: {
43988
+ type: GasTokenType.NATIVE,
43989
+ limit: ethers.BigNumber.from(gasLimit),
43990
+ },
43991
+ };
43992
+ };
43993
+ const buy = async (config, provider, orders, overrides = {
43994
+ waitFulfillmentSettlements: true,
43995
+ }) => {
43996
+ if (orders.length === 0) {
43997
+ throw new CheckoutError('No orders were provided to the orders array. Please provide at least one order.', CheckoutErrorType.FULFILL_ORDER_LISTING_ERROR);
43998
+ }
43999
+ let order;
44000
+ let spenderAddress = '';
44001
+ let decimals = 18;
44002
+ const gasLimit = constants.estimatedFulfillmentGasGwei;
44003
+ const orderbook = createOrderbookInstance(config);
44004
+ const blockchainClient = createBlockchainDataInstance(config);
44005
+ const fulfillerAddress = await measureAsyncExecution(config, 'Time to get the address from the provider', provider.getSigner().getAddress());
44006
+ // Prefetch balances and store them in memory
44007
+ resetBlockscoutClientMap();
44008
+ getAllBalances(config, provider, fulfillerAddress, getL1ChainId(config));
44009
+ getAllBalances(config, provider, fulfillerAddress, getL2ChainId(config));
44010
+ const { id, takerFees } = orders[0];
44011
+ let orderChainName;
44012
+ try {
44013
+ order = await measureAsyncExecution(config, 'Time to fetch the listing from the orderbook', orderbook.getListing(id));
44014
+ const { seaportContractAddress, chainName } = orderbook.config();
44015
+ orderChainName = chainName;
44016
+ spenderAddress = seaportContractAddress;
44017
+ }
44018
+ catch (err) {
44019
+ throw new CheckoutError('An error occurred while getting the order listing', CheckoutErrorType.GET_ORDER_LISTING_ERROR, {
44020
+ error: err,
44021
+ orderId: id,
44022
+ });
44023
+ }
44024
+ if (order.result.buy.length === 0) {
44025
+ throw new CheckoutError('An error occurred with the get order listing', CheckoutErrorType.GET_ORDER_LISTING_ERROR, {
44026
+ orderId: id,
44027
+ message: 'No buy side tokens found on order',
44028
+ });
44029
+ }
44030
+ const buyToken = order.result.buy[0];
44031
+ if (buyToken.type === 'ERC20') {
44032
+ const token = await measureAsyncExecution(config, 'Time to get decimals of token contract for the buy token', blockchainClient.getToken({ contractAddress: buyToken.contractAddress, chainName: orderChainName }));
44033
+ if (token.result.decimals)
44034
+ decimals = token.result.decimals;
44035
+ }
44036
+ let fees = [];
44037
+ if (takerFees && takerFees.length > 0) {
44038
+ fees = calculateFees(takerFees, buyToken.amount, decimals);
44039
+ }
44040
+ let unsignedApprovalTransactions = [];
44041
+ let unsignedFulfillmentTransactions = [];
44042
+ let orderActions = [];
44043
+ const fulfillOrderStartTime = performance.now();
44044
+ try {
44045
+ const { actions } = await measureAsyncExecution(config, 'Time to call fulfillOrder from the orderbook', orderbook.fulfillOrder(id, fulfillerAddress, fees));
44046
+ orderActions = actions;
44047
+ unsignedApprovalTransactions = await measureAsyncExecution(config, 'Time to construct the unsigned approval transactions', getUnsignedERC20ApprovalTransactions(actions));
44048
+ }
44049
+ catch (err) {
44050
+ const elapsedTimeInSeconds = (performance.now() - fulfillOrderStartTime) / 1000;
44051
+ debugLogger(config, 'Time to call fulfillOrder from the orderbook', elapsedTimeInSeconds);
44052
+ if (err.message.includes(OrderStatusName.EXPIRED)) {
44053
+ throw new CheckoutError('Order is expired', CheckoutErrorType.ORDER_EXPIRED_ERROR, { orderId: id });
44054
+ }
44055
+ // The balances error will be handled by bulk order fulfillment but for now we
44056
+ // need to assert on this string to check that the error is not a balances error
44057
+ if (!err.message.includes('The fulfiller does not have the balances needed to fulfill')) {
44058
+ throw new CheckoutError('Error occurred while trying to fulfill the order', CheckoutErrorType.FULFILL_ORDER_LISTING_ERROR, {
44059
+ orderId: id,
44060
+ error: err,
44061
+ });
44062
+ }
44063
+ }
44064
+ try {
44065
+ unsignedFulfillmentTransactions = await measureAsyncExecution(config, 'Time to construct the unsigned fulfillment transactions', getUnsignedFulfillmentTransactions(orderActions));
44066
+ }
44067
+ catch {
44068
+ // if cannot estimate gas then silently continue and use gas limit in smartCheckout
44069
+ // but get the fulfillment transactions after they have approved the spending
44070
+ }
44071
+ let amount = ethers.BigNumber.from('0');
44072
+ let type = ItemType.NATIVE;
44073
+ let contractAddress = '';
44074
+ const buyArray = order.result.buy;
44075
+ if (buyArray.length > 0) {
44076
+ switch (buyArray[0].type) {
44077
+ case 'NATIVE':
44078
+ type = ItemType.NATIVE;
44079
+ break;
44080
+ case 'ERC20':
44081
+ type = ItemType.ERC20;
44082
+ contractAddress = buyArray[0].contractAddress;
44083
+ break;
44084
+ default:
44085
+ throw new CheckoutError('Purchasing token type is unsupported', CheckoutErrorType.UNSUPPORTED_TOKEN_TYPE_ERROR, {
44086
+ orderId: id,
44087
+ });
44088
+ }
44089
+ }
44090
+ buyArray.forEach((item) => {
44091
+ if (item.type !== ItemType.ERC721) {
44092
+ amount = amount.add(ethers.BigNumber.from(item.amount));
44093
+ }
44094
+ });
44095
+ const feeArray = order.result.fees;
44096
+ feeArray.forEach((item) => {
44097
+ amount = amount.add(ethers.BigNumber.from(item.amount));
44098
+ });
44099
+ const itemRequirements = [
44100
+ getItemRequirement(type, contractAddress, amount, spenderAddress),
44101
+ ];
44102
+ const smartCheckoutResult = await measureAsyncExecution(config, 'Total time running smart checkout', smartCheckout(config, provider, itemRequirements, getTransactionOrGas(gasLimit, unsignedFulfillmentTransactions)));
44103
+ if (smartCheckoutResult.sufficient) {
44104
+ const approvalResult = await signApprovalTransactions(provider, unsignedApprovalTransactions);
44105
+ if (approvalResult.type === SignTransactionStatusType.FAILED) {
44106
+ return {
44107
+ status: CheckoutStatus.FAILED,
44108
+ transactionHash: approvalResult.transactionHash,
44109
+ reason: approvalResult.reason,
44110
+ smartCheckoutResult,
44111
+ };
44112
+ }
44113
+ try {
44114
+ if (unsignedFulfillmentTransactions.length === 0) {
44115
+ unsignedFulfillmentTransactions = await getUnsignedFulfillmentTransactions(orderActions);
44116
+ }
44117
+ }
44118
+ catch (err) {
44119
+ throw new CheckoutError('Error fetching fulfillment transaction', CheckoutErrorType.FULFILL_ORDER_LISTING_ERROR, { error: err });
44120
+ }
44121
+ if (overrides.waitFulfillmentSettlements) {
44122
+ const fulfillmentResult = await signFulfillmentTransactions(provider, unsignedFulfillmentTransactions);
44123
+ if (fulfillmentResult.type === SignTransactionStatusType.FAILED) {
44124
+ return {
44125
+ status: CheckoutStatus.FAILED,
44126
+ transactionHash: fulfillmentResult.transactionHash,
44127
+ reason: fulfillmentResult.reason,
44128
+ smartCheckoutResult,
44129
+ };
44130
+ }
44131
+ return {
44132
+ status: CheckoutStatus.SUCCESS,
44133
+ smartCheckoutResult,
44134
+ };
44135
+ }
44136
+ let transactions;
44137
+ try {
44138
+ const response = await Promise.all(unsignedFulfillmentTransactions.map((transaction) => sendTransaction(provider, transaction)));
44139
+ transactions = response.map((result) => result.transactionResponse);
44140
+ }
44141
+ catch (err) {
44142
+ throw new CheckoutError('An error occurred while executing the fulfillment transaction', CheckoutErrorType.EXECUTE_FULFILLMENT_TRANSACTION_ERROR, {
44143
+ message: err.message,
44144
+ });
44145
+ }
44146
+ return {
44147
+ status: CheckoutStatus.FULFILLMENTS_UNSETTLED,
44148
+ smartCheckoutResult,
44149
+ transactions,
44150
+ };
44151
+ }
44152
+ return {
44153
+ status: CheckoutStatus.INSUFFICIENT_FUNDS,
44154
+ smartCheckoutResult,
44155
+ };
44156
+ };
44157
+
44158
+ const cancel = async (config, provider, orderIds, overrides = {
44159
+ waitFulfillmentSettlements: true,
44160
+ }) => {
44161
+ let unsignedCancelOrderTransaction;
44162
+ if (orderIds.length === 0) {
44163
+ throw new CheckoutError('No orderIds were provided to the orderIds array. Please provide at least one orderId.', CheckoutErrorType.CANCEL_ORDER_LISTING_ERROR);
44164
+ }
44165
+ // Update this when bulk cancel is supported
44166
+ const orderId = orderIds[0];
44167
+ try {
44168
+ const offererAddress = await measureAsyncExecution(config, 'Time to get the address from the provider', provider.getSigner().getAddress());
44169
+ const orderbook = createOrderbookInstance(config);
44170
+ const cancelOrderResponse = await measureAsyncExecution(config, 'Time to get the cancel order from the orderbook', orderbook.cancelOrdersOnChain([orderId], offererAddress));
44171
+ unsignedCancelOrderTransaction = await cancelOrderResponse.cancellationAction.buildTransaction();
44172
+ }
44173
+ catch (err) {
44174
+ throw new CheckoutError('An error occurred while cancelling the order listing', CheckoutErrorType.CANCEL_ORDER_LISTING_ERROR, {
44175
+ orderId,
44176
+ error: err,
44177
+ });
44178
+ }
44179
+ if (overrides.waitFulfillmentSettlements) {
44180
+ const result = await signFulfillmentTransactions(provider, [unsignedCancelOrderTransaction]);
44181
+ if (result.type === SignTransactionStatusType.FAILED) {
44182
+ return {
44183
+ status: CheckoutStatus.FAILED,
44184
+ transactionHash: result.transactionHash,
44185
+ reason: result.reason,
44186
+ };
44187
+ }
44188
+ return {
44189
+ status: CheckoutStatus.SUCCESS,
44190
+ };
44191
+ }
44192
+ let transactions;
44193
+ try {
44194
+ const response = await Promise.all([unsignedCancelOrderTransaction].map((transaction) => sendTransaction(provider, transaction)));
44195
+ transactions = response.map((result) => result.transactionResponse);
44196
+ }
44197
+ catch (err) {
44198
+ throw new CheckoutError('An error occurred while executing the fulfillment transaction', CheckoutErrorType.EXECUTE_FULFILLMENT_TRANSACTION_ERROR, {
44199
+ message: err.message,
44200
+ });
44201
+ }
44202
+ return {
44203
+ status: CheckoutStatus.FULFILLMENTS_UNSETTLED,
44204
+ transactions,
44205
+ };
44206
+ };
44207
+
44208
+ const getERC721Requirement = (id, contractAddress, spenderAddress) => ({
44209
+ type: ItemType.ERC721,
44210
+ id,
44211
+ contractAddress,
44212
+ spenderAddress,
44213
+ });
44214
+ const getBuyToken = (buyToken, decimals = 18) => {
44215
+ const bnAmount = ethers.utils.parseUnits(buyToken.amount, decimals);
44216
+ if (buyToken.type === ItemType.NATIVE) {
44217
+ return {
44218
+ type: ItemType.NATIVE,
44219
+ amount: bnAmount.toString(),
44220
+ };
44221
+ }
44222
+ return {
44223
+ type: ItemType.ERC20,
44224
+ amount: bnAmount.toString(),
44225
+ contractAddress: buyToken.tokenAddress,
44226
+ };
44227
+ };
44228
+ const sell = async (config, provider, orders) => {
44229
+ let orderbook;
44230
+ let listing;
44231
+ let spenderAddress = '';
44232
+ if (orders.length === 0) {
44233
+ throw new CheckoutError('No orders were provided to the orders array. Please provide at least one order.', CheckoutErrorType.PREPARE_ORDER_LISTING_ERROR);
44234
+ }
44235
+ const { buyToken, sellToken, makerFees, orderExpiry, } = orders[0];
44236
+ let decimals = 18;
44237
+ if (buyToken.type === ItemType.ERC20) {
44238
+ // get this from the allowed list
44239
+ const buyTokenContract = new ethers.Contract(buyToken.tokenAddress, JSON.stringify(ERC20ABI), provider);
44240
+ decimals = await measureAsyncExecution(config, 'Time to get decimals of token contract for the buy token', buyTokenContract.decimals());
44241
+ }
44242
+ const buyTokenOrNative = getBuyToken(buyToken, decimals);
44243
+ try {
44244
+ const walletAddress = await measureAsyncExecution(config, 'Time to get the address from the provider', provider.getSigner().getAddress());
44245
+ orderbook = createOrderbookInstance(config);
44246
+ const { seaportContractAddress } = orderbook.config();
44247
+ spenderAddress = seaportContractAddress;
44248
+ listing = await measureAsyncExecution(config, 'Time to prepare the listing from the orderbook', orderbook.prepareListing({
44249
+ makerAddress: walletAddress,
44250
+ buy: buyTokenOrNative,
44251
+ sell: {
44252
+ type: ItemType.ERC721,
44253
+ contractAddress: sellToken.collectionAddress,
44254
+ tokenId: sellToken.id,
44255
+ },
44256
+ orderExpiry,
44257
+ }));
44258
+ }
44259
+ catch (err) {
44260
+ throw new CheckoutError('An error occurred while preparing the listing', CheckoutErrorType.PREPARE_ORDER_LISTING_ERROR, {
44261
+ error: err,
44262
+ id: sellToken.id,
44263
+ collectionAddress: sellToken.collectionAddress,
44264
+ });
44895
44265
  }
44896
- for (const receipt of receipts) {
44897
- if (receipt.status === 0) {
44266
+ const itemRequirements = [
44267
+ getERC721Requirement(sellToken.id, sellToken.collectionAddress, spenderAddress),
44268
+ ];
44269
+ const smartCheckoutResult = await measureAsyncExecution(config, 'Total time running smart checkout', smartCheckout(config, provider, itemRequirements, {
44270
+ type: TransactionOrGasType.GAS,
44271
+ gasToken: {
44272
+ type: GasTokenType.NATIVE,
44273
+ limit: ethers.BigNumber.from(constants.estimatedFulfillmentGasGwei),
44274
+ },
44275
+ }));
44276
+ if (smartCheckoutResult.sufficient) {
44277
+ const unsignedTransactions = await getUnsignedERC721Transactions(listing.actions);
44278
+ const approvalResult = await signApprovalTransactions(provider, unsignedTransactions.approvalTransactions);
44279
+ if (approvalResult.type === SignTransactionStatusType.FAILED) {
44898
44280
  return {
44899
- type: SignTransactionStatusType.FAILED,
44900
- transactionHash: receipt.transactionHash,
44901
- reason: 'Fulfillment transaction failed and was reverted',
44281
+ status: CheckoutStatus.FAILED,
44282
+ transactionHash: approvalResult.transactionHash,
44283
+ reason: approvalResult.reason,
44284
+ smartCheckoutResult,
44902
44285
  };
44903
44286
  }
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,
44287
+ const unsignedMessage = getUnsignedMessage(listing.orderHash, listing.orderComponents, listing.actions);
44288
+ if (!unsignedMessage) {
44289
+ // For sell it is expected the orderbook will always return an unsigned message
44290
+ // If for some reason it is missing then we cannot proceed with the create listing
44291
+ throw new CheckoutError('The unsigned message is missing after preparing the listing', CheckoutErrorType.SIGN_MESSAGE_ERROR, {
44292
+ id: sellToken.id,
44293
+ collectionAddress: sellToken.collectionAddress,
44294
+ });
44295
+ }
44296
+ const signedMessage = await signMessage(provider, unsignedMessage);
44297
+ let orderId = '';
44298
+ const createListingParams = {
44299
+ orderComponents: signedMessage.orderComponents,
44300
+ orderHash: signedMessage.orderHash,
44301
+ orderSignature: signedMessage.signedMessage,
44302
+ makerFees: [],
44917
44303
  };
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());
44304
+ if (makerFees !== undefined) {
44305
+ const orderBookFees = calculateFees(makerFees, buyTokenOrNative.amount, decimals);
44306
+ if (orderBookFees.length !== makerFees.length) {
44307
+ throw new CheckoutError('One of the fees is too small, must be greater than 0.000001', CheckoutErrorType.CREATE_ORDER_LISTING_ERROR);
44308
+ }
44309
+ createListingParams.makerFees = orderBookFees;
44934
44310
  }
44935
- if (action.purpose === TransactionPurpose.FULFILL_ORDER) {
44936
- fulfillmentPromises.push(action.buildTransaction());
44311
+ try {
44312
+ const order = await orderbook.createListing(createListingParams);
44313
+ orderId = order.result.id;
44314
+ }
44315
+ catch (err) {
44316
+ throw new CheckoutError('An error occurred while creating the listing', CheckoutErrorType.CREATE_ORDER_LISTING_ERROR, {
44317
+ error: err,
44318
+ collectionId: sellToken.id,
44319
+ collectionAddress: sellToken.collectionAddress,
44320
+ });
44937
44321
  }
44322
+ return {
44323
+ status: CheckoutStatus.SUCCESS,
44324
+ orderIds: [orderId],
44325
+ smartCheckoutResult,
44326
+ };
44938
44327
  }
44939
- approvalTransactions = await Promise.all(approvalPromises);
44940
- fulfillmentTransactions = await Promise.all(fulfillmentPromises);
44941
44328
  return {
44942
- approvalTransactions,
44943
- fulfillmentTransactions,
44329
+ status: CheckoutStatus.INSUFFICIENT_FUNDS,
44330
+ smartCheckoutResult,
44944
44331
  };
44945
44332
  };
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
- }
44333
+
44334
+ class FiatRampService {
44335
+ config;
44336
+ /**
44337
+ * Constructs a new instance of the FiatRampService class.
44338
+ * @param {CheckoutConfiguration} config - The config required for the FiatRampService.
44339
+ */
44340
+ constructor(config) {
44341
+ this.config = config;
44955
44342
  }
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
- }
44343
+ async feeEstimate() {
44344
+ const config = (await this.config.remote.getConfig('onramp'));
44345
+ return config[OnRampProvider.TRANSAK]?.fees;
44968
44346
  }
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
- }
44347
+ async createWidgetUrl(params) {
44348
+ return (await this.getTransakWidgetUrl(params));
44984
44349
  }
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);
44350
+ async getTransakWidgetUrl(params) {
44351
+ let widgetUrl = `${TRANSAK_API_BASE_URL[this.config.environment]}?`;
44352
+ const onRampConfig = (await this.config.remote.getConfig('onramp'));
44353
+ const apiKey = onRampConfig[OnRampProvider.TRANSAK].publishableApiKey;
44354
+ const transakPublishableKey = `apiKey=${apiKey}`;
44355
+ const zkevmNetwork = 'network=immutablezkevm';
44356
+ const defaultPaymentMethod = 'defaultPaymentMethod=credit_debit_card';
44357
+ const disableBankTransfer = 'disablePaymentMethods=sepa_bank_transfer,gbp_bank_transfer,'
44358
+ + 'pm_cash_app,pm_jwire,pm_paymaya,pm_bpi,pm_ubp,pm_grabpay,pm_shopeepay,pm_gcash,pm_pix,'
44359
+ + 'pm_astropay,pm_pse,inr_bank_transfer';
44360
+ const productsAvailed = 'productsAvailed=buy';
44361
+ const exchangeScreenTitle = 'exchangeScreenTitle=Buy';
44362
+ const themeColor = 'themeColor=0D0D0D';
44363
+ widgetUrl += `${transakPublishableKey}&`
44364
+ + `${zkevmNetwork}&`
44365
+ + `${defaultPaymentMethod}&`
44366
+ + `${disableBankTransfer}&`
44367
+ + `${productsAvailed}&`
44368
+ + `${exchangeScreenTitle}&`
44369
+ + `${themeColor}`;
44370
+ if (params.isPassport && params.email) {
44371
+ const encodedEmail = encodeURIComponent(params.email);
44372
+ widgetUrl += `&email=${encodedEmail}&isAutoFillUserData=true&disableWalletAddressForm=true`;
45023
44373
  }
45024
- else if (Object.hasOwn(orderFee.amount, 'token')) {
45025
- currentFeeBn = calculateFeesToken(orderFee, decimals);
45026
- totalTokenFees = totalTokenFees.add(currentFeeBn);
44374
+ if (params.tokenAmount && params.tokenSymbol) {
44375
+ widgetUrl += `&defaultCryptoAmount=${params.tokenAmount}&cryptoCurrencyCode=${params.tokenSymbol}`;
45027
44376
  }
45028
44377
  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);
44378
+ widgetUrl += '&defaultCryptoCurrency=IMX';
45033
44379
  }
45034
- if (currentFeeBn.gt(0)) {
45035
- calculateFeesResult.push({
45036
- amount: currentFeeBn.toString(),
45037
- recipientAddress: orderFee.recipient,
45038
- });
44380
+ if (params.walletAddress) {
44381
+ widgetUrl += `&walletAddress=${params.walletAddress}`;
45039
44382
  }
45040
- } // for
45041
- return calculateFeesResult;
45042
- };
44383
+ return widgetUrl;
44384
+ }
44385
+ }
45043
44386
 
45044
- const getItemRequirement = (type, tokenAddress, amount, spenderAddress) => {
45045
- switch (type) {
45046
- case ItemType.ERC20:
44387
+ async function getItemRequirementsFromRequirements(provider, requirements) {
44388
+ // Get all decimal values by calling contracts for each ERC20
44389
+ const decimalPromises = [];
44390
+ requirements.forEach((itemRequirementParam) => {
44391
+ if (itemRequirementParam.type === ItemType.ERC20) {
44392
+ const { tokenAddress } = itemRequirementParam;
44393
+ decimalPromises.push(getTokenContract(tokenAddress, ERC20ABI, provider).decimals());
44394
+ }
44395
+ });
44396
+ const decimals = await Promise.all(decimalPromises);
44397
+ // Map ItemRequirementsParam objects to ItemRequirement by parsing amounts from formatted string to BigNumebrs
44398
+ const itemRequirements = requirements.map((itemRequirementParam, index) => {
44399
+ if (itemRequirementParam.type === ItemType.NATIVE) {
45047
44400
  return {
45048
- type,
45049
- amount,
45050
- tokenAddress,
45051
- spenderAddress,
44401
+ ...itemRequirementParam,
44402
+ amount: ethers.utils.parseUnits(itemRequirementParam.amount, 18),
45052
44403
  };
45053
- case ItemType.NATIVE:
45054
- default:
44404
+ }
44405
+ if (itemRequirementParam.type === ItemType.ERC20) {
45055
44406
  return {
45056
- type: ItemType.NATIVE,
45057
- amount,
44407
+ ...itemRequirementParam,
44408
+ amount: ethers.utils.parseUnits(itemRequirementParam.amount, decimals[index]),
45058
44409
  };
44410
+ }
44411
+ return itemRequirementParam;
44412
+ });
44413
+ return itemRequirements;
44414
+ }
44415
+
44416
+ /**
44417
+ * Validates and builds a version string based on the given SemanticVersion object.
44418
+ * If the version is undefined or has an invalid major version, it returns the default checkout version.
44419
+ * If the version is all zeros, it also returns the default checkout version.
44420
+ * Otherwise, it constructs a validated version string based on the major, minor, patch, and build numbers.
44421
+ */
44422
+ function validateAndBuildVersion(version) {
44423
+ const defaultPackageVersion = globalPackageVersion();
44424
+ if (version === undefined || version.major === undefined)
44425
+ return defaultPackageVersion;
44426
+ if (!Number.isInteger(version.major) || version.major < 0)
44427
+ return defaultPackageVersion;
44428
+ if (version.minor !== undefined && version.minor < 0)
44429
+ return defaultPackageVersion;
44430
+ if (version.patch !== undefined && version.patch < 0)
44431
+ return defaultPackageVersion;
44432
+ if (version.major === 0 && version.minor === undefined)
44433
+ return defaultPackageVersion;
44434
+ if (version.major === 0 && version.minor === 0 && version.patch === undefined)
44435
+ return defaultPackageVersion;
44436
+ if (version.major === 0 && version.minor === undefined && version.patch === undefined)
44437
+ return defaultPackageVersion;
44438
+ if (version.major === 0 && version.minor === 0 && version.patch === 0)
44439
+ return defaultPackageVersion;
44440
+ let validatedVersion = version.major.toString();
44441
+ if (version.minor === undefined)
44442
+ return validatedVersion;
44443
+ if (Number.isInteger(version.minor)) {
44444
+ validatedVersion += `.${version.minor.toString()}`;
45059
44445
  }
45060
- };
45061
- const getTransactionOrGas = (gasLimit, fulfillmentTransactions) => {
45062
- if (fulfillmentTransactions.length > 0) {
45063
- return {
45064
- type: TransactionOrGasType.TRANSACTION,
45065
- transaction: fulfillmentTransactions[0],
44446
+ if (version.patch === undefined)
44447
+ return validatedVersion;
44448
+ if (Number.isInteger(version.patch)) {
44449
+ validatedVersion += `.${version.patch.toString()}`;
44450
+ }
44451
+ if (version.prerelease === undefined || version.prerelease !== 'alpha')
44452
+ return validatedVersion;
44453
+ if (version.prerelease === 'alpha') {
44454
+ validatedVersion += `-${version.prerelease}`;
44455
+ }
44456
+ if (version.build === undefined)
44457
+ return validatedVersion;
44458
+ if (Number.isInteger(version.build) && version.build >= 0) {
44459
+ validatedVersion += `.${version.build.toString()}`;
44460
+ }
44461
+ return validatedVersion;
44462
+ }
44463
+
44464
+ function loadUnresolved(version) {
44465
+ if (window === undefined) {
44466
+ throw new Error('missing window object: please run Checkout client side');
44467
+ }
44468
+ if (document === undefined) {
44469
+ throw new Error('missing document object: please run Checkout client side');
44470
+ }
44471
+ const scriptId = 'immutable-checkout-widgets-bundle';
44472
+ const validVersion = validateAndBuildVersion(version);
44473
+ // Prevent the script to be loaded more than once
44474
+ // by checking the presence of the script and its version.
44475
+ const initScript = document.getElementById(scriptId);
44476
+ if (initScript)
44477
+ return { loaded: true, element: initScript };
44478
+ const tag = document.createElement('script');
44479
+ let cdnUrl = `https://cdn.jsdelivr.net/npm/@imtbl/sdk@${validVersion}/dist/browser/checkout/widgets.js`;
44480
+ tag.setAttribute('id', scriptId);
44481
+ tag.setAttribute('data-version', validVersion);
44482
+ tag.setAttribute('src', cdnUrl);
44483
+ document.head.appendChild(tag);
44484
+ return { loaded: false, element: tag };
44485
+ }
44486
+
44487
+ const PUBLISHABLE_KEY_PREFIX = 'pk_imapik-';
44488
+ const publishableKeyDomainAllowlist = [
44489
+ 'https://checkout-api.dev.immutable.com',
44490
+ 'https://checkout-api.sandbox.immutable.com',
44491
+ 'https://checkout-api.immutable.com',
44492
+ ];
44493
+ class HttpClient {
44494
+ config;
44495
+ axiosInstance;
44496
+ constructor(config) {
44497
+ this.config = config;
44498
+ this.axiosInstance = globalAxios$1.create();
44499
+ this.setupInterceptors();
44500
+ }
44501
+ // eslint-disable-next-line class-methods-use-this
44502
+ shouldAddPublishableKey(url) {
44503
+ // Check if the request is going to a whitelisted domain
44504
+ return publishableKeyDomainAllowlist.some((domain) => url.startsWith(domain));
44505
+ }
44506
+ setupInterceptors() {
44507
+ this.axiosInstance.interceptors.request.use((config) => {
44508
+ const publishableKey = this.config?.baseConfig?.publishableKey;
44509
+ if (publishableKey && this.shouldAddPublishableKey(config.url || '')) {
44510
+ if (!publishableKey.startsWith(PUBLISHABLE_KEY_PREFIX)) {
44511
+ throw new Error('Invalid Publishable key. Create your Publishable key in Immutable developer hub.'
44512
+ + ' https://hub.immutable.com');
44513
+ }
44514
+ // Add publishable key header for whitelisted domains
44515
+ // eslint-disable-next-line no-param-reassign
44516
+ config.headers['x-immutable-publishable-key'] = publishableKey;
44517
+ }
44518
+ return config;
44519
+ }, (error) => Promise.reject(error));
44520
+ }
44521
+ async request(config) {
44522
+ return await this.axiosInstance.request(config);
44523
+ }
44524
+ async get(url, config) {
44525
+ const requestConfig = {
44526
+ ...config,
44527
+ url,
45066
44528
  };
44529
+ return await this.request(requestConfig);
45067
44530
  }
45068
- return {
45069
- type: TransactionOrGasType.GAS,
45070
- gasToken: {
45071
- type: GasTokenType.NATIVE,
45072
- limit: ethers.BigNumber.from(gasLimit),
45073
- },
45074
- };
44531
+ async post(url, data, config) {
44532
+ const requestConfig = {
44533
+ ...config,
44534
+ data,
44535
+ url,
44536
+ };
44537
+ return await this.request(requestConfig);
44538
+ }
44539
+ async put(url, data, config) {
44540
+ const requestConfig = {
44541
+ ...config,
44542
+ data,
44543
+ url,
44544
+ };
44545
+ return await this.request(requestConfig);
44546
+ }
44547
+ async delete(url, data, config) {
44548
+ const requestConfig = {
44549
+ ...config,
44550
+ data,
44551
+ url,
44552
+ };
44553
+ return await this.request(requestConfig);
44554
+ }
44555
+ }
44556
+
44557
+ const SANDBOX_CONFIGURATION = {
44558
+ baseConfig: {
44559
+ environment: Environment$1.SANDBOX,
44560
+ },
44561
+ passport: undefined,
45075
44562
  };
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);
44563
+ const WIDGETS_SCRIPT_TIMEOUT = 100;
44564
+ // Checkout SDK
44565
+ class Checkout {
44566
+ readOnlyProviders;
44567
+ httpClient;
44568
+ config;
44569
+ fiatRampService;
44570
+ availability;
44571
+ passport;
44572
+ /**
44573
+ * Constructs a new instance of the CheckoutModule class.
44574
+ * @param {CheckoutModuleConfiguration} [config=SANDBOX_CONFIGURATION] - The configuration object for the CheckoutModule.
44575
+ */
44576
+ constructor(config = SANDBOX_CONFIGURATION) {
44577
+ this.httpClient = new HttpClient(config);
44578
+ this.config = new CheckoutConfiguration(config, this.httpClient);
44579
+ this.fiatRampService = new FiatRampService(this.config);
44580
+ this.readOnlyProviders = new Map();
44581
+ this.availability = availabilityService(this.config.isDevelopment, this.config.isProduction);
44582
+ this.passport = config.passport;
44583
+ }
44584
+ /**
44585
+ * Loads the widgets bundle and initiate the widgets factory.
44586
+ * @param {WidgetsInit} init - The initialisation parameters for loading the widgets bundle and applying configuration
44587
+ */
44588
+ async widgets(init) {
44589
+ const checkout = this;
44590
+ // Preload the configurations
44591
+ await checkout.config.remote.getConfig();
44592
+ const factory = new Promise((resolve, reject) => {
44593
+ function checkForWidgetsBundleLoaded() {
44594
+ if (typeof ImmutableCheckoutWidgets !== 'undefined') {
44595
+ resolve(new ImmutableCheckoutWidgets.WidgetsFactory(checkout, init.config));
44596
+ }
44597
+ else {
44598
+ // If ImmutableCheckoutWidgets is not defined, wait for set amount of time.
44599
+ // When time has elapsed, check again if ImmutableCheckoutWidgets is defined.
44600
+ // Once it's defined, the promise will resolve and setTimeout won't be called again.
44601
+ setTimeout(checkForWidgetsBundleLoaded, WIDGETS_SCRIPT_TIMEOUT);
44602
+ }
44603
+ }
44604
+ try {
44605
+ const script = loadUnresolved(init.version);
44606
+ if (script.loaded && typeof ImmutableCheckoutWidgets !== 'undefined') {
44607
+ resolve(new ImmutableCheckoutWidgets.WidgetsFactory(checkout, init.config));
44608
+ }
44609
+ else {
44610
+ checkForWidgetsBundleLoaded();
44611
+ }
44612
+ }
44613
+ catch (err) {
44614
+ reject(new CheckoutError('Failed to load widgets script', CheckoutErrorType.WIDGETS_SCRIPT_LOAD_ERROR, { error: err }));
44615
+ }
44616
+ });
44617
+ return factory;
44618
+ }
44619
+ /**
44620
+ * Creates a provider using the given parameters.
44621
+ * @param {CreateProviderParams} params - The parameters for creating the provider.
44622
+ * @returns {Promise<CreateProviderResult>} A promise that resolves to the created provider.
44623
+ */
44624
+ async createProvider(params) {
44625
+ return await createProvider(params.walletProviderName, this.passport);
44626
+ }
44627
+ /**
44628
+ * Checks if a wallet is connected to the specified provider.
44629
+ * @param {CheckConnectionParams} params - The parameters for checking the wallet connection.
44630
+ * @returns {Promise<CheckConnectionResult>} - A promise that resolves to the result of the check.
44631
+ */
44632
+ async checkIsWalletConnected(params) {
44633
+ const web3Provider = await validateProvider(this.config, params.provider, { allowUnsupportedProvider: true });
44634
+ return checkIsWalletConnected(web3Provider);
45081
44635
  }
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;
44636
+ /**
44637
+ * Connects to a blockchain network using the specified provider.
44638
+ * @param {ConnectParams} params - The parameters for connecting to the network.
44639
+ * @returns {Promise<ConnectResult>} A promise that resolves to an object containing the provider and network information.
44640
+ * @throws {Error} If the provider is not valid or if there is an error connecting to the network.
44641
+ */
44642
+ async connect(params) {
44643
+ const web3Provider = await validateProvider(this.config, params.provider, { allowUnsupportedProvider: true });
44644
+ await connectSite(web3Provider);
44645
+ return { provider: web3Provider };
45100
44646
  }
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,
44647
+ /**
44648
+ * Switches the network for the current wallet provider.
44649
+ * @param {SwitchNetworkParams} params - The parameters for switching the network.
44650
+ * @returns {Promise<SwitchNetworkResult>} - A promise that resolves to the result of switching the network.
44651
+ */
44652
+ async switchNetwork(params) {
44653
+ const web3Provider = await validateProvider(this.config, params.provider, {
44654
+ allowUnsupportedProvider: true,
44655
+ allowMistmatchedChainId: true,
45105
44656
  });
44657
+ const switchNetworkRes = await switchWalletNetwork(this.config, web3Provider, params.chainId);
44658
+ return switchNetworkRes;
45106
44659
  }
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
- });
44660
+ /**
44661
+ * Retrieves the token information given the token address. This function makes RPC calls to
44662
+ * ERC20 contracts to fetch the main contract information (e.g. symbol).
44663
+ * @param {GetTokenInfoParams} params - The parameters for retrieving the token information.
44664
+ * @returns {Promise<TokenInfo>} - A promise that resolves to the token info request.
44665
+ */
44666
+ async getTokenInfo(params) {
44667
+ return await getERC20TokenInfo(params.provider, params.tokenAddress);
45112
44668
  }
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;
44669
+ /**
44670
+ * Retrieves the balance of a wallet address.
44671
+ * @param {GetBalanceParams} params - The parameters for retrieving the balance.
44672
+ * @returns {Promise<GetBalanceResult>} - A promise that resolves to the balance result.
44673
+ */
44674
+ async getBalance(params) {
44675
+ const web3Provider = await validateProvider(this.config, params.provider);
44676
+ if (!params.tokenAddress || params.tokenAddress === '') {
44677
+ return await getBalance(this.config, web3Provider, params.walletAddress);
44678
+ }
44679
+ return await getERC20Balance(web3Provider, params.walletAddress, params.tokenAddress);
45118
44680
  }
45119
- let fees = [];
45120
- if (takerFees && takerFees.length > 0) {
45121
- fees = calculateFees(takerFees, buyToken.amount, decimals);
44681
+ /**
44682
+ * Retrieves the balances of all tokens for a given wallet address on a specific chain.
44683
+ * @param {GetAllBalancesParams} params - The parameters for retrieving the balances.
44684
+ * @returns {Promise<GetAllBalancesResult>} - A promise that resolves to the result of retrieving the balances.
44685
+ */
44686
+ async getAllBalances(params) {
44687
+ return getAllBalances(this.config, params.provider, params.walletAddress, params.chainId);
45122
44688
  }
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));
44689
+ /**
44690
+ * Retrieves the supported networks based on the provided parameters.
44691
+ * @param {GetNetworkAllowListParams} params - The parameters for retrieving the network allow list.
44692
+ * @returns {Promise<GetNetworkAllowListResult>} - A promise that resolves to the network allow list result.
44693
+ */
44694
+ async getNetworkAllowList(params) {
44695
+ return await getNetworkAllowList(this.config, params);
45131
44696
  }
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
- }
44697
+ /**
44698
+ * Retrieves the supported tokens based on the provided parameters.
44699
+ * @param {GetTokenAllowListParams} params - The parameters for retrieving the token allow list.
44700
+ * @returns {Promise<GetTokenAllowListResult>} - A promise that resolves to the token allow list result.
44701
+ */
44702
+ async getTokenAllowList(params) {
44703
+ return await getTokenAllowList(this.config, params);
45146
44704
  }
45147
- try {
45148
- unsignedFulfillmentTransactions = await measureAsyncExecution(config, 'Time to construct the unsigned fulfillment transactions', getUnsignedFulfillmentTransactions(orderActions));
44705
+ /**
44706
+ * Retrieves the default supported wallets based on the provided parameters.
44707
+ * @param {GetWalletAllowListParams} params - The parameters for retrieving the wallet allow list.
44708
+ * @returns {Promise<GetWalletAllowListResult>} - A promise that resolves to the wallet allow list result.
44709
+ */
44710
+ async getWalletAllowList(params) {
44711
+ return await getWalletAllowList(params);
45149
44712
  }
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
44713
+ /**
44714
+ * Sends a transaction using the specified provider and transaction parameters.
44715
+ * @param {SendTransactionParams} params - The parameters for sending the transaction.
44716
+ * @returns {Promise<SendTransactionResult>} A promise that resolves to the result of the transaction.
44717
+ */
44718
+ async sendTransaction(params) {
44719
+ const web3Provider = await validateProvider(this.config, params.provider);
44720
+ return await sendTransaction(web3Provider, params.transaction);
45153
44721
  }
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
- }
44722
+ /**
44723
+ * Retrieves network information using the specified provider.
44724
+ * @param {GetNetworkParams} params - The parameters for retrieving network information.
44725
+ * @returns {Promise<NetworkInfo>} A promise that resolves to the network information.
44726
+ */
44727
+ async getNetworkInfo(params) {
44728
+ const web3Provider = await validateProvider(this.config, params.provider, {
44729
+ allowUnsupportedProvider: true,
44730
+ allowMistmatchedChainId: true,
44731
+ });
44732
+ return await getNetworkInfo(this.config, web3Provider);
45172
44733
  }
45173
- buyArray.forEach((item) => {
45174
- if (item.type !== ItemType.ERC721) {
45175
- amount = amount.add(ethers.BigNumber.from(item.amount));
44734
+ /**
44735
+ * Determines the requirements for performing a buy.
44736
+ * @param {BuyParams} params - The parameters for the buy.
44737
+ */
44738
+ async buy(params) {
44739
+ if (params.orders.length > 1) {
44740
+ // eslint-disable-next-line no-console
44741
+ console.warn('This endpoint currently only processes the first order in the array.');
45176
44742
  }
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
- };
44743
+ const web3Provider = await validateProvider(this.config, params.provider);
44744
+ return await buy(this.config, web3Provider, params.orders, params.overrides);
44745
+ }
44746
+ /**
44747
+ * Determines the requirements for performing a sell.
44748
+ * @param {SellParams} params - The parameters for the sell.
44749
+ * Only currently actions the first order in the array until we support batch processing.
44750
+ * Only currently actions the first fee in the fees array of each order until we support multiple fees.
44751
+ */
44752
+ async sell(params) {
44753
+ if (params.orders.length > 1) {
44754
+ // eslint-disable-next-line no-console
44755
+ console.warn('This endpoint currently only processes the first order in the array.');
45195
44756
  }
44757
+ const web3Provider = await validateProvider(this.config, params.provider);
44758
+ return await sell(this.config, web3Provider, params.orders);
44759
+ }
44760
+ /**
44761
+ * Cancels a sell.
44762
+ * @param {CancelParams} params - The parameters for the cancel.
44763
+ */
44764
+ async cancel(params) {
44765
+ // eslint-disable-next-line no-console
44766
+ console.warn('This endpoint currently only processes the first order in the array.');
44767
+ const web3Provider = await validateProvider(this.config, params.provider);
44768
+ return await cancel(this.config, web3Provider, params.orderIds, params.overrides);
44769
+ }
44770
+ /**
44771
+ * Determines the transaction requirements to complete a purchase.
44772
+ * @params {SmartCheckoutParams} params - The parameters for smart checkout.
44773
+ */
44774
+ async smartCheckout(params) {
44775
+ const web3Provider = await validateProvider(this.config, params.provider);
44776
+ let itemRequirements = [];
45196
44777
  try {
45197
- if (unsignedFulfillmentTransactions.length === 0) {
45198
- unsignedFulfillmentTransactions = await getUnsignedFulfillmentTransactions(orderActions);
45199
- }
44778
+ itemRequirements = await getItemRequirementsFromRequirements(web3Provider, params.itemRequirements);
45200
44779
  }
45201
44780
  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
- };
44781
+ throw new CheckoutError('Failed to map item requirements', CheckoutErrorType.ITEM_REQUIREMENTS_ERROR, { error: err });
45218
44782
  }
45219
- let transactions;
45220
- try {
45221
- const response = await Promise.all(unsignedFulfillmentTransactions.map((transaction) => sendTransaction(provider, transaction)));
45222
- transactions = response.map((result) => result.transactionResponse);
44783
+ return await smartCheckout(this.config, web3Provider, itemRequirements, params.transactionOrGasAmount);
44784
+ }
44785
+ /**
44786
+ * Checks if the given object is a Web3 provider.
44787
+ * @param {Web3Provider} web3Provider - The object to check.
44788
+ * @returns {boolean} - True if the object is a Web3 provider, false otherwise.
44789
+ */
44790
+ static isWeb3Provider(web3Provider) {
44791
+ return isWeb3Provider(web3Provider);
44792
+ }
44793
+ /**
44794
+ * Estimates the gas required for a swap or bridge transaction.
44795
+ * @param {GasEstimateParams} params - The parameters for the gas estimation.
44796
+ * @returns {Promise<GasEstimateSwapResult | GasEstimateBridgeToL2Result>} - A promise that resolves to the gas estimation result.
44797
+ */
44798
+ async gasEstimate(params) {
44799
+ this.readOnlyProviders = await createReadOnlyProviders(this.config, this.readOnlyProviders);
44800
+ return await gasEstimator(params, this.readOnlyProviders, this.config);
44801
+ }
44802
+ /**
44803
+ * Creates and returns a URL for the fiat ramp widget.
44804
+ * @param {FiatRampParams} params - The parameters for creating the url.
44805
+ * @returns {Promise<string>} - A promise that resolves to a string url.
44806
+ */
44807
+ async createFiatRampUrl(params) {
44808
+ let tokenAmount;
44809
+ let tokenSymbol = 'IMX';
44810
+ let email;
44811
+ const walletAddress = await params.web3Provider.getSigner().getAddress();
44812
+ const isPassport = params.web3Provider.provider?.isPassport || false;
44813
+ if (isPassport && params.passport) {
44814
+ const userInfo = await params.passport.getUserInfo();
44815
+ email = userInfo?.email;
45223
44816
  }
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
- });
44817
+ const tokenList = await getTokenAllowList(this.config, { type: TokenFilterTypes.ONRAMP });
44818
+ const token = tokenList.tokens?.find((t) => isMatchingAddress(t.address, params.tokenAddress));
44819
+ if (token) {
44820
+ tokenAmount = params.tokenAmount;
44821
+ tokenSymbol = token.symbol;
45228
44822
  }
45229
- return {
45230
- status: CheckoutStatus.FULFILLMENTS_UNSETTLED,
45231
- smartCheckoutResult,
45232
- transactions,
44823
+ return await this.fiatRampService.createWidgetUrl({
44824
+ exchangeType: params.exchangeType,
44825
+ isPassport,
44826
+ walletAddress,
44827
+ tokenAmount,
44828
+ tokenSymbol,
44829
+ email,
44830
+ });
44831
+ }
44832
+ /**
44833
+ * Fetches fiat ramp fee estimations.
44834
+ * @returns {Promise<OnRampProviderFees>} - A promise that resolves to OnRampProviderFees.
44835
+ */
44836
+ async getExchangeFeeEstimate() {
44837
+ return await this.fiatRampService.feeEstimate();
44838
+ }
44839
+ /**
44840
+ * Fetches Swap widget availability.
44841
+ * @returns {Promise<boolean>} - A promise that resolves to a boolean.
44842
+ */
44843
+ async isSwapAvailable() {
44844
+ return this.availability.checkDexAvailability();
44845
+ }
44846
+ }
44847
+
44848
+ class BlockExplorerService {
44849
+ /**
44850
+ * getTransationLink returns the link to the transaction on blockscout
44851
+ * @param hash transaction hash
44852
+ * @returns link to the transaction on blockscout
44853
+ */
44854
+ static getTransactionLink(chainId, hash) {
44855
+ const url = BLOCKSCOUT_CHAIN_URL_MAP?.[chainId]?.url;
44856
+ if (!url || !hash)
44857
+ return undefined;
44858
+ return `${url}/tx/${hash}`;
44859
+ }
44860
+ }
44861
+
44862
+ var checkout = /*#__PURE__*/Object.freeze({
44863
+ __proto__: null,
44864
+ BlockExplorerService: BlockExplorerService,
44865
+ get BridgeEventType () { return BridgeEventType; },
44866
+ get ChainId () { return ChainId; },
44867
+ get ChainName () { return ChainName; },
44868
+ get ChainSlug () { return ChainSlug; },
44869
+ Checkout: Checkout,
44870
+ CheckoutConfiguration: CheckoutConfiguration,
44871
+ get CheckoutErrorType () { return CheckoutErrorType; },
44872
+ get CheckoutStatus () { return CheckoutStatus; },
44873
+ get ConnectEventType () { return ConnectEventType; },
44874
+ get ConnectTargetLayer () { return ConnectTargetLayer; },
44875
+ get ExchangeType () { return ExchangeType; },
44876
+ get FeeType () { return FeeType; },
44877
+ get FundingStepType () { return FundingStepType; },
44878
+ get GasEstimateType () { return GasEstimateType; },
44879
+ get GasTokenType () { return GasTokenType; },
44880
+ IMMUTABLE_API_BASE_URL: IMMUTABLE_API_BASE_URL,
44881
+ get IMTBLWidgetEvents () { return IMTBLWidgetEvents; },
44882
+ get ItemType () { return ItemType; },
44883
+ get NetworkFilterTypes () { return NetworkFilterTypes; },
44884
+ get OnRampEventType () { return OnRampEventType; },
44885
+ get OrchestrationEventType () { return OrchestrationEventType; },
44886
+ get ProviderEventType () { return ProviderEventType; },
44887
+ get RoutingOutcomeType () { return RoutingOutcomeType; },
44888
+ get SaleEventType () { return SaleEventType; },
44889
+ get SalePaymentTypes () { return SalePaymentTypes; },
44890
+ get SwapEventType () { return SwapEventType; },
44891
+ get TokenFilterTypes () { return TokenFilterTypes; },
44892
+ get TransactionOrGasType () { return TransactionOrGasType; },
44893
+ get WalletEventType () { return WalletEventType; },
44894
+ get WalletFilterTypes () { return WalletFilterTypes; },
44895
+ get WalletProviderName () { return WalletProviderName; },
44896
+ get WidgetTheme () { return WidgetTheme; },
44897
+ get WidgetType () { return WidgetType; }
44898
+ });
44899
+
44900
+ function isChainValid(chainID, config) {
44901
+ return chainID === config.ethConfiguration.chainID;
44902
+ }
44903
+ async function validateChain(signer, config) {
44904
+ const chainID = await signer.getChainId();
44905
+ if (!isChainValid(chainID, config)) {
44906
+ throw new Error('The wallet used for this operation is not connected to the correct network.');
44907
+ }
44908
+ }
44909
+
44910
+ async function transfer({ signers: { ethSigner, starkSigner }, request, config, }) {
44911
+ await validateChain(ethSigner, config.immutableXConfig);
44912
+ const ethAddress = await ethSigner.getAddress();
44913
+ const transfersApi = new coreSdk.TransfersApi(config.immutableXConfig.apiConfiguration);
44914
+ const transferAmount = request.type === 'ERC721' ? '1' : request.amount;
44915
+ const signableResult = await transfersApi.getSignableTransferV1({
44916
+ getSignableTransferRequest: {
44917
+ sender: ethAddress,
44918
+ token: convertToSignableToken(request),
44919
+ amount: transferAmount,
44920
+ receiver: request.receiver,
44921
+ },
44922
+ });
44923
+ const { signable_message: signableMessage, payload_hash: payloadHash } = signableResult.data;
44924
+ const ethSignature = await signRaw(signableMessage, ethSigner);
44925
+ const starkSignature = await starkSigner.signMessage(payloadHash);
44926
+ const transferSigningParams = {
44927
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
44928
+ sender_stark_key: signableResult.data.sender_stark_key,
44929
+ sender_vault_id: signableResult.data.sender_vault_id,
44930
+ receiver_stark_key: signableResult.data.receiver_stark_key,
44931
+ receiver_vault_id: signableResult.data.receiver_vault_id,
44932
+ asset_id: signableResult.data.asset_id,
44933
+ amount: signableResult.data.amount,
44934
+ nonce: signableResult.data.nonce,
44935
+ expiration_timestamp: signableResult.data.expiration_timestamp,
44936
+ stark_signature: starkSignature,
44937
+ };
44938
+ const response = await transfersApi.createTransferV1({
44939
+ createTransferRequest: transferSigningParams,
44940
+ xImxEthAddress: ethAddress,
44941
+ xImxEthSignature: ethSignature,
44942
+ });
44943
+ return {
44944
+ sent_signature: response?.data.sent_signature,
44945
+ status: response?.data.status?.toString(),
44946
+ time: response?.data.time,
44947
+ transfer_id: response?.data.transfer_id,
44948
+ };
44949
+ }
44950
+ async function batchTransfer({ signers: { ethSigner, starkSigner }, request, config, }) {
44951
+ await validateChain(ethSigner, config.immutableXConfig);
44952
+ const ethAddress = await ethSigner.getAddress();
44953
+ const transfersApi = new coreSdk.TransfersApi(config.immutableXConfig.apiConfiguration);
44954
+ const signableRequests = request.map((nftTransfer) => ({
44955
+ amount: '1',
44956
+ token: convertToSignableToken({
44957
+ type: 'ERC721',
44958
+ tokenId: nftTransfer.tokenId,
44959
+ tokenAddress: nftTransfer.tokenAddress,
44960
+ }),
44961
+ receiver: nftTransfer.receiver,
44962
+ }));
44963
+ const signableResult = await transfersApi.getSignableTransfer({
44964
+ getSignableTransferRequestV2: {
44965
+ sender_ether_key: ethAddress,
44966
+ signable_requests: signableRequests,
44967
+ },
44968
+ });
44969
+ const signableMessage = signableResult.data.signable_message;
44970
+ if (signableMessage === undefined) {
44971
+ throw new Error('Invalid response from Signable registration offchain');
44972
+ }
44973
+ const ethSignature = await signRaw(signableMessage, ethSigner);
44974
+ const requests = [];
44975
+ for (const resp of signableResult.data.signable_responses) {
44976
+ // TODO: remove once fixed
44977
+ // eslint-disable-next-line no-await-in-loop
44978
+ const starkSignature = await starkSigner.signMessage(resp.payload_hash);
44979
+ const req = {
44980
+ sender_vault_id: resp.sender_vault_id,
44981
+ receiver_stark_key: resp.receiver_stark_key,
44982
+ receiver_vault_id: resp.receiver_vault_id,
44983
+ asset_id: resp.asset_id,
44984
+ amount: resp.amount,
44985
+ nonce: resp.nonce,
44986
+ expiration_timestamp: resp.expiration_timestamp,
44987
+ stark_signature: starkSignature,
45233
44988
  };
44989
+ requests.push(req);
45234
44990
  }
44991
+ // TODO: throw error on missing payload hash?
44992
+ const transferSigningParams = {
44993
+ sender_stark_key: signableResult.data.sender_stark_key,
44994
+ requests,
44995
+ };
44996
+ const response = await transfersApi.createTransfer({
44997
+ createTransferRequestV2: transferSigningParams,
44998
+ xImxEthAddress: ethAddress,
44999
+ xImxEthSignature: ethSignature,
45000
+ });
45001
+ return {
45002
+ transfer_ids: response?.data.transfer_ids,
45003
+ };
45004
+ }
45005
+
45006
+ async function createOrder({ signers, request, config, }) {
45007
+ await validateChain(signers.ethSigner, config.immutableXConfig);
45008
+ const ethAddress = await signers.ethSigner.getAddress();
45009
+ const ordersApi = new coreSdk.OrdersApi(config.immutableXConfig.apiConfiguration);
45010
+ const amountSell = request.sell.type === 'ERC721' ? '1' : request.sell.amount;
45011
+ const amountBuy = request.buy.type === 'ERC721' ? '1' : request.buy.amount;
45012
+ const getSignableOrderRequest = {
45013
+ user: ethAddress,
45014
+ amount_buy: amountBuy,
45015
+ token_buy: convertToSignableToken(request.buy),
45016
+ amount_sell: amountSell,
45017
+ token_sell: convertToSignableToken(request.sell),
45018
+ fees: request.fees,
45019
+ expiration_timestamp: request.expiration_timestamp,
45020
+ };
45021
+ const getSignableOrderResponse = await ordersApi.getSignableOrder({
45022
+ getSignableOrderRequestV3: getSignableOrderRequest,
45023
+ });
45024
+ const { signable_message: signableMessage, payload_hash: payloadHash } = getSignableOrderResponse.data;
45025
+ const ethSignature = await signRaw(signableMessage, signers.ethSigner);
45026
+ const starkSignature = await signers.starkSigner.signMessage(payloadHash);
45027
+ const resp = getSignableOrderResponse.data;
45028
+ const orderParams = {
45029
+ createOrderRequest: {
45030
+ amount_buy: resp.amount_buy,
45031
+ amount_sell: resp.amount_sell,
45032
+ asset_id_buy: resp.asset_id_buy,
45033
+ asset_id_sell: resp.asset_id_sell,
45034
+ expiration_timestamp: resp.expiration_timestamp,
45035
+ fees: request.fees,
45036
+ nonce: resp.nonce,
45037
+ stark_key: resp.stark_key,
45038
+ stark_signature: starkSignature,
45039
+ vault_id_buy: resp.vault_id_buy,
45040
+ vault_id_sell: resp.vault_id_sell,
45041
+ },
45042
+ xImxEthAddress: ethAddress,
45043
+ xImxEthSignature: ethSignature,
45044
+ };
45045
+ const createOrderResponse = await ordersApi.createOrderV3(orderParams);
45235
45046
  return {
45236
- status: CheckoutStatus.INSUFFICIENT_FUNDS,
45237
- smartCheckoutResult,
45047
+ ...createOrderResponse.data,
45238
45048
  };
45239
- };
45049
+ }
45050
+ async function cancelOrder({ signers, request, config, }) {
45051
+ const ordersApi = new coreSdk.OrdersApi(config.immutableXConfig.apiConfiguration);
45052
+ const getSignableCancelOrderResponse = await ordersApi.getSignableCancelOrderV3({
45053
+ getSignableCancelOrderRequest: {
45054
+ order_id: request.order_id,
45055
+ },
45056
+ });
45057
+ const { signable_message: signableMessage, payload_hash: payloadHash } = getSignableCancelOrderResponse.data;
45058
+ const ethSignature = await signRaw(signableMessage, signers.ethSigner);
45059
+ const starkSignature = await signers.starkSigner.signMessage(payloadHash);
45060
+ const ethAddress = await signers.ethSigner.getAddress();
45061
+ const cancelOrderResponse = await ordersApi.cancelOrderV3({
45062
+ id: request.order_id.toString(),
45063
+ cancelOrderRequest: {
45064
+ order_id: request.order_id,
45065
+ stark_signature: starkSignature,
45066
+ },
45067
+ xImxEthAddress: ethAddress,
45068
+ xImxEthSignature: ethSignature,
45069
+ });
45070
+ return {
45071
+ order_id: cancelOrderResponse.data.order_id,
45072
+ status: cancelOrderResponse.data.status,
45073
+ };
45074
+ }
45240
45075
 
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];
45076
+ async function registerOffchain(signers, config) {
45077
+ await validateChain(signers.ethSigner, config.immutableXConfig);
45078
+ const usersApi = new coreSdk.UsersApi(config.immutableXConfig.apiConfiguration);
45079
+ const userAddress = await signers.ethSigner.getAddress();
45080
+ const starkPublicKey = await signers.starkSigner.getAddress();
45081
+ const signableResult = await usersApi.getSignableRegistrationOffchain({
45082
+ getSignableRegistrationRequest: {
45083
+ ether_key: userAddress,
45084
+ stark_key: starkPublicKey,
45085
+ },
45086
+ });
45087
+ const { signable_message: signableMessage, payload_hash: payloadHash } = signableResult.data;
45088
+ const ethSignature = await signRaw(signableMessage, signers.ethSigner);
45089
+ const starkSignature = await signers.starkSigner.signMessage(payloadHash);
45090
+ const registeredUser = await usersApi.registerUser({
45091
+ registerUserRequest: {
45092
+ eth_signature: ethSignature,
45093
+ ether_key: userAddress,
45094
+ stark_signature: starkSignature,
45095
+ stark_key: starkPublicKey,
45096
+ },
45097
+ });
45098
+ return registeredUser.data;
45099
+ }
45100
+ async function isRegisteredOffchain(ethAddress, config) {
45250
45101
  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,
45102
+ const usersApi = new coreSdk.UsersApi(config.immutableXConfig.apiConfiguration);
45103
+ const getUsersResult = await usersApi.getUsers({
45104
+ user: ethAddress,
45260
45105
  });
45106
+ const { accounts } = getUsersResult.data;
45107
+ return accounts?.length > 0;
45261
45108
  }
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
- };
45109
+ catch (ex) {
45110
+ if (ex instanceof globalAxios$1.AxiosError && ex.response?.status === 404) {
45111
+ return false;
45270
45112
  }
45271
- return {
45272
- status: CheckoutStatus.SUCCESS,
45273
- };
45113
+ throw ex;
45274
45114
  }
45275
- let transactions;
45115
+ }
45116
+ async function isRegisteredOnChain(starkPublicKey, ethSigner, config) {
45117
+ await validateChain(ethSigner, config.immutableXConfig);
45118
+ const registrationContract = coreSdk.Contracts.Registration.connect(config.immutableXConfig.ethConfiguration.registrationContractAddress, ethSigner);
45276
45119
  try {
45277
- const response = await Promise.all([unsignedCancelOrderTransaction].map((transaction) => sendTransaction(provider, transaction)));
45278
- transactions = response.map((result) => result.transactionResponse);
45120
+ return await registrationContract.isRegistered(starkPublicKey);
45279
45121
  }
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
- });
45122
+ catch (ex) {
45123
+ if (ex.reason === 'USER_UNREGISTERED') {
45124
+ return false;
45125
+ }
45126
+ throw ex;
45284
45127
  }
45128
+ }
45129
+ async function getSignableRegistrationOnchain(etherKey, starkPublicKey, usersApi) {
45130
+ const response = await usersApi.getSignableRegistration({
45131
+ getSignableRegistrationRequest: {
45132
+ ether_key: etherKey,
45133
+ stark_key: starkPublicKey,
45134
+ },
45135
+ });
45285
45136
  return {
45286
- status: CheckoutStatus.FULFILLMENTS_UNSETTLED,
45287
- transactions,
45137
+ operator_signature: response.data.operator_signature,
45138
+ payload_hash: response.data.payload_hash,
45139
+ readable_transaction: response.data.readable_transaction,
45140
+ verification_signature: response.data.verification_signature,
45288
45141
  };
45289
- };
45142
+ }
45290
45143
 
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
- };
45144
+ const assertIsDefined = (value) => {
45145
+ if (value !== undefined)
45146
+ return value;
45147
+ throw new Error('undefined field exception');
45310
45148
  };
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,
45149
+ async function prepareWithdrawalAction(params) {
45150
+ const { signers: { ethSigner, starkSigner }, type, config, } = params;
45151
+ await validateChain(ethSigner, params.config);
45152
+ const withdrawalsApi = new coreSdk.WithdrawalsApi(config.apiConfiguration);
45153
+ const withdrawalAmount = type === 'ERC721' ? '1' : params.amount;
45154
+ const signableWithdrawalResult = await withdrawalsApi.getSignableWithdrawal({
45155
+ getSignableWithdrawalRequest: {
45156
+ user: await ethSigner.getAddress(),
45157
+ token: convertToSignableToken(params),
45158
+ amount: withdrawalAmount,
45159
+ },
45160
+ });
45161
+ const { signable_message: signableMessage, payload_hash: payloadHash } = signableWithdrawalResult.data;
45162
+ const starkSignature = await starkSigner.signMessage(payloadHash);
45163
+ const { ethAddress, ethSignature } = await signMessage$1(signableMessage, ethSigner);
45164
+ const prepareWithdrawalResponse = await withdrawalsApi.createWithdrawal({
45165
+ createWithdrawalRequest: {
45166
+ stark_key: assertIsDefined(signableWithdrawalResult.data.stark_key),
45167
+ amount: withdrawalAmount,
45168
+ asset_id: assertIsDefined(signableWithdrawalResult.data.asset_id),
45169
+ vault_id: assertIsDefined(signableWithdrawalResult.data.vault_id),
45170
+ nonce: assertIsDefined(signableWithdrawalResult.data.nonce),
45171
+ stark_signature: starkSignature,
45172
+ },
45173
+ xImxEthAddress: ethAddress,
45174
+ xImxEthSignature: ethSignature,
45175
+ });
45176
+ return prepareWithdrawalResponse.data;
45177
+ }
45178
+
45179
+ async function getEncodeAssetInfo(assetType, tokenType, config, tokenData) {
45180
+ const encodingApi = new coreSdk.EncodingApi(config.apiConfiguration);
45181
+ const result = await encodingApi.encodeAsset({
45182
+ assetType,
45183
+ encodeAssetRequest: {
45184
+ token: {
45185
+ type: tokenType,
45186
+ ...(tokenData && { data: tokenData }),
45338
45187
  },
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
45188
  },
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
- };
45189
+ });
45190
+ return result.data;
45191
+ }
45416
45192
 
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;
45193
+ async function executeRegisterAndWithdrawERC20({ ethSigner, assetType, starkPublicKey, config, }) {
45194
+ const etherKey = await ethSigner.getAddress();
45195
+ const imxConfig = config.immutableXConfig;
45196
+ const usersApi = new coreSdk.UsersApi(imxConfig.apiConfiguration);
45197
+ const signableResult = await getSignableRegistrationOnchain(etherKey, starkPublicKey, usersApi);
45198
+ const contract = coreSdk.Contracts.Registration.connect(config.immutableXConfig.ethConfiguration.registrationContractAddress, ethSigner);
45199
+ const populatedTransaction = await contract.populateTransaction.registerAndWithdraw(etherKey, starkPublicKey, signableResult.operator_signature, assetType);
45200
+ return ethSigner.sendTransaction(populatedTransaction);
45201
+ }
45202
+ async function executeWithdrawERC20(ethSigner, assetType, starkPublicKey, config) {
45203
+ const contract = coreSdk.Contracts.Core.connect(config.ethConfiguration.coreContractAddress, ethSigner);
45204
+ const populatedTransaction = await contract.populateTransaction.withdraw(starkPublicKey, assetType);
45205
+ return ethSigner.sendTransaction(populatedTransaction);
45206
+ }
45207
+ async function completeERC20WithdrawalAction({ ethSigner, starkPublicKey, token, config, }) {
45208
+ await validateChain(ethSigner, config.immutableXConfig);
45209
+ const imxConfig = config.immutableXConfig;
45210
+ const assetType = await getEncodeAssetInfo('asset', 'ERC20', imxConfig, {
45211
+ token_address: token.tokenAddress,
45212
+ });
45213
+ const isRegistered = await isRegisteredOnChain(starkPublicKey, ethSigner, config);
45214
+ if (!isRegistered) {
45215
+ return executeRegisterAndWithdrawERC20({
45216
+ ethSigner,
45217
+ assetType: assetType.asset_type,
45218
+ starkPublicKey,
45219
+ config,
45220
+ });
45425
45221
  }
45426
- async feeEstimate() {
45427
- const config = (await this.config.remote.getConfig('onramp'));
45428
- return config[OnRampProvider.TRANSAK]?.fees;
45222
+ return executeWithdrawERC20(ethSigner, assetType.asset_type, starkPublicKey, imxConfig);
45223
+ }
45224
+
45225
+ async function executeWithdrawMintableERC721(ethSigner, assetType, starkPublicKey, mintingBlob, config) {
45226
+ const contract = coreSdk.Contracts.Core.connect(config.ethConfiguration.coreContractAddress, ethSigner);
45227
+ const populatedTransaction = await contract.populateTransaction.withdrawAndMint(starkPublicKey, assetType, mintingBlob);
45228
+ return ethSigner.sendTransaction(populatedTransaction);
45229
+ }
45230
+ async function executeRegisterAndWithdrawMintableERC721(ethSigner, assetType, starkPublicKey, mintingBlob, config) {
45231
+ const etherKey = await ethSigner.getAddress();
45232
+ const usersApi = new coreSdk.UsersApi(config.apiConfiguration);
45233
+ const signableResult = await getSignableRegistrationOnchain(etherKey, starkPublicKey, usersApi);
45234
+ const contract = coreSdk.Contracts.Registration.connect(config.ethConfiguration.registrationContractAddress, ethSigner);
45235
+ const populatedTransaction = await contract.populateTransaction.regsiterAndWithdrawAndMint(etherKey, starkPublicKey, signableResult.operator_signature, assetType, mintingBlob);
45236
+ return ethSigner.sendTransaction(populatedTransaction);
45237
+ }
45238
+ function getMintingBlob(token) {
45239
+ const { id } = token.data;
45240
+ const blueprint = token.data.blueprint || '';
45241
+ return encUtils__namespace.sanitizeHex(encUtils__namespace.utf8ToHex(`{${id}}:{${blueprint}}`));
45242
+ }
45243
+ async function completeMintableERC721Withdrawal(ethSigner, starkPublicKey, token, config) {
45244
+ const imxConfig = config.immutableXConfig;
45245
+ const assetType = await getEncodeAssetInfo('mintable-asset', 'ERC721', imxConfig, {
45246
+ id: token.data.id,
45247
+ token_address: token.data.tokenAddress,
45248
+ ...(token.data.blueprint && { blueprint: token.data.blueprint }),
45249
+ });
45250
+ const mintingBlob = getMintingBlob(token);
45251
+ const isRegistered = await isRegisteredOnChain(starkPublicKey, ethSigner, config);
45252
+ if (!isRegistered) {
45253
+ return executeRegisterAndWithdrawMintableERC721(ethSigner, assetType.asset_type, starkPublicKey, mintingBlob, imxConfig);
45429
45254
  }
45430
- async createWidgetUrl(params) {
45431
- return (await this.getTransakWidgetUrl(params));
45255
+ return executeWithdrawMintableERC721(ethSigner, assetType.asset_type, starkPublicKey, mintingBlob, imxConfig);
45256
+ }
45257
+ async function executeRegisterAndWithdrawERC721(ethSigner, assetType, starkPublicKey, tokenId, config) {
45258
+ const etherKey = await ethSigner.getAddress();
45259
+ const usersApi = new coreSdk.UsersApi(config.apiConfiguration);
45260
+ const signableResult = await getSignableRegistrationOnchain(etherKey, starkPublicKey, usersApi);
45261
+ const contract = coreSdk.Contracts.Registration.connect(config.ethConfiguration.registrationContractAddress, ethSigner);
45262
+ const populatedTransaction = await contract.populateTransaction.registerAndWithdrawNft(etherKey, starkPublicKey, signableResult.operator_signature, assetType, tokenId);
45263
+ return ethSigner.sendTransaction(populatedTransaction);
45264
+ }
45265
+ async function executeWithdrawERC721(ethSigner, assetType, starkPublicKey, tokenId, config) {
45266
+ const contract = coreSdk.Contracts.Core.connect(config.ethConfiguration.coreContractAddress, ethSigner);
45267
+ const populatedTransaction = await contract.populateTransaction.withdrawNft(starkPublicKey, assetType, tokenId);
45268
+ return ethSigner.sendTransaction(populatedTransaction);
45269
+ }
45270
+ async function completeERC721Withdrawal(ethSigner, starkPublicKey, token, config) {
45271
+ const imxConfig = config.immutableXConfig;
45272
+ const assetType = await getEncodeAssetInfo('asset', 'ERC721', imxConfig, {
45273
+ token_id: token.tokenId,
45274
+ token_address: token.tokenAddress,
45275
+ });
45276
+ const isRegistered = await isRegisteredOnChain(starkPublicKey, ethSigner, config);
45277
+ if (!isRegistered) {
45278
+ return executeRegisterAndWithdrawERC721(ethSigner, assetType.asset_type, starkPublicKey, token.tokenId, imxConfig);
45432
45279
  }
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}`;
45280
+ return executeWithdrawERC721(ethSigner, assetType.asset_type, starkPublicKey, token.tokenId, imxConfig);
45281
+ }
45282
+ async function completeERC721WithdrawalAction({ ethSigner, starkPublicKey, token, config, }) {
45283
+ await validateChain(ethSigner, config.immutableXConfig);
45284
+ const { tokenAddress } = token;
45285
+ const { tokenId } = token;
45286
+ const imxConfig = config.immutableXConfig;
45287
+ const mintsApi = new coreSdk.MintsApi(imxConfig.apiConfiguration);
45288
+ return await mintsApi
45289
+ .getMintableTokenDetailsByClientTokenId({
45290
+ tokenAddress,
45291
+ tokenId,
45292
+ })
45293
+ .then((mintableToken) => completeMintableERC721Withdrawal(ethSigner, starkPublicKey, {
45294
+ type: 'ERC721',
45295
+ data: {
45296
+ id: tokenId,
45297
+ tokenAddress,
45298
+ blueprint: mintableToken.data.blueprint,
45299
+ },
45300
+ }, config))
45301
+ .catch((error) => {
45302
+ if (error.response?.status === 404) {
45303
+ // token is already minted on L1
45304
+ return completeERC721Withdrawal(ethSigner, starkPublicKey, token, config);
45465
45305
  }
45466
- return widgetUrl;
45306
+ throw error; // unable to recover from any other kind of error
45307
+ });
45308
+ }
45309
+
45310
+ async function executeRegisterAndWithdrawEth(ethSigner, assetType, starkPublicKey, config) {
45311
+ const etherKey = await ethSigner.getAddress();
45312
+ const usersApi = new coreSdk.UsersApi(config.apiConfiguration);
45313
+ const signableResult = await getSignableRegistrationOnchain(etherKey, starkPublicKey, usersApi);
45314
+ const contract = coreSdk.Contracts.Registration.connect(config.ethConfiguration.registrationContractAddress, ethSigner);
45315
+ const populatedTransaction = await contract.populateTransaction.registerAndWithdraw(etherKey, starkPublicKey, signableResult.operator_signature, assetType);
45316
+ return ethSigner.sendTransaction(populatedTransaction);
45317
+ }
45318
+ async function executeWithdrawEth(ethSigner, assetType, starkPublicKey, config) {
45319
+ const contract = coreSdk.Contracts.Core.connect(config.ethConfiguration.coreContractAddress, ethSigner);
45320
+ const populatedTransaction = await contract.populateTransaction.withdraw(starkPublicKey, assetType);
45321
+ return ethSigner.sendTransaction(populatedTransaction);
45322
+ }
45323
+ async function completeEthWithdrawalAction({ ethSigner, starkPublicKey, config, }) {
45324
+ await validateChain(ethSigner, config.immutableXConfig);
45325
+ const imxConfig = config.immutableXConfig;
45326
+ const assetType = await getEncodeAssetInfo('asset', 'ETH', imxConfig);
45327
+ const isRegistered = await isRegisteredOnChain(starkPublicKey, ethSigner, config);
45328
+ if (!isRegistered) {
45329
+ return executeRegisterAndWithdrawEth(ethSigner, assetType.asset_type, starkPublicKey, imxConfig);
45330
+ }
45331
+ return executeWithdrawEth(ethSigner, assetType.asset_type, starkPublicKey, imxConfig);
45332
+ }
45333
+
45334
+ async function prepareWithdrawal({ signers, withdrawal, config, }) {
45335
+ return prepareWithdrawalAction({
45336
+ signers,
45337
+ config: config.immutableXConfig,
45338
+ ...withdrawal,
45339
+ });
45340
+ }
45341
+ // TODO: remove once fixed
45342
+ // eslint-disable-next-line consistent-return
45343
+ async function completeWithdrawal({ signers: { ethSigner }, starkPublicKey, token, config, }) {
45344
+ // TODO: please add a reasonable default here
45345
+ // eslint-disable-next-line default-case
45346
+ switch (token.type) {
45347
+ case 'ETH':
45348
+ return completeEthWithdrawalAction({ ethSigner, starkPublicKey, config });
45349
+ case 'ERC20':
45350
+ return completeERC20WithdrawalAction({
45351
+ ethSigner,
45352
+ starkPublicKey,
45353
+ token,
45354
+ config,
45355
+ });
45356
+ case 'ERC721':
45357
+ return completeERC721WithdrawalAction({
45358
+ ethSigner,
45359
+ starkPublicKey,
45360
+ token,
45361
+ config,
45362
+ });
45467
45363
  }
45468
45364
  }
45469
45365
 
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
- }
45366
+ async function createTrade({ signers: { ethSigner, starkSigner }, request, config, }) {
45367
+ await validateChain(ethSigner, config.immutableXConfig);
45368
+ const ethAddress = await ethSigner.getAddress();
45369
+ const tradesApi = new coreSdk.TradesApi(config.immutableXConfig.apiConfiguration);
45370
+ const signableResult = await tradesApi.getSignableTrade({
45371
+ getSignableTradeRequest: {
45372
+ user: ethAddress,
45373
+ order_id: request.order_id,
45374
+ fees: request.fees,
45375
+ },
45478
45376
  });
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;
45377
+ const { signable_message: signableMessage, payload_hash: payloadHash } = signableResult.data;
45378
+ const ethSignature = await signRaw(signableMessage, ethSigner);
45379
+ const starkSignature = await starkSigner.signMessage(payloadHash);
45380
+ const createTradeResponse = await tradesApi.createTradeV3({
45381
+ createTradeRequest: {
45382
+ amount_buy: signableResult.data.amount_buy,
45383
+ amount_sell: signableResult.data.amount_sell,
45384
+ asset_id_buy: signableResult.data.asset_id_buy,
45385
+ asset_id_sell: signableResult.data.asset_id_sell,
45386
+ expiration_timestamp: signableResult.data.expiration_timestamp,
45387
+ fee_info: signableResult.data.fee_info,
45388
+ fees: request.fees,
45389
+ include_fees: true,
45390
+ nonce: signableResult.data.nonce,
45391
+ order_id: request.order_id,
45392
+ stark_key: signableResult.data.stark_key,
45393
+ vault_id_buy: signableResult.data.vault_id_buy,
45394
+ vault_id_sell: signableResult.data.vault_id_sell,
45395
+ stark_signature: starkSignature,
45396
+ },
45397
+ xImxEthAddress: ethAddress,
45398
+ xImxEthSignature: ethSignature,
45495
45399
  });
45496
- return itemRequirements;
45400
+ return createTradeResponse.data;
45497
45401
  }
45498
45402
 
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()}`;
45403
+ async function executeRegisterAndDepositEth(ethSigner, amount, assetType, starkPublicKey, vaultId, config, usersApi) {
45404
+ const etherKey = await ethSigner.getAddress();
45405
+ const coreContract = coreSdk.Contracts.Core.connect(config.ethConfiguration.coreContractAddress, ethSigner);
45406
+ const signableResult = await getSignableRegistrationOnchain(etherKey, starkPublicKey, usersApi);
45407
+ const populatedTransaction = await coreContract.populateTransaction.registerAndDepositEth(etherKey, starkPublicKey, signableResult.operator_signature, assetType, vaultId);
45408
+ return ethSigner.sendTransaction({ ...populatedTransaction, value: amount });
45409
+ }
45410
+ async function executeDepositEth(ethSigner, amount, assetType, starkPublicKey, vaultId, config) {
45411
+ const coreContract = coreSdk.Contracts.Core.connect(config.ethConfiguration.coreContractAddress, ethSigner);
45412
+ const populatedTransaction = await coreContract.populateTransaction['deposit(uint256,uint256,uint256)'](starkPublicKey, assetType, vaultId);
45413
+ return ethSigner.sendTransaction({ ...populatedTransaction, value: amount });
45414
+ }
45415
+ async function depositEth({ signers: { ethSigner }, deposit, config, }) {
45416
+ await validateChain(ethSigner, config.immutableXConfig);
45417
+ const user = await ethSigner.getAddress();
45418
+ const data = {
45419
+ decimals: 18,
45420
+ };
45421
+ const amount = units.parseUnits(deposit.amount, 'wei');
45422
+ const imxConfig = config.immutableXConfig;
45423
+ const depositsApi = new coreSdk.DepositsApi(imxConfig.apiConfiguration);
45424
+ const encodingApi = new coreSdk.EncodingApi(imxConfig.apiConfiguration);
45425
+ const usersApi = new coreSdk.UsersApi(imxConfig.apiConfiguration);
45426
+ const getSignableDepositRequest = {
45427
+ user,
45428
+ token: {
45429
+ type: deposit.type,
45430
+ data,
45431
+ },
45432
+ amount: amount.toString(),
45433
+ };
45434
+ const signableDepositResult = await depositsApi.getSignableDeposit({
45435
+ getSignableDepositRequest,
45436
+ });
45437
+ const encodingResult = await encodingApi.encodeAsset({
45438
+ assetType: 'asset',
45439
+ encodeAssetRequest: {
45440
+ token: {
45441
+ type: deposit.type,
45442
+ },
45443
+ },
45444
+ });
45445
+ const assetType = encodingResult.data.asset_type;
45446
+ const starkPublicKey = signableDepositResult.data.stark_key;
45447
+ const vaultId = signableDepositResult.data.vault_id;
45448
+ const isRegistered = await isRegisteredOnChain(starkPublicKey, ethSigner, config);
45449
+ if (!isRegistered) {
45450
+ return executeRegisterAndDepositEth(ethSigner, amount, assetType, starkPublicKey, vaultId, imxConfig, usersApi);
45528
45451
  }
45529
- if (version.patch === undefined)
45530
- return validatedVersion;
45531
- if (Number.isInteger(version.patch)) {
45532
- validatedVersion += `.${version.patch.toString()}`;
45452
+ return executeDepositEth(ethSigner, amount, assetType, starkPublicKey, vaultId, imxConfig);
45453
+ }
45454
+
45455
+ async function executeRegisterAndDepositERC20(ethSigner, quantizedAmount, assetType, starkPublicKey, vaultId, config, usersApi) {
45456
+ const etherKey = await ethSigner.getAddress();
45457
+ const coreContract = coreSdk.Contracts.Core.connect(config.coreContractAddress, ethSigner);
45458
+ const signableResult = await getSignableRegistrationOnchain(etherKey, starkPublicKey, usersApi);
45459
+ const populatedTransaction = await coreContract.populateTransaction.registerAndDepositERC20(etherKey, starkPublicKey, signableResult.operator_signature, assetType, vaultId, quantizedAmount);
45460
+ return ethSigner.sendTransaction(populatedTransaction);
45461
+ }
45462
+ async function executeDepositERC20(ethSigner, quantizedAmount, assetType, starkPublicKey, vaultId, config) {
45463
+ const coreContract = coreSdk.Contracts.Core.connect(config.coreContractAddress, ethSigner);
45464
+ const populatedTransaction = await coreContract.populateTransaction.depositERC20(starkPublicKey, assetType, vaultId, quantizedAmount);
45465
+ return ethSigner.sendTransaction(populatedTransaction);
45466
+ }
45467
+ async function depositERC20({ signers: { ethSigner }, deposit, config, }) {
45468
+ await validateChain(ethSigner, config.immutableXConfig);
45469
+ const { apiConfiguration, ethConfiguration } = config.immutableXConfig;
45470
+ const user = await ethSigner.getAddress();
45471
+ const tokensApi = new coreSdk.TokensApi(apiConfiguration);
45472
+ const depositsApi = new coreSdk.DepositsApi(apiConfiguration);
45473
+ const encodingApi = new coreSdk.EncodingApi(apiConfiguration);
45474
+ const usersApi = new coreSdk.UsersApi(apiConfiguration);
45475
+ // Get decimals for this specific ERC20
45476
+ const token = await tokensApi.getToken({ address: deposit.tokenAddress });
45477
+ // TODO: remove once fixed
45478
+ // eslint-disable-next-line radix
45479
+ const decimals = parseInt(token.data.decimals);
45480
+ const data = {
45481
+ decimals,
45482
+ token_address: deposit.tokenAddress,
45483
+ };
45484
+ const amount = units.parseUnits(deposit.amount, 0); // 0 to always use undecimalized value
45485
+ // Approve whether an amount of token from an account can be spent by a third-party account
45486
+ const tokenContract = coreSdk.Contracts.IERC20.connect(deposit.tokenAddress, ethSigner);
45487
+ const approveTransaction = await tokenContract.populateTransaction.approve(ethConfiguration.coreContractAddress, amount);
45488
+ await ethSigner.sendTransaction(approveTransaction);
45489
+ const getSignableDepositRequest = {
45490
+ user,
45491
+ token: {
45492
+ type: deposit.type,
45493
+ data,
45494
+ },
45495
+ amount: amount.toString(),
45496
+ };
45497
+ const signableDepositResult = await depositsApi.getSignableDeposit({
45498
+ getSignableDepositRequest,
45499
+ });
45500
+ // Perform encoding on asset details to get an assetType (required for stark contract request)
45501
+ const encodingResult = await encodingApi.encodeAsset({
45502
+ assetType: 'asset',
45503
+ encodeAssetRequest: {
45504
+ token: {
45505
+ type: deposit.type,
45506
+ data: {
45507
+ token_address: deposit.tokenAddress,
45508
+ },
45509
+ },
45510
+ },
45511
+ });
45512
+ const assetType = encodingResult.data.asset_type;
45513
+ const starkPublicKey = signableDepositResult.data.stark_key;
45514
+ const vaultId = signableDepositResult.data.vault_id;
45515
+ const quantizedAmount = bignumber.BigNumber.from(signableDepositResult.data.amount);
45516
+ const isRegistered = await isRegisteredOnChain(starkPublicKey, ethSigner, config);
45517
+ if (!isRegistered) {
45518
+ return executeRegisterAndDepositERC20(ethSigner, quantizedAmount, assetType, starkPublicKey, vaultId, ethConfiguration, usersApi);
45533
45519
  }
45534
- if (version.prerelease === undefined || version.prerelease !== 'alpha')
45535
- return validatedVersion;
45536
- if (version.prerelease === 'alpha') {
45537
- validatedVersion += `-${version.prerelease}`;
45520
+ return executeDepositERC20(ethSigner, quantizedAmount, assetType, starkPublicKey, vaultId, ethConfiguration);
45521
+ }
45522
+
45523
+ async function executeDepositERC721(ethSigner, tokenId, assetType, starkPublicKey, vaultId, config) {
45524
+ const coreContract = coreSdk.Contracts.Core.connect(config.ethConfiguration.coreContractAddress, ethSigner);
45525
+ const populatedTransaction = await coreContract.populateTransaction.depositNft(starkPublicKey, assetType, vaultId, tokenId);
45526
+ return ethSigner.sendTransaction(populatedTransaction);
45527
+ }
45528
+ async function depositERC721({ signers: { ethSigner }, deposit, config, }) {
45529
+ await validateChain(ethSigner, config.immutableXConfig);
45530
+ const user = await ethSigner.getAddress();
45531
+ const { immutableXConfig } = config;
45532
+ const depositsApi = new coreSdk.DepositsApi(immutableXConfig.apiConfiguration);
45533
+ const encodingApi = new coreSdk.EncodingApi(immutableXConfig.apiConfiguration);
45534
+ const usersApi = new coreSdk.UsersApi(immutableXConfig.apiConfiguration);
45535
+ const data = {
45536
+ token_address: deposit.tokenAddress,
45537
+ token_id: deposit.tokenId,
45538
+ };
45539
+ const amount = '1';
45540
+ const getSignableDepositRequest = {
45541
+ user,
45542
+ token: {
45543
+ type: deposit.type,
45544
+ data,
45545
+ },
45546
+ amount: amount.toString(),
45547
+ };
45548
+ const signableDepositResult = await depositsApi.getSignableDeposit({
45549
+ getSignableDepositRequest,
45550
+ });
45551
+ // Perform encoding on asset details to get an assetType (required for stark contract request)
45552
+ const encodingResult = await encodingApi.encodeAsset({
45553
+ assetType: 'asset',
45554
+ encodeAssetRequest: {
45555
+ token: {
45556
+ type: deposit.type,
45557
+ data: {
45558
+ token_address: deposit.tokenAddress,
45559
+ token_id: deposit.tokenId,
45560
+ },
45561
+ },
45562
+ },
45563
+ });
45564
+ const assetType = encodingResult.data.asset_type;
45565
+ const starkPublicKey = signableDepositResult.data.stark_key;
45566
+ const vaultId = signableDepositResult.data.vault_id;
45567
+ const isRegistered = await isRegisteredOnChain(starkPublicKey, ethSigner, config);
45568
+ // Approve whether an amount of token from an account can be spent by a third-party account
45569
+ const tokenContract = coreSdk.Contracts.IERC721.connect(deposit.tokenAddress, ethSigner);
45570
+ const operator = immutableXConfig.ethConfiguration.coreContractAddress;
45571
+ const isApprovedForAll = await tokenContract.isApprovedForAll(user, operator);
45572
+ if (!isApprovedForAll) {
45573
+ await tokenContract.setApprovalForAll(operator, true);
45538
45574
  }
45539
- if (version.build === undefined)
45540
- return validatedVersion;
45541
- if (Number.isInteger(version.build) && version.build >= 0) {
45542
- validatedVersion += `.${version.build.toString()}`;
45575
+ if (!isRegistered) {
45576
+ const signableResult = await getSignableRegistrationOnchain(user, starkPublicKey, usersApi);
45577
+ const coreContract = coreSdk.Contracts.Core.connect(immutableXConfig.ethConfiguration.coreContractAddress, ethSigner);
45578
+ // Note: proxy registration contract registerAndDepositNft method is not used as
45579
+ // it currently fails erc721 transfer ownership check
45580
+ await coreContract.registerUser(user, starkPublicKey, signableResult.operator_signature);
45543
45581
  }
45544
- return validatedVersion;
45582
+ return executeDepositERC721(ethSigner, deposit.tokenId, assetType, starkPublicKey, vaultId, immutableXConfig);
45545
45583
  }
45546
45584
 
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');
45585
+ // TODO: remove once fixed deposit variable shadowing
45586
+ // eslint-disable-next-line consistent-return, @typescript-eslint/no-shadow
45587
+ async function deposit({ signers, deposit, config }) {
45588
+ // TODO: please add a reasonable default here
45589
+ // eslint-disable-next-line default-case
45590
+ switch (deposit.type) {
45591
+ case 'ETH':
45592
+ return depositEth({ signers, deposit, config });
45593
+ case 'ERC20':
45594
+ return depositERC20({ signers, deposit, config });
45595
+ case 'ERC721':
45596
+ return depositERC721({ signers, deposit, config });
45553
45597
  }
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
45598
  }
45569
45599
 
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 {
45600
+ async function exchangeTransfer({ signers, request, config, }) {
45601
+ await validateChain(signers.ethSigner, config.immutableXConfig);
45602
+ const exchangeApi = new coreSdk.ExchangesApi(config.immutableXConfig.apiConfiguration);
45603
+ const ethAddress = await signers.ethSigner.getAddress();
45604
+ const transferAmount = request.amount;
45605
+ const signableResult = await exchangeApi.getExchangeSignableTransfer({
45606
+ id: request.transactionID,
45607
+ getSignableTransferRequest: {
45608
+ sender: ethAddress,
45609
+ token: convertToSignableToken(request),
45610
+ amount: transferAmount,
45611
+ receiver: request.receiver,
45612
+ },
45613
+ });
45614
+ const { signable_message: signableMessage, payload_hash: payloadHash } = signableResult.data;
45615
+ const ethSignature = await signRaw(signableMessage, signers.ethSigner);
45616
+ const starkSignature = await signers.starkSigner.signMessage(payloadHash);
45617
+ const transferSigningParams = {
45618
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
45619
+ sender_stark_key: signableResult.data.sender_stark_key,
45620
+ sender_vault_id: signableResult.data.sender_vault_id,
45621
+ receiver_stark_key: signableResult.data.receiver_stark_key,
45622
+ receiver_vault_id: signableResult.data.receiver_vault_id,
45623
+ asset_id: signableResult.data.asset_id,
45624
+ amount: signableResult.data.amount,
45625
+ nonce: signableResult.data.nonce,
45626
+ expiration_timestamp: signableResult.data.expiration_timestamp,
45627
+ stark_signature: starkSignature,
45628
+ };
45629
+ const response = await exchangeApi.createExchangeTransfer({
45630
+ id: request.transactionID,
45631
+ createTransferRequest: transferSigningParams,
45632
+ xImxEthAddress: ethAddress,
45633
+ xImxEthSignature: ethSignature,
45634
+ });
45635
+ return {
45636
+ sent_signature: response?.data.sent_signature,
45637
+ status: response?.data.status?.toString(),
45638
+ time: response?.data.time,
45639
+ transfer_id: response?.data.transfer_id,
45640
+ };
45641
+ }
45642
+
45643
+ class GenericIMXProvider {
45577
45644
  config;
45578
- axiosInstance;
45579
- constructor(config) {
45645
+ signers;
45646
+ constructor(config, ethSigner, starkSigner) {
45580
45647
  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));
45648
+ this.signers = { ethSigner, starkSigner };
45588
45649
  }
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));
45650
+ async getAddress() {
45651
+ return this.signers.ethSigner.getAddress();
45603
45652
  }
45604
- async request(config) {
45605
- return await this.axiosInstance.request(config);
45653
+ async isRegisteredOffchain() {
45654
+ const ethAddress = await this.getAddress();
45655
+ return isRegisteredOffchain(ethAddress, this.config);
45606
45656
  }
45607
- async get(url, config) {
45608
- const requestConfig = {
45609
- ...config,
45610
- url,
45611
- };
45612
- return await this.request(requestConfig);
45657
+ registerOffchain() {
45658
+ return registerOffchain(this.signers, this.config);
45613
45659
  }
45614
- async post(url, data, config) {
45615
- const requestConfig = {
45616
- ...config,
45617
- data,
45618
- url,
45619
- };
45620
- return await this.request(requestConfig);
45660
+ batchNftTransfer(request) {
45661
+ return batchTransfer({
45662
+ signers: this.signers,
45663
+ request,
45664
+ config: this.config,
45665
+ });
45621
45666
  }
45622
- async put(url, data, config) {
45623
- const requestConfig = {
45624
- ...config,
45625
- data,
45626
- url,
45627
- };
45628
- return await this.request(requestConfig);
45667
+ cancelOrder(request) {
45668
+ return cancelOrder({
45669
+ signers: this.signers,
45670
+ request,
45671
+ config: this.config,
45672
+ });
45629
45673
  }
45630
- async delete(url, data, config) {
45631
- const requestConfig = {
45632
- ...config,
45633
- data,
45634
- url,
45635
- };
45636
- return await this.request(requestConfig);
45674
+ completeWithdrawal(starkPublicKey, token) {
45675
+ return completeWithdrawal({
45676
+ config: this.config,
45677
+ signers: this.signers,
45678
+ token,
45679
+ starkPublicKey,
45680
+ });
45637
45681
  }
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;
45682
+ createOrder(request) {
45683
+ return createOrder({
45684
+ signers: this.signers,
45685
+ request,
45686
+ config: this.config,
45687
+ });
45666
45688
  }
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
- }
45689
+ createTrade(request) {
45690
+ return createTrade({
45691
+ signers: this.signers,
45692
+ request,
45693
+ config: this.config,
45699
45694
  });
45700
- return factory;
45701
45695
  }
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);
45696
+ deposit(tokenAmount) {
45697
+ return deposit({
45698
+ signers: this.signers,
45699
+ deposit: tokenAmount,
45700
+ config: this.config,
45701
+ });
45709
45702
  }
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);
45703
+ exchangeTransfer(request) {
45704
+ return exchangeTransfer({
45705
+ signers: this.signers,
45706
+ request,
45707
+ config: this.config,
45708
+ });
45718
45709
  }
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 };
45710
+ async isRegisteredOnchain() {
45711
+ const starkPublicKey = await this.signers.starkSigner.getAddress();
45712
+ return isRegisteredOnChain(starkPublicKey, this.signers.ethSigner, this.config);
45729
45713
  }
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,
45714
+ prepareWithdrawal(request) {
45715
+ return prepareWithdrawal({
45716
+ signers: this.signers,
45717
+ withdrawal: request,
45718
+ config: this.config,
45739
45719
  });
45740
- const switchNetworkRes = await switchWalletNetwork(this.config, web3Provider, params.chainId);
45741
- return switchNetworkRes;
45742
45720
  }
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);
45721
+ transfer(request) {
45722
+ return transfer({
45723
+ signers: this.signers,
45724
+ request,
45725
+ config: this.config,
45726
+ });
45751
45727
  }
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);
45728
+ }
45729
+
45730
+ const WALLET_ACTION = {
45731
+ // TODO: remove once fixed - consider using an enum
45732
+ // eslint-disable-next-line @typescript-eslint/naming-convention
45733
+ SWITCH_CHAIN: 'wallet_switchEthereumChain',
45734
+ // eslint-disable-next-line @typescript-eslint/naming-convention
45735
+ CONNECT: 'eth_requestAccounts',
45736
+ };
45737
+ function isRequestableProvider(provider) {
45738
+ return !!provider?.request;
45739
+ }
45740
+ async function connectProvider(provider, chainID) {
45741
+ await provider.request({ method: WALLET_ACTION.CONNECT });
45742
+ if (chainID) {
45743
+ await provider.request({
45744
+ method: WALLET_ACTION.SWITCH_CHAIN,
45745
+ params: [{ chainId: `0x${chainID.toString(16)}` }],
45746
+ });
45763
45747
  }
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);
45748
+ }
45749
+
45750
+ const ERRORS = {
45751
+ // TODO: remove once fixed - consider using something in line with the naming convention
45752
+ // eslint-disable-next-line @typescript-eslint/naming-convention
45753
+ PROVIDER_NOT_FOUND: 'The Metamask provider was not found',
45754
+ };
45755
+ async function connect$1({ chainID, }) {
45756
+ const provider = (await detectEthereumProvider());
45757
+ if (!isRequestableProvider(provider)) {
45758
+ throw new Error(ERRORS.PROVIDER_NOT_FOUND);
45771
45759
  }
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);
45760
+ await connectProvider(provider, chainID);
45761
+ // NOTE: if we want to listen to Metamask events in the future, we can add a
45762
+ // listener here.
45763
+ return new ethers.ethers.providers.Web3Provider(provider);
45764
+ }
45765
+
45766
+ const COMMUNICATION_TYPE = 'message';
45767
+ var RequestEventType;
45768
+ (function (RequestEventType) {
45769
+ RequestEventType["GET_CONNECTION_REQUEST"] = "GET_CONNECTION_REQUEST";
45770
+ RequestEventType["CONNECT_WALLET_REQUEST"] = "CONNECT_WALLET_REQUEST";
45771
+ RequestEventType["SIGN_MESSAGE_REQUEST"] = "SIGN_MESSAGE_REQUEST";
45772
+ RequestEventType["DISCONNECT_WALLET_REQUEST"] = "DISCONNECT_WALLET_REQUEST";
45773
+ })(RequestEventType || (RequestEventType = {}));
45774
+ var ResponseEventType;
45775
+ (function (ResponseEventType) {
45776
+ ResponseEventType["CONNECT_WALLET_RESPONSE"] = "CONNECT_WALLET_RESPONSE";
45777
+ ResponseEventType["SIGN_MESSAGE_RESPONSE"] = "SIGN_MESSAGE_RESPONSE";
45778
+ ResponseEventType["GET_CONNECTION_RESPONSE"] = "GET_CONNECTION_RESPONSE";
45779
+ ResponseEventType["DISCONNECT_WALLET_RESPONSE"] = "DISCONNECT_WALLET_RESPONSE";
45780
+ })(ResponseEventType || (ResponseEventType = {}));
45781
+
45782
+ function postRequestMessage(iframe, payload) {
45783
+ if (iframe && iframe.contentWindow) {
45784
+ iframe.contentWindow.postMessage(payload, new URL(iframe.src).origin);
45779
45785
  }
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);
45786
+ }
45787
+
45788
+ function messageResponseListener(iframe, event, eventType, callback) {
45789
+ if (iframe && event.source !== iframe.contentWindow) {
45790
+ return;
45787
45791
  }
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);
45792
+ const l2WalletMessage = event.data;
45793
+ if (l2WalletMessage.type !== eventType) {
45794
+ return;
45795
45795
  }
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);
45796
+ callback(l2WalletMessage.details);
45797
+ }
45798
+
45799
+ class ImxSigner {
45800
+ publicAddress;
45801
+ iframe;
45802
+ constructor(publicAddress, iframe) {
45803
+ this.publicAddress = publicAddress;
45804
+ this.iframe = iframe;
45804
45805
  }
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);
45806
+ getAddress() {
45807
+ return this.publicAddress;
45816
45808
  }
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);
45809
+ signMessage(rawMessage) {
45810
+ return new Promise((resolve, reject) => {
45811
+ const listener = (event) => {
45812
+ messageResponseListener(this.iframe, event, ResponseEventType.SIGN_MESSAGE_RESPONSE, (messageDetails) => {
45813
+ window.removeEventListener(COMMUNICATION_TYPE, listener);
45814
+ if (!messageDetails.success) {
45815
+ reject(new Error(messageDetails.error?.message));
45816
+ }
45817
+ resolve(messageDetails.data.signedMessage);
45818
+ });
45819
+ };
45820
+ window.addEventListener(COMMUNICATION_TYPE, listener);
45821
+ postRequestMessage(this.iframe, {
45822
+ type: RequestEventType.SIGN_MESSAGE_REQUEST,
45823
+ details: { starkPublicKey: this.publicAddress, message: rawMessage },
45824
+ });
45825
+ });
45828
45826
  }
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);
45827
+ getIFrame() {
45828
+ return this.iframe;
45842
45829
  }
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);
45830
+ }
45831
+
45832
+ const IMX_WALLET_IFRAME_ID = 'imx-wallet-app';
45833
+ const IMX_WALLET_IFRAME_HOSTS = {
45834
+ [Environment$1.SANDBOX]: 'https://wallets.sandbox.immutable.com',
45835
+ [Environment$1.PRODUCTION]: 'https://wallets.immutable.com',
45836
+ };
45837
+ const IMX_WALLET_IFRAME_STYLE = 'display: none;';
45838
+ function getIFrame() {
45839
+ return document.querySelector(`iframe#${IMX_WALLET_IFRAME_ID}`);
45840
+ }
45841
+ async function setupIFrame(env) {
45842
+ return new Promise((resolve) => {
45843
+ const iframe = document.createElement('iframe');
45844
+ iframe.setAttribute('id', IMX_WALLET_IFRAME_ID);
45845
+ iframe.setAttribute('src', IMX_WALLET_IFRAME_HOSTS[env]);
45846
+ iframe.setAttribute('style', IMX_WALLET_IFRAME_STYLE);
45847
+ document.body.appendChild(iframe);
45848
+ iframe.onload = () => resolve(iframe);
45849
+ });
45850
+ }
45851
+ async function getOrSetupIFrame(env) {
45852
+ const iframe = getIFrame();
45853
+ if (iframe)
45854
+ return iframe;
45855
+ return await setupIFrame(env);
45856
+ }
45857
+
45858
+ const DEFAULT_CONNECTION_MESSAGE = 'Only sign this request if you’ve initiated an action with Immutable X.';
45859
+ const CONNECTION_FAILED_ERROR = 'The L2 IMX Wallet connection has failed';
45860
+ async function connect(l1Provider, env) {
45861
+ const l1Signer = l1Provider.getSigner();
45862
+ const address = await l1Signer.getAddress();
45863
+ const signature = await l1Signer.signMessage(DEFAULT_CONNECTION_MESSAGE);
45864
+ const iframe = await getOrSetupIFrame(env);
45865
+ return new Promise((resolve, reject) => {
45866
+ const listener = (event) => {
45867
+ messageResponseListener(iframe, event, ResponseEventType.CONNECT_WALLET_RESPONSE, (messageDetails) => {
45868
+ window.removeEventListener(COMMUNICATION_TYPE, listener);
45869
+ if (!messageDetails.success) {
45870
+ reject(new Error(CONNECTION_FAILED_ERROR));
45871
+ }
45872
+ resolve(new ImxSigner(messageDetails.data.starkPublicKey, iframe));
45873
+ });
45874
+ };
45875
+ window.addEventListener(COMMUNICATION_TYPE, listener);
45876
+ postRequestMessage(iframe, {
45877
+ type: RequestEventType.CONNECT_WALLET_REQUEST,
45878
+ details: { ethAddress: address, signature },
45879
+ });
45880
+ });
45881
+ }
45882
+ async function disconnect(imxSigner) {
45883
+ const iframe = imxSigner.getIFrame();
45884
+ return new Promise((resolve, reject) => {
45885
+ const listener = (event) => {
45886
+ messageResponseListener(iframe, event, ResponseEventType.DISCONNECT_WALLET_RESPONSE, (messageDetails) => {
45887
+ window.removeEventListener(COMMUNICATION_TYPE, listener);
45888
+ if (!messageDetails.success && messageDetails.error) {
45889
+ reject(messageDetails.error);
45890
+ }
45891
+ iframe.remove();
45892
+ resolve();
45893
+ });
45894
+ };
45895
+ window.addEventListener(COMMUNICATION_TYPE, listener);
45896
+ postRequestMessage(iframe, {
45897
+ type: RequestEventType.DISCONNECT_WALLET_REQUEST,
45898
+ details: { starkPublicKey: imxSigner.getAddress() },
45899
+ });
45900
+ });
45901
+ }
45902
+
45903
+ var ProviderErrorType;
45904
+ (function (ProviderErrorType) {
45905
+ ProviderErrorType["PROVIDER_CONNECTION_ERROR"] = "PROVIDER_CONNECTION_ERROR";
45906
+ ProviderErrorType["WALLET_CONNECTION_ERROR"] = "WALLET_CONNECTION_ERROR";
45907
+ })(ProviderErrorType || (ProviderErrorType = {}));
45908
+ class ProviderError extends Error {
45909
+ type;
45910
+ constructor(message, type) {
45911
+ super(message);
45912
+ this.type = type;
45852
45913
  }
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);
45914
+ }
45915
+ const withProviderError = async (fn, customError) => {
45916
+ try {
45917
+ return await fn();
45867
45918
  }
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);
45919
+ catch (error) {
45920
+ const errorMessage = customError.message || `${error.message}` || 'UnknownError';
45921
+ throw new ProviderError(errorMessage, customError.type);
45875
45922
  }
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);
45923
+ };
45924
+
45925
+ class MetaMaskIMXProvider extends GenericIMXProvider {
45926
+ static imxSigner;
45927
+ static async connect(config) {
45928
+ return await withProviderError(async () => {
45929
+ const metaMaskProvider = await connect$1({
45930
+ chainID: config.immutableXConfig.ethConfiguration.chainID,
45931
+ });
45932
+ this.imxSigner = await connect(metaMaskProvider, config.baseConfig.environment);
45933
+ return new MetaMaskIMXProvider(config, metaMaskProvider.getSigner(), this.imxSigner);
45934
+ }, { type: ProviderErrorType.WALLET_CONNECTION_ERROR });
45884
45935
  }
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;
45936
+ static async disconnect() {
45937
+ if (!this.imxSigner) {
45938
+ throw new ProviderError('Attempted to disconnect from the MetaMask IMX provider without an established connection', ProviderErrorType.PROVIDER_CONNECTION_ERROR);
45905
45939
  }
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();
45940
+ return withProviderError(async () => {
45941
+ await disconnect(this.imxSigner);
45942
+ }, { type: ProviderErrorType.PROVIDER_CONNECTION_ERROR });
45921
45943
  }
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();
45944
+ static async signMessage(message) {
45945
+ if (!this.imxSigner) {
45946
+ throw new ProviderError('Attempted to sign a message with the MetaMask IMX provider without an established connection', ProviderErrorType.PROVIDER_CONNECTION_ERROR);
45947
+ }
45948
+ return withProviderError(async () => await this.imxSigner.signMessage(message), { type: ProviderErrorType.PROVIDER_CONNECTION_ERROR });
45928
45949
  }
45929
45950
  }
45930
45951
 
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}`;
45952
+ class ProviderConfiguration {
45953
+ immutableXConfig;
45954
+ baseConfig;
45955
+ constructor({ baseConfig, overrides }) {
45956
+ this.baseConfig = baseConfig;
45957
+ if (overrides) {
45958
+ this.immutableXConfig = overrides.immutableXConfig;
45959
+ }
45960
+ else {
45961
+ // TODO: remove once a sensible default is chosen
45962
+ // eslint-disable-next-line default-case
45963
+ switch (baseConfig.environment) {
45964
+ case Environment$1.SANDBOX: {
45965
+ this.immutableXConfig = coreSdk.Config.SANDBOX;
45966
+ break;
45967
+ }
45968
+ case Environment$1.PRODUCTION: {
45969
+ this.immutableXConfig = coreSdk.Config.PRODUCTION;
45970
+ break;
45971
+ }
45972
+ }
45973
+ }
45942
45974
  }
45943
45975
  }
45944
45976
 
45945
- var checkout = /*#__PURE__*/Object.freeze({
45977
+ var x = /*#__PURE__*/Object.freeze({
45946
45978
  __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; }
45979
+ GenericIMXProvider: GenericIMXProvider,
45980
+ IMXClient: IMXClient,
45981
+ IMXError: coreSdk.IMXError,
45982
+ MetaMaskIMXProvider: MetaMaskIMXProvider,
45983
+ ProviderConfiguration: ProviderConfiguration,
45984
+ imxClientCreateStarkSigner: coreSdk.createStarkSigner,
45985
+ imxClientGenerateLegacyStarkPrivateKey: coreSdk.generateLegacyStarkPrivateKey
45981
45986
  });
45982
45987
 
45983
45988
  exports.blockchainData = blockchain_data;
45984
45989
  exports.checkout = checkout;
45985
45990
  exports.config = config;
45986
- exports.immutablexClient = immutablex_client;
45987
45991
  exports.orderbook = orderbook;
45988
45992
  exports.passport = passport;
45989
- exports.provider = provider;
45993
+ exports.x = x;