@ledgerhq/coin-algorand
Version:
Ledger Algorand Coin integration
132 lines • 5.73 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getTransactionStatus = void 0;
const algosdk_1 = require("algosdk");
const bignumber_js_1 = require("bignumber.js");
const invariant_1 = __importDefault(require("invariant"));
const errors_1 = require("@ledgerhq/errors");
const errors_2 = require("@ledgerhq/errors");
const errors_3 = require("./errors");
const logic_1 = require("./logic");
const tokens_1 = require("./tokens");
/*
* Here are the list of the differents things we check
* - Check if recipient is the same in case of send
* - Check if recipient is valid
* - Check if amounts are set
* - Check if fees are loaded
* - Check if is a send Max and set the amount
* - Check if Token is already optin at the recipient
* - Check if memo is too long
*/
const getTransactionStatus = async (account, transaction) => {
const errors = {};
const warnings = {};
const tokenAccount = !transaction.subAccountId
? null
: account.subAccounts && account.subAccounts.find(ta => ta.id === transaction.subAccountId);
if (!transaction.recipient) {
errors.recipient = new errors_1.RecipientRequired();
}
else if (!(await (0, algosdk_1.isValidAddress)(transaction.recipient))) {
errors.recipient = new errors_1.InvalidAddress("", {
currencyName: account.currency.name,
});
}
else if (transaction.mode === "send" && account.freshAddress === transaction.recipient) {
errors.recipient = new errors_1.InvalidAddressBecauseDestinationIsAlsoSource();
}
const estimatedFees = transaction.fees || new bignumber_js_1.BigNumber(0);
let amount = transaction.amount;
let totalSpent = estimatedFees;
(0, invariant_1.default)(account.algorandResources, "Algorand family expected");
const algorandResources = account.algorandResources;
const algoSpendableBalance = (0, logic_1.computeAlgoMaxSpendable)({
accountBalance: account.balance,
nbAccountAssets: algorandResources.nbAssets,
mode: transaction.mode,
});
switch (transaction.mode) {
case "send": {
if (amount.lte(0) && !transaction.useAllAmount) {
errors.amount = new errors_1.AmountRequired();
}
if (!transaction.fees || !transaction.fees.gt(0)) {
errors.fees = new errors_1.FeeNotLoaded();
}
if (tokenAccount &&
tokenAccount.type === "TokenAccount" &&
!errors.recipient &&
!(await (0, logic_1.recipientHasAsset)(transaction.recipient, (0, tokens_1.extractTokenId)(tokenAccount.token.id)))) {
errors.recipient = new errors_3.AlgorandASANotOptInInRecipient();
}
amount = transaction.useAllAmount
? tokenAccount
? tokenAccount.balance
: algoSpendableBalance.minus(estimatedFees)
: amount;
if (amount.lt(0)) {
amount = new bignumber_js_1.BigNumber(0);
}
totalSpent = tokenAccount ? amount : amount.plus(estimatedFees);
if (!errors.recipient && !(await (0, logic_1.isAmountValid)(transaction.recipient, amount))) {
errors.amount = new errors_1.NotEnoughBalanceBecauseDestinationNotCreated("", {
minimalAmount: "0.1 ALGO",
});
}
if (!tokenAccount && amount.gt(0) && estimatedFees.times(10).gt(amount)) {
warnings.feeTooHigh = new errors_1.FeeTooHigh();
}
if ((amount.lte(0) && transaction.useAllAmount) || // if use all Amount sets an amount at 0
(!errors.recipient && !errors.amount && tokenAccount
? totalSpent.gt(tokenAccount.balance)
: totalSpent.gt(algoSpendableBalance)) // if spendable balance lower than total
) {
errors.amount = new errors_1.NotEnoughBalance();
}
// if spendable balance lower than fees for token
if (!errors.amount && tokenAccount && algoSpendableBalance.lt(estimatedFees)) {
errors.amount = new errors_1.NotEnoughBalanceInParentAccount();
}
break;
}
case "optIn": {
if (!transaction.fees || !transaction.fees.gt(0)) {
errors.fees = new errors_1.FeeNotLoaded();
}
// This error doesn't need to be translate,
// it will use to block until the user choose an assetId
if (!transaction.assetId) {
errors.assetId = new Error("Asset Id is not set");
}
if (algoSpendableBalance.lt(estimatedFees)) {
errors.amount = new errors_1.NotEnoughBalance();
}
break;
}
case "claimReward": {
if (algoSpendableBalance.lt(totalSpent)) {
errors.amount = new errors_1.NotEnoughBalance();
}
if (estimatedFees.gt(algorandResources.rewards)) {
warnings.claimReward = new errors_2.ClaimRewardsFeesWarning();
}
break;
}
}
if (transaction.memo && transaction.memo.length > logic_1.ALGORAND_MAX_MEMO_SIZE) {
throw new Error("Memo is too long");
}
return {
errors,
warnings,
estimatedFees,
amount,
totalSpent,
};
};
exports.getTransactionStatus = getTransactionStatus;
//# sourceMappingURL=getTransactionStatus.js.map