@ledgerhq/live-common
Version:
Common ground for the Ledger Live apps
268 lines (227 loc) • 10.2 kB
text/typescript
import { genAccount } from "@ledgerhq/ledger-wallet-framework/mocks/account";
import { getCryptoCurrencyById } from "../currencies/index";
import { Account } from "@ledgerhq/types-live";
import type { TokenCurrency } from "@ledgerhq/types-cryptoassets";
import BigNumber from "bignumber.js";
import { getTotalStakeableAssets } from "./getTotalStakeableAssets";
import { setupMockCryptoAssetsStore } from "@ledgerhq/cryptoassets/cal-client/test-helpers";
// Setup mock store for unit tests
setupMockCryptoAssetsStore();
const ETH = getCryptoCurrencyById("ethereum");
const BTC = getCryptoCurrencyById("bitcoin");
// Create mock tokens for tests
const ZRX_TOKEN: TokenCurrency = {
type: "TokenCurrency",
id: "ethereum/erc20/0x_project",
contractAddress: "0xE41d2489571d322189246DaFA5ebDe1F4699F498",
parentCurrency: ETH,
tokenType: "erc20",
name: "0x Project",
ticker: "ZRX",
delisted: false,
disableCountervalue: false,
units: [{ name: "ZRX", code: "ZRX", magnitude: 18 }],
};
const REP_TOKEN: TokenCurrency = {
type: "TokenCurrency",
id: "ethereum/erc20/augur",
contractAddress: "0x1985365e9f78359a9B6AD760e32412f4a445E862",
parentCurrency: ETH,
tokenType: "erc20",
name: "Augur",
ticker: "REP",
delisted: false,
disableCountervalue: false,
units: [{ name: "REP", code: "REP", magnitude: 18 }],
};
const mockedAccounts: Account[] = [
genAccount("mocked-account-1", {
currency: ETH,
tokensData: [ZRX_TOKEN, REP_TOKEN],
}),
];
describe("getTotalStakeableAssets", () => {
it("should return empty Set if no accounts", () => {
const result = getTotalStakeableAssets([], [], []);
expect(result.combinedIds).toBeInstanceOf(Set);
expect(result.combinedIds.size).toBe(0);
expect(result.stakeableAssets).toEqual([]);
});
it("should return empty Set if accounts is null", () => {
const result = getTotalStakeableAssets(null, [], []);
expect(result.combinedIds).toBeInstanceOf(Set);
expect(result.combinedIds.size).toBe(0);
expect(result.stakeableAssets).toEqual([]);
});
it("should return empty Set if accounts is undefined", () => {
const result = getTotalStakeableAssets(undefined, [], []);
expect(result.combinedIds).toBeInstanceOf(Set);
expect(result.combinedIds.size).toBe(0);
expect(result.stakeableAssets).toEqual([]);
});
it("should return empty Set if no staking currencies enabled", () => {
const result = getTotalStakeableAssets(mockedAccounts, [], []);
expect(result.combinedIds).toBeInstanceOf(Set);
expect(result.combinedIds.size).toBe(0);
expect(result.stakeableAssets).toEqual([]);
});
it("should return Set with matching currency ID when staking currency is enabled", () => {
const account = mockedAccounts[0];
const stakingCurrenciesEnabled = [ETH.id]; // "ethereum"
expect(account.balance).toBeTruthy();
expect(account.balance instanceof BigNumber).toBe(true);
expect(account.balance.gt(0)).toBe(true);
const result = getTotalStakeableAssets([account], stakingCurrenciesEnabled, []);
expect(result.combinedIds).toBeInstanceOf(Set);
expect(result.combinedIds.size).toBe(1);
expect(result.combinedIds.has(ETH.id)).toBe(true);
expect(result.stakeableAssets.length).toBe(1);
expect(result.stakeableAssets[0]).toEqual({
ticker: ETH.ticker,
networkName: ETH.name,
id: ETH.id,
});
});
it("should return Set with matching token IDs when staking tokens are enabled", () => {
const account = mockedAccounts[0];
const stakingCurrenciesEnabled = [ZRX_TOKEN.id, REP_TOKEN.id];
expect(account.subAccounts).toBeDefined();
expect(account.subAccounts?.length).toBe(2);
const result = getTotalStakeableAssets([account], stakingCurrenciesEnabled, []);
expect(result.combinedIds).toBeInstanceOf(Set);
expect(result.combinedIds.size).toBe(2);
expect(result.combinedIds.has(ZRX_TOKEN.id)).toBe(true);
expect(result.combinedIds.has(REP_TOKEN.id)).toBe(true);
expect(result.stakeableAssets.length).toBe(2);
expect(result.stakeableAssets).toEqual(
expect.arrayContaining([
expect.objectContaining({ id: ZRX_TOKEN.id, ticker: ZRX_TOKEN.ticker }),
expect.objectContaining({ id: REP_TOKEN.id, ticker: REP_TOKEN.ticker }),
]),
);
});
it("should return Set with both currency and token IDs when both are enabled", () => {
const account = mockedAccounts[0];
const stakingCurrenciesEnabled = [ETH.id, ZRX_TOKEN.id, REP_TOKEN.id];
const result = getTotalStakeableAssets([account], stakingCurrenciesEnabled, []);
expect(result.combinedIds).toBeInstanceOf(Set);
expect(result.combinedIds.size).toBe(3);
expect(result.combinedIds.has(ETH.id)).toBe(true);
expect(result.combinedIds.has(ZRX_TOKEN.id)).toBe(true);
expect(result.combinedIds.has(REP_TOKEN.id)).toBe(true);
expect(result.stakeableAssets.length).toBe(3);
expect(result.stakeableAssets).toEqual(
expect.arrayContaining([
expect.objectContaining({ id: ETH.id, ticker: ETH.ticker }),
expect.objectContaining({ id: ZRX_TOKEN.id, ticker: ZRX_TOKEN.ticker }),
expect.objectContaining({ id: REP_TOKEN.id, ticker: REP_TOKEN.ticker }),
]),
);
});
it("should filter out currencies without funds", () => {
const account = mockedAccounts[0];
const accountWithZeroBalance = { ...account, balance: new BigNumber(0) };
const stakingCurrenciesEnabled = [ETH.id];
const result = getTotalStakeableAssets([accountWithZeroBalance], stakingCurrenciesEnabled, []);
expect(result.combinedIds).toBeInstanceOf(Set);
expect(result.combinedIds.size).toBe(0);
expect(result.stakeableAssets).toEqual([]);
});
it("should filter out tokens without funds", () => {
const account = mockedAccounts[0];
const [zrxAccount, repAccount] = account.subAccounts || [];
const emptyRepAccount = { ...repAccount, balance: new BigNumber(0) };
const accountWithEmptyToken = { ...account, subAccounts: [zrxAccount, emptyRepAccount] };
const stakingCurrenciesEnabled = [ZRX_TOKEN.id, REP_TOKEN.id];
const result = getTotalStakeableAssets([accountWithEmptyToken], stakingCurrenciesEnabled, []);
expect(result.combinedIds).toBeInstanceOf(Set);
expect(result.combinedIds.size).toBe(1);
expect(result.combinedIds.has(ZRX_TOKEN.id)).toBe(true);
expect(result.combinedIds.has(REP_TOKEN.id)).toBe(false);
expect(result.stakeableAssets.length).toBe(1);
expect(result.stakeableAssets[0]).toEqual(
expect.objectContaining({ id: ZRX_TOKEN.id, ticker: ZRX_TOKEN.ticker }),
);
});
it("should include partner staking currencies enabled", () => {
const account = mockedAccounts[0];
const stakingCurrenciesEnabled = [ETH.id];
const partnerStakingCurrenciesEnabled = [ZRX_TOKEN.id];
const result = getTotalStakeableAssets(
[account],
stakingCurrenciesEnabled,
partnerStakingCurrenciesEnabled,
);
expect(result.combinedIds).toBeInstanceOf(Set);
expect(result.combinedIds.size).toBe(2);
expect(result.combinedIds.has(ETH.id)).toBe(true);
expect(result.combinedIds.has(ZRX_TOKEN.id)).toBe(true);
expect(result.stakeableAssets.length).toBe(2);
expect(result.stakeableAssets).toEqual(
expect.arrayContaining([
expect.objectContaining({ id: ETH.id, ticker: ETH.ticker }),
expect.objectContaining({ id: ZRX_TOKEN.id, ticker: ZRX_TOKEN.ticker }),
]),
);
});
it("should deduplicate IDs when same currency appears in both lists", () => {
const account = mockedAccounts[0];
const stakingCurrenciesEnabled = [ETH.id];
const partnerStakingCurrenciesEnabled = [ETH.id]; // Same currency
const result = getTotalStakeableAssets(
[account],
stakingCurrenciesEnabled,
partnerStakingCurrenciesEnabled,
);
expect(result.combinedIds).toBeInstanceOf(Set);
expect(result.combinedIds.size).toBe(1);
expect(result.combinedIds.has(ETH.id)).toBe(true);
expect(result.stakeableAssets.length).toBe(1);
expect(result.stakeableAssets[0]).toEqual({
ticker: ETH.ticker,
networkName: ETH.name,
id: ETH.id,
});
});
it("should handle multiple accounts with different currencies", () => {
const ethAccount = mockedAccounts[0];
const btcAccount = genAccount("mocked-account-2", {
currency: BTC,
});
const accounts = [ethAccount, btcAccount];
const stakingCurrenciesEnabled = [ETH.id, BTC.id];
const result = getTotalStakeableAssets(accounts, stakingCurrenciesEnabled, []);
expect(result.combinedIds).toBeInstanceOf(Set);
expect(result.combinedIds.size).toBe(2);
expect(result.combinedIds.has(ETH.id)).toBe(true);
expect(result.combinedIds.has(BTC.id)).toBe(true);
expect(result.stakeableAssets.length).toBe(2);
expect(result.stakeableAssets).toEqual(
expect.arrayContaining([
expect.objectContaining({ id: ETH.id, ticker: ETH.ticker }),
expect.objectContaining({ id: BTC.id, ticker: BTC.ticker }),
]),
);
});
it("should only include IDs that match staking currencies enabled", () => {
const account = mockedAccounts[0];
const stakingCurrenciesEnabled = [ZRX_TOKEN.id]; // Only ZRX enabled, not ETH or REP
const result = getTotalStakeableAssets([account], stakingCurrenciesEnabled, []);
expect(result.combinedIds).toBeInstanceOf(Set);
expect(result.combinedIds.size).toBe(1);
expect(result.combinedIds.has(ZRX_TOKEN.id)).toBe(true);
expect(result.combinedIds.has(ETH.id)).toBe(false);
expect(result.combinedIds.has(REP_TOKEN.id)).toBe(false);
expect(result.stakeableAssets.length).toBe(1);
expect(result.stakeableAssets[0]).toEqual(
expect.objectContaining({ id: ZRX_TOKEN.id, ticker: ZRX_TOKEN.ticker }),
);
});
it("should handle empty arrays for staking currencies", () => {
const account = mockedAccounts[0];
const result = getTotalStakeableAssets([account], [], []);
expect(result.combinedIds).toBeInstanceOf(Set);
expect(result.combinedIds.size).toBe(0);
expect(result.stakeableAssets).toEqual([]);
});
});