You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
173 lines
5.0 KiB
173 lines
5.0 KiB
2 years ago
|
import BigNumber from 'bignumber.js';
|
||
|
import { TRANSACTION_ENVELOPE_TYPES } from '../constants/transaction';
|
||
|
import {
|
||
|
conversionUtil,
|
||
|
multiplyCurrencies,
|
||
|
subtractCurrencies,
|
||
|
} from '../modules/conversion.utils';
|
||
|
import { isSwapsDefaultTokenSymbol } from '../modules/swaps.utils';
|
||
|
|
||
|
const TOKEN_TRANSFER_LOG_TOPIC_HASH =
|
||
|
'0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';
|
||
|
|
||
|
export const TRANSACTION_NO_CONTRACT_ERROR_KEY = 'transactionErrorNoContract';
|
||
|
|
||
|
export const TEN_SECONDS_IN_MILLISECONDS = 10_000;
|
||
|
|
||
|
export function calcGasTotal(gasLimit = '0', gasPrice = '0') {
|
||
|
return multiplyCurrencies(gasLimit, gasPrice, {
|
||
|
toNumericBase: 'hex',
|
||
|
multiplicandBase: 16,
|
||
|
multiplierBase: 16,
|
||
|
});
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Given a number and specified precision, returns that number in base 10 with a maximum of precision
|
||
|
* significant digits, but without any trailing zeros after the decimal point To be used when wishing
|
||
|
* to display only as much digits to the user as necessary
|
||
|
*
|
||
|
* @param {string | number | BigNumber} n - The number to format
|
||
|
* @param {number} precision - The maximum number of significant digits in the return value
|
||
|
* @returns {string} The number in decimal form, with <= precision significant digits and no decimal trailing zeros
|
||
|
*/
|
||
|
export function toPrecisionWithoutTrailingZeros(n, precision) {
|
||
|
return new BigNumber(n)
|
||
|
.toPrecision(precision)
|
||
|
.replace(/(\.[0-9]*[1-9])0*|(\.0*)/u, '$1');
|
||
|
}
|
||
|
|
||
|
export function calcTokenAmount(value, decimals) {
|
||
|
const multiplier = Math.pow(10, Number(decimals || 0));
|
||
|
return new BigNumber(String(value)).div(multiplier);
|
||
|
}
|
||
|
|
||
|
export function getSwapsTokensReceivedFromTxMeta(
|
||
|
tokenSymbol,
|
||
|
txMeta,
|
||
|
tokenAddress,
|
||
|
accountAddress,
|
||
|
tokenDecimals,
|
||
|
approvalTxMeta,
|
||
|
chainId,
|
||
|
) {
|
||
|
const txReceipt = txMeta?.txReceipt;
|
||
|
const networkAndAccountSupports1559 =
|
||
|
txMeta?.txReceipt?.type === TRANSACTION_ENVELOPE_TYPES.FEE_MARKET;
|
||
|
if (isSwapsDefaultTokenSymbol(tokenSymbol, chainId)) {
|
||
|
if (
|
||
|
!txReceipt ||
|
||
|
!txMeta ||
|
||
|
!txMeta.postTxBalance ||
|
||
|
!txMeta.preTxBalance
|
||
|
) {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
if (txMeta.swapMetaData && txMeta.preTxBalance === txMeta.postTxBalance) {
|
||
|
// If preTxBalance and postTxBalance are equal, postTxBalance hasn't been updated on time
|
||
|
// because of the RPC provider delay, so we return an estimated receiving amount instead.
|
||
|
return txMeta.swapMetaData.token_to_amount;
|
||
|
}
|
||
|
|
||
|
let approvalTxGasCost = '0x0';
|
||
|
if (approvalTxMeta && approvalTxMeta.txReceipt) {
|
||
|
approvalTxGasCost = calcGasTotal(
|
||
|
approvalTxMeta.txReceipt.gasUsed,
|
||
|
networkAndAccountSupports1559
|
||
|
? approvalTxMeta.txReceipt.effectiveGasPrice // Base fee + priority fee.
|
||
|
: approvalTxMeta.txParams.gasPrice,
|
||
|
);
|
||
|
}
|
||
|
|
||
|
const gasCost = calcGasTotal(
|
||
|
txReceipt.gasUsed,
|
||
|
networkAndAccountSupports1559
|
||
|
? txReceipt.effectiveGasPrice
|
||
|
: txMeta.txParams.gasPrice,
|
||
|
);
|
||
|
const totalGasCost = new BigNumber(gasCost, 16)
|
||
|
.plus(approvalTxGasCost, 16)
|
||
|
.toString(16);
|
||
|
|
||
|
const preTxBalanceLessGasCost = subtractCurrencies(
|
||
|
txMeta.preTxBalance,
|
||
|
totalGasCost,
|
||
|
{
|
||
|
aBase: 16,
|
||
|
bBase: 16,
|
||
|
toNumericBase: 'hex',
|
||
|
},
|
||
|
);
|
||
|
|
||
|
const ethReceived = subtractCurrencies(
|
||
|
txMeta.postTxBalance,
|
||
|
preTxBalanceLessGasCost,
|
||
|
{
|
||
|
aBase: 16,
|
||
|
bBase: 16,
|
||
|
fromDenomination: 'WEI',
|
||
|
toDenomination: 'ETH',
|
||
|
toNumericBase: 'dec',
|
||
|
numberOfDecimals: 6,
|
||
|
},
|
||
|
);
|
||
|
return ethReceived;
|
||
|
}
|
||
|
const txReceiptLogs = txReceipt?.logs;
|
||
|
if (txReceiptLogs && txReceipt?.status !== '0x0') {
|
||
|
const tokenTransferLog = txReceiptLogs.find((txReceiptLog) => {
|
||
|
const isTokenTransfer =
|
||
|
txReceiptLog.topics &&
|
||
|
txReceiptLog.topics[0] === TOKEN_TRANSFER_LOG_TOPIC_HASH;
|
||
|
const isTransferFromGivenToken = txReceiptLog.address === tokenAddress;
|
||
|
const isTransferFromGivenAddress =
|
||
|
txReceiptLog.topics &&
|
||
|
txReceiptLog.topics[2] &&
|
||
|
txReceiptLog.topics[2].match(accountAddress.slice(2));
|
||
|
return (
|
||
|
isTokenTransfer &&
|
||
|
isTransferFromGivenToken &&
|
||
|
isTransferFromGivenAddress
|
||
|
);
|
||
|
});
|
||
|
return tokenTransferLog
|
||
|
? toPrecisionWithoutTrailingZeros(
|
||
|
calcTokenAmount(tokenTransferLog.data, tokenDecimals).toString(10),
|
||
|
6,
|
||
|
)
|
||
|
: '';
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
export const TRANSACTION_ENVELOPE_TYPE_NAMES = {
|
||
|
FEE_MARKET: 'fee-market',
|
||
|
LEGACY: 'legacy',
|
||
|
};
|
||
|
|
||
|
export function hexWEIToDecGWEI(decGWEI) {
|
||
|
return conversionUtil(decGWEI, {
|
||
|
fromNumericBase: 'hex',
|
||
|
toNumericBase: 'dec',
|
||
|
fromDenomination: 'WEI',
|
||
|
toDenomination: 'GWEI',
|
||
|
});
|
||
|
}
|
||
|
|
||
|
export function decimalToHex(decimal) {
|
||
|
return conversionUtil(decimal, {
|
||
|
fromNumericBase: 'dec',
|
||
|
toNumericBase: 'hex',
|
||
|
});
|
||
|
}
|
||
|
|
||
|
export function hexWEIToDecETH(hexWEI) {
|
||
|
return conversionUtil(hexWEI, {
|
||
|
fromNumericBase: 'hex',
|
||
|
toNumericBase: 'dec',
|
||
|
fromDenomination: 'WEI',
|
||
|
toDenomination: 'ETH',
|
||
|
});
|
||
|
}
|