@ledgerhq/coin-tron
Version:
Ledger Tron Coin integration
183 lines • 7 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getBlockInfo = getBlockInfo;
exports.getBlock = getBlock;
const logs_1 = require("@ledgerhq/logs");
const bignumber_js_1 = __importDefault(require("bignumber.js"));
const network_1 = require("../network");
const format_1 = require("../network/format");
const trongrid_adapters_1 = require("../network/trongrid/trongrid-adapters");
const utils_1 = require("../network/utils");
async function getBlockInfo(height) {
if (!Number.isSafeInteger(height) || height <= 0) {
throw new Error(`Invalid block height: ${height}`);
}
const block = await (0, network_1.getBlock)(height);
return {
height: block.height,
hash: block.hash,
time: block.time ?? new Date(0),
};
}
async function getBlock(height) {
if (!Number.isSafeInteger(height) || height <= 0) {
throw new Error(`Invalid block height: ${height}`);
}
const [data, txInfos] = await Promise.all([
(0, network_1.getBlockWithTransactions)(height),
(0, network_1.getTransactionInfoByBlockNum)(height).catch(error => {
(0, logs_1.log)("tron/getBlock", "Failed to fetch transaction info, falling back to ret fees", {
height,
error,
});
return [];
}),
]);
const header = data.block_header.raw_data;
const blockTimestamp = header.timestamp ?? 0;
const info = {
height: header.number ?? height,
hash: data.blockID,
time: blockTimestamp ? new Date(blockTimestamp) : new Date(0),
};
if (header.parentHash && info.height > 1) {
info.parent = { height: info.height - 1, hash: header.parentHash };
}
const rawTxs = data.transactions ?? [];
const txInfoById = buildTxInfoMap(txInfos);
const transactions = rawTxs
.map(tx => toBlockTransaction(tx, blockTimestamp, info.height, txInfoById))
.filter((tx) => tx !== null);
return { info, transactions };
}
function buildTxInfoMap(txInfos) {
return new Map(txInfos.map(tx => [tx.id, tx]));
}
function toBlockTransaction(tx, blockTimestamp, blockHeight, txInfoById) {
const txInfo = formatBlockTransaction(tx, blockTimestamp, blockHeight);
if (!txInfo)
return null;
const txDetail = txInfoById.get(tx.txID);
const fee = txDetail?.fee ?? tx.ret?.[0]?.fee ?? 0;
return {
hash: txInfo.txID,
failed: txInfo.hasFailed,
fees: BigInt(fee),
feesPayer: txInfo.from,
operations: txInfo.hasFailed ? [] : toBlockOperations(txInfo),
};
}
function formatBlockTransaction(tx, blockTimestamp, blockHeight) {
try {
const contract = tx.raw_data.contract[0];
if (!contract)
return null;
const type = contract.type;
const params = contract.parameter.value;
const ownerAddress = params.owner_address;
if (!ownerAddress)
return null;
const from = (0, format_1.encode58Check)(ownerAddress);
const contractRet = tx.ret?.[0]?.contractRet ?? "SUCCESS";
const hasFailed = contractRet !== "SUCCESS";
const isTrc20 = type === "TriggerSmartContract" && params.contract_address;
const isTrc10 = type === "TransferAssetContract";
const tokenType = isTrc10 ? "trc10" : isTrc20 ? "trc20" : undefined;
let to;
let value;
if (isTrc20 && params.data) {
const decoded = (0, utils_1.abiDecodeTrc20Transfer)(params.data);
if (decoded) {
to = (0, format_1.encode58Check)(decoded.to);
value = decoded.amount;
}
else {
value = new bignumber_js_1.default(0);
}
}
else {
to = params.to_address ? (0, format_1.encode58Check)(params.to_address) : undefined;
value = params.amount ? new bignumber_js_1.default(params.amount) : new bignumber_js_1.default(0);
}
const tokenId = isTrc10
? decodeHexAssetName(params.asset_name)
: isTrc20 && params.contract_address
? (0, format_1.encode58Check)(params.contract_address)
: undefined;
return {
txID: tx.txID,
date: new Date(blockTimestamp),
type,
tokenId,
tokenType,
tokenAddress: isTrc20 && params.contract_address ? (0, format_1.encode58Check)(params.contract_address) : undefined,
from,
to,
value,
blockHeight,
hasFailed,
};
}
catch (error) {
(0, logs_1.log)("tron/getBlock", "formatBlockTransaction error", {
txId: tx.txID,
error,
});
return null;
}
}
function toBlockOperations(txInfo) {
if (isTransfer(txInfo) && txInfo.to && txInfo.value && !txInfo.value.isZero()) {
const asset = (0, trongrid_adapters_1.inferAssetInfo)(txInfo);
const value = txInfo.value;
if (value.isNaN() || !value.isFinite()) {
return [{ type: "other", operationType: "NONE", contractType: txInfo.type }];
}
const amount = BigInt(value.integerValue().toFixed(0));
return [
{ type: "transfer", address: txInfo.from, peer: txInfo.to, asset, amount: -amount },
{ type: "transfer", address: txInfo.to, peer: txInfo.from, asset, amount },
];
}
const operationType = getOperationType(txInfo.type);
return [{ type: "other", operationType: operationType, contractType: txInfo.type }];
}
function isTransfer(txInfo) {
return (txInfo.type === "TransferContract" ||
txInfo.type === "TransferAssetContract" ||
(txInfo.type === "TriggerSmartContract" && txInfo.tokenType === "trc20"));
}
function getOperationType(contractType) {
switch (contractType) {
case "ContractApproval":
return "APPROVE";
case "ExchangeTransactionContract":
return "OUT";
case "VoteWitnessContract":
return "VOTE";
case "WithdrawBalanceContract":
return "REWARD";
case "FreezeBalanceContract":
case "FreezeBalanceV2Contract":
return "FREEZE";
case "UnfreezeBalanceV2Contract":
return "UNFREEZE";
case "WithdrawExpireUnfreezeContract":
return "WITHDRAW_EXPIRE_UNFREEZE";
case "UnDelegateResourceContract":
return "UNDELEGATE_RESOURCE";
case "UnfreezeBalanceContract":
return "LEGACY_UNFREEZE";
default:
return "NONE";
}
}
function decodeHexAssetName(hexAssetName) {
if (!hexAssetName)
return undefined;
return Buffer.from(hexAssetName, "hex").toString("utf8");
}
//# sourceMappingURL=getBlock.js.map