@ledgerhq/coin-hedera
Version:
Ledger Hedera Coin integration
97 lines • 4.12 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getBlock = getBlock;
const constants_1 = require("../constants");
const api_1 = require("../network/api");
const getBlockInfo_1 = require("./getBlockInfo");
const utils_1 = require("./utils");
function toHederaAsset(mirrorTransfer) {
if ("token_id" in mirrorTransfer) {
return {
type: "hts",
assetReference: mirrorTransfer.token_id,
};
}
return { type: "native" };
}
function toBlockOperation(payerAccount, chargedFee, mirrorTransfer) {
const isTokenTransfer = "token_id" in mirrorTransfer;
const address = mirrorTransfer.account;
const asset = toHederaAsset(mirrorTransfer);
let amount = BigInt(mirrorTransfer.amount);
// exclude fee from payer's operation amount (fees are accounted for separately, so operations must not represent fees)
if (payerAccount === address && !isTokenTransfer) {
amount += BigInt(chargedFee);
}
return {
type: "transfer",
address,
asset,
amount,
};
}
function createStakingRewardOperations(tx) {
return tx.staking_reward_transfers.map(rewardTransfer => ({
type: "transfer",
address: rewardTransfer.account,
asset: { type: "native" },
amount: BigInt(rewardTransfer.amount),
}));
}
async function getBlock(height) {
const { start, end } = (0, utils_1.getDateRangeFromBlockHeight)(height);
// block data should be immutable: do not allow querying blocks on non-finalized time range
if (end.getTime() > new Date().getTime() - constants_1.FINALITY_MS)
throw new Error(`Block ${height} is not available yet`);
const blockInfo = await (0, getBlockInfo_1.getBlockInfo)(height);
const transactions = await api_1.apiClient.getTransactionsByTimestampRange({
startTimestamp: `gte:${start.getTime() / 1000}`,
endTimestamp: `lt:${end.getTime() / 1000}`,
});
// analyze CRYPTOUPDATEACCOUNT transactions to distinguish staking operations from regular account updates.
// this creates a map of transaction_hash -> StakingAnalysis to avoid repeated lookups.
const stakingAnalyses = await Promise.all(transactions
.filter(tx => tx.name === constants_1.HEDERA_TRANSACTION_NAMES.UpdateAccount)
.map(async (tx) => {
const payerAccount = (0, utils_1.extractFeesPayer)(tx);
const analysis = await (0, utils_1.analyzeStakingOperation)(payerAccount, tx);
return [tx.transaction_hash, analysis];
}));
const stakingAnalysisMap = new Map(stakingAnalyses);
const blockTransactions = transactions.map(tx => {
const payerAccount = (0, utils_1.extractFeesPayer)(tx);
const stakingAnalysis = stakingAnalysisMap.get(tx.transaction_hash);
let operations;
if (stakingAnalysis) {
operations = [
{
type: "other",
operationType: stakingAnalysis.operationType,
stakedNodeId: stakingAnalysis.targetStakingNodeId,
previousStakedNodeId: stakingAnalysis.previousStakingNodeId,
stakedAmount: stakingAnalysis.stakedAmount,
},
];
}
else {
const allTransfers = [...tx.transfers, ...tx.token_transfers];
operations = allTransfers.map(transfer => toBlockOperation(payerAccount, tx.charged_tx_fee, transfer));
}
// add staking reward operations if present (can occur on any transaction type)
const rewardOperations = createStakingRewardOperations(tx);
operations.push(...rewardOperations);
return {
hash: tx.transaction_hash,
failed: tx.result !== "SUCCESS",
operations,
fees: BigInt(tx.charged_tx_fee),
feesPayer: payerAccount,
details: { memo: (0, utils_1.getMemoFromBase64)(tx.memo_base64) },
};
});
return {
info: blockInfo,
transactions: blockTransactions,
};
}
//# sourceMappingURL=getBlock.js.map