Skip to content

Commit

Permalink
cardano bridge mock
Browse files Browse the repository at this point in the history
  • Loading branch information
lvndry committed Aug 17, 2023
1 parent 3ee785d commit d1bee96
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { AccountsPage } from "../../models/AccountsPage";

test.use({ userdata: "skip-onboarding" });

const currencies = ["BTC", "LTC", "ETH", "ATOM", "XTZ", "XRP", "Tron"];
const currencies = ["BTC", "LTC", "ETH", "ATOM", "XTZ", "XRP", "Tron", "Cardano"];

test.describe.parallel("Accounts @smoke", () => {
for (const currency of currencies) {
Expand Down
170 changes: 170 additions & 0 deletions libs/ledger-live-common/src/families/cardano/bridge/mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
import BigNumber from "bignumber.js";
import {
CardanoAccount,
Token,
Transaction as CardanoTransaction,
TransactionStatus,
} from "../types";
import { utils as TyphonUtils } from "@stricahq/typhonjs";
import type { AccountBridge, CurrencyBridge, Account } from "@ledgerhq/types-live";
import { decodeTokenAssetId, decodeTokenCurrencyId } from "../buildSubAccounts";
import {
AmountRequired,
FeeNotLoaded,
InvalidAddress,
NotEnoughBalance,
RecipientRequired,
} from "@ledgerhq/errors";
import { isValidAddress } from "../logic";
import { getNetworkParameters } from "../networks";
import { CardanoMinAmountError, CardanoNotEnoughFunds } from "../errors";
import { buildTransaction } from "../js-buildTransaction";
import { defaultUpdateTransaction } from "@ledgerhq/coin-framework/bridge/jsHelpers";
import {
scanAccounts,
signOperation,
broadcast,
sync,
makeAccountBridgeReceive,
} from "../../../bridge/mockHelpers";

const receive = makeAccountBridgeReceive();

const createTransaction = (): CardanoTransaction => {
return {
family: "cardano",
mode: "send",
amount: new BigNumber(100),
recipient: "",
poolId: "",
};
};

const estimateMaxSpendable = ({ account }) => {
return account.balance;
};

const getTransactionStatus = async (
account: CardanoAccount,
transaction: CardanoTransaction,
): Promise<TransactionStatus> => {
const errors = { fees: new Error(), recipient: new Error(), amount: new Error() };
const warnings = {};
const estimatedFees = transaction.fees || new BigNumber(0);

const tokenAccount =
transaction.subAccountId && account.subAccounts
? account.subAccounts.find(a => {
return a.id === transaction.subAccountId;
})
: undefined;

const mockAccount = tokenAccount || account;
let amount = transaction.useAllAmount
? await estimateMaxSpendable({ account: mockAccount })
: transaction.amount;

let totalSpent = transaction.amount.plus(estimatedFees);
const networkParams = getNetworkParameters(account.currency.id);

const useAllAmount = !!transaction.useAllAmount;

let tokensToSend: Array<Token> = [];

if (transaction.subAccountId) {
// Token transaction
if (!tokenAccount || tokenAccount.type !== "TokenAccount") {
throw new Error("TokenAccount not found");
}

const { assetId } = decodeTokenCurrencyId(tokenAccount.token.id);
const { policyId, assetName } = decodeTokenAssetId(assetId);
amount = transaction.useAllAmount ? tokenAccount.balance : transaction.amount;
totalSpent = amount;
tokensToSend = [
{
policyId,
assetName,
amount,
},
];
} else {
// ADA transaction
amount = transaction.useAllAmount ? await estimateMaxSpendable({ account }) : amount;
totalSpent = amount.plus(estimatedFees);
}

const minTransactionAmount = TyphonUtils.calculateMinUtxoAmount(
tokensToSend,
new BigNumber(account.cardanoResources.protocolParams.lovelacePerUtxoWord),
false,
);

if (!transaction.fees) {
errors.fees = new FeeNotLoaded();
}

if (!transaction.recipient) {
errors.recipient = new RecipientRequired();
} else if (!isValidAddress(transaction.recipient, networkParams.networkId)) {
errors.recipient = new InvalidAddress();
}

if (!amount.gt(0)) {
errors.amount = useAllAmount ? new CardanoNotEnoughFunds() : new AmountRequired();
} else if (!transaction.subAccountId && amount.lt(minTransactionAmount)) {
errors.amount = new CardanoMinAmountError("", {
amount: minTransactionAmount.div(1e6).toString(),
});
} else if (tokenAccount ? totalSpent.gt(tokenAccount.balance) : totalSpent.gt(account.balance)) {
errors.amount = new NotEnoughBalance();
} else {
try {
await buildTransaction(account, transaction);
} catch (e: any) {
if (
e.message.toLowerCase() === "not enough ada" ||
e.message.toLowerCase() === "not enough tokens"
) {
errors.amount = new CardanoNotEnoughFunds();
} else {
throw e;
}
}
}

return Promise.resolve({
errors,
warnings,
estimatedFees,
amount,
totalSpent,
});
};

const prepareTransaction = async (account: Account, transaction: CardanoTransaction) => {
return transaction;
};

const accountBridge: AccountBridge<CardanoTransaction> = {
createTransaction,
updateTransaction: defaultUpdateTransaction,
getTransactionStatus,
estimateMaxSpendable,
prepareTransaction,
sync,
receive,
signOperation,
broadcast,
};

const currencyBridge: CurrencyBridge = {
preload: () => Promise.resolve({}),
hydrate: () => {},
scanAccounts,
};

export default {
accountBridge,
currencyBridge,
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import type { AccountLike, Account } from "@ledgerhq/types-live";
import { getMainAccount } from "../../account";
import type { CardanoAccount, Transaction } from "./types";
import { createTransaction } from "./js-transaction";
import { address as TyphonAddress, types as TyphonTypes } from "@stricahq/typhonjs";
import {
address as TyphonAddress,
types as TyphonTypes,
Transaction as TyphonTransaction,
} from "@stricahq/typhonjs";
import { buildTransaction } from "./js-buildTransaction";

/**
Expand Down Expand Up @@ -36,7 +40,7 @@ const estimateMaxSpendable = async ({
amount: new BigNumber(0),
useAllAmount: true,
};
let typhonTransaction;
let typhonTransaction: TyphonTransaction;
try {
typhonTransaction = await buildTransaction(a as CardanoAccount, t);
} catch (error) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ async function getSendTransactionStatus(
const warnings: Record<string, Error> = {};
const useAllAmount = !!t.useAllAmount;

const cardanoResources = a.cardanoResources as CardanoResources;
const cardanoResources = a.cardanoResources;
const networkParams = getNetworkParameters(a.currency.id);

const estimatedFees = t.fees || new BigNumber(0);
Expand Down
2 changes: 2 additions & 0 deletions libs/ledger-live-common/src/generated/bridge/mock.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import algorand from "../../families/algorand/bridge/mock";
import bitcoin from "../../families/bitcoin/bridge/mock";
import cardano from "../../families/cardano/bridge/mock";
import cosmos from "../../families/cosmos/bridge/mock";
import ethereum from "../../families/ethereum/bridge/mock";
import polkadot from "../../families/polkadot/bridge/mock";
Expand All @@ -12,6 +13,7 @@ import tron from "../../families/tron/bridge/mock";
export default {
algorand,
bitcoin,
cardano,
cosmos,
ethereum,
polkadot,
Expand Down

0 comments on commit d1bee96

Please sign in to comment.