@tristeroresearch/mach-sdk
Version:
A TypeScript SDK for integrating with Mach's API.
307 lines (306 loc) • 11.6 kB
JavaScript
/**
* A configuration file for the SDK
* Loads the config from the Mach API
* The config contains the available tokens, networks, and swap contracts for the Mach Platform
* Uses a singleton pattern to ensure that the config is only loaded once
* Provides getters to access the config variables
* Provides a setter to update the config object and the wallet clients
* @module config
*/
import { getChainName, getGasToken } from './configs/chainInfo';
import { getChainId } from './configs/chainInfo';
import { WETH_ADDRESSES } from './configs/tokenAddresses';
import { ConfigLoadingStatus } from './enums';
import { createWalletClients } from './utils/createWalletClients.util';
import { apiGetConfig } from './api';
import { BACKEND_API_URL, TESTNET_BACKEND_API_URL } from './configs/env';
import { DEFAULT_INTEGRATOR, DEFAULT_MAX_FEE_PER_GAS, DEFAULT_MAX_PRIORITY_FEE_PER_GAS, DEFAULT_GAS_LIMIT_MULTIPLIER, DEFAULT_GAS_FEE_MULTIPLIER, } from './configs/defaults';
import { recreateMachExchangeApi } from './libs/axios';
let _config = {
integrator: '',
apiUrl: '',
origin: '',
chains: [],
preloadChains: false,
debug: false,
resolverPaused: false,
loading: ConfigLoadingStatus.Loading,
availableTokens: [],
availableNetworks: {},
swapContracts: {},
publicClient: null,
account: null,
key: null,
priorityFeePerGas: BigInt(0),
feePerGas: BigInt(0),
gasLimitMultiplier: BigInt(0),
machGasRecommendationOverride: false,
gasLimit: BigInt(0),
gasFeeMultiplier: BigInt(0),
isTestnet: false,
};
export const setConfig = (newConfig) => {
_config = {
..._config,
...newConfig,
};
};
/**
* Loads the config from the Mach API
* The config contains the available tokens, networks, and swap contracts for the Mach Platform
* Uses a singleton pattern to ensure that the config is only loaded once
* Provides getters to access the config variables
* Provides a setter to update the config object and the wallet clients
* @returns {Object} An object with methods to get and set the config and wallet clients
*/
export const config = (async () => {
const _config = {
integrator: '',
apiUrl: '',
origin: '',
chains: [],
preloadChains: true,
debug: false,
resolverPaused: false,
loading: ConfigLoadingStatus.Loading,
availableTokens: [],
availableNetworks: {},
swapContracts: {},
publicClient: null,
account: null,
key: null,
priorityFeePerGas: BigInt(0),
feePerGas: BigInt(0),
gasLimitMultiplier: BigInt(0),
machGasRecommendationOverride: false,
gasLimit: BigInt(0),
gasFeeMultiplier: BigInt(0),
isTestnet: false,
};
const _isLoaded = false;
//Set priorityFeePerGas, feePerGas, and gasLimitMultiplier to default values
function initializeConfig() {
_config.integrator = DEFAULT_INTEGRATOR;
_config.apiUrl = BACKEND_API_URL;
_config.origin = '';
_config.priorityFeePerGas = DEFAULT_MAX_PRIORITY_FEE_PER_GAS;
_config.feePerGas = DEFAULT_MAX_FEE_PER_GAS;
_config.gasLimitMultiplier = DEFAULT_GAS_LIMIT_MULTIPLIER;
_config.gasFeeMultiplier = DEFAULT_GAS_FEE_MULTIPLIER;
}
// Load the config from the Mach API
async function loadConfig(force = false) {
// If the config is already loaded and not forcing reload, return
if (_isLoaded && !force)
return;
// Fetch the config from the Mach API
// If the config is not available, an error will be thrown in the apiGetConfig function
// Since the config is critical to the SDK, we want to fail fast if it's not available
const configData = await apiGetConfig();
const { deployments } = configData;
// Initialize the availableTokens, availableNetworks, and swapContracts objects
const availableTokens = [];
const availableNetworks = {};
const swapContracts = { cctp: {}, optimistic: {} };
// Iterate over the networks in the deployments object
Object.keys(deployments).forEach((networkKey) => {
const { abbreviation, assets = {}, chain_id, cctp_id, lz_cid, contracts = {}, } = deployments[networkKey];
// Add the network to the availableNetworks object
availableNetworks[chain_id] = {
name: getChainName(networkKey),
gasToken: getGasToken(networkKey),
abbreviation,
icon: `/assets/network/${networkKey}.png`,
cctp_id,
lz_id: lz_cid,
};
// Add the network to the availableNetworks object
availableNetworks[networkKey] = {
name: getChainName(networkKey),
gasToken: getGasToken(networkKey),
abbreviation,
icon: `/assets/network/${networkKey}.png`,
cctp_id,
lz_id: lz_cid,
};
// If the network has a WETH address, add it to the availableTokens object
if (WETH_ADDRESSES[getChainId(networkKey)]) {
availableTokens.push({
symbol: `W${getGasToken(networkKey)}`,
logoURI: `/assets/token/w${getGasToken(networkKey).toLowerCase()}.png`,
name: `W${getGasToken(networkKey)}`,
unit: `w${getGasToken(networkKey).toLowerCase()}`,
chainId: chain_id,
zeroChainID: lz_cid,
address: WETH_ADDRESSES[getChainId(networkKey)],
decimals: 18,
native: false,
wrapped: true,
});
}
// Iterate over the assets in the deployments object, and add them to the availableTokens object
for (const [key, value] of Object.entries(assets)) {
availableTokens.push({
symbol: key,
logoURI: `/assets/token/${key?.toLowerCase()}.png`,
name: key,
unit: key?.toLowerCase(),
chainId: chain_id,
zeroChainID: lz_cid,
address: value.address,
decimals: value.decimals,
native: false,
wrapped: value.wrapped,
});
}
// Iterate over the contracts in the deployments object, and add them to the swapContracts object
for (const [type, address] of Object.entries(contracts)) {
// If the type is not in the swapContracts object, initialize it
if (!swapContracts[type])
swapContracts[type] = {};
// Add the contract address to the swapContracts object
swapContracts[type][chain_id] = address;
}
});
//Assign the loaded config variables to the _config object
Object.assign(_config, {
availableTokens,
availableNetworks,
swapContracts,
});
}
initializeConfig();
// Load the config from the Mach API
await loadConfig();
let _loading;
return {
set loading(loading) {
_loading = loading;
},
get() {
return _config;
},
getWalletKey() {
return _config.account.key;
},
getWalletAddress() {
return _config.account.address;
},
getPublicClient() {
return _config.publicClient;
},
getTokens() {
return _config.availableTokens;
},
getNetworks() {
return _config.availableNetworks;
},
getSwapContracts() {
return _config.swapContracts;
},
async setWalletClients(privateKey, srcChain) {
const clients = await createWalletClients(srcChain, privateKey);
const publicClient = clients.publicClient;
const account = clients.account;
// Update the _config object with publicClient and account
_config.publicClient = publicClient;
_config.account = account;
},
updateConfigWithClients(key, publicClient, account) {
_config.key = key;
_config.publicClient = publicClient;
_config.account = account;
},
getConfig() {
return _config;
},
getIntegrator() {
return _config.integrator;
},
setIntegrator(integrator) {
_config.integrator = integrator;
},
getApiUrl() {
return _config.apiUrl;
},
async setApiUrl(apiUrl) {
_config.apiUrl = apiUrl;
// Recreate the axios instance with the new URL
recreateMachExchangeApi(apiUrl);
// Reload the config when API URL changes, forcing a reload
await loadConfig(true);
},
getPriorityFeePerGas() {
return _config.priorityFeePerGas;
},
setPriorityFeePerGas(priorityFeePerGas) {
_config.priorityFeePerGas = priorityFeePerGas;
},
getPriorityFee() {
return _config.priorityFeePerGas;
},
setPriorityFee(priorityFee) {
_config.priorityFeePerGas = priorityFee;
},
getFeePerGas() {
return _config.feePerGas;
},
setFeePerGas(feePerGas) {
_config.feePerGas = feePerGas;
},
getGasFee() {
return _config.feePerGas;
},
getGasLimit() {
return _config.gasLimit;
},
setGasLimit(gasLimit) {
_config.gasLimit = gasLimit;
},
setGasFee(gasFee) {
_config.feePerGas = gasFee;
},
getGasLimitMultiplier() {
return _config.gasLimitMultiplier;
},
setGasLimitMultiplier(gasLimitMultiplier) {
_config.gasLimitMultiplier = gasLimitMultiplier;
},
getGasRecommendationOverride() {
return _config.machGasRecommendationOverride;
},
setGasRecommendationOverride(gasRecommendationOverride) {
_config.machGasRecommendationOverride = gasRecommendationOverride;
},
getTestnetMode() {
return _config.isTestnet;
},
getMainnetMode() {
return !_config.isTestnet;
},
async setTestnetMode(isTestnet) {
_config.isTestnet = isTestnet;
// Automatically set the appropriate API URL based on testnet mode
const apiUrl = isTestnet ? TESTNET_BACKEND_API_URL : BACKEND_API_URL;
await this.setApiUrl(apiUrl);
},
async setMainnetMode(isMainnet) {
_config.isTestnet = !isMainnet;
// Automatically set the appropriate API URL based on mainnet mode
const apiUrl = isMainnet ? BACKEND_API_URL : TESTNET_BACKEND_API_URL;
await this.setApiUrl(apiUrl);
},
getGasFeeMultiplier() {
return _config.gasFeeMultiplier;
},
setGasFeeMultiplier(gasFeeMultiplier) {
_config.gasFeeMultiplier = gasFeeMultiplier;
},
getOrigin() {
return _config.origin;
},
setOrigin(origin) {
_config.origin = origin;
},
};
})();