@ledgerhq/coin-cardano
Version:
Ledger Cardano Coin integration
127 lines • 6.21 kB
JavaScript
import BigNumber from "bignumber.js";
import { HashType } from "@stricahq/typhonjs/dist/types";
import { encodeOperationId } from "@ledgerhq/coin-framework/operation";
import { formatCurrencyUnit } from "@ledgerhq/coin-framework/currencies";
import ShelleyTypeAddress from "@stricahq/typhonjs/dist/address/ShelleyTypeAddress";
import { types as TyphonTypes } from "@stricahq/typhonjs";
import { getAccountStakeCredential, getOperationType } from "./logic";
import { MEMO_LABEL } from "./constants";
export const buildOptimisticOperation = (account, unsignedTransaction, transaction) => {
const cardanoResources = account.cardanoResources;
const accountCreds = new Set([...cardanoResources.externalCredentials, ...cardanoResources.internalCredentials].map(cred => cred.key));
const stakeCredential = getAccountStakeCredential(account.xpub, account.index);
const protocolParams = account.cardanoResources.protocolParams;
const accountInput = unsignedTransaction
.getInputs()
.reduce((total, i) => accountCreds.has(i.address.paymentCredential.hash.toString("hex"))
? total.plus(i.amount)
: total.plus(0), new BigNumber(0));
const accountOutput = unsignedTransaction
.getOutputs()
.reduce((total, o) => o.address instanceof ShelleyTypeAddress &&
accountCreds.has(o.address.paymentCredential.hash.toString("hex"))
? total.plus(o.amount)
: total.plus(0), new BigNumber(0));
const txCertificates = unsignedTransaction.getCertificates();
const stakeRegistrationCertificates = [];
const stakeDeRegistrationCertificates = [];
txCertificates.forEach(c => {
if (c.type === TyphonTypes.CertificateType.STAKE_REGISTRATION) {
stakeRegistrationCertificates.push(c);
}
else if (c.type === TyphonTypes.CertificateType.STAKE_DE_REGISTRATION) {
stakeDeRegistrationCertificates.push(c);
}
});
const txWithdrawals = unsignedTransaction.getWithdrawals();
const transactionHash = unsignedTransaction.getTransactionHash().toString("hex");
const auxiliaryData = unsignedTransaction.getAuxiliaryData();
const extra = {};
if (auxiliaryData) {
const memoMetadata = auxiliaryData.metadata.find(m => m.label === MEMO_LABEL);
if (memoMetadata && memoMetadata.data instanceof Map) {
const msg = memoMetadata.data.get("msg");
if (Array.isArray(msg) && msg.length) {
extra.memo = msg.join(", ");
}
}
}
let operationValue = accountOutput.minus(accountInput);
if (stakeRegistrationCertificates.length) {
const walletRegistration = stakeRegistrationCertificates.find(c => c.cert.stakeCredential.type === HashType.ADDRESS &&
c.cert.stakeCredential.hash.toString("hex") === stakeCredential.key);
if (walletRegistration) {
extra.deposit = formatCurrencyUnit(account.currency.units[0], new BigNumber(protocolParams.stakeKeyDeposit), {
showCode: true,
disableRounding: true,
});
}
}
if (stakeDeRegistrationCertificates.length) {
const walletDeRegistration = stakeDeRegistrationCertificates.find(c => c.cert.stakeCredential.type === HashType.ADDRESS &&
c.cert.stakeCredential.hash.toString("hex") === stakeCredential.key);
if (walletDeRegistration) {
operationValue = operationValue.minus(protocolParams.stakeKeyDeposit);
extra.refund = formatCurrencyUnit(account.currency.units[0], new BigNumber(protocolParams.stakeKeyDeposit), {
showCode: true,
disableRounding: true,
});
}
}
if (txWithdrawals && txWithdrawals.length) {
const walletWithdraw = txWithdrawals.find(w => w.rewardAccount.stakeCredential.type === HashType.ADDRESS &&
w.rewardAccount.stakeCredential.hash.toString("hex") === stakeCredential.key);
if (walletWithdraw) {
operationValue = operationValue.minus(walletWithdraw.amount);
extra.rewards = formatCurrencyUnit(account.currency.units[0], new BigNumber(walletWithdraw.amount), {
showCode: true,
disableRounding: true,
});
}
}
const opType = txCertificates.find(c => c.type === TyphonTypes.CertificateType.STAKE_DELEGATION)
? "DELEGATE"
: txCertificates.find(c => c.type === TyphonTypes.CertificateType.STAKE_KEY_DE_REGISTRATION)
? "UNDELEGATE"
: getOperationType({
valueChange: operationValue,
fees: unsignedTransaction.getFee(),
});
const op = {
id: encodeOperationId(account.id, transactionHash, opType),
hash: transactionHash,
type: opType,
value: operationValue.absoluteValue(),
fee: unsignedTransaction.getFee(),
blockHash: undefined,
blockHeight: null,
senders: unsignedTransaction.getInputs().map(i => i.address.getBech32()),
recipients: unsignedTransaction.getOutputs().map(o => o.address.getBech32()),
accountId: account.id,
date: new Date(),
extra,
};
const tokenAccount = transaction.subAccountId
? account.subAccounts?.find(ta => ta.id === transaction.subAccountId)
: null;
if (tokenAccount && opType === "OUT") {
op.subOperations = [
{
id: encodeOperationId(tokenAccount.id, transactionHash, opType),
hash: transactionHash,
type: opType,
value: transaction.useAllAmount ? tokenAccount.balance : transaction.amount,
fee: transaction.fees,
blockHash: undefined,
blockHeight: null,
senders: unsignedTransaction.getInputs().map(i => i.address.getBech32()),
recipients: unsignedTransaction.getOutputs().map(o => o.address.getBech32()),
accountId: tokenAccount.id,
date: new Date(),
extra: {},
},
];
}
return op;
};
//# sourceMappingURL=buildOptimisticOperation.js.map