@broxus/js-core
Version:
MobX-based JavaScript Core library
296 lines (295 loc) • 14 kB
JavaScript
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 });
}
}