@ledgerhq/live-common
Version:
Common ground for the Ledger Live apps
131 lines (113 loc) • 4.39 kB
text/typescript
import { Account, AccountLike } from "@ledgerhq/types-live";
import { v5 as uuidv5 } from "uuid";
import { WalletState, accountNameWithDefaultSelector } from "@ledgerhq/live-wallet/store";
import byFamily from "../generated/walletApiAdapter";
import type { Transaction } from "../generated/types";
import { isTokenAccount } from "../account";
import {
WalletAPIAccount,
WalletAPICurrency,
WalletAPITransaction,
WalletAPISupportedCurrency,
GetWalletAPITransactionSignFlowInfos,
} from "./types";
import { FAMILIES_MAPPING_LL_TO_WAPI, FAMILIES_MAPPING_WAPI_TO_LL } from "./constants";
// The namespace is a randomly generated uuid v4 from https://www.uuidgenerator.net/
const NAMESPACE = "c3c78073-6844-409e-9e75-171ab4c7f9a2";
const uuidToAccountId = new Map<string, string>();
export const getAccountIdFromWalletAccountId = (walletAccountId: string): string | undefined =>
uuidToAccountId.get(walletAccountId);
export const getWalletApiIdFromAccountId = (id: string): string => uuidv5(id, NAMESPACE);
export const setWalletApiIdForAccountId = (accountId: string): void => {
const walletApiId = getWalletApiIdFromAccountId(accountId);
uuidToAccountId.set(walletApiId, accountId);
};
export function accountToWalletAPIAccount(
walletState: WalletState,
account: AccountLike,
parentAccount?: Account | null,
): WalletAPIAccount {
const walletApiId = getWalletApiIdFromAccountId(account.id);
uuidToAccountId.set(walletApiId, account.id);
if (isTokenAccount(account)) {
if (!parentAccount) {
throw new Error("No 'parentAccount' account provided for token account");
}
const parentWalletApiId = getWalletApiIdFromAccountId(parentAccount.id);
uuidToAccountId.set(parentWalletApiId, parentAccount.id);
const parentAccountName = accountNameWithDefaultSelector(walletState, parentAccount);
return {
id: walletApiId,
parentAccountId: parentWalletApiId,
balance: account.balance,
address: parentAccount.freshAddress,
blockHeight: parentAccount.blockHeight,
lastSyncDate: parentAccount.lastSyncDate,
name: `${parentAccountName} (${account.token.ticker})`,
currency: account.token.id,
spendableBalance: account.spendableBalance,
};
}
const name = accountNameWithDefaultSelector(walletState, account);
return {
id: walletApiId,
name,
address: account.freshAddress,
currency: account.currency.id,
balance: account.balance,
spendableBalance: account.spendableBalance,
blockHeight: account.blockHeight,
lastSyncDate: account.lastSyncDate,
};
}
export function currencyToWalletAPICurrency(
currency: WalletAPISupportedCurrency,
): WalletAPICurrency {
if (currency.type === "TokenCurrency") {
return {
type: "TokenCurrency",
standard: "ERC20",
id: currency.id,
ticker: currency.ticker,
contract: currency.contractAddress,
name: currency.name,
parent: currency.parentCurrency.id,
color: currency.parentCurrency.color,
decimals: currency.units[0].magnitude,
};
}
return {
type: "CryptoCurrency",
id: currency.id,
ticker: currency.ticker,
name: currency.name,
family: FAMILIES_MAPPING_LL_TO_WAPI[currency.family] ?? currency.family,
color: currency.color,
decimals: currency.units[0].magnitude,
};
}
export const getWalletAPITransactionSignFlowInfos: GetWalletAPITransactionSignFlowInfos<
WalletAPITransaction,
Transaction
> = ({ walletApiTransaction, account }) => {
const liveFamily =
FAMILIES_MAPPING_WAPI_TO_LL[walletApiTransaction.family] ?? walletApiTransaction.family;
const familyModule = byFamily[liveFamily];
if (familyModule) {
return familyModule.getWalletAPITransactionSignFlowInfos({ walletApiTransaction, account });
}
/**
* If we don't have an explicit implementation for this family, we fallback
* to just returning the transaction as is
* This is not ideal and could lead to unforseen issues since we can't make
* sure that what is received from the WalletAPI is compatible with the
* Ledger Live implementation of the family
* Not having an explicit WalletAPI adapter for a family should be considered
* an error and thorw an exception
*/
return {
canEditFees: false,
liveTx: { ...walletApiTransaction } as Partial<Transaction>,
hasFeesProvided: false,
};
};