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