UNPKG

@ledgerhq/coin-tron

Version:
187 lines (165 loc) 5.91 kB
import { log } from "@ledgerhq/logs"; import BigNumber from "bignumber.js"; import bs58check from "bs58check"; import get from "lodash/get"; import { TrongridExtraTxInfo, TrongridTxInfo, TrongridTxType } from "../types"; import { TransactionTronAPI, Trc20API } from "./types"; export const decode58Check = (base58: string): string => Buffer.from(bs58check.decode(base58)).toString("hex"); export const encode58Check = (hex: string): string => bs58check.encode(Buffer.from(hex, "hex")); export const formatTrongridTrc20TxResponse = (tx: Trc20API): TrongridTxInfo | null | undefined => { try { const { from, to, block_timestamp, detail, value, transaction_id, token_info, type } = tx; const txID = transaction_id; let txType: TrongridTxType; let tokenId: string | undefined; const fee = tx.detail.ret[0].fee || undefined; const bnFee = new BigNumber(fee || 0); let formattedValue; // token_info.address is missing for unindexed contracts (e.g. LP/DEX pool tokens not in TronGrid registry) // fall back to the contract_address from the raw transaction, which is always present const contractAddressHex = detail.raw_data?.contract?.[0]?.parameter?.value?.contract_address; const tokenAddress = token_info.address ?? (contractAddressHex ? encode58Check(contractAddressHex) : undefined); switch (type) { case "Approval": txType = "ContractApproval"; formattedValue = bnFee; break; default: txType = "TriggerSmartContract"; tokenId = tokenAddress; formattedValue = value ? new BigNumber(value) : new BigNumber(0); break; } const date = new Date(block_timestamp); const blockHeight = detail ? detail.blockNumber : undefined; const ownerAddressHex = detail.raw_data?.contract?.[0]?.parameter?.value?.owner_address; const feesPayer = ownerAddressHex ? encode58Check(ownerAddressHex) : from; return { txID, date, type: txType, tokenId: tokenId, tokenAddress, tokenType: "trc20", from, to, blockHeight, value: formattedValue, fee: bnFee, hasFailed: false, // trc20 txs are succeeded if returned by trongrid, feesPayer, }; } catch (e) { log("tron-error", `could not parse transaction ${tx}`); throw e; } }; export const formatTrongridTxResponse = async ( tx: TransactionTronAPI, getValidatorName: (address: string) => Promise<string | null | undefined>, ): Promise<TrongridTxInfo | null | undefined> => { try { const { txID, block_timestamp, blockNumber, unfreeze_amount, withdraw_amount } = tx; const date = new Date(block_timestamp); const type = tx.raw_data.contract[0].type; const { amount, asset_name, owner_address, to_address, contract_address, quant, frozen_balance, votes, unfreeze_balance, balance, receiver_address, } = tx.raw_data.contract[0].parameter.value; const hasFailed = get(tx, "ret[0].contractRet", "SUCCESS") !== "SUCCESS"; const tokenId = type === "TransferAssetContract" ? asset_name : type === "TriggerSmartContract" && contract_address ? encode58Check(contract_address) : undefined; const from = encode58Check(owner_address); const to = to_address ? encode58Check(to_address) : undefined; const getValue = (): BigNumber => { switch (type) { case "WithdrawBalanceContract": return new BigNumber(withdraw_amount || 0); case "ExchangeTransactionContract": return new BigNumber(quant || 0); default: return amount ? new BigNumber(amount) : new BigNumber(0); } }; const value = getValue(); const fee = get(tx, "ret[0].fee", undefined); const blockHeight = blockNumber; const isTrc20 = type === "TriggerSmartContract" && contract_address; const isTrc10 = type === "TransferAssetContract"; const tokenType = isTrc10 ? "trc10" : isTrc20 ? "trc20" : undefined; const txInfo: TrongridTxInfo = { txID, date, type, tokenId, // TRX native is TransferContract, TRC20 uses TriggerSmartContract tokenType, tokenAddress: isTrc20 ? encode58Check(contract_address) : undefined, from, to, value: !value.isNaN() ? value : new BigNumber(0), fee: new BigNumber(fee || 0), blockHeight, hasFailed, feesPayer: from, }; const getExtra = async (): Promise<TrongridExtraTxInfo | null | undefined> => { switch (type) { case "VoteWitnessContract": return { votes: votes && (await Promise.all( votes.map(async v => ({ name: await getValidatorName(encode58Check(v.vote_address)), address: encode58Check(v.vote_address), voteCount: v.vote_count, })), )), }; case "FreezeBalanceContract": case "FreezeBalanceV2Contract": return { frozenAmount: new BigNumber(frozen_balance!), }; case "UnfreezeBalanceV2Contract": return { unfreezeAmount: new BigNumber(unfreeze_balance!), }; case "UnDelegateResourceContract": return { unDelegatedAmount: new BigNumber(balance!), receiverAddress: encode58Check(receiver_address!), }; case "UnfreezeBalanceContract": return { unfreezeAmount: new BigNumber(unfreeze_amount || 0), }; default: return undefined; } }; const extra = await getExtra(); if (extra) { txInfo.extra = extra; } return txInfo; } catch { log("tron-error", "could not parse transaction", tx); return undefined; } };