@ledgerhq/coin-hedera
Version:
Ledger Hedera Coin integration
125 lines • 6.17 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildIterateResult = exports.getAccountShape = void 0;
const account_1 = require("@ledgerhq/ledger-wallet-framework/account");
const jsHelpers_1 = require("@ledgerhq/ledger-wallet-framework/bridge/jsHelpers");
const derivation_1 = require("@ledgerhq/ledger-wallet-framework/derivation");
const bignumber_js_1 = require("bignumber.js");
const invariant_1 = __importDefault(require("invariant"));
const constants_1 = require("../constants");
const logic_1 = require("../logic");
const utils_1 = require("../logic/utils");
const api_1 = require("../network/api");
const utils_2 = require("../network/utils");
const utils_3 = require("./utils");
const getAccountShape = async (info, { blacklistedTokenIds }) => {
const { currency, derivationMode, address, initialAccount } = info;
const config = (0, utils_1.resolveConfig)(currency.id);
(0, invariant_1.default)(address, "hedera: address is expected");
const evmAddress = await (0, utils_2.toEVMAddress)({ configOrCurrencyId: config, accountId: address });
(0, invariant_1.default)(evmAddress, `hedera: evm address is missing for ${address}`);
const liveAccountId = (0, account_1.encodeAccountId)({
type: "js",
version: "2",
currencyId: currency.id,
xpubOrAddress: address,
derivationMode,
});
// get current account balance and tokens
// tokens are fetched with separate requests to get "created_timestamp" for each token
// based on this, ASSOCIATE_TOKEN operations can be connected with tokens
const [mirrorAccount, mirrorTokens, erc20Tokens] = await Promise.all([
api_1.apiClient.getAccount({ configOrCurrencyId: config, address }),
api_1.apiClient.getAccountTokens({ configOrCurrencyId: config, address }),
(0, utils_2.getERC20BalancesForAccountV2)({ configOrCurrencyId: config, address }),
]);
const accountBalance = new bignumber_js_1.BigNumber(mirrorAccount.balance.balance);
// we should sync again when new tokens are added or blacklist changes
const syncHash = await (0, account_1.getSyncHash)(currency.id, blacklistedTokenIds);
const shouldSyncFromScratch = !initialAccount || syncHash !== initialAccount?.syncHash;
const pendingOperations = shouldSyncFromScratch ? [] : (initialAccount?.pendingOperations ?? []);
const oldOperations = shouldSyncFromScratch ? [] : (initialAccount?.operations ?? []);
const latestOperation = oldOperations[0];
// grab latest operation timestamps for incremental sync
let latestOperationTimestamp = null;
if (!shouldSyncFromScratch && latestOperation) {
const timestamp = Math.floor(latestOperation.date.getTime() / 1000);
latestOperationTimestamp = new bignumber_js_1.BigNumber(timestamp).toFixed(9);
}
const latestAccountOperations = await (0, logic_1.listOperationsV2)({
currencyId: currency.id,
address,
evmAddress,
mirrorTokens,
erc20Tokens,
...(latestOperationTimestamp && { cursor: latestOperationTimestamp }),
fetchAllPages: true,
skipFeesForTokenOperations: false,
useEncodedHash: true,
useSyntheticBlocks: false,
});
const newOperations = await (0, utils_3.prepareOperations)(latestAccountOperations.coinOperations, latestAccountOperations.tokenOperations);
const enrichedNewOperations = (0, utils_3.applyPendingExtras)(newOperations, pendingOperations);
const operations = shouldSyncFromScratch
? enrichedNewOperations
: (0, jsHelpers_1.mergeOps)(oldOperations, enrichedNewOperations);
const delegation = typeof mirrorAccount.staked_node_id === "number"
? {
nodeId: mirrorAccount.staked_node_id,
delegated: accountBalance,
pendingReward: new bignumber_js_1.BigNumber(mirrorAccount.pending_reward),
}
: null;
const newSubAccounts = await (0, utils_3.getSubAccounts)({
ledgerAccountId: liveAccountId,
latestTokenOperations: latestAccountOperations.tokenOperations,
mirrorTokens,
erc20Tokens,
});
const subAccounts = shouldSyncFromScratch
? newSubAccounts
: (0, utils_3.mergeSubAccounts)(initialAccount, newSubAccounts);
return {
id: liveAccountId,
freshAddress: address,
syncHash,
lastSyncDate: new Date(),
balance: accountBalance,
spendableBalance: accountBalance,
operations: operations,
operationsCount: operations.length,
// NOTE: there are no "blocks" in hedera
// set a value just so that operations are considered confirmed according to isConfirmedOperation
blockHeight: constants_1.HARDCODED_BLOCK_HEIGHT,
subAccounts,
hederaResources: {
maxAutomaticTokenAssociations: mirrorAccount.max_automatic_token_associations,
isAutoTokenAssociationEnabled: mirrorAccount.max_automatic_token_associations === -1,
delegation,
},
};
};
exports.getAccountShape = getAccountShape;
const buildIterateResult = async ({ result: rootResult }) => {
return async ({ currency, derivationMode, index }) => {
const mirrorAccounts = await api_1.apiClient.getAccountsForPublicKey({
configOrCurrencyId: currency.id,
publicKey: rootResult.publicKey,
});
const addresses = mirrorAccounts.map(a => a.account);
const derivationScheme = (0, derivation_1.getDerivationScheme)({ derivationMode, currency });
const freshAddressPath = (0, derivation_1.runDerivationScheme)(derivationScheme, currency, { account: index });
return addresses[index]
? {
address: addresses[index],
publicKey: addresses[index],
path: freshAddressPath,
}
: null;
};
};
exports.buildIterateResult = buildIterateResult;
//# sourceMappingURL=synchronisation.js.map