@ledgerhq/live-common
Version:
Common ground for the Ledger Live apps
138 lines • 6.3 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.genericPrepareTransaction = genericPrepareTransaction;
exports.getAssetInfos = getAssetInfos;
const alpaca_1 = require("./alpaca");
const bridge_1 = require("./bridge");
const utils_1 = require("./utils");
const bignumber_js_1 = __importDefault(require("bignumber.js"));
const index_1 = require("@ledgerhq/ledger-wallet-framework/account/index");
function bnEq(a, b) {
return !a && !b ? true : !a || !b ? false : a.eq(b);
}
function assetInfosFallback(transaction) {
return {
assetReference: transaction.assetReference ?? "",
assetOwner: transaction.assetOwner ?? "",
};
}
function propagateField(estimation, field, dest) {
const value = estimation?.parameters?.[field];
if (typeof value !== "bigint" && typeof value !== "number" && typeof value !== "string")
return;
switch (field) {
case "type":
dest[field] = Number(value.toString());
return;
case "storageLimit":
case "gasLimit":
case "gasPrice":
case "maxFeePerGas":
case "maxPriorityFeePerGas":
case "additionalFees":
dest[field] = new bignumber_js_1.default(value.toString());
return;
default:
return;
}
}
function genericPrepareTransaction(network, kind) {
return async (account, transaction) => {
const { computeIntentType, estimateFees, validateIntent } = (0, alpaca_1.getAlpacaApi)(account.currency.id, kind);
const bridgeApi = (0, bridge_1.getBridgeApi)(account.currency, network);
const getAssetFromTokenForCurrency = bridgeApi.getAssetFromToken;
const { assetReference, assetOwner } = getAssetFromTokenForCurrency
? await getAssetInfos(transaction, account.freshAddress, getAssetFromTokenForCurrency)
: assetInfosFallback(transaction);
const customParametersFees = transaction.customFees?.parameters?.fees;
/**
* Ticking `useAllAmount` constantly resets the amount to 0. This is problematic
* because some Blockchain need the actual transaction amount to compute the fees
* (Example with EVM and ERC20 transactions)
* In case of `useAllAmount` and token transaction, we read the token account spendable
* balance instead.
*/
let amount = transaction.amount;
if (transaction.useAllAmount && transaction.subAccountId) {
const subAccount = account.subAccounts?.find(acc => acc.id === transaction.subAccountId);
amount = subAccount?.spendableBalance ?? amount;
}
// Pass any parameters that help estimating fees
// This includes `assetOwner` and `assetReference` that are not used by some apps that only rely on `subAccountId`
// TODO Remove `assetOwner` and `assetReference` in order to maintain one unique way of identifying the type of asset
// https://ledgerhq.atlassian.net/browse/LIVE-24044
const intent = (0, utils_1.transactionToIntent)(account, {
...transaction,
assetOwner,
assetReference,
amount,
}, computeIntentType);
const customFeesParameters = (0, utils_1.bigNumberToBigIntDeep)({
gasPrice: transaction.gasPrice,
maxFeePerGas: transaction.maxFeePerGas,
maxPriorityFeePerGas: transaction.maxPriorityFeePerGas,
gasLimit: transaction.customGasLimit,
gasOptions: transaction.gasOptions,
});
const estimation = customParametersFees
? { value: BigInt(customParametersFees.toFixed()) }
: await estimateFees(intent, customFeesParameters);
const fees = new bignumber_js_1.default(estimation.value.toString());
if (!bnEq(transaction.fees, fees)) {
const next = {
...transaction,
fees,
assetReference,
assetOwner,
customFees: {
parameters: {
fees: customParametersFees ? new bignumber_js_1.default(customParametersFees.toString()) : undefined,
},
},
};
// Propagate needed fields
const fieldsToPropagate = [
"type",
"storageLimit",
"gasPrice",
// gas limit must not change in case it is custom
...(transaction.customGasLimit ? [] : ["gasLimit"]),
"maxFeePerGas",
"maxPriorityFeePerGas",
"additionalFees",
];
for (const field of fieldsToPropagate) {
propagateField(estimation, field, next);
}
// align with stellar/xrp: when send max (or staking intents), reflect validated amount in UI
if (transaction.useAllAmount || ["stake", "unstake"].includes(transaction.mode ?? "")) {
// TODO Remove the call to `validateIntent` https://ledgerhq.atlassian.net/browse/LIVE-22228
const { amount } = await validateIntent((0, utils_1.transactionToIntent)(account, {
...transaction,
assetOwner,
assetReference,
}, computeIntentType), (0, utils_1.extractBalances)(account, getAssetFromTokenForCurrency));
next.amount = new bignumber_js_1.default(amount.toString());
}
return next;
}
return transaction;
};
}
async function getAssetInfos(tr, owner, getAssetFromToken) {
if (tr.subAccountId) {
const { token } = await (0, index_1.decodeTokenAccountId)(tr.subAccountId);
if (!token)
return assetInfosFallback(tr);
const asset = getAssetFromToken(token, owner);
return {
assetOwner: ("assetOwner" in asset && asset.assetOwner) || "",
assetReference: ("assetReference" in asset && asset.assetReference) || "",
};
}
return assetInfosFallback(tr);
}
//# sourceMappingURL=prepareTransaction.js.map