@ledgerhq/live-common
Version:
Common ground for the Ledger Live apps
202 lines • 9.58 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const groupAccountsByAsset_1 = require("../groupAccountsByAsset");
const cryptoCurrencies_1 = require("../../../mock/fixtures/cryptoCurrencies");
const bignumber_js_1 = __importDefault(require("bignumber.js"));
// Mock calculate function
jest.mock("@ledgerhq/live-countervalues/logic", () => ({
calculate: jest.fn((state, { value }) => {
// Mock: return the balance directly as fiat value for simple testing
return value;
}),
}));
describe("groupAccountsByAsset", () => {
const mockCurrency = (0, cryptoCurrencies_1.createFixtureCryptoCurrency)("bitcoin");
const mockEthCurrency = (0, cryptoCurrencies_1.createFixtureCryptoCurrency)("ethereum");
const mockCounterValuesState = {};
const mockTargetCurrency = (0, cryptoCurrencies_1.createFixtureCryptoCurrency)("usd");
const mockUSDCToken = {
type: "TokenCurrency",
id: "ethereum/erc20/usdc",
contractAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
parentCurrency: mockEthCurrency,
tokenType: "erc20",
name: "USD Coin",
ticker: "USDC",
units: [{ name: "USD Coin", code: "USDC", magnitude: 6 }],
};
const mockBTCAccount = {
type: "Account",
id: "btc-account-1",
seedIdentifier: "seed-id",
derivationMode: "",
currency: mockCurrency,
balance: new bignumber_js_1.default(100000000),
spendableBalance: new bignumber_js_1.default(100000000),
blockHeight: 0,
operations: [],
operationsCount: 0,
pendingOperations: [],
index: 0,
freshAddress: "btc-address",
freshAddressPath: "44'/0'/0'/0/0",
used: true,
swapHistory: [],
nfts: [],
lastSyncDate: new Date(),
creationDate: new Date(),
balanceHistoryCache: {
HOUR: { balances: [], latestDate: null },
DAY: { balances: [], latestDate: null },
WEEK: { balances: [], latestDate: null },
},
};
const mockUSDCAccount = {
type: "TokenAccount",
id: "usdc-account-1",
token: mockUSDCToken,
parentId: "eth-account-1",
balance: new bignumber_js_1.default(1000000),
spendableBalance: new bignumber_js_1.default(1000000),
operations: [],
operationsCount: 0,
pendingOperations: [],
swapHistory: [],
creationDate: new Date(),
balanceHistoryCache: {
HOUR: { balances: [], latestDate: null },
DAY: { balances: [], latestDate: null },
WEEK: { balances: [], latestDate: null },
},
};
it("should group accounts by asset ID and aggregate balances", () => {
const accounts = [mockBTCAccount, mockUSDCAccount];
const result = (0, groupAccountsByAsset_1.groupAccountsByAsset)(accounts, mockCounterValuesState, mockTargetCurrency);
expect(result).toEqual({
[mockCurrency.id]: {
totalBalance: new bignumber_js_1.default(100000000),
totalFiatValue: new bignumber_js_1.default(100000000),
accounts: [mockBTCAccount],
referenceCurrency: mockCurrency,
},
[mockUSDCToken.id]: {
totalBalance: new bignumber_js_1.default(1000000),
totalFiatValue: new bignumber_js_1.default(1000000),
accounts: [mockUSDCAccount],
referenceCurrency: mockUSDCToken,
},
});
});
it("should aggregate multiple accounts with the same asset", () => {
const secondBTCAccount = {
...mockBTCAccount,
id: "btc-account-2",
balance: new bignumber_js_1.default(50000000), // 0.5 BTC
};
const accounts = [mockBTCAccount, secondBTCAccount];
const result = (0, groupAccountsByAsset_1.groupAccountsByAsset)(accounts, mockCounterValuesState, mockTargetCurrency);
expect(result[mockCurrency.id]).toEqual({
totalBalance: new bignumber_js_1.default(150000000),
totalFiatValue: new bignumber_js_1.default(150000000),
accounts: [mockBTCAccount, secondBTCAccount],
referenceCurrency: mockCurrency,
});
});
it("should handle empty accounts array", () => {
const result = (0, groupAccountsByAsset_1.groupAccountsByAsset)([], mockCounterValuesState, mockTargetCurrency);
expect(result).toEqual({});
});
it("should handle accounts with zero balance", () => {
const zeroBalanceAccount = {
...mockBTCAccount,
balance: new bignumber_js_1.default(0),
};
const accounts = [zeroBalanceAccount];
const result = (0, groupAccountsByAsset_1.groupAccountsByAsset)(accounts, mockCounterValuesState, mockTargetCurrency);
expect(result[mockCurrency.id]).toEqual({
totalBalance: new bignumber_js_1.default(0),
totalFiatValue: new bignumber_js_1.default(0),
accounts: [zeroBalanceAccount],
referenceCurrency: mockCurrency,
});
});
it("should set referenceCurrency to the first currency encountered for each asset group", () => {
const accounts = [mockBTCAccount, mockUSDCAccount];
const result = (0, groupAccountsByAsset_1.groupAccountsByAsset)(accounts, mockCounterValuesState, mockTargetCurrency);
expect(result[mockCurrency.id].referenceCurrency).toEqual(mockCurrency);
expect(result[mockUSDCToken.id].referenceCurrency).toEqual(mockUSDCToken);
});
it("should normalize balances when tokens have different magnitudes", () => {
// Create BSC USDC with different magnitude (18 decimals instead of 6)
const mockBscUSDCToken = {
...mockUSDCToken,
id: "bsc/bep20/usdc",
name: "USD Coin (BSC)",
ticker: "USDC",
units: [{ name: "USD Coin", code: "USDC", magnitude: 18 }], // 18 decimals
};
const mockEthUSDCAccount = {
...mockUSDCAccount,
id: "eth-usdc-account",
token: mockUSDCToken,
balance: new bignumber_js_1.default(1000000), // 1 USDC with 6 decimals
};
const mockBscUSDCAccount = {
...mockUSDCAccount,
id: "bsc-usdc-account",
token: mockBscUSDCToken,
balance: new bignumber_js_1.default("1000000000000000000"), // 1 USDC with 18 decimals
};
// Both should be grouped under the same token ID for this test
// First account (ETH USDC) becomes reference currency with 6 decimals
const accounts = [mockEthUSDCAccount, mockBscUSDCAccount];
const result = (0, groupAccountsByAsset_1.groupAccountsByAsset)(accounts, mockCounterValuesState, mockTargetCurrency);
const ethGroup = result[mockUSDCToken.id];
expect(ethGroup.referenceCurrency).toEqual(mockUSDCToken); // First currency is reference
expect(ethGroup.accounts).toHaveLength(1);
expect(ethGroup.totalBalance).toEqual(new bignumber_js_1.default(1000000)); // 1 USDC normalized to 6 decimals
const bscGroup = result[mockBscUSDCToken.id];
expect(bscGroup.referenceCurrency).toEqual(mockBscUSDCToken);
expect(bscGroup.accounts).toHaveLength(1);
expect(bscGroup.totalBalance).toEqual(new bignumber_js_1.default("1000000000000000000")); // 1 USDC with 18 decimals
});
it("should normalize balances correctly when adding accounts with different magnitudes to same asset group", () => {
// Create two USDC tokens with same ID but different magnitudes
const ethUSDCToken = {
...mockUSDCToken,
units: [{ name: "USD Coin", code: "USDC", magnitude: 6 }], // 6 decimals
};
const bscUSDCToken = {
...mockUSDCToken,
units: [{ name: "USD Coin", code: "USDC", magnitude: 18 }], // 18 decimals
};
const ethAccount = {
...mockUSDCAccount,
id: "eth-usdc",
token: ethUSDCToken,
balance: new bignumber_js_1.default(1000000), // 1 USDC with 6 decimals
};
const bscAccount = {
...mockUSDCAccount,
id: "bsc-usdc",
token: bscUSDCToken,
balance: new bignumber_js_1.default("1000000000000000000"), // 1 USDC with 18 decimals
};
// Process ETH account first to make it the reference currency
const accounts = [ethAccount, bscAccount];
const result = (0, groupAccountsByAsset_1.groupAccountsByAsset)(accounts, mockCounterValuesState, mockTargetCurrency);
const group = result[mockUSDCToken.id];
expect(group.referenceCurrency).toEqual(ethUSDCToken); // First currency is reference (6 decimals)
expect(group.accounts).toHaveLength(2);
// BSC balance should be normalized from 18 decimals to 6 decimals
// 1000000000000000000 (18 decimals) -> 1000000 (6 decimals)
// magnitudeDiff = 6 - 18 = -12
// normalized = 1000000000000000000 * 10^(-12) = 1000000
const expectedTotal = new bignumber_js_1.default(1000000).plus(new bignumber_js_1.default(1000000)); // 2 USDC total
expect(group.totalBalance).toEqual(expectedTotal);
});
});
//# sourceMappingURL=groupAccountsByAsset.test.js.map