@ledgerhq/coin-tezos
Version:
124 lines (113 loc) • 4.11 kB
text/typescript
import {
AmountRequired,
FeeTooHigh,
InvalidAddressBecauseDestinationIsAlsoSource,
NotEnoughBalance,
NotEnoughBalanceBecauseDestinationNotCreated,
NotEnoughBalanceToDelegate,
RecommendUndelegation,
} from "@ledgerhq/errors";
import { log } from "@ledgerhq/logs";
import BigNumber from "bignumber.js";
import { AccountBridge } from "@ledgerhq/types-live";
import { InvalidAddressBecauseAlreadyDelegated } from "../types/errors";
import { validateRecipient } from "../logic";
import { isAccountDelegating } from "../network/bakers";
import api from "../network/tzkt";
import { Transaction } from "../types";
const EXISTENTIAL_DEPOSIT = new BigNumber(275000);
export const getTransactionStatus: AccountBridge<Transaction>["getTransactionStatus"] = async (
account,
transaction,
) => {
const errors: Record<string, Error> = {};
const warnings: Record<string, Error> = {};
let resetTotalSpent = false;
// Recipient validation logic
if (transaction.mode !== "undelegate") {
if (account.freshAddress === transaction.recipient) {
errors.recipient = new InvalidAddressBecauseDestinationIsAlsoSource();
} else {
const { recipientError, recipientWarning } = await validateRecipient(transaction.recipient);
if (recipientError) {
errors.recipient = recipientError;
}
if (recipientWarning) {
warnings.recipient = recipientWarning;
}
}
}
// Pre validation of amount field
const estimatedFees = transaction.estimatedFees || new BigNumber(0);
if (transaction.mode === "send") {
if (!errors.amount && transaction.amount.eq(0) && !transaction.useAllAmount) {
resetTotalSpent = true;
errors.amount = new AmountRequired();
} else if (transaction.amount.gt(0) && estimatedFees.times(10).gt(transaction.amount)) {
warnings.feeTooHigh = new FeeTooHigh();
}
const thresholdWarning = 0.5 * 10 ** account.currency.units[0].magnitude;
if (
!errors.amount &&
account.balance.minus(transaction.amount).minus(estimatedFees).lt(thresholdWarning)
) {
if (isAccountDelegating(account)) {
if (transaction.useAllAmount) {
errors.amount = new RecommendUndelegation();
} else {
warnings.amount = new RecommendUndelegation();
}
}
}
}
// effective amount
// if we also have taquitoError, we interprete them and they override the previously inferred errors
if (transaction.taquitoError) {
log("taquitoerror", String(transaction.taquitoError));
// remap taquito errors
if (
transaction.taquitoError.endsWith("balance_too_low") ||
transaction.taquitoError.endsWith("subtraction_underflow")
) {
if (transaction.mode === "send") {
resetTotalSpent = true;
errors.amount = new NotEnoughBalance();
} else {
errors.amount = new NotEnoughBalanceToDelegate();
}
} else if (transaction.taquitoError.endsWith("delegate.unchanged")) {
errors.recipient = new InvalidAddressBecauseAlreadyDelegated();
} else if (!errors.amount) {
// unidentified error case
errors.amount = new Error(transaction.taquitoError);
resetTotalSpent = true;
}
}
if (!errors.amount && account.balance.lte(0)) {
resetTotalSpent = true;
errors.amount = new NotEnoughBalance();
}
if (!errors.amount && transaction.mode === "delegate" && account.balance.lte(estimatedFees)) {
resetTotalSpent = true;
errors.amount = new NotEnoughBalance();
}
// Catch a specific case that requires a minimum amount
if (
!errors.amount &&
transaction.mode === "send" &&
transaction.amount.lt(EXISTENTIAL_DEPOSIT) &&
(await api.getAccountByAddress(transaction.recipient)).type === "empty"
) {
resetTotalSpent = true;
errors.amount = new NotEnoughBalanceBecauseDestinationNotCreated("", {
minimalAmount: "0.275 XTZ",
});
}
return {
errors,
warnings,
estimatedFees,
amount: transaction.amount,
totalSpent: resetTotalSpent ? new BigNumber(0) : transaction.amount.plus(estimatedFees),
};
};