@ledgerhq/coin-multiversx
Version:
Ledger MultiversX Coin integration
128 lines • 5.41 kB
JavaScript
import { getCryptoAssetsStore } from "@ledgerhq/cryptoassets/state";
import BigNumber from "bignumber.js";
import { emptyHistoryCache, encodeTokenAccountId } from "@ledgerhq/coin-framework/account/index";
import { mergeOps } from "@ledgerhq/coin-framework/bridge/jsHelpers";
import { getESDTOperations, getAccountESDTTokens } from "./api";
import { addPrefixToken, extractTokenId } from "./logic";
async function buildMultiversXESDTTokenAccount({ parentAccountId, accountAddress, token, balance, }) {
const tokenAccountId = encodeTokenAccountId(parentAccountId, token);
const tokenIdentifierHex = extractTokenId(token.id);
const tokenIdentifier = Buffer.from(tokenIdentifierHex, "hex").toString();
const operations = await getESDTOperations(tokenAccountId, accountAddress, tokenIdentifier, 0);
const tokenAccount = {
type: "TokenAccount",
id: tokenAccountId,
parentId: parentAccountId,
token,
operationsCount: operations.length,
operations,
pendingOperations: [],
balance,
spendableBalance: balance,
swapHistory: [],
creationDate: operations.length > 0 ? operations[operations.length - 1].date : new Date(),
balanceHistoryCache: emptyHistoryCache, // calculated in the jsHelpers
};
return tokenAccount;
}
function buildExistingAccountMaps(existingAccount, blacklistedTokenIds) {
const existingAccountByTicker = {};
const existingAccountTickers = [];
if (!existingAccount?.subAccounts) {
return { existingAccountByTicker, existingAccountTickers };
}
for (const existingSubAccount of existingAccount.subAccounts) {
if (existingSubAccount.type !== "TokenAccount")
continue;
const { ticker, id } = existingSubAccount.token;
if (!blacklistedTokenIds.includes(id)) {
existingAccountTickers.push(ticker);
existingAccountByTicker[ticker] = existingSubAccount;
}
}
return { existingAccountByTicker, existingAccountTickers };
}
async function syncESDTTokenAccountOperations(tokenAccount, address) {
const oldOperations = tokenAccount?.operations || [];
const startAt = oldOperations.length ? Math.floor(oldOperations[0].date.valueOf() / 1000) : 0;
const tokenIdentifierHex = extractTokenId(tokenAccount.token.id);
const tokenIdentifier = Buffer.from(tokenIdentifierHex, "hex").toString();
const newOperations = await getESDTOperations(tokenAccount.id, address, tokenIdentifier, startAt);
const operations = mergeOps(oldOperations, newOperations);
if (operations === oldOperations)
return tokenAccount;
return {
...tokenAccount,
operations,
operationsCount: operations.length,
};
}
async function updateTokenAccountBalance(tokenAccount, newBalance) {
if (newBalance.eq(tokenAccount.balance)) {
return tokenAccount;
}
return {
...tokenAccount,
balance: newBalance,
spendableBalance: newBalance,
};
}
async function processESDT({ esdt, accountId, accountAddress, existingAccountByTicker, existingAccountTickers, blacklistedTokenIds, }) {
const esdtIdentifierHex = Buffer.from(esdt.identifier).toString("hex");
const token = await getCryptoAssetsStore().findTokenById(addPrefixToken(esdtIdentifierHex));
if (!token || blacklistedTokenIds.includes(token.id)) {
return null;
}
const existingTokenAccount = existingAccountByTicker[token.ticker];
const balance = new BigNumber(esdt.balance);
let tokenAccount;
if (existingTokenAccount) {
const syncedTokenAccount = await syncESDTTokenAccountOperations(existingTokenAccount, accountAddress);
tokenAccount = await updateTokenAccountBalance(syncedTokenAccount, balance);
}
else {
tokenAccount = await buildMultiversXESDTTokenAccount({
parentAccountId: accountId,
accountAddress,
token,
balance,
});
}
existingAccountTickers.push(token.ticker);
existingAccountByTicker[token.ticker] = tokenAccount;
return tokenAccount;
}
async function MultiversXBuildESDTTokenAccounts({ accountId, accountAddress, existingAccount, syncConfig, }) {
const { blacklistedTokenIds = [] } = syncConfig;
const tokenAccounts = [];
const { existingAccountByTicker, existingAccountTickers } = buildExistingAccountMaps(existingAccount, blacklistedTokenIds);
const accountESDTs = await getAccountESDTTokens(accountAddress);
for (const esdt of accountESDTs) {
const tokenAccount = await processESDT({
esdt,
accountId,
accountAddress,
existingAccountByTicker,
existingAccountTickers,
blacklistedTokenIds,
});
if (tokenAccount) {
tokenAccounts.push(tokenAccount);
}
}
// Preserve order of tokenAccounts from the existing token accounts
tokenAccounts.sort((a, b) => {
const i = existingAccountTickers.indexOf(a.token.ticker);
const j = existingAccountTickers.indexOf(b.token.ticker);
if (i === j)
return 0;
if (i < 0)
return 1;
if (j < 0)
return -1;
return i - j;
});
return tokenAccounts;
}
export default MultiversXBuildESDTTokenAccounts;
//# sourceMappingURL=buildSubAccounts.js.map