@ledgerhq/coin-stellar
Version:
Ledger Stellar Coin integration
90 lines (77 loc) • 2.96 kB
text/typescript
import { encodeAccountId } from "@ledgerhq/coin-framework/account/index";
import { inferSubOperations } from "@ledgerhq/coin-framework/serialization/index";
import { Account } from "@ledgerhq/types-live";
import { GetAccountShape, mergeOps } from "@ledgerhq/coin-framework/bridge/jsHelpers";
import { fetchAccount, fetchAllOperations } from "../network";
import { buildSubAccounts } from "./tokens";
import { StellarBurnAddressError, StellarOperation } from "../types";
import { STELLAR_BURN_ADDRESS } from "./logic";
import { getEnv } from "@ledgerhq/live-env";
export const getAccountShape: GetAccountShape<Account> = async (info, syncConfig) => {
const { address, currency, initialAccount, derivationMode } = info;
// FIXME Workaround for burn address, see https://ledgerhq.atlassian.net/browse/LIVE-4014
if (address === STELLAR_BURN_ADDRESS) throw new StellarBurnAddressError();
const accountId = encodeAccountId({
type: "js",
version: "2",
currencyId: currency.id,
xpubOrAddress: address,
derivationMode,
});
const { blockHeight, balance, spendableBalance, assets } = await fetchAccount(address);
const oldOperations = (initialAccount?.operations || []) as StellarOperation[];
const lastPagingToken = oldOperations[0]?.extra.pagingToken || "";
const isInitSync = lastPagingToken === "";
const newOperations =
(await fetchAllOperations(
accountId,
address,
isInitSync ? "desc" : "asc",
lastPagingToken,
/**
* For an account with a particularly high number of historical transactions,
* retrieving all the data would take a considerable amount of time and is likely to
* fail due to poor network connection quality or other reasons. Therefore, we set a
* limit on the number of retrieval operations here.
* If users want to access historical records from earlier, I would suggest they use a professional blockchain explorer.
*/
isInitSync ? getEnv("API_STELLAR_HORIZON_INITIAL_FETCH_MAX_OPERATIONS") : undefined,
)) || [];
const allOperations = mergeOps(oldOperations, newOperations) as StellarOperation[];
const assetOperations: StellarOperation[] = [];
allOperations.forEach(operation => {
if (
operation?.extra?.assetCode &&
operation?.extra?.assetIssuer &&
!["OPT_IN", "OPT_OUT"].includes(operation.type)
) {
assetOperations.push(operation);
}
});
const subAccounts =
buildSubAccounts({
currency,
accountId,
assets,
syncConfig,
operations: assetOperations,
}) || [];
const shape = {
id: accountId,
balance,
spendableBalance,
operationsCount: allOperations.length,
blockHeight,
subAccounts,
};
return {
...shape,
operations: allOperations.map(op => {
const subOperations = inferSubOperations(op.hash, subAccounts);
return {
...op,
subOperations,
};
}),
};
};