@ledgerhq/coin-filecoin
Version:
Ledger Filecoin Coin integration
166 lines • 5.97 kB
JavaScript
import { log } from "@ledgerhq/logs";
import { parseCurrencyUnit } from "@ledgerhq/coin-framework/currencies";
import { getCryptoCurrencyById } from "@ledgerhq/cryptoassets";
import { BigNumber } from "bignumber.js";
import { TxStatus } from "../types";
import { fetchBalances, fetchBlockHeight, fetchTxs } from "../api/api";
import { encodeAccountId } from "@ledgerhq/coin-framework/account";
import { encodeOperationId } from "@ledgerhq/coin-framework/operation";
import flatMap from "lodash/flatMap";
import { buildTokenAccounts } from "../erc20/tokenAccounts";
export const getUnit = () => getCryptoCurrencyById("filecoin").units[0];
export const processTxs = (txs) => {
// Group all tx types related to same tx cid into the same object
const txsByTxCid = txs.reduce((txsByTxCidResult, currentTx) => {
const { hash: txCid, type: txType } = currentTx;
const txByType = txsByTxCidResult[txCid] || {};
switch (txType) {
case "Send":
txByType.Send = currentTx;
break;
case "InvokeContract":
txByType.InvokeContract = currentTx;
break;
case "Fee":
txByType.Fee = currentTx;
break;
default:
log("warn", `tx type [${txType}] on tx cid [${txCid}] was not recognized.`);
break;
}
txsByTxCidResult[txCid] = txByType;
return txsByTxCidResult;
}, {});
// Once all tx types have been grouped, we want to find
const processedTxs = [];
for (const txCid in txsByTxCid) {
const item = txsByTxCid[txCid];
const feeTx = item.Fee;
let mainTx;
if ("Send" in item) {
mainTx = item.Send;
}
else if ("InvokeContract" in item) {
mainTx = item.InvokeContract;
}
else {
log("warn", `unexpected tx type, tx with cid [${txCid}] and payload [${JSON.stringify(item)}]`);
}
if (!mainTx) {
if (feeTx) {
log("warn", `feeTx [${feeTx.hash}] found without a mainTx linked to it.`);
}
continue;
}
if (feeTx) {
mainTx.fee = feeTx.amount;
}
processedTxs.push(mainTx);
}
return processedTxs;
};
export const mapTxToOps = (accountId, { address }) => (tx) => {
const { to, from, hash, timestamp, amount, fee, status } = tx;
const ops = [];
const date = new Date(timestamp * 1000);
const value = parseCurrencyUnit(getUnit(), amount.toString());
const feeToUse = parseCurrencyUnit(getUnit(), (fee || 0).toString());
const isSending = address === from;
const isReceiving = address === to;
const hasFailed = status !== TxStatus.Ok;
if (isSending) {
const type = value.eq(0) ? "FEES" : "OUT";
ops.push({
id: encodeOperationId(accountId, hash, type),
hash,
type,
value: value.plus(feeToUse),
fee: feeToUse,
blockHeight: tx.height,
blockHash: null,
accountId,
senders: [from],
recipients: [to],
date,
extra: {},
hasFailed,
});
}
if (isReceiving) {
const type = value.eq(0) ? "FEES" : "IN";
ops.push({
id: encodeOperationId(accountId, hash, type),
hash,
type,
value,
fee: feeToUse,
blockHeight: tx.height,
blockHash: null,
accountId,
senders: [from],
recipients: [to],
date,
extra: {},
hasFailed,
});
}
return ops;
};
export const getAddress = (a) => ({ address: a.freshAddress, derivationPath: a.freshAddressPath });
export const getTxToBroadcast = (operation, signature, rawData) => {
const { sender, recipient, gasLimit, gasFeeCap, gasPremium, method, version, nonce, signatureType, params, value, } = rawData;
return {
message: {
version,
method,
nonce,
params: params ?? "",
to: recipient,
from: sender,
gaslimit: gasLimit.toNumber(),
gaspremium: gasPremium.toString(),
gasfeecap: gasFeeCap.toString(),
value,
},
signature: {
type: signatureType,
data: signature,
},
};
};
export const getAccountShape = async (info) => {
const { address, currency, derivationMode } = info;
const accountId = encodeAccountId({
type: "js",
version: "2",
currencyId: currency.id,
xpubOrAddress: address,
derivationMode,
});
const blockHeight = await fetchBlockHeight();
const balance = await fetchBalances(address);
const rawTxs = await fetchTxs(address);
const tokenAccounts = await buildTokenAccounts(address, accountId, info.initialAccount);
const result = {
id: accountId,
subAccounts: tokenAccounts,
balance: new BigNumber(balance.total_balance),
spendableBalance: new BigNumber(balance.spendable_balance),
operations: flatMap(processTxs(rawTxs), mapTxToOps(accountId, info)).sort((a, b) => b.date.getTime() - a.date.getTime()),
blockHeight: blockHeight.current_block_identifier.index,
};
return result;
};
export const getSubAccount = (account, tx) => {
const subAccount = tx.subAccountId && account.subAccounts
? account.subAccounts.find(sa => sa.id === tx.subAccountId)
: null;
return subAccount;
};
/**
* convert a value in a given unit to a normalized value
* For instance, for 1 BTC, valueFromUnit(1, btcUnit) returns 100000000
* @memberof countervalue
*/
export const valueFromUnit = (valueInUnit, unit) => valueInUnit.times(new BigNumber(10).pow(unit.magnitude));
//# sourceMappingURL=utils.js.map