@faast/tron-payments
Version:
Library to assist in processing tron payments, such as deriving addresses and sweeping funds
184 lines • 7.86 kB
JavaScript
import { NetworkType, Payport, FeeRateType, TransactionStatus } from '@faast/payments-common';
import { DelegateLogger, isNil, assertType } from '@faast/ts-common';
import TronWeb from 'tronweb';
import { toMainDenominationString, toBaseDenominationString, isValidXprv, isValidXpub, isValidAddress, isValidExtraId, isValidPrivateKey, privateKeyToAddress, toMainDenominationBigNumber, } from './helpers';
import { COIN_NAME, COIN_SYMBOL, DECIMAL_PLACES, DEFAULT_EVENT_SERVER, DEFAULT_FULL_NODE, DEFAULT_SOLIDITY_NODE, MIN_BALANCE_SUN, MIN_BALANCE_TRX, PACKAGE_NAME, } from './constants';
import { BaseTronPaymentsConfig } from './types';
import { retryIfDisconnected, toError } from './utils';
import BigNumber from 'bignumber.js';
import { pick } from 'lodash';
export class TronPaymentsUtils {
constructor(config = {}) {
this.coinSymbol = COIN_SYMBOL;
this.coinName = COIN_NAME;
this.coinDecimals = DECIMAL_PLACES;
this.isValidXprv = isValidXprv;
this.isValidXpub = isValidXpub;
this.isValidPrivateKey = isValidPrivateKey;
this.privateKeyToAddress = privateKeyToAddress;
assertType(BaseTronPaymentsConfig, config);
this.networkType = config.network || NetworkType.Mainnet;
this.logger = new DelegateLogger(config.logger, PACKAGE_NAME);
this.fullNode = config.fullNode || DEFAULT_FULL_NODE;
this.solidityNode = config.solidityNode || DEFAULT_SOLIDITY_NODE;
this.eventServer = config.eventServer || DEFAULT_EVENT_SERVER;
this.tronweb = new TronWeb(this.fullNode, this.solidityNode, this.eventServer);
}
async init() { }
async destroy() { }
isValidExtraId(extraId) {
return isValidExtraId(extraId);
}
isValidAddress(address) {
return isValidAddress(address);
}
standardizeAddress(address) {
if (!isValidAddress(address)) {
return null;
}
return address;
}
async _getPayportValidationMessage(payport) {
const { address, extraId } = payport;
if (!isValidAddress(address)) {
return 'Invalid payport address';
}
if (!isNil(extraId) && !isValidExtraId(extraId)) {
return 'Invalid payport extraId';
}
}
async getPayportValidationMessage(payport) {
try {
payport = assertType(Payport, payport, 'payport');
}
catch (e) {
return e.message;
}
return this._getPayportValidationMessage(payport);
}
async validatePayport(payport) {
payport = assertType(Payport, payport, 'payport');
const message = await this._getPayportValidationMessage(payport);
if (message) {
throw new Error(message);
}
}
async isValidPayport(payport) {
return Payport.is(payport) && !(await this._getPayportValidationMessage(payport));
}
toMainDenomination(amount) {
return toMainDenominationString(amount);
}
toBaseDenomination(amount) {
return toBaseDenominationString(amount);
}
getFeeRateRecommendation(level) {
return { feeRate: '0', feeRateType: FeeRateType.Base };
}
async _retryDced(fn) {
return retryIfDisconnected(fn, this.logger);
}
getCurrentBlockNumber() {
return this._retryDced(async () => (await this.tronweb.trx.getCurrentBlock()).block_header.raw_data.number);
}
async getAddressUtxos() {
return [];
}
async getAddressNextSequenceNumber() {
return null;
}
canSweepBalanceSun(balanceSun) {
return balanceSun > MIN_BALANCE_SUN;
}
isAddressBalanceSweepable(balanceTrx) {
return new BigNumber(balanceTrx).gt(MIN_BALANCE_TRX);
}
async getAddressBalance(address) {
try {
const balanceSun = await this._retryDced(() => this.tronweb.trx.getBalance(address));
const sweepable = this.canSweepBalanceSun(balanceSun);
const confirmedBalance = toMainDenominationBigNumber(balanceSun);
const spendableBalance = BigNumber.max(0, confirmedBalance.minus(MIN_BALANCE_TRX));
return {
confirmedBalance: confirmedBalance.toString(),
unconfirmedBalance: '0',
spendableBalance: spendableBalance.toString(),
sweepable,
requiresActivation: false,
minimumBalance: String(MIN_BALANCE_TRX),
};
}
catch (e) {
throw toError(e);
}
}
extractTxFields(tx) {
var _a, _b, _c, _d, _e;
const contractParam = (_e = (_d = (_c = (_b = (_a = tx.raw_data) === null || _a === void 0 ? void 0 : _a.contract) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.parameter) === null || _d === void 0 ? void 0 : _d.value) !== null && _e !== void 0 ? _e : null;
if (!(contractParam && typeof contractParam.amount === 'number')) {
throw new Error('Unable to get transaction');
}
const amountSun = contractParam.amount || 0;
const amountTrx = this.toMainDenomination(amountSun);
const toAddress = this.tronweb.address.fromHex(contractParam.to_address);
const fromAddress = this.tronweb.address.fromHex(contractParam.owner_address);
return {
amountTrx,
amountSun,
toAddress,
fromAddress,
};
}
async getTransactionInfo(txid) {
var _a, _b, _c, _d, _e;
try {
const [tx, txInfo, currentBlock] = await Promise.all([
this._retryDced(() => this.tronweb.trx.getTransaction(txid)),
this._retryDced(() => this.tronweb.trx.getTransactionInfo(txid)),
this._retryDced(() => this.tronweb.trx.getCurrentBlock()),
]);
const { amountTrx, fromAddress, toAddress } = this.extractTxFields(tx);
const contractRet = (_b = (_a = tx.ret) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.contractRet;
const isExecuted = contractRet === 'SUCCESS';
const block = txInfo.blockNumber || null;
const feeTrx = this.toMainDenomination(txInfo.fee || 0);
const currentBlockNumber = (_e = (_d = (_c = currentBlock.block_header) === null || _c === void 0 ? void 0 : _c.raw_data) === null || _d === void 0 ? void 0 : _d.number) !== null && _e !== void 0 ? _e : 0;
const confirmations = currentBlockNumber && block ? currentBlockNumber - block : 0;
const isConfirmed = confirmations > 0;
const confirmationTimestamp = txInfo.blockTimeStamp ? new Date(txInfo.blockTimeStamp) : null;
let status = TransactionStatus.Pending;
if (isConfirmed) {
if (!isExecuted) {
status = TransactionStatus.Failed;
}
status = TransactionStatus.Confirmed;
}
return {
id: tx.txID,
amount: amountTrx,
toAddress,
fromAddress,
toExtraId: null,
fromIndex: null,
toIndex: null,
fee: feeTrx,
sequenceNumber: null,
isExecuted,
isConfirmed,
confirmations,
confirmationId: block ? String(block) : null,
confirmationTimestamp,
status,
data: {
...tx,
...txInfo,
currentBlock: pick(currentBlock, 'block_header', 'blockID'),
},
};
}
catch (e) {
throw toError(e);
}
}
}
//# sourceMappingURL=TronPaymentsUtils.js.map