UNPKG

@ledgerhq/coin-hedera

Version:
200 lines 12.1 kB
import { Timestamp, Transaction as HederaSDKTransaction, TransactionId } from "@hashgraph/sdk"; import type { AssetInfo, TransactionIntent } from "@ledgerhq/coin-module-framework/api/types"; import type { Currency, ExplorerView, TokenCurrency } from "@ledgerhq/types-cryptoassets"; import type { AccountLike, Operation as LiveOperation } from "@ledgerhq/types-live"; import BigNumber from "bignumber.js"; import { HEDERA_DELEGATION_STATUS, HEDERA_OPERATION_TYPES } from "../constants"; import type { EnrichedERC20Transfer, HederaAccount, HederaMemo, HederaMirrorTransaction, HederaOperationExtra, HederaTxData, HederaValidator, MergedTransaction, OperationDetailsExtraField, StakingAnalysis, Transaction, TransactionStaking, TransactionStatus, TransactionTokenAssociate, SyntheticBlock } from "../types"; export declare const serializeSignature: (signature: Uint8Array) => string; export declare const deserializeSignature: (signature: string) => Buffer<ArrayBuffer>; export declare const serializeTransaction: (tx: HederaSDKTransaction) => string; export declare const deserializeTransaction: (tx: string) => HederaSDKTransaction; export declare const getOperationValue: ({ asset, operation, }: { asset: AssetInfo; operation: LiveOperation<HederaOperationExtra>; }) => bigint; /** * Extract the transaction initiator account from a Hedera transaction_id. * * Hedera transaction IDs follow the format `0.0.ACCOUNT-TIMESTAMP-NONCE`. * The first segment (before the first `-`) is the Hedera native account ID of * the transaction initiator. * * This always returns a Hedera-native account ID (e.g. `0.0.12345`), never * an EVM address, since the Mirror Node transaction_id always uses the native format. * * In most cases, the transaction initiator is also the fee payer, but not always: see `extractFeesPayer`. */ export declare function extractInitiator(transactionId: string): string; /** * Extract the fee payer account for a Hedera mirror transaction. * * In most cases, the transaction initiator is also the fee payer, but not always: failed * transactions can be charged to the initiator, or not. The most reliable signal for * determining the fee payer is to analyze the actual balance changes (transfers) and the * charged transaction fee. * * This helper implements a best-effort heuristic: * - it first inspects the transfers and charged fee to infer a unique fee payer when possible; * - if it cannot unambiguously identify a single payer from balance changes, it falls back to * the transaction initiator derived from the transaction id. */ export declare function extractFeesPayer(transaction: Pick<HederaMirrorTransaction, "transaction_id" | "transfers" | "charged_tx_fee">): string; export declare const getHederaTransactionBodyBytes: (tx: HederaSDKTransaction) => Uint8Array<ArrayBufferLike>; export declare const mapIntentToSDKOperation: (txIntent: TransactionIntent) => HEDERA_OPERATION_TYPES; export declare const getMemoFromBase64: (memoBase64: string | undefined) => string | null; export declare function base64ToUrlSafeBase64(data: string): string; export declare const getTransactionExplorer: (explorerView: ExplorerView | null | undefined, operation: LiveOperation) => string | undefined; export declare const isTokenAssociateTransaction: (tx: Transaction | null | undefined) => tx is TransactionTokenAssociate; export declare const isAutoTokenAssociationEnabled: (account: AccountLike) => boolean; export declare const isTokenAssociationRequired: (account: AccountLike, token: TokenCurrency | null | undefined) => boolean; export declare const isValidExtra: (extra: unknown) => extra is HederaOperationExtra; export declare const getOperationDetailsExtraFields: (extra: HederaOperationExtra) => OperationDetailsExtraField[]; export declare const sendRecipientCanNext: (status: TransactionStatus) => boolean; export declare const getCurrencyToUSDRate: import("@ledgerhq/live-network/cache").CacheRes<[currency: Currency], BigNumber | null>; export declare const checkAccountTokenAssociationStatus: import("@ledgerhq/live-network/cache").CacheRes<[accountId: string, token: TokenCurrency], boolean>; export declare const getChecksum: (accountId: string) => string | null; export declare const safeParseAccountId: (address: string) => Promise<[Error, null] | [null, { accountId: string; checksum: string | null; }]>; export declare function getBlockHash(blockHeight: number): string; /** * Calculates a synthetic block height based on Hedera consensus timestamp. * * @param consensusTimestamp - Hedera consensus timestamp * @param blockWindowSeconds - Duration of one synthetic block in seconds (default: 10) * @returns Deterministic synthetic block (height and hash) */ export declare function getSyntheticBlock(consensusTimestamp: string, blockWindowSeconds?: number): SyntheticBlock; /** * Calculates the date range based on a synthetic block height. * * @param blockHeight - The synthetic block height * @param blockWindowSeconds - Duration of one synthetic block in seconds (default: 10) * @returns block date range */ export declare function getDateRangeFromBlockHeight(blockHeight: number, blockWindowSeconds?: number): { start: Date; end: Date; }; export declare const formatTransactionId: (transactionId: TransactionId) => string; /** * Fetches EVM address for given Hedera account ID (e.g. "0.0.1234"). * It returns null if the fetch fails. * * @param accountId - Hedera account ID in the format `shard.realm.num` * @returns EVM address (`0x...`) or null if fetch fails */ export declare const toEVMAddress: (accountId: string) => Promise<string | null>; /** * Converts EVM address in hexadecimal format to its corresponding Hedera account ID. * Only long-zero addresses can be mathematically converted back to account IDs. * Non-long-zero addresses support would require mirror node call and is not needed for now * Uses shard 0 and realm 0 by default for the conversion. * If the conversion fails, it returns null. * * @param evmAddress - EVM address in hexadecimal format (should start with '0x') * @param shard - Optional shard ID (defaults to 0) * @param realm - Optional realm ID (defaults to 0) * @returns Hedera account ID in the format `shard.realm.num` or null if conversion fails */ export declare const fromEVMAddress: (evmAddress: string, shard?: number, realm?: number) => string | null; export declare const extractCompanyFromNodeDescription: (description: string) => string; export declare const sortValidators: (validators: HederaValidator[]) => HederaValidator[]; export declare const filterValidatorBySearchTerm: (validator: HederaValidator, search: string) => boolean; export declare const getValidatorFromAccount: (account: HederaAccount) => HederaValidator | null; export declare const getDefaultValidator: (validators: HederaValidator[]) => HederaValidator | null; export declare const getDelegationStatus: (validator: HederaValidator | null) => HEDERA_DELEGATION_STATUS; export declare const isStakingTransaction: (tx: Transaction | null | undefined) => tx is TransactionStaking; export declare const hasSpecificIntentData: <Type extends "staking" | "erc20">(txIntent: TransactionIntent<HederaMemo, HederaTxData>, expectedType: Type) => txIntent is Extract<TransactionIntent<HederaMemo, HederaTxData>, { data: { type: Type; }; }>; export declare const calculateAPY: (rewardRateStart: number) => number; /** * Calculates the uncommitted balance change for an account between two timestamps. * * This function handles the timing mismatch between Mirror Node balance snapshots and actual transactions. * Balance snapshots are taken at regular intervals, not at every transaction, so querying by exact timestamp * may return a snapshot from before moment you need. * * @param address - Hedera account ID (e.g., "0.0.12345") * @param startTimestamp - Start of the time range (exclusive, format: "1234567890.123456789") * @param endTimestamp - End of the time range (inclusive, format: "1234567890.123456789") * @returns The net balance change as BigInt (sum of all transfers to/from the account) */ export declare const calculateUncommittedBalanceChange: ({ address, startTimestamp, endTimestamp, }: { address: string; startTimestamp: string; endTimestamp: string; }) => Promise<BigNumber>; /** * Hedera uses the AccountUpdateTransaction for multiple purposes, including staking operations. * Mirror node classifies all such transactions under the same name: "CRYPTOUPDATEACCOUNT". * * This function distinguishes between: * - DELEGATE: Account started staking (staked_node_id changed from null to a node ID) * - UNDELEGATE: Account stopped staking (staked_node_id changed from a node ID to null) * - REDELEGATE: Account changed staking node (staked_node_id changed from one node to another) * * The analysis works by: * 1. Fetching the account state BEFORE the transaction (using lt: timestamp filter) * 2. Fetching the account state AFTER the transaction (using eq: timestamp filter) * 3. Comparing the staked_node_id field to determine what changed * 4. Calculating the actual staked amount by replaying uncommitted transactions between * the latest balance snapshot and the staking operation to handle snapshot timing mismatches * * @performance * Makes 3 API calls per operation: * - account state before * - account state after * - transaction history based on latest balance snapshot * * Batching would complicate code for minimal gain given low staking op frequency. */ export declare const analyzeStakingOperation: (address: string, mirrorTx: HederaMirrorTransaction) => Promise<StakingAnalysis | null>; export declare const toEntityId: ({ num, shard, realm, }: { num: number; shard?: number; realm?: number; }) => string; /** * Merges transactions from Mirror Node and Hgraph ERC20 transfers into a unified, sorted list. * * This function handles the complexity of combining two data sources that may have different indexing speeds: * - Mirror Node transactions (native HBAR transfers, HTS tokens, contract calls, etc.) * - Hgraph ERC20 transfers (indexed separately, may lag behind Mirror Node) * * Key behaviors: * 1. Merges both sources into a single array with type discrimination * 2. Sorts by consensus timestamp (nanosecond precision) in specified order * 3. Detects and handles ERC20 indexing delays by filtering out transactions after Hgraph's latest timestamp * 4. Applies pagination limit and generates next cursor for pagination * * @param mirrorTransactions - Transactions from Mirror Node API * @param enrichedERC20Transfers - enriched ERC20 transfers from Hgraph API * @param order - Sort order: "asc" or "desc" * @param limit - Maximum number of transactions to return (only applied when fetchAllPages is false) * @param latestHgraphIndexedTimestampNs - Latest consensus timestamp indexed by Hgraph (used for delay detection) * @param fetchAllPages - If true, returns all transactions; if false, applies limit * @returns Object containing merged transactions and next cursor that can be used for pagination */ export declare const mergeTransactionsFromDifferentSources: ({ mirrorTransactions, enrichedERC20Transfers, order, limit, latestHgraphIndexedTimestampNs, fetchAllPages, }: { mirrorTransactions: HederaMirrorTransaction[]; enrichedERC20Transfers: EnrichedERC20Transfer[]; order: "asc" | "desc"; limit: number; latestHgraphIndexedTimestampNs: BigNumber; fetchAllPages: boolean; }) => { merged: MergedTransaction[]; nextCursor: string | null; }; export declare function millisToSeconds(millis: number | BigNumber): BigNumber; export declare function secondsToNanos(seconds: number | BigNumber): BigNumber; export declare function nanosToSeconds(nanos: number | BigNumber): BigNumber; export declare function toTimestamp(consensusTimestamp: string): Timestamp; export declare function createStakingRewardOperationHash(hash: string): string; //# sourceMappingURL=utils.d.ts.map