@ledgerhq/coin-cardano
Version:
Ledger Cardano Coin integration
117 lines • 5.39 kB
JavaScript
import { decodeTokenAccountId, emptyHistoryCache, encodeTokenAccountId, } from "@ledgerhq/coin-framework/account/index";
import keyBy from "lodash/keyBy";
import groupBy from "lodash/groupBy";
import BigNumber from "bignumber.js";
import { findTokenById } from "@ledgerhq/cryptoassets";
import { utils as TyphonUtils } from "@stricahq/typhonjs";
import { mergeOps } from "@ledgerhq/coin-framework/bridge/jsHelpers";
import { encodeOperationId } from "@ledgerhq/coin-framework/operation";
import { getAccountChange, getMemoFromTx, isHexString } from "./logic";
export const getTokenAssetId = ({ policyId, assetName, }) => `${policyId}${assetName}`;
export const decodeTokenAssetId = (id) => {
const policyId = id.slice(0, 56);
const assetName = id.slice(56);
return { policyId, assetName };
};
const encodeTokenCurrencyId = (parentCurrency, assetId) => `${parentCurrency.id}/native/${assetId}`;
export const decodeTokenCurrencyId = (id) => {
const [parentCurrencyId, type, assetId] = id.split("/");
return {
parentCurrencyId,
type,
assetId,
};
};
/**
* @returns operations of tokens that are defined in ledgerjs cryptoassets
*/
const mapTxToTokenAccountOperation = ({ parentAccountId, parentCurrency, newTransactions, accountCredentialsMap, }) => {
const operations = [];
newTransactions.forEach(tx => {
const accountChange = getAccountChange(tx, accountCredentialsMap);
accountChange.tokens.forEach(token => {
const assetId = getTokenAssetId({
policyId: token.policyId,
assetName: token.assetName,
});
const tokenCurrencyId = encodeTokenCurrencyId(parentCurrency, assetId);
const tokenCurrency = findTokenById(tokenCurrencyId);
// skip the unsupported tokens by ledger-live
if (tokenCurrency === null || tokenCurrency === undefined) {
return;
}
const tokenAccountId = encodeTokenAccountId(parentAccountId, tokenCurrency);
const tokenOperationType = token.amount.lt(0) ? "OUT" : "IN";
const memo = getMemoFromTx(tx);
const extra = {};
if (memo) {
extra.memo = memo;
}
const operation = {
accountId: tokenAccountId,
id: encodeOperationId(tokenAccountId, tx.hash, tokenOperationType),
hash: tx.hash,
type: tokenOperationType,
fee: new BigNumber(tx.fees),
value: token.amount.absoluteValue(),
senders: tx.inputs.map(i => isHexString(i.address)
? TyphonUtils.getAddressFromHex(Buffer.from(i.address, "hex")).getBech32()
: i.address),
recipients: tx.outputs.map(o => isHexString(o.address)
? TyphonUtils.getAddressFromHex(Buffer.from(o.address, "hex")).getBech32()
: o.address),
blockHeight: tx.blockHeight,
date: new Date(tx.timestamp),
extra,
blockHash: undefined,
};
operations.push(operation);
});
});
return operations;
};
export function buildSubAccounts({ initialAccount, parentAccountId, parentCurrency, newTransactions, tokens, accountCredentialsMap, }) {
const tokenAccountsById = {};
if (initialAccount && initialAccount.subAccounts) {
for (const existingAccount of initialAccount.subAccounts) {
if (existingAccount.type === "TokenAccount") {
tokenAccountsById[existingAccount.id] = existingAccount;
}
}
}
const tokenOperations = mapTxToTokenAccountOperation({
parentAccountId,
parentCurrency,
newTransactions: newTransactions,
accountCredentialsMap,
});
const tokenOperationsByAccId = groupBy(tokenOperations, o => o.accountId);
const tokensBalanceByAssetId = keyBy(tokens, t => getTokenAssetId(t));
for (const tokenAccountId in tokenOperationsByAccId) {
const initialTokenAccount = tokenAccountsById[tokenAccountId];
const oldOperations = initialTokenAccount?.operations || [];
const newOperations = tokenOperationsByAccId[tokenAccountId] || [];
const operations = mergeOps(oldOperations, newOperations);
const { token: tokenCurrency } = decodeTokenAccountId(tokenAccountId);
if (tokenCurrency) {
const accountBalance = tokensBalanceByAssetId[tokenCurrency.contractAddress]?.amount || new BigNumber(0);
const tokenAccount = {
type: "TokenAccount",
id: tokenAccountId,
parentId: parentAccountId,
token: tokenCurrency,
balance: accountBalance,
spendableBalance: accountBalance,
creationDate: operations.length > 0 ? operations[operations.length - 1].date : new Date(),
operationsCount: operations.length,
operations,
pendingOperations: [],
balanceHistoryCache: emptyHistoryCache,
swapHistory: [],
};
tokenAccountsById[tokenAccountId] = tokenAccount;
}
}
return Object.values(tokenAccountsById);
}
//# sourceMappingURL=buildSubAccounts.js.map