@ledgerhq/live-common
Version:
Common ground for the Ledger Live apps
209 lines • 8.85 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildOptimisticOperation = exports.transactionToIntent = exports.adaptCoreOperationToLiveOperation = exports.extractBalance = exports.findCryptoCurrencyByNetwork = void 0;
const operation_1 = require("@ledgerhq/coin-framework/operation");
const bignumber_js_1 = __importDefault(require("bignumber.js"));
const utils_1 = require("@ledgerhq/coin-framework/utils");
const currencies_1 = require("@ledgerhq/cryptoassets/currencies");
function findCryptoCurrencyByNetwork(network) {
const networksRemap = {
xrp: "ripple",
};
return (0, currencies_1.findCryptoCurrencyById)(networksRemap[network] ?? network);
}
exports.findCryptoCurrencyByNetwork = findCryptoCurrencyByNetwork;
function extractBalance(balances, type) {
return (balances.find(balance => balance.asset.type === type) ?? {
asset: { type },
value: 0n,
});
}
exports.extractBalance = extractBalance;
function adaptCoreOperationToLiveOperation(accountId, op) {
const opType = op.type;
const extra = {};
if (op.details?.ledgerOpType !== undefined) {
extra.ledgerOpType = op.details.ledgerOpType;
}
if (op.details?.assetAmount !== undefined) {
extra.assetAmount = op.details.assetAmount;
}
if (op.asset?.type !== "native") {
extra.assetReference =
"assetReference" in (op.asset ?? {}) ? op.asset.assetReference : "";
extra.assetOwner = "assetOwner" in (op.asset ?? {}) ? op.asset.assetOwner : "";
}
if (op.details?.memo) {
extra.memo = op.details.memo;
}
const bnFees = new bignumber_js_1.default(op.tx.fees.toString());
const res = {
id: (0, operation_1.encodeOperationId)(accountId, op.tx.hash, op.type),
hash: op.tx.hash,
accountId,
type: opType,
value: op.asset.type === "native" && ["OUT", "FEES", "DELEGATE", "UNDELEGATE"].includes(opType)
? new bignumber_js_1.default(op.value.toString()).plus(bnFees)
: new bignumber_js_1.default(op.value.toString()),
fee: bnFees,
blockHash: op.tx.block.hash,
blockHeight: op.tx.block.height,
senders: op.senders,
recipients: op.recipients,
date: op.tx.date,
transactionSequenceNumber: op.details?.sequence,
hasFailed: op.details?.status === "failed",
extra,
};
return res;
}
exports.adaptCoreOperationToLiveOperation = adaptCoreOperationToLiveOperation;
/**
* Default implementation of `computeIntentType` is a simple whitelist
* with a fallback to "Payment"
*/
function defaultComputeIntentType(transaction) {
if (!transaction.mode)
return "Payment"; // NOTE: assuming payment by default here, can be changed based on transaction.mode
const modeRemap = {
delegate: "stake",
undelegate: "unstake",
};
const mode = modeRemap[transaction.mode] ?? transaction.mode;
if (["changeTrust", "send", "send-legacy", "send-eip1559", "stake", "unstake"].includes(mode))
return mode;
throw new Error(`Unsupported transaction mode: ${transaction.mode}`);
}
/**
* Converts a transaction object into a `TransactionIntent` object, which is used to represent
* the intent of a transaction in a standardized format.
*
* @template MemoType - The type of memo supported by the transaction, defaults to `MemoNotSupported`.
*
* @param account - The account initiating the transaction. Contains details such as the sender's address.
* @param transaction - The transaction object containing details about the operation to be performed.
* - `assetOwner` (optional): The issuer of the asset, if applicable.
* - `assetReference` (optional): The code of the asset, if applicable.
* - `mode` (optional): The mode of the transaction, e.g., "changetrust" or "send".
* - `fees` (optional): The fees associated with the transaction.
* - `memoType` (optional): The type of memo to attach to the transaction.
* - `memoValue` (optional): The value of the memo to attach to the transaction.
* @param computeIntentType - An optional function to compute the intent type that supersedes the default implementation if present
*
* @returns A `TransactionIntent` object containing the standardized representation of the transaction.
* - Includes details such as type, sender, recipient, amount, fees, asset, and an optional memo.
* - If `assetReference` and `assetOwner` are provided, the asset is represented as a token.
* - If `memoType` and `memoValue` are provided, a memo is included; otherwise, a default memo of type "NO_MEMO" is added.
*
* @throws An error if the transaction mode is unsupported.
*/
function transactionToIntent(account, transaction, computeIntentType) {
const intentType = (computeIntentType ?? defaultComputeIntentType)(transaction);
const isStaking = ["stake", "unstake"].includes(intentType);
const amount = isStaking ? 0n : (0, utils_1.fromBigNumberToBigInt)(transaction.amount, 0n);
const useAllAmount = isStaking || !!transaction.useAllAmount;
const res = {
intentType: isStaking ? "staking" : "transaction",
type: intentType,
sender: account.freshAddress,
recipient: transaction.recipient,
amount,
asset: { type: "native", name: account.currency.name, unit: account.currency.units[0] },
useAllAmount,
feesStrategy: transaction.feesStrategy ?? undefined,
data: Buffer.isBuffer(transaction.data)
? { type: "buffer", value: transaction.data }
: { type: "none" },
};
if (transaction.assetReference && transaction.assetOwner) {
const { subAccountId } = transaction;
const { subAccounts } = account;
const tokenAccount = subAccountId ? subAccounts?.find(ta => ta.id === subAccountId) : null;
res.asset = {
type: tokenAccount?.token.tokenType ?? "token",
assetReference: transaction.assetReference,
name: tokenAccount?.token.name ?? transaction.assetReference,
unit: account.currency.units[0],
assetOwner: transaction.assetOwner,
};
}
if (transaction.memoType && transaction.memoValue) {
res.memo = {
type: transaction.memoType,
value: transaction.memoValue,
};
}
else {
res.memo = { type: "NO_MEMO" };
}
return res;
}
exports.transactionToIntent = transactionToIntent;
const buildOptimisticOperation = (account, transaction, sequenceNumber) => {
let type;
switch (transaction.mode) {
case "changeTrust":
type = "OPT_IN";
break;
case "delegate":
case "stake":
type = "DELEGATE";
break;
case "undelegate":
case "unstake":
type = "UNDELEGATE";
break;
default:
type = "OUT";
break;
}
const fees = BigInt(transaction.fees?.toString() || "0");
const { subAccountId } = transaction;
const { subAccounts } = account;
const operation = {
id: (0, operation_1.encodeOperationId)(account.id, "", type),
hash: "",
type: type,
value: subAccountId ? new bignumber_js_1.default(fees.toString()) : transaction.amount,
fee: new bignumber_js_1.default(fees.toString()),
blockHash: null,
blockHeight: null,
senders: [account.freshAddress.toString()],
recipients: [transaction.recipient],
transactionSequenceNumber: sequenceNumber ?? 0,
accountId: account.id,
date: new Date(),
extra: {
ledgerOpType: type,
blockTime: new Date(),
index: "0",
},
};
const tokenAccount = subAccountId ? subAccounts?.find(ta => ta.id === subAccountId) : null;
if (tokenAccount && subAccountId) {
operation.subOperations = [
{
id: `${subAccountId}--OUT`,
hash: "",
type: "OUT",
value: transaction.useAllAmount ? tokenAccount.balance : transaction.amount,
fee: new bignumber_js_1.default(0),
blockHash: null,
blockHeight: null,
senders: [account.freshAddress],
recipients: [transaction.recipient],
accountId: subAccountId,
date: new Date(),
extra: {
ledgerOpType: type,
},
},
];
}
return operation;
};
exports.buildOptimisticOperation = buildOptimisticOperation;
//# sourceMappingURL=utils.js.map