UNPKG

@broxus/js-core

Version:

MobX-based JavaScript Core library

296 lines (295 loc) 14 kB
import { debug, groupCollapsed, groupEnd, sliceString } from '@broxus/js-utils'; import { inheritTextStyle, successLabelStyle, successTextStyle, warningLabelStyle } from '../../console'; import { DEFAULT_NATIVE_CURRENCY_DECIMALS } from '../../constants'; import { dexAccountContract } from '../../models/dex-account/contracts'; import { getFullContractState, getRandomInt, resolveTvmAddress, toInt } from '../../utils'; import { getScanLink } from '../../utils/get-scan-link'; export class DexAccountUtils { /** * Sends a delayed message to add a pair to the Account * @param {ProviderRpcClient} provider * @param {Address | string} dexAccountAddress * @param {DexAccountAddPairAbiParams} params * @param {Pick<SendInternalParams, 'from'> & Omit<Partial<SendInternalParams>, 'from'>} args * @returns {Promise<DelayedMessageExecution>} */ static async addPair(provider, dexAccountAddress, params, args) { return dexAccountContract(provider, dexAccountAddress) .methods.addPair({ left_root: resolveTvmAddress(params.leftRootAddress), right_root: resolveTvmAddress(params.rightRootAddress), }) .sendDelayed({ amount: toInt(3, DEFAULT_NATIVE_CURRENCY_DECIMALS), bounce: false, ...args, }); } /** * Sends a delayed message to add a pool to the Account * @param {ProviderRpcClient} provider * @param {Address | string} dexAccountAddress * @param {DexAccountAddPoolAbiParams} params * @param {Pick<SendInternalParams, 'from'> & Omit<Partial<SendInternalParams>, 'from'>} args * @returns {Promise<DelayedMessageExecution>} */ static async addPool(provider, dexAccountAddress, params, args) { return dexAccountContract(provider, dexAccountAddress) .methods.addPool({ _roots: params.roots.map(resolveTvmAddress), }) .sendDelayed({ amount: toInt(3, DEFAULT_NATIVE_CURRENCY_DECIMALS), bounce: false, ...args, }); } /** * Sends a delayed message to deposit liquidity into a pair via the Account * @param {ProviderRpcClient} provider * @param {Address | string} dexAccountAddress * @param {DexAccountDepositLiquidityAbiParams} params * @param {Partial<SendInternalParams>} [args] * @returns {Promise<DelayedMessageExecution>} */ static async depositLiquidity(provider, dexAccountAddress, params, args) { return dexAccountContract(provider, dexAccountAddress) .methods.depositLiquidity({ auto_change: params.autoChange, call_id: params.callId ?? getRandomInt(), expected_lp_root: resolveTvmAddress(params.expectedLpAddress), left_amount: params.leftAmount, left_root: resolveTvmAddress(params.leftRootAddress), right_amount: params.rightAmount, right_root: resolveTvmAddress(params.rightRootAddress), send_gas_to: resolveTvmAddress(params.sendGasTo), }) .sendDelayed({ amount: toInt(2.6, DEFAULT_NATIVE_CURRENCY_DECIMALS), bounce: false, from: resolveTvmAddress(params.sendGasTo), ...args, }); } /** * Sends a delayed message to deposit liquidity into a stable pool via the Account * @param {ProviderRpcClient} provider * @param {Address | string} dexAccountAddress * @param {DexAccountDepositLiquidityAbiParams} params * @param {Partial<SendInternalParams>} [args] * @returns {Promise<DelayedMessageExecution>} */ static async depositLiquidityV2(provider, dexAccountAddress, params, args) { return dexAccountContract(provider, dexAccountAddress) .methods.depositLiquidityV2({ _autoChange: true, _callId: params.callId ?? getRandomInt(), _expected: { ...params.expected, root: resolveTvmAddress(params.expected.root), }, _operations: params.operations.map(operation => ({ ...operation, root: resolveTvmAddress(operation.root), })), _referrer: resolveTvmAddress(params.referrer), _remainingGasTo: resolveTvmAddress(params.remainingGasTo), }) .sendDelayed({ amount: toInt(2.6, DEFAULT_NATIVE_CURRENCY_DECIMALS), bounce: false, from: resolveTvmAddress(params.remainingGasTo), ...args, }); } /** * Sends a delayed message to withdraw token from the Account * @param {ProviderRpcClient} provider * @param {Address | string} dexAccountAddress * @param {DexAccountWithdrawAbiParams} params * @param {Partial<SendInternalParams>} [args] * @returns {Promise<DelayedMessageExecution>} */ static async withdraw(provider, dexAccountAddress, params, args) { return dexAccountContract(provider, dexAccountAddress) .methods.withdraw({ amount: params.amount, call_id: params.callId ?? getRandomInt(), deploy_wallet_grams: params.deployWalletGrams ?? toInt(0.1, DEFAULT_NATIVE_CURRENCY_DECIMALS), recipient_address: resolveTvmAddress(params.recipientAddress), send_gas_to: resolveTvmAddress(params.sendGasTo), token_root: resolveTvmAddress(params.tokenAddress), }) .sendDelayed({ amount: toInt(2.1, DEFAULT_NATIVE_CURRENCY_DECIMALS), bounce: false, from: resolveTvmAddress(params.sendGasTo), ...args, }); } /** * Sends a delayed message to withdraw liquidity (LP tokens) from the Account * @param {ProviderRpcClient} provider * @param {Address | string} dexAccountAddress * @param {DexAccountWithdrawLiquidityAbiParams} params * @param {Partial<SendInternalParams>} [args] * @returns {Promise<DelayedMessageExecution>} * @deprecated */ static async withdrawLiquidity(provider, dexAccountAddress, params, args) { return dexAccountContract(provider, dexAccountAddress) .methods.withdrawLiquidity({ call_id: params.callId ?? getRandomInt(), left_root: resolveTvmAddress(params.leftRootAddress), lp_amount: params.amount, lp_root: resolveTvmAddress(params.lpRootAddress), right_root: resolveTvmAddress(params.rightRootAddress), send_gas_to: resolveTvmAddress(params.sendGasTo), }) .sendDelayed({ amount: toInt(2.7, DEFAULT_NATIVE_CURRENCY_DECIMALS), bounce: false, from: resolveTvmAddress(params.sendGasTo), ...args, }); } /** * Returns DEX Account owner address * @param {ProviderRpcClient} connection * @param {Address | string} dexAccountAddress * @param {FullContractState} cachedState * @returns {Promise<Address>} */ static async getOwner(connection, dexAccountAddress, cachedState) { const state = cachedState ?? await getFullContractState(connection, dexAccountAddress); const result = await dexAccountContract(connection, dexAccountAddress) .methods.getOwner({ answerId: 0 }) .call({ cachedState: state, responsible: true }); return result.value0; } /** * Returns token balance by the given DEX Account and token address addresses * @param {ProviderRpcClient} connection * @param {Address | string} dexAccountAddress * @param {Address | string} tokenAddress * @param {FullContractState | undefined} [cachedState] * @returns {Promise<string | undefined>} */ static async getBalance(connection, dexAccountAddress, tokenAddress, cachedState) { const state = cachedState ?? await getFullContractState(connection, dexAccountAddress); const result = await dexAccountContract(connection, dexAccountAddress) .methods.getWalletData({ answerId: 0, token_root: resolveTvmAddress(tokenAddress), }) .call({ cachedState: state, responsible: true }); return result.balance; } /** * Returns map of a user tokens balances in a DEX account * @param {ProviderRpcClient} connection * @param {Address | string} dexAccountAddress * @param {FullContractState} [cachedState] * @returns {Promise<Map<string, string>>} */ static async getBalances(connection, dexAccountAddress, cachedState) { const state = cachedState ?? await getFullContractState(connection, dexAccountAddress); const balances = await dexAccountContract(connection, dexAccountAddress) .methods.getBalances({}) .call({ cachedState: state }) .then(result => result.value0.reduce((acc, [address, balance]) => acc.set(address.toString().toLowerCase(), balance.toString()), new Map())); if (process.env.NODE_ENV !== 'production') { const entries = Array.from(balances.entries()); if (entries.length > 0) { const providerState = await connection.getProviderState(); groupCollapsed(`%c${this.prototype.constructor.name}%c Balances has been synced for the account [%c${sliceString(dexAccountAddress.toString())}%c]`, successLabelStyle, inheritTextStyle, successTextStyle, inheritTextStyle); entries.forEach(([token, balance], idx) => { if (idx > 0) { debug('============'); } const link = getScanLink(token, providerState.networkId.toString()); debug(`Token address: %c${sliceString(token)}%c ${link}`, successTextStyle, inheritTextStyle); debug(`Balance: %c${balance}`, successTextStyle); }); groupEnd(); } else { debug(`%c${this.prototype.constructor.name}%c Wallets not found for checks the balances`, warningLabelStyle, inheritTextStyle); } } return balances; } /** * * @param {ProviderRpcClient} connection * @param {Address | string} dexAccountAddress * @param {FullContractState} [cachedState] * @returns Promise<string> */ static async getVersion(connection, dexAccountAddress, cachedState) { const state = cachedState ?? await getFullContractState(connection, dexAccountAddress); const result = await dexAccountContract(connection, dexAccountAddress) .methods.getVersion({ answerId: 0 }) .call({ cachedState: state, responsible: true }); return result.value0; } /** * Returns token wallet by the given DEX Account and token address addresses * @param {ProviderRpcClient} connection * @param {Address | string} dexAccountAddress * @param {Address | string} tokenAddress * @param {FullContractState | undefined} [cachedState] * @returns Promise<Address> */ static async getWallet(connection, dexAccountAddress, tokenAddress, cachedState) { const state = cachedState ?? await getFullContractState(connection, dexAccountAddress); const result = await dexAccountContract(connection, dexAccountAddress) .methods.getWalletData({ answerId: 0, token_root: resolveTvmAddress(tokenAddress), }) .call({ cachedState: state, responsible: true }); return result.wallet; } /** * * @param {ProviderRpcClient} connection * @param {Address | string} dexAccountAddress * @param {FullContractState} [cachedState] * @returns {Promise<Map<string, Address>>} */ static async getWallets(connection, dexAccountAddress, cachedState) { const state = cachedState ?? await getFullContractState(connection, dexAccountAddress); const wallets = await dexAccountContract(connection, dexAccountAddress) .methods.getWallets({}) .call({ cachedState: state }) .then(result => result.value0.reduce((acc, [tokenAddress, walletAddress]) => acc.set(tokenAddress.toString().toLowerCase(), walletAddress), new Map())); if (process.env.NODE_ENV !== 'production') { const entries = Array.from(wallets.entries()); if (entries.length > 0) { groupCollapsed(`%c${this.prototype.constructor.name}%c Wallets has been synced for the account [%c${sliceString(dexAccountAddress.toString())}%c]`, successLabelStyle, inheritTextStyle, successTextStyle, inheritTextStyle); entries.forEach(([token, wallet], idx) => { if (idx > 0) { debug('============'); } debug(`Token address: %c${sliceString(token)}%c ${getScanLink(token)}`, successTextStyle, inheritTextStyle); debug(`Wallet address: %c${sliceString(wallet.toString())}%c ${getScanLink(wallet.toString())}`, successTextStyle, inheritTextStyle); }); groupEnd(); } else { debug(`%c${this.prototype.constructor.name}%c Wallets not found`, warningLabelStyle, inheritTextStyle); } } return wallets; } static decodeEvent(connection, dexAccountAddress, args) { return dexAccountContract(connection, dexAccountAddress).decodeEvent(args); } static decodeTransaction(connection, dexAccountAddress, args) { return dexAccountContract(connection, dexAccountAddress).decodeTransaction(args); } static decodeTransactionEvents(connection, dexAccountAddress, transaction) { return dexAccountContract(connection, dexAccountAddress).decodeTransactionEvents({ transaction }); } }