diff --git a/.changeset/tidy-eagles-brand.md b/.changeset/tidy-eagles-brand.md new file mode 100644 index 000000000000..8ac0fc07c07d --- /dev/null +++ b/.changeset/tidy-eagles-brand.md @@ -0,0 +1,5 @@ +--- +"@ledgerhq/ledger-wallet-framework": minor +--- + +Add Zod branded `CryptoCurrencyId`/`TokenCurrencyId` types so a raw string can no longer be passed where a currency id is required without crossing an explicit validation boundary. diff --git a/apps/ledger-live-desktop/.oxlintrc.json b/apps/ledger-live-desktop/.oxlintrc.json index 1c3209e8d6dc..9af7dd44974f 100644 --- a/apps/ledger-live-desktop/.oxlintrc.json +++ b/apps/ledger-live-desktop/.oxlintrc.json @@ -22,20 +22,8 @@ "suspicious": "warn", "pedantic": "off" }, - "plugins": [ - "eslint", - "import", - "oxc", - "unicorn", - "typescript", - "react", - "jest" - ], - "ignorePatterns": [ - "*.min.js", - "src/mvvm/hooks/redux.ts", - "tests/artifacts/**" - ], + "plugins": ["eslint", "import", "oxc", "unicorn", "typescript", "react", "jest"], + "ignorePatterns": ["*.min.js", "src/mvvm/hooks/redux.ts", "tests/artifacts/**"], "rules": { "eslint/no-unused-vars": "warn", "eslint/no-empty-pattern": "warn", @@ -73,7 +61,11 @@ "Currency", "Unit", "FiatCurrency", - "ExplorerView" + "ExplorerView", + "CryptoCurrencyId", + "TokenCurrencyId", + "CryptoCurrencyIdSchema", + "TokenCurrencyIdSchema" ], "message": "Wallet-framework currency types are for coin-modules. Import from @domain/entity-currency-* (unions from @domain/entity-currency)." }, @@ -85,30 +77,26 @@ "Currency", "Unit", "FiatCurrency", - "ExplorerView" + "ExplorerView", + "CryptoCurrencyId", + "TokenCurrencyId", + "CryptoCurrencyIdSchema", + "TokenCurrencyIdSchema" ], "message": "Wallet-framework currency types are for coin-modules. Import from @domain/entity-currency-* (unions from @domain/entity-currency)." } ], "patterns": [ { - "group": [ - "@ledgerhq/live-common/lib/**", - "@ledgerhq/live-common/lib-es/**" - ], + "group": ["@ledgerhq/live-common/lib/**", "@ledgerhq/live-common/lib-es/**"], "message": "Please remove the /lib import from live-common import." }, { - "group": [ - "~/mvvm/**" - ], + "group": ["~/mvvm/**"], "message": "Use 'LLD' alias instead of '~/mvvm'. Replace '~/mvvm' with 'LLD' in your imports." }, { - "group": [ - "**/renderer/families/*/**", - "~/renderer/families/*/**" - ], + "group": ["**/renderer/families/*/**", "~/renderer/families/*/**"], "message": "families files must not be imported directly. use the bridge or export them through the LLDCoinFamily interface instead." }, { @@ -155,12 +143,10 @@ "env": { "jest": true }, - "plugins": [ - "jest" - ], + "plugins": ["jest"], "rules": { "typescript/no-explicit-any": "warn" } } ] -} \ No newline at end of file +} diff --git a/apps/ledger-live-mobile/.oxlintrc.json b/apps/ledger-live-mobile/.oxlintrc.json index 0a36d7a80713..b31d750df84e 100644 --- a/apps/ledger-live-mobile/.oxlintrc.json +++ b/apps/ledger-live-mobile/.oxlintrc.json @@ -14,16 +14,7 @@ "suspicious": "warn", "pedantic": "off" }, - "plugins": [ - "eslint", - "import", - "oxc", - "unicorn", - "typescript", - "react", - "jest", - "jsx-a11y" - ], + "plugins": ["eslint", "import", "oxc", "unicorn", "typescript", "react", "jest", "jsx-a11y"], "ignorePatterns": [ "*.min.js", "node_modules", @@ -41,10 +32,7 @@ "eslint/no-unused-expressions": "warn", "eslint/no-unsafe-optional-chaining": "off", "eslint/no-useless-rename": "warn", - "eslint/no-console": [ - "error", - { "allow": ["warn", "error"] } - ], + "eslint/no-console": ["error", { "allow": ["warn", "error"] }], "eslint/no-restricted-imports": [ "error", { @@ -73,7 +61,11 @@ "Currency", "Unit", "FiatCurrency", - "ExplorerView" + "ExplorerView", + "CryptoCurrencyId", + "TokenCurrencyId", + "CryptoCurrencyIdSchema", + "TokenCurrencyIdSchema" ], "message": "Wallet-framework currency types are for coin-modules. Import from @domain/entity-currency-* (unions from @domain/entity-currency)." }, @@ -85,17 +77,18 @@ "Currency", "Unit", "FiatCurrency", - "ExplorerView" + "ExplorerView", + "CryptoCurrencyId", + "TokenCurrencyId", + "CryptoCurrencyIdSchema", + "TokenCurrencyIdSchema" ], "message": "Wallet-framework currency types are for coin-modules. Import from @domain/entity-currency-* (unions from @domain/entity-currency)." } ], "patterns": [ { - "group": [ - "@ledgerhq/live-common/lib/**", - "@ledgerhq/live-common/lib-es/**" - ], + "group": ["@ledgerhq/live-common/lib/**", "@ledgerhq/live-common/lib-es/**"], "message": "Please remove the /lib import from live-common import." }, { @@ -159,11 +152,7 @@ }, "overrides": [ { - "files": [ - "**/*.test.{ts,tsx}", - "**/__tests__/**", - "e2e/**/*.{ts,tsx}" - ], + "files": ["**/*.test.{ts,tsx}", "**/__tests__/**", "e2e/**/*.{ts,tsx}"], "env": { "jest": true }, "plugins": ["jest"], "rules": { @@ -197,7 +186,11 @@ "Currency", "Unit", "FiatCurrency", - "ExplorerView" + "ExplorerView", + "CryptoCurrencyId", + "TokenCurrencyId", + "CryptoCurrencyIdSchema", + "TokenCurrencyIdSchema" ], "message": "Wallet-framework currency types are for coin-modules. Import from @domain/entity-currency-* (unions from @domain/entity-currency)." }, @@ -209,17 +202,18 @@ "Currency", "Unit", "FiatCurrency", - "ExplorerView" + "ExplorerView", + "CryptoCurrencyId", + "TokenCurrencyId", + "CryptoCurrencyIdSchema", + "TokenCurrencyIdSchema" ], "message": "Wallet-framework currency types are for coin-modules. Import from @domain/entity-currency-* (unions from @domain/entity-currency)." } ], "patterns": [ { - "group": [ - "@ledgerhq/live-common/lib/**", - "@ledgerhq/live-common/lib-es/**" - ], + "group": ["@ledgerhq/live-common/lib/**", "@ledgerhq/live-common/lib-es/**"], "message": "Please remove the /lib import from live-common import." }, { diff --git a/apps/ledger-live-mobile/src/mvvm/components/TopBar/__tests__/useTopBarViewModel.test.ts b/apps/ledger-live-mobile/src/mvvm/components/TopBar/__tests__/useTopBarViewModel.test.ts index a2588f5ce156..bc77b2a23611 100644 --- a/apps/ledger-live-mobile/src/mvvm/components/TopBar/__tests__/useTopBarViewModel.test.ts +++ b/apps/ledger-live-mobile/src/mvvm/components/TopBar/__tests__/useTopBarViewModel.test.ts @@ -1,4 +1,5 @@ import { renderHook, withReadOnlyDisabled, act } from "@tests/test-renderer"; +import { CryptoCurrencyIdSchema } from "@domain/entity-currency-crypto"; import { NavigatorName, ScreenName } from "~/const"; import { State } from "~/reducers/types"; import { track } from "~/analytics"; @@ -167,7 +168,10 @@ describe("useTopBarViewModel", () => { mockedUseSyncIndicator.mockReturnValue({ ...defaultSyncState, isError: true, - errorCurrencyIds: ["bitcoin", "ethereum"], + errorCurrencyIds: [ + CryptoCurrencyIdSchema.parse("bitcoin"), + CryptoCurrencyIdSchema.parse("ethereum"), + ], }); const { result } = renderHook(() => useTopBarViewModel(mockNavigation as never)); diff --git a/apps/wallet-cli/src/wallet/compatibility/coinframework.ts b/apps/wallet-cli/src/wallet/compatibility/coinframework.ts index 0b4ce899c0fc..9f1db61a8524 100644 --- a/apps/wallet-cli/src/wallet/compatibility/coinframework.ts +++ b/apps/wallet-cli/src/wallet/compatibility/coinframework.ts @@ -33,7 +33,7 @@ export class CoinFrameworkAdapter { const tokenAssets = balanceRes.filter(b => b.asset.type !== "native"); const tokenBalances = await Promise.all( - tokenAssets.map(async ({ asset, value }) => { + tokenAssets.map(async ({ asset, value }): Promise => { const token = await bridgeApi.getTokenFromAsset?.(asset); if (!token) return null; return { assetId: token.id, balance: BigNumberStrSchema.parse(String(value)) }; diff --git a/libs/coin-modules/coin-aleo/src/__tests__/fixtures/currency.fixture.ts b/libs/coin-modules/coin-aleo/src/__tests__/fixtures/currency.fixture.ts index 502f0d29d044..4a1d263deba5 100644 --- a/libs/coin-modules/coin-aleo/src/__tests__/fixtures/currency.fixture.ts +++ b/libs/coin-modules/coin-aleo/src/__tests__/fixtures/currency.fixture.ts @@ -1,11 +1,16 @@ -import type { CryptoCurrency, TokenCurrency } from "@ledgerhq/ledger-wallet-framework/types"; +import { + type CryptoCurrency, + type TokenCurrency, + CryptoCurrencyIdSchema, + TokenCurrencyIdSchema, +} from "@ledgerhq/ledger-wallet-framework/types"; export const MOCK_TOKEN_PROGRAM_ID = "usad_stablecoin.aleo"; export const getMockedCurrency = (overrides?: Partial): CryptoCurrency => { return { type: "CryptoCurrency", - id: "aleo", + id: CryptoCurrencyIdSchema.parse("aleo"), coinType: 683, name: "Aleo", managerAppName: "Aleo", @@ -33,9 +38,9 @@ export const getMockedCurrency = (overrides?: Partial): CryptoCu export const getMockedTokenCurrency = (overrides?: Partial): TokenCurrency => { return { type: "TokenCurrency", - id: "usad", + id: TokenCurrencyIdSchema.parse("usad"), contractAddress: MOCK_TOKEN_PROGRAM_ID, - parentCurrencyId: "aleo", + parentCurrencyId: CryptoCurrencyIdSchema.parse("aleo"), tokenType: "arc22", name: "USAD", ticker: "USAD", diff --git a/libs/coin-modules/coin-aleo/src/bridge/tokens.test.ts b/libs/coin-modules/coin-aleo/src/bridge/tokens.test.ts index b2e96be465dd..d0dac7b3749e 100644 --- a/libs/coin-modules/coin-aleo/src/bridge/tokens.test.ts +++ b/libs/coin-modules/coin-aleo/src/bridge/tokens.test.ts @@ -1,6 +1,7 @@ import BigNumber from "bignumber.js"; import type { TokenAccount } from "@ledgerhq/types-live"; import { setCryptoAssetsStore } from "@ledgerhq/ledger-wallet-framework/cryptoAssetsStore"; +import { TokenCurrencyIdSchema } from "@ledgerhq/ledger-wallet-framework/types"; import { encodeTokenAccountId } from "@ledgerhq/ledger-wallet-framework/account"; import { encodeAccountId } from "@ledgerhq/ledger-wallet-framework/account/accountId"; import { encodeOperationId } from "@ledgerhq/ledger-wallet-framework/operation"; @@ -270,7 +271,10 @@ describe("tokens utils", () => { it("should append sub-accounts that do not exist on the initial account", () => { const existingSubAccount = getMockedTokenAccount(mockTokenCurrency); - const newToken = getMockedTokenCurrency({ id: "other-token", contractAddress: "other.aleo" }); + const newToken = getMockedTokenCurrency({ + id: TokenCurrencyIdSchema.parse("other-token"), + contractAddress: "other.aleo", + }); const newSubAccount = getMockedTokenAccount(newToken); const initialAccount = getMockedAccount({ subAccounts: [existingSubAccount] }); diff --git a/libs/coin-modules/coin-aleo/src/logic/listOperations.test.ts b/libs/coin-modules/coin-aleo/src/logic/listOperations.test.ts index f692fbeb9bcc..bd76bbfa14bf 100644 --- a/libs/coin-modules/coin-aleo/src/logic/listOperations.test.ts +++ b/libs/coin-modules/coin-aleo/src/logic/listOperations.test.ts @@ -1,4 +1,5 @@ import { fetchAccountTransactionsFromHeight } from "../network/utils"; +import { TokenCurrencyIdSchema } from "@ledgerhq/ledger-wallet-framework/types"; import { getMockedTransaction } from "../__tests__/fixtures/api.fixture"; import { getMockedConfig } from "../__tests__/fixtures/config.fixture"; import { @@ -213,7 +214,7 @@ describe("listOperations", () => { it("should include multiple token operations when several CAL tokens are present", async () => { const secondProgramId = "usad_stablecoin.aleo"; const secondTokenCurrency = getMockedTokenCurrency({ - id: "aleo/token/usad_stablecoin.aleo", + id: TokenCurrencyIdSchema.parse("aleo/token/usad_stablecoin.aleo"), contractAddress: secondProgramId, ticker: "USAD", }); diff --git a/libs/coin-modules/coin-algorand/src/deviceTransactionConfig.ts b/libs/coin-modules/coin-algorand/src/deviceTransactionConfig.ts index 4753016bd9e7..6315f373aa8c 100644 --- a/libs/coin-modules/coin-algorand/src/deviceTransactionConfig.ts +++ b/libs/coin-modules/coin-algorand/src/deviceTransactionConfig.ts @@ -2,7 +2,7 @@ import { formatCurrencyUnit } from "@ledgerhq/coin-module-framework/currencies"; import { getCryptoAssetsStore } from "@ledgerhq/ledger-wallet-framework/cryptoAssetsStore"; import { getAccountCurrency } from "@ledgerhq/ledger-wallet-framework/account"; import type { CommonDeviceTransactionField as DeviceTransactionField } from "@ledgerhq/ledger-wallet-framework/transaction/common"; -import { TokenCurrency } from "@ledgerhq/ledger-wallet-framework/types"; +import type { TokenCurrency } from "@ledgerhq/ledger-wallet-framework/types"; import { AccountLike } from "@ledgerhq/types-live"; import { extractTokenId } from "./tokens"; import type { AlgorandTransaction, Transaction, TransactionStatus } from "./types"; diff --git a/libs/coin-modules/coin-aptos/src/__tests__/bridge/logic.test.ts b/libs/coin-modules/coin-aptos/src/__tests__/bridge/logic.test.ts index 68a958c56267..4d9274fcf956 100644 --- a/libs/coin-modules/coin-aptos/src/__tests__/bridge/logic.test.ts +++ b/libs/coin-modules/coin-aptos/src/__tests__/bridge/logic.test.ts @@ -1,5 +1,9 @@ import { EntryFunctionPayloadResponse } from "@aptos-labs/ts-sdk"; import { setCryptoAssetsStore } from "@ledgerhq/ledger-wallet-framework/cryptoAssetsStore"; +import { + TokenCurrencyIdSchema, + CryptoCurrencyIdSchema, +} from "@ledgerhq/ledger-wallet-framework/types"; import { decodeTokenAccountId, encodeTokenAccountId, @@ -462,9 +466,9 @@ describe("Aptos sync logic", () => { if (address === "0xd111::staked_coin::stakedaptos") { return { type: "TokenCurrency" as const, - id: "aptos/coin/dstapt::staked_coin::stakedaptos", + id: TokenCurrencyIdSchema.parse("aptos/coin/dstapt::staked_coin::stakedaptos"), contractAddress: "0xd111::staked_coin::StakedAptos", - parentCurrencyId: "aptos", + parentCurrencyId: CryptoCurrencyIdSchema.parse("aptos"), name: "dstAPT", tokenType: "coin", ticker: "dstAPT", @@ -746,9 +750,11 @@ describe("Aptos sync logic", () => { if (address === "0x2ebb") { return { type: "TokenCurrency" as const, - id: "aptos/fungible_asset/cellana_0x2ebb2ccac5e027a87fa0e2e5f656a3a4238d6a48d93ec9b610d570fc0aa0df12", + id: TokenCurrencyIdSchema.parse( + "aptos/fungible_asset/cellana_0x2ebb2ccac5e027a87fa0e2e5f656a3a4238d6a48d93ec9b610d570fc0aa0df12", + ), contractAddress: "0x2ebb", - parentCurrencyId: "aptos", + parentCurrencyId: CryptoCurrencyIdSchema.parse("aptos"), name: "CELLANA", tokenType: "fungible_asset", ticker: "CELL", diff --git a/libs/coin-modules/coin-aptos/src/__tests__/bridge/synchronisation.test.ts b/libs/coin-modules/coin-aptos/src/__tests__/bridge/synchronisation.test.ts index a20c1a3c6726..6f3382eae06f 100644 --- a/libs/coin-modules/coin-aptos/src/__tests__/bridge/synchronisation.test.ts +++ b/libs/coin-modules/coin-aptos/src/__tests__/bridge/synchronisation.test.ts @@ -3,7 +3,12 @@ import { decodeTokenAccountId } from "@ledgerhq/ledger-wallet-framework/account" import { emptyHistoryCache } from "@ledgerhq/ledger-wallet-framework/account/index"; import { AccountShapeInfo, mergeOps } from "@ledgerhq/ledger-wallet-framework/bridge/jsHelpers"; import { getEnv } from "@ledgerhq/live-env"; -import { CryptoCurrency, TokenCurrency } from "@ledgerhq/ledger-wallet-framework/types"; +import { + CryptoCurrency, + TokenCurrency, + TokenCurrencyIdSchema, + CryptoCurrencyIdSchema, +} from "@ledgerhq/ledger-wallet-framework/types"; import { Operation, SyncConfig, TokenAccount } from "@ledgerhq/types-live"; import BigNumber from "bignumber.js"; import { createFixtureAccount } from "../../bridge/bridge.fixture"; @@ -816,9 +821,9 @@ describe("getAccountShape", () => { mockedDecodeTokenAccountId.mockResolvedValue({ token: { type: "TokenCurrency", - id: "aptos/coin/dstapt_0xd111::staked_coin::stakedaptos", + id: TokenCurrencyIdSchema.parse("aptos/coin/dstapt_0xd111::staked_coin::stakedaptos"), contractAddress: "0xd111::staked_coin::StakedAptos", - parentCurrencyId: "aptos", + parentCurrencyId: CryptoCurrencyIdSchema.parse("aptos"), name: "dstAPT", tokenType: "coin", ticker: "dstAPT", @@ -1341,9 +1346,9 @@ describe("getSubAccounts", () => { mockedDecodeTokenAccountId.mockResolvedValue({ token: { type: "TokenCurrency", - id: "aptos/coin/dstapt_0xd111::staked_coin::stakedaptos", + id: TokenCurrencyIdSchema.parse("aptos/coin/dstapt_0xd111::staked_coin::stakedaptos"), contractAddress: "0xd111::staked_coin::StakedAptos", - parentCurrencyId: "aptos", + parentCurrencyId: CryptoCurrencyIdSchema.parse("aptos"), name: "dstAPT", tokenType: "coin", ticker: "dstAPT", @@ -1917,9 +1922,9 @@ describe("getStake", () => { mockedDecodeTokenAccountId.mockResolvedValue({ token: { type: "TokenCurrency", - id: "aptos/coin/dstapt_0xd111::staked_coin::stakedaptos", + id: TokenCurrencyIdSchema.parse("aptos/coin/dstapt_0xd111::staked_coin::stakedaptos"), contractAddress: "0xd111::staked_coin::StakedAptos", - parentCurrencyId: "aptos", + parentCurrencyId: CryptoCurrencyIdSchema.parse("aptos"), name: "dstAPT", tokenType: "coin", ticker: "dstAPT", diff --git a/libs/coin-modules/coin-bitcoin/src/logic.ts b/libs/coin-modules/coin-bitcoin/src/logic.ts index cb9c3a2cca8f..c9a497ac9ac4 100644 --- a/libs/coin-modules/coin-bitcoin/src/logic.ts +++ b/libs/coin-modules/coin-bitcoin/src/logic.ts @@ -13,11 +13,11 @@ import { $Shape } from "utility-types"; import type { TX, Input as WalletInput, Output as WalletOutput } from "@ledgerhq/wallet-btc/index"; import { BigNumber } from "bignumber.js"; import { encodeOperationId } from "@ledgerhq/ledger-wallet-framework/operation"; -import type { CryptoCurrency, CryptoCurrencyId } from "@ledgerhq/ledger-wallet-framework/types"; +import type { CryptoCurrency } from "@ledgerhq/ledger-wallet-framework/types"; import type { Account, OperationType } from "@ledgerhq/types-live"; // correspond ~ to min relay fees but determined empirically for a tx to be accepted by network -const minFees: Partial> = { +const minFees: Partial> = { bitcoin: 1000, bitcoin_gold: 1000, qtum: 4000, @@ -117,9 +117,7 @@ type CoinLogic = { export const bchToCashaddrAddressWithoutPrefix = (recipient: string): string => recipient ? recipient.substring(recipient.indexOf(":") + 1) : recipient; -export const perCoinLogic: Partial< - Record -> = { +export const perCoinLogic: Partial> = { zencash: { hasExtraData: true, // FIXME (legacy) investigate why we need this here and drop }, @@ -192,7 +190,7 @@ export function inferTransactionSequenceNumberFromInputs( export const mapTxToOperations = ( tx: TX, - currencyId: CryptoCurrencyId | "LBRY" | "groestcoin" | "osmo", + currencyId: string, accountId: string, accountAddresses: Set, changeAddresses: Set, diff --git a/libs/coin-modules/coin-canton/src/bridge/buildSubAccounts.test.ts b/libs/coin-modules/coin-canton/src/bridge/buildSubAccounts.test.ts index 7603db12954a..64666c4058bd 100644 --- a/libs/coin-modules/coin-canton/src/bridge/buildSubAccounts.test.ts +++ b/libs/coin-modules/coin-canton/src/bridge/buildSubAccounts.test.ts @@ -1,4 +1,8 @@ -import { TokenCurrency } from "@ledgerhq/ledger-wallet-framework/types"; +import { + TokenCurrency, + TokenCurrencyIdSchema, + CryptoCurrencyIdSchema, +} from "@ledgerhq/ledger-wallet-framework/types"; import type { Operation } from "@ledgerhq/types-live"; import BigNumber from "bignumber.js"; import type { TransferProposal } from "../network/gateway"; @@ -7,9 +11,9 @@ import { buildSubAccounts, CantonTokenAccount } from "./buildSubAccounts"; const makeTokenCurrency = (overrides: Partial = {}): TokenCurrency => { return { type: "TokenCurrency", - id: overrides.id ?? "canton_network/cip56/TOKEN_A", + id: overrides.id ?? TokenCurrencyIdSchema.parse("canton_network/cip56/TOKEN_A"), contractAddress: overrides.contractAddress ?? "admin-TOKEN_A", - parentCurrencyId: overrides.parentCurrencyId ?? "canton_network", + parentCurrencyId: overrides.parentCurrencyId ?? CryptoCurrencyIdSchema.parse("canton_network"), tokenType: "canton", name: overrides.name ?? "Token A", ticker: overrides.ticker ?? "TOKA", diff --git a/libs/coin-modules/coin-canton/src/test/fixtures.ts b/libs/coin-modules/coin-canton/src/test/fixtures.ts index 704c8fdc36c9..b48a3277e368 100644 --- a/libs/coin-modules/coin-canton/src/test/fixtures.ts +++ b/libs/coin-modules/coin-canton/src/test/fixtures.ts @@ -5,7 +5,7 @@ import { } from "@ledgerhq/ledger-wallet-framework/account"; import { SignerContext } from "@ledgerhq/ledger-wallet-framework/signer"; import prepareTransferMock from "@ledgerhq/hw-app-canton/tests/fixtures/prepare-transfer.json"; -import { CryptoCurrency } from "@ledgerhq/ledger-wallet-framework/types"; +import { CryptoCurrency, CryptoCurrencyIdSchema } from "@ledgerhq/ledger-wallet-framework/types"; import type { Account } from "@ledgerhq/types-live"; import BigNumber from "bignumber.js"; import coinConfig, { type CantonCoinConfig } from "../config"; @@ -48,7 +48,7 @@ export function createFactory(defaults: T) { export const createMockCantonCurrency = (): CryptoCurrency => { const mockCurrency = { - id: "canton_network", + id: CryptoCurrencyIdSchema.parse("canton_network"), name: "Canton", type: "CryptoCurrency", family: "canton", diff --git a/libs/coin-modules/coin-cardano/src/buildSubAccounts.unit.test.ts b/libs/coin-modules/coin-cardano/src/buildSubAccounts.unit.test.ts index 44e2039ceea3..78d698bf3bef 100644 --- a/libs/coin-modules/coin-cardano/src/buildSubAccounts.unit.test.ts +++ b/libs/coin-modules/coin-cardano/src/buildSubAccounts.unit.test.ts @@ -1,5 +1,10 @@ import { setCryptoAssetsStore } from "@ledgerhq/ledger-wallet-framework/cryptoAssetsStore"; import type { CryptoCurrency, TokenCurrency } from "@ledgerhq/ledger-wallet-framework/types"; +import { + TokenCurrencyIdSchema, + CryptoCurrencyIdSchema, +} from "@ledgerhq/ledger-wallet-framework/types"; + import BigNumber from "bignumber.js"; import { APITransaction } from "./api/api-types"; @@ -22,9 +27,9 @@ const parentCurrency = { id: PARENT_CURRENCY_ID } as CryptoCurrency; const tokenCurrency: TokenCurrency = { type: "TokenCurrency", - id: TOKEN_CURRENCY_ID, + id: TokenCurrencyIdSchema.parse(TOKEN_CURRENCY_ID), contractAddress: POLICY_ID, - parentCurrency, + parentCurrencyId: CryptoCurrencyIdSchema.parse(PARENT_CURRENCY_ID), tokenType: "native", name: "Test Token", ticker: "TEST", diff --git a/libs/coin-modules/coin-celo/src/bridge/syncHelpers.test.ts b/libs/coin-modules/coin-celo/src/bridge/syncHelpers.test.ts index 89b36d037c5a..a82ac58366ac 100644 --- a/libs/coin-modules/coin-celo/src/bridge/syncHelpers.test.ts +++ b/libs/coin-modules/coin-celo/src/bridge/syncHelpers.test.ts @@ -1,7 +1,11 @@ import { getCryptoCurrencyById } from "@ledgerhq/ledger-wallet-framework/currencies"; import { getSyncHash as baseGetSyncHash } from "@ledgerhq/ledger-wallet-framework/account/sync"; import { getEnv, setEnv } from "@ledgerhq/live-env"; -import type { TokenCurrency, CryptoCurrencyId } from "@ledgerhq/ledger-wallet-framework/types"; +import { + CryptoCurrencyIdSchema, + type TokenCurrency, + type CryptoCurrencyId, +} from "@ledgerhq/ledger-wallet-framework/types"; import BigNumber from "bignumber.js"; import { getCoinConfig } from "@ledgerhq/coin-evm/config"; import { makeAccount, makeOperation, makeTokenAccount } from "./syncHelpers.fixtures"; @@ -317,7 +321,7 @@ describe("Celo sync helpers", () => { it("should provide a new hash if currency is using a new node config", async () => { const hash1 = await getSyncHash({ ...currency, - id: "celo", + id: CryptoCurrencyIdSchema.parse("celo"), ethereumLikeInfo: { chainId: 42220 }, }); const hash2 = await getSyncHash({ @@ -345,7 +349,7 @@ describe("Celo sync helpers", () => { it("should provide a new hash if currency is using a new explorer config", async () => { const hash1 = await getSyncHash({ ...currency, - id: "celo", + id: CryptoCurrencyIdSchema.parse("celo"), }); const hash2 = await getSyncHash({ ...currency, diff --git a/libs/coin-modules/coin-celo/src/bridge/synchronisation.integ.test.ts b/libs/coin-modules/coin-celo/src/bridge/synchronisation.integ.test.ts index 2e64cb6fba08..a1db527c3e1a 100644 --- a/libs/coin-modules/coin-celo/src/bridge/synchronisation.integ.test.ts +++ b/libs/coin-modules/coin-celo/src/bridge/synchronisation.integ.test.ts @@ -1,7 +1,6 @@ import { setCoinConfig, EvmCoinConfig } from "@ledgerhq/coin-evm/config"; import { getCryptoCurrencyById } from "@ledgerhq/ledger-wallet-framework/currencies"; import { setCryptoAssetsStore } from "@ledgerhq/ledger-wallet-framework/cryptoAssetsStore"; -import type { CryptoAssetsStore } from "@ledgerhq/types-live"; import BigNumber from "bignumber.js"; import { getAccountShape } from "./synchronisation"; @@ -24,7 +23,7 @@ describe("Integration — getAccountShape with real implementations", () => { findTokenById: async () => undefined, findTokenByAddressInCurrency: async () => undefined, getTokensSyncHash: async () => "0", - } as CryptoAssetsStore); + }); setCoinConfig( () => diff --git a/libs/coin-modules/coin-concordium/src/test/testHelpers.ts b/libs/coin-modules/coin-concordium/src/test/testHelpers.ts index 9ae4b4b182e0..fbc181eaa2d4 100644 --- a/libs/coin-modules/coin-concordium/src/test/testHelpers.ts +++ b/libs/coin-modules/coin-concordium/src/test/testHelpers.ts @@ -7,6 +7,7 @@ import type { AccountLike, Account } from "@ledgerhq/types-live"; import BigNumber from "bignumber.js"; +import { CryptoCurrencyIdSchema } from "@ledgerhq/ledger-wallet-framework/types"; import type { Transaction, TransactionStatus } from "../types"; /** @@ -201,7 +202,7 @@ export function createTestCryptoCurrency( ): import("@ledgerhq/ledger-wallet-framework/types").CryptoCurrency { return { type: "CryptoCurrency", - id: "concordium_testnet", + id: CryptoCurrencyIdSchema.parse("concordium_testnet"), coinType: 919, name: "Concordium", managerAppName: "Concordium", diff --git a/libs/coin-modules/coin-evm/src/logic/estimateFees.test.ts b/libs/coin-modules/coin-evm/src/logic/estimateFees.test.ts index 40099e1ae624..12eb076186ba 100644 --- a/libs/coin-modules/coin-evm/src/logic/estimateFees.test.ts +++ b/libs/coin-modules/coin-evm/src/logic/estimateFees.test.ts @@ -5,7 +5,7 @@ import type { SendTransactionIntent, TransactionIntent, } from "@ledgerhq/coin-module-framework/api/index"; -import { CryptoCurrency } from "@ledgerhq/ledger-wallet-framework/types"; +import { CryptoCurrency, CryptoCurrencyIdSchema } from "@ledgerhq/ledger-wallet-framework/types"; import BigNumber from "bignumber.js"; import { EvmCoinConfig, setCoinConfig } from "../config"; import { GasEstimationError } from "../errors"; @@ -392,7 +392,11 @@ describe("estimateFees", () => { nodeApiMock.getOptimismAdditionalFees.mockResolvedValue(new BigNumber(8000)); const result = await estimateFees( - { ...mockCurrency, id: "optimism", ethereumLikeInfo: { chainId: 10 } }, + { + ...mockCurrency, + id: CryptoCurrencyIdSchema.parse("optimism"), + ethereumLikeInfo: { chainId: 10 }, + }, { intentType: "transaction", type: "send-legacy", @@ -430,7 +434,11 @@ describe("estimateFees", () => { nodeApiMock.getOptimismAdditionalFees.mockResolvedValue(new BigNumber(8000)); const result = await estimateFees( - { ...mockCurrency, id: "optimism", ethereumLikeInfo: { chainId: 10 } }, + { + ...mockCurrency, + id: CryptoCurrencyIdSchema.parse("optimism"), + ethereumLikeInfo: { chainId: 10 }, + }, { intentType: "transaction", type: "send-legacy", @@ -477,7 +485,11 @@ describe("estimateFees", () => { amount: 1000000n, }; const result = await estimateFees( - { ...mockCurrency, id: "sei_evm", ethereumLikeInfo: { chainId: 1329 } }, + { + ...mockCurrency, + id: CryptoCurrencyIdSchema.parse("sei_evm"), + ethereumLikeInfo: { chainId: 1329 }, + }, tokenIntent, ); expect(result).toEqual({ @@ -514,7 +526,11 @@ describe("estimateFees", () => { useAllAmount: true, }; const result = await estimateFees( - { ...mockCurrency, id: "sei_evm", ethereumLikeInfo: { chainId: 1329 } }, + { + ...mockCurrency, + id: CryptoCurrencyIdSchema.parse("sei_evm"), + ethereumLikeInfo: { chainId: 1329 }, + }, delegateMaxIntent, ); expect(result.parameters).toMatchObject({ @@ -535,7 +551,11 @@ describe("estimateFees", () => { }; const result = await estimateFees( - { ...mockCurrency, id: "sei_evm", ethereumLikeInfo: { chainId: 1329 } }, + { + ...mockCurrency, + id: CryptoCurrencyIdSchema.parse("sei_evm"), + ethereumLikeInfo: { chainId: 1329 }, + }, redelegateNoDst, ); @@ -565,7 +585,11 @@ describe("estimateFees", () => { amount: 1000000n, }; const result = await estimateFees( - { ...mockCurrency, id: "sei_evm", ethereumLikeInfo: { chainId: 1329 } }, + { + ...mockCurrency, + id: CryptoCurrencyIdSchema.parse("sei_evm"), + ethereumLikeInfo: { chainId: 1329 }, + }, tokenIntent, ); expect(result).toEqual({ diff --git a/libs/coin-modules/coin-evm/src/network/explorer/ledger.test.ts b/libs/coin-modules/coin-evm/src/network/explorer/ledger.test.ts index 8642067c5d31..9b631889b6a9 100644 --- a/libs/coin-modules/coin-evm/src/network/explorer/ledger.test.ts +++ b/libs/coin-modules/coin-evm/src/network/explorer/ledger.test.ts @@ -1,7 +1,7 @@ import { AssertionError, fail } from "assert"; import { getEnv, setEnv } from "@ledgerhq/live-env"; import { delay } from "@ledgerhq/live-promise"; -import { CryptoCurrency } from "@ledgerhq/ledger-wallet-framework/types"; +import { CryptoCurrency, CryptoCurrencyIdSchema } from "@ledgerhq/ledger-wallet-framework/types"; import axios from "axios"; import eip55 from "eip55"; import { getCoinConfig } from "../../config"; @@ -21,7 +21,7 @@ jest.mock("@ledgerhq/live-promise"); ); const fakeCurrency = Object.freeze>({ - id: "ethereum", + id: CryptoCurrencyIdSchema.parse("ethereum"), ethereumLikeInfo: { chainId: 1, }, diff --git a/libs/coin-modules/coin-evm/src/network/gasTracker/ledger.test.ts b/libs/coin-modules/coin-evm/src/network/gasTracker/ledger.test.ts index c7cf081d38a0..5b7d8966c4d7 100644 --- a/libs/coin-modules/coin-evm/src/network/gasTracker/ledger.test.ts +++ b/libs/coin-modules/coin-evm/src/network/gasTracker/ledger.test.ts @@ -1,7 +1,7 @@ import { AssertionError } from "assert"; import { getEnv, setEnv } from "@ledgerhq/live-env"; import network from "@ledgerhq/live-network/network"; -import { CryptoCurrency } from "@ledgerhq/ledger-wallet-framework/types"; +import { CryptoCurrency, CryptoCurrencyIdSchema } from "@ledgerhq/ledger-wallet-framework/types"; import BigNumber from "bignumber.js"; import { getCoinConfig } from "../../config"; import { LedgerGasTrackerUsedIncorrectly, NoGasTrackerFound } from "../../errors"; @@ -12,7 +12,7 @@ jest.mock("@ledgerhq/live-network/network"); const mockedNetwork = jest.mocked(network); const fakeCurrency: Partial = { - id: "ethereum", + id: CryptoCurrencyIdSchema.parse("ethereum"), ethereumLikeInfo: { chainId: 1, }, diff --git a/libs/coin-modules/coin-evm/src/network/node/ledger.test.ts b/libs/coin-modules/coin-evm/src/network/node/ledger.test.ts index f4aae5877a54..1ecdac1c079d 100644 --- a/libs/coin-modules/coin-evm/src/network/node/ledger.test.ts +++ b/libs/coin-modules/coin-evm/src/network/node/ledger.test.ts @@ -1,7 +1,7 @@ import { AssertionError, fail } from "assert"; import { getCryptoCurrencyById } from "@ledgerhq/ledger-wallet-framework/currencies"; import { delay } from "@ledgerhq/live-promise"; -import { CryptoCurrency } from "@ledgerhq/ledger-wallet-framework/types"; +import { CryptoCurrency, CryptoCurrencyIdSchema } from "@ledgerhq/ledger-wallet-framework/types"; import axios from "axios"; import BigNumber from "bignumber.js"; import { Transaction } from "ethers"; @@ -613,7 +613,7 @@ describe("EVM Family", () => { expect( await api.getOptimismAdditionalFees( - { ...currency, id: "optimism" }, + { ...currency, id: CryptoCurrencyIdSchema.parse("optimism") }, transaction.serialized, ), ).toEqual(new BigNumber("100000000")); @@ -657,7 +657,10 @@ describe("EVM Family", () => { }); expect( - await api.getScrollAdditionalFees({ ...currency, id: "scroll" }, transaction.serialized), + await api.getScrollAdditionalFees( + { ...currency, id: CryptoCurrencyIdSchema.parse("scroll") }, + transaction.serialized, + ), ).toEqual(new BigNumber("100000000")); }); }); diff --git a/libs/coin-modules/coin-hedera/src/bridge/utils.test.ts b/libs/coin-modules/coin-hedera/src/bridge/utils.test.ts index e16cf4896dc1..dd086d4adb5f 100644 --- a/libs/coin-modules/coin-hedera/src/bridge/utils.test.ts +++ b/libs/coin-modules/coin-hedera/src/bridge/utils.test.ts @@ -1,6 +1,7 @@ import { setCryptoAssetsStore } from "@ledgerhq/ledger-wallet-framework/cryptoAssetsStore"; import { encodeTokenAccountId } from "@ledgerhq/ledger-wallet-framework/account"; import { encodeOperationId } from "@ledgerhq/ledger-wallet-framework/operation"; +import { TokenCurrencyIdSchema } from "@ledgerhq/ledger-wallet-framework/types"; import BigNumber from "bignumber.js"; import { getMockedAccount, getMockedTokenAccount } from "../test/fixtures/account.fixture"; import { @@ -67,8 +68,12 @@ describe("bridge utils", () => { describe("mergeSubAccounts", () => { it("returns newSubAccounts if no initial account exists", () => { - const mockedTokenCurrency1 = getMockedHTSTokenCurrency({ id: "token1" }); - const mockedTokenCurrency2 = getMockedHTSTokenCurrency({ id: "token2" }); + const mockedTokenCurrency1 = getMockedHTSTokenCurrency({ + id: TokenCurrencyIdSchema.parse("token1"), + }); + const mockedTokenCurrency2 = getMockedHTSTokenCurrency({ + id: TokenCurrencyIdSchema.parse("token2"), + }); const mockedTokenAccount1 = getMockedTokenAccount(mockedTokenCurrency1, { id: "ta1" }); const mockedTokenAccount2 = getMockedTokenAccount(mockedTokenCurrency2, { id: "ta2" }); const initialAccount = undefined; @@ -112,8 +117,10 @@ describe("bridge utils", () => { }); it("adds new sub accounts that are not present in initial account", () => { - const existingToken = getMockedHTSTokenCurrency({ id: "token1" }); - const newToken = getMockedHTSTokenCurrency({ id: "token2" }); + const existingToken = getMockedHTSTokenCurrency({ + id: TokenCurrencyIdSchema.parse("token1"), + }); + const newToken = getMockedHTSTokenCurrency({ id: TokenCurrencyIdSchema.parse("token2") }); const existingTokenAccount = getMockedTokenAccount(existingToken, { id: "ta1" }); const newTokenAccount = getMockedTokenAccount(newToken, { id: "ta2" }); const mockedAccount = getMockedAccount({ subAccounts: [existingTokenAccount] }); diff --git a/libs/coin-modules/coin-hedera/src/logic/listOperations.v2.test.ts b/libs/coin-modules/coin-hedera/src/logic/listOperations.v2.test.ts index 2fcf4083173c..b065645ae744 100644 --- a/libs/coin-modules/coin-hedera/src/logic/listOperations.v2.test.ts +++ b/libs/coin-modules/coin-hedera/src/logic/listOperations.v2.test.ts @@ -1,6 +1,7 @@ import { setCryptoAssetsStore } from "@ledgerhq/ledger-wallet-framework/cryptoAssetsStore"; import { encodeTokenAccountId } from "@ledgerhq/ledger-wallet-framework/account/accountId"; import { encodeOperationId } from "@ledgerhq/ledger-wallet-framework/operation"; +import { TokenCurrencyIdSchema } from "@ledgerhq/ledger-wallet-framework/types"; import { getEnv } from "@ledgerhq/live-env"; import BigNumber from "bignumber.js"; import { apiClient } from "../network/api"; @@ -1207,11 +1208,11 @@ describe("listOperationsV2", () => { it("should produce two token operations for a swap with two different-token transfers", async () => { const sharedHash = "erc20-in-transfer-hash"; const mockTokenA = getMockedERC20TokenCurrency({ - id: "hedera/erc20/0xTokenA", + id: TokenCurrencyIdSchema.parse("hedera/erc20/0xTokenA"), contractAddress: "0xTokenA", }); const mockTokenB = getMockedERC20TokenCurrency({ - id: "hedera/erc20/0xTokenB", + id: TokenCurrencyIdSchema.parse("hedera/erc20/0xTokenB"), contractAddress: "0xTokenB", }); diff --git a/libs/coin-modules/coin-hedera/src/preload-data.test.ts b/libs/coin-modules/coin-hedera/src/preload-data.test.ts index 333c2fa53a3a..d4734cc4e2c8 100644 --- a/libs/coin-modules/coin-hedera/src/preload-data.test.ts +++ b/libs/coin-modules/coin-hedera/src/preload-data.test.ts @@ -1,4 +1,5 @@ import { getCryptoCurrencyById } from "@ledgerhq/ledger-wallet-framework/currencies"; +import { CryptoCurrencyIdSchema } from "@ledgerhq/ledger-wallet-framework/types"; import { getCurrentHederaPreloadData, getHederaPreloadData, @@ -32,7 +33,10 @@ describe("preload-data", () => { }); it("should throw for unsupported currency", () => { - const unsupportedCurrency = getMockedCurrency({ id: "bitcoin", family: "bitcoin" }); + const unsupportedCurrency = getMockedCurrency({ + id: CryptoCurrencyIdSchema.parse("bitcoin"), + family: "bitcoin", + }); expect(() => getCurrentHederaPreloadData(unsupportedCurrency)).toThrow( "unsupported currency bitcoin", @@ -52,7 +56,10 @@ describe("preload-data", () => { }); it("should throw for unsupported currency", () => { - const unsupportedCurrency = getMockedCurrency({ id: "bitcoin", family: "bitcoin" }); + const unsupportedCurrency = getMockedCurrency({ + id: CryptoCurrencyIdSchema.parse("bitcoin"), + family: "bitcoin", + }); expect(() => getHederaPreloadData(unsupportedCurrency)).toThrow( "unsupported currency bitcoin", @@ -62,7 +69,10 @@ describe("preload-data", () => { describe("setHederaPreloadData", () => { it("should throw for unsupported currency", () => { - const unsupportedCurrency = getMockedCurrency({ id: "bitcoin", family: "bitcoin" }); + const unsupportedCurrency = getMockedCurrency({ + id: CryptoCurrencyIdSchema.parse("bitcoin"), + family: "bitcoin", + }); expect(() => setHederaPreloadData({ validators: [] }, unsupportedCurrency)).toThrow( "unsupported currency bitcoin", diff --git a/libs/coin-modules/coin-hedera/src/test/fixtures/currency.fixture.ts b/libs/coin-modules/coin-hedera/src/test/fixtures/currency.fixture.ts index f3cf11e6b008..fcf8f3eca364 100644 --- a/libs/coin-modules/coin-hedera/src/test/fixtures/currency.fixture.ts +++ b/libs/coin-modules/coin-hedera/src/test/fixtures/currency.fixture.ts @@ -1,10 +1,14 @@ import type { CryptoCurrency, TokenCurrency } from "@ledgerhq/ledger-wallet-framework/types"; +import { + CryptoCurrencyIdSchema, + TokenCurrencyIdSchema, +} from "@ledgerhq/ledger-wallet-framework/types"; import invariant from "invariant"; export const getMockedCurrency = (overrides?: Partial): CryptoCurrency => { return { type: "CryptoCurrency", - id: "hedera", + id: CryptoCurrencyIdSchema.parse("hedera"), managerAppName: "Hedera", coinType: 3030, scheme: "hedera", @@ -29,61 +33,47 @@ export const getMockedCurrency = (overrides?: Partial): CryptoCu }; }; +const makeHederaToken = (params: { + id: string; + contractAddress: string; + tokenType: "hts" | "erc20"; + name: string; + ticker: string; +}): TokenCurrency => ({ + type: "TokenCurrency", + id: TokenCurrencyIdSchema.parse(params.id), + contractAddress: params.contractAddress, + parentCurrencyId: CryptoCurrencyIdSchema.parse("hedera"), + tokenType: params.tokenType, + name: params.name, + ticker: params.ticker, + delisted: false, + disableCountervalue: false, + units: [{ name: params.ticker, code: params.ticker, magnitude: 6 }], +}); + const HARDCODED_HEDERA_TOKENS: TokenCurrency[] = [ - { - type: "TokenCurrency", + makeHederaToken({ id: "hedera/hts/usd_coin_0.0.456858", contractAddress: "0.0.456858", - parentCurrencyId: "hedera", tokenType: "hts", name: "USD Coin", ticker: "USDC", - delisted: false, - disableCountervalue: false, - units: [ - { - name: "USDC", - code: "USDC", - magnitude: 6, - }, - ], - }, - { - type: "TokenCurrency", + }), + makeHederaToken({ id: "hedera/hts/xpack_0.0.7243470", contractAddress: "0.0.7243470", - parentCurrencyId: "hedera", tokenType: "hts", name: "xPACK", ticker: "XPACK", - delisted: false, - disableCountervalue: false, - units: [ - { - name: "XPACK", - code: "XPACK", - magnitude: 6, - }, - ], - }, - { - type: "TokenCurrency", + }), + makeHederaToken({ id: "hedera/erc20/audd_0x39ceba2b467fa987546000eb5d1373acf1f3a2e1", contractAddress: "0x39ceba2b467fa987546000eb5d1373acf1f3a2e1", - parentCurrencyId: "hedera", tokenType: "erc20", name: "AUDD", ticker: "AUDD", - delisted: false, - disableCountervalue: false, - units: [ - { - name: "AUDD", - code: "AUDD", - magnitude: 6, - }, - ], - }, + }), ]; export const getTokenCurrencyFromCAL = ( @@ -119,9 +109,9 @@ export const getTokenCurrencyFromCALByType = ( export const getMockedHTSTokenCurrency = (overrides?: Partial): TokenCurrency => { return { - id: "hedera/hts/test1_0.0.1234567", + id: TokenCurrencyIdSchema.parse("hedera/hts/test1_0.0.1234567"), contractAddress: "0.0.1001", - parentCurrencyId: "hedera", + parentCurrencyId: CryptoCurrencyIdSchema.parse("hedera"), tokenType: "hts", name: "Test HTS token", ticker: "TEST1", @@ -139,9 +129,9 @@ export const getMockedHTSTokenCurrency = (overrides?: Partial): T export const getMockedERC20TokenCurrency = (overrides?: Partial): TokenCurrency => { return { - id: "hedera/erc20/_0x915fe7c00730c08708581e30e27d9c0605be40bd", + id: TokenCurrencyIdSchema.parse("hedera/erc20/_0x915fe7c00730c08708581e30e27d9c0605be40bd"), contractAddress: "0x915fe7c00730c08708581e30e27d9c0605be40bd", - parentCurrencyId: "hedera", + parentCurrencyId: CryptoCurrencyIdSchema.parse("hedera"), tokenType: "erc20", name: "Test ERC20 token", ticker: "TEST2", diff --git a/libs/coin-modules/coin-solana/src/prepareTransaction.integ.test.ts b/libs/coin-modules/coin-solana/src/prepareTransaction.integ.test.ts index 00a17463cba9..a7651b8bebb4 100644 --- a/libs/coin-modules/coin-solana/src/prepareTransaction.integ.test.ts +++ b/libs/coin-modules/coin-solana/src/prepareTransaction.integ.test.ts @@ -2,7 +2,11 @@ import { setCryptoAssetsStore } from "@ledgerhq/ledger-wallet-framework/cryptoAs import { getCryptoCurrencyById } from "@ledgerhq/ledger-wallet-framework/currencies"; import { NotEnoughGas } from "./errors"; import { encodeAccountId } from "@ledgerhq/ledger-wallet-framework/account/accountId"; -import type { TokenCurrency } from "@ledgerhq/ledger-wallet-framework/types"; +import { + CryptoCurrencyIdSchema, + TokenCurrencyIdSchema, + type TokenCurrency, +} from "@ledgerhq/ledger-wallet-framework/types"; import { ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; import { Keypair, PublicKey } from "@solana/web3.js"; import BigNumber from "bignumber.js"; @@ -28,9 +32,11 @@ const BALANCE_AT_BUG_THRESHOLD = SPENDABLE_AT_BUG_THRESHOLD.plus(MAIN_ACCOUNT_RE const VIBECODOOR_TOKEN: TokenCurrency = { type: "TokenCurrency", - id: "solana/spl/the_vibecodoor_aj1mspd4vjdn5r3xptnhsjhqggwdlge8brqi2w6pump", + id: TokenCurrencyIdSchema.parse( + "solana/spl/the_vibecodoor_aj1mspd4vjdn5r3xptnhsjhqggwdlge8brqi2w6pump", + ), contractAddress: VIBECODOOR_MINT, - parentCurrencyId: "solana", + parentCurrencyId: CryptoCurrencyIdSchema.parse("solana"), tokenType: "spl", name: "The Vibecodoor", ticker: "Vibecodoor", diff --git a/libs/coin-modules/coin-stacks/src/bridge/utils/misc.integ.test.ts b/libs/coin-modules/coin-stacks/src/bridge/utils/misc.integ.test.ts index 2e789eb51a3d..42b144ce464d 100644 --- a/libs/coin-modules/coin-stacks/src/bridge/utils/misc.integ.test.ts +++ b/libs/coin-modules/coin-stacks/src/bridge/utils/misc.integ.test.ts @@ -1,5 +1,5 @@ import { setCryptoAssetsStore } from "@ledgerhq/ledger-wallet-framework/cryptoAssetsStore"; -import type { Operation, CryptoAssetsStore } from "@ledgerhq/types-live"; +import type { Operation } from "@ledgerhq/types-live"; import { fetchFullTxs } from "../../network/index"; import { mapTxToOps } from "./misc"; @@ -12,7 +12,7 @@ describe("misc integration tests", () => { findTokenById: async () => undefined, findTokenByAddressInCurrency: async () => undefined, getTokensSyncHash: async () => "0", - } as CryptoAssetsStore); + }); }); test("convert raw transactions to live operations", async () => { diff --git a/libs/coin-modules/coin-sui/src/bridge/index.test.ts b/libs/coin-modules/coin-sui/src/bridge/index.test.ts index 0f81a28101f7..7d1cca75bb94 100644 --- a/libs/coin-modules/coin-sui/src/bridge/index.test.ts +++ b/libs/coin-modules/coin-sui/src/bridge/index.test.ts @@ -1,6 +1,9 @@ import type { CoinConfig } from "@ledgerhq/coin-module-framework/config"; import type { SignerContext } from "@ledgerhq/ledger-wallet-framework/signer"; -import type { CryptoCurrency } from "@ledgerhq/ledger-wallet-framework/types"; +import { + CryptoCurrencyIdSchema, + type CryptoCurrency, +} from "@ledgerhq/ledger-wallet-framework/types"; import type { AccountBridge, CurrencyBridge } from "@ledgerhq/types-live"; import { BigNumber } from "bignumber.js"; import type { SuiCoinConfig } from "../config"; @@ -80,7 +83,7 @@ describe("bridge/index", () => { // Setup mock currency mockCurrency = { - id: "sui", + id: CryptoCurrencyIdSchema.parse("sui"), name: "Sui", family: "sui", units: [], diff --git a/libs/coin-modules/coin-sui/src/bridge/synchronisation.migration.integ.test.ts b/libs/coin-modules/coin-sui/src/bridge/synchronisation.migration.integ.test.ts index b780c0c30d7f..8c492586ed5f 100644 --- a/libs/coin-modules/coin-sui/src/bridge/synchronisation.migration.integ.test.ts +++ b/libs/coin-modules/coin-sui/src/bridge/synchronisation.migration.integ.test.ts @@ -1,6 +1,5 @@ import { getCryptoCurrencyById } from "@ledgerhq/ledger-wallet-framework/currencies"; import { setCryptoAssetsStore } from "@ledgerhq/ledger-wallet-framework/cryptoAssetsStore"; -import type { CryptoAssetsStore } from "@ledgerhq/types-live"; import { getJsonRpcFullnodeUrl, type StakeObject } from "@mysten/sui/jsonRpc"; import coinConfig from "../config"; import { FIGMENT_SUI_VALIDATOR_ADDRESS } from "../constants"; @@ -24,7 +23,7 @@ beforeAll(() => { findTokenByAddressInCurrency: async () => undefined, findTokenById: async () => undefined, getTokensSyncHash: async () => "0", - } as unknown as CryptoAssetsStore); + }); }); const SHAPE_INFO = { diff --git a/libs/coin-modules/coin-sui/src/bridge/synchronisation.test.ts b/libs/coin-modules/coin-sui/src/bridge/synchronisation.test.ts index b20391f871cd..dcfe8178f30a 100644 --- a/libs/coin-modules/coin-sui/src/bridge/synchronisation.test.ts +++ b/libs/coin-modules/coin-sui/src/bridge/synchronisation.test.ts @@ -1,7 +1,6 @@ import { getCryptoCurrencyById } from "@ledgerhq/ledger-wallet-framework/currencies"; import { setCryptoAssetsStore } from "@ledgerhq/ledger-wallet-framework/cryptoAssetsStore"; import type { TokenCurrency } from "@ledgerhq/ledger-wallet-framework/types"; -import type { CryptoAssetsStore } from "@ledgerhq/types-live"; import { getJsonRpcFullnodeUrl } from "@mysten/sui/jsonRpc"; import BigNumber from "bignumber.js"; import coinConfig from "../config"; @@ -29,7 +28,7 @@ setCryptoAssetsStore({ mockedFindTokenByAddressInCurrency(address, currencyId), findTokenById: async () => undefined, getTokensSyncHash: async () => "0", -} as unknown as CryptoAssetsStore); +}); describe("getAccountShape", () => { const mockGetAccountBalances = networkModule.getAccountBalances as jest.Mock; diff --git a/libs/coin-modules/coin-sui/src/signer/getAddress.test.ts b/libs/coin-modules/coin-sui/src/signer/getAddress.test.ts index c01d53db477d..77d763fe7093 100644 --- a/libs/coin-modules/coin-sui/src/signer/getAddress.test.ts +++ b/libs/coin-modules/coin-sui/src/signer/getAddress.test.ts @@ -1,3 +1,4 @@ +import { CryptoCurrencyIdSchema } from "@ledgerhq/ledger-wallet-framework/types"; import { getAddress as getAddressResolver } from "./"; describe("getAddress resolver", () => { @@ -25,7 +26,7 @@ describe("getAddress resolver", () => { const result = await getAddress(mockDeviceId, { currency: { type: "CryptoCurrency", - id: "sui", + id: CryptoCurrencyIdSchema.parse("sui"), coinType: 784, name: "Sui", managerAppName: "Sui", @@ -65,7 +66,7 @@ describe("getAddress resolver", () => { getAddress(mockDeviceId, { currency: { type: "CryptoCurrency", - id: "sui", + id: CryptoCurrencyIdSchema.parse("sui"), coinType: 784, name: "Sui", managerAppName: "Sui", @@ -100,7 +101,7 @@ describe("getAddress resolver", () => { getAddress(mockDeviceId, { currency: { type: "CryptoCurrency", - id: "sui", + id: CryptoCurrencyIdSchema.parse("sui"), coinType: 784, name: "Sui", managerAppName: "Sui", diff --git a/libs/coin-modules/coin-sui/src/test/config.test.ts b/libs/coin-modules/coin-sui/src/test/config.test.ts index 358cd02be678..64314a2407ea 100644 --- a/libs/coin-modules/coin-sui/src/test/config.test.ts +++ b/libs/coin-modules/coin-sui/src/test/config.test.ts @@ -1,9 +1,12 @@ -import { CryptoCurrency } from "@ledgerhq/ledger-wallet-framework/types"; +import { + CryptoCurrencyIdSchema, + type CryptoCurrency, +} from "@ledgerhq/ledger-wallet-framework/types"; import coinConfig from "../config"; describe("Configuration", () => { const mockCurrency: CryptoCurrency = { - id: "sui", + id: CryptoCurrencyIdSchema.parse("sui"), name: "sui", family: "sui", units: [], diff --git a/libs/coin-modules/coin-ton/src/__tests__/unit/txn.unit.test.ts b/libs/coin-modules/coin-ton/src/__tests__/unit/txn.unit.test.ts index 86020abad4cb..871516f58d29 100644 --- a/libs/coin-modules/coin-ton/src/__tests__/unit/txn.unit.test.ts +++ b/libs/coin-modules/coin-ton/src/__tests__/unit/txn.unit.test.ts @@ -1,4 +1,8 @@ import { setCryptoAssetsStore } from "@ledgerhq/ledger-wallet-framework/cryptoAssetsStore"; +import { + CryptoCurrencyIdSchema, + TokenCurrencyIdSchema, +} from "@ledgerhq/ledger-wallet-framework/types"; import { encodeOperationId } from "@ledgerhq/ledger-wallet-framework/operation"; import { Builder, Slice } from "@ton/core"; import BigNumber from "bignumber.js"; @@ -154,10 +158,12 @@ describe("Transaction functions", () => { address.includes("2f956143c461769579baef2e32cc2d7bc18283f40d20bb03e432cd603ac33ffc") ) { return { - id: "ton/jetton/eqavlwfdxgf2lxm67y4yzc17wykd9a0guwpkms1gosm__not", + id: TokenCurrencyIdSchema.parse( + "ton/jetton/eqavlwfdxgf2lxm67y4yzc17wykd9a0guwpkms1gosm__not", + ), type: "TokenCurrency" as const, contractAddress: "EQAVLwfDxGF2LXm67Y4yzC17WYkd9A0gUWPkMS1gOsM__NOT", - parentCurrencyId: "ton", + parentCurrencyId: CryptoCurrencyIdSchema.parse("ton"), tokenType: "jetton", name: "NOT", ticker: "NOT", diff --git a/libs/coin-modules/coin-vechain/src/bridge/synchronisation.test.ts b/libs/coin-modules/coin-vechain/src/bridge/synchronisation.test.ts index e0d0c916676c..8b628be2a29f 100644 --- a/libs/coin-modules/coin-vechain/src/bridge/synchronisation.test.ts +++ b/libs/coin-modules/coin-vechain/src/bridge/synchronisation.test.ts @@ -3,7 +3,11 @@ import { makeScanAccounts } from "@ledgerhq/ledger-wallet-framework/bridge/jsHel import { getCryptoCurrencyById } from "@ledgerhq/ledger-wallet-framework/currencies"; import { getCryptoAssetsStore } from "@ledgerhq/ledger-wallet-framework/cryptoAssetsStore"; import { setCryptoAssetsStore } from "@ledgerhq/ledger-wallet-framework/cryptoAssetsStore"; -import type { TokenCurrency } from "@ledgerhq/ledger-wallet-framework/types"; +import { + CryptoCurrencyIdSchema, + TokenCurrencyIdSchema, + type TokenCurrency, +} from "@ledgerhq/ledger-wallet-framework/types"; import BigNumber from "bignumber.js"; import { setupServer } from "msw/node"; import { firstValueFrom } from "rxjs"; @@ -34,9 +38,9 @@ describe("scanAccounts", () => { beforeAll(() => { const vthoToken: TokenCurrency = { type: "TokenCurrency", - id: "vechain/vip180/vtho", + id: TokenCurrencyIdSchema.parse("vechain/vip180/vtho"), contractAddress: "0x0000000000000000000000000000456E65726779", - parentCurrencyId: "vechain", + parentCurrencyId: CryptoCurrencyIdSchema.parse("vechain"), tokenType: "vip180", name: "VeThor", ticker: "VTHO", diff --git a/libs/coin-tester-modules/coin-tester-cardano/src/fixtures.ts b/libs/coin-tester-modules/coin-tester-cardano/src/fixtures.ts index 002706708a2a..f0f0f95b1a53 100644 --- a/libs/coin-tester-modules/coin-tester-cardano/src/fixtures.ts +++ b/libs/coin-tester-modules/coin-tester-cardano/src/fixtures.ts @@ -1,6 +1,7 @@ import { getCryptoCurrencyById } from "@ledgerhq/ledger-wallet-framework/currencies"; import { decodeAccountId } from "@ledgerhq/ledger-wallet-framework/account"; import type { CryptoCurrency, TokenCurrency } from "@ledgerhq/ledger-wallet-framework/types"; +import { TokenCurrencyIdSchema } from "@ledgerhq/ledger-wallet-framework/types"; import type { Account } from "@ledgerhq/types-live"; import BigNumber from "bignumber.js"; @@ -22,7 +23,7 @@ export const TEST_TOKEN_POLICY_ID = "1234567890123456789012345678901234567890123 export const TEST_TOKEN_ASSET_NAME = "4d59544f4b454e"; export const TEST_TOKEN: TokenCurrency = { type: "TokenCurrency", - id: `cardano/native/${TEST_TOKEN_POLICY_ID}${TEST_TOKEN_ASSET_NAME}`, + id: TokenCurrencyIdSchema.parse(`cardano/native/${TEST_TOKEN_POLICY_ID}${TEST_TOKEN_ASSET_NAME}`), contractAddress: `${TEST_TOKEN_POLICY_ID}${TEST_TOKEN_ASSET_NAME}`, parentCurrencyId: CARDANO.id, tokenType: "native", diff --git a/libs/coin-tester-modules/coin-tester-cardano/src/scenarii/cardanoTokenYaci.ts b/libs/coin-tester-modules/coin-tester-cardano/src/scenarii/cardanoTokenYaci.ts index 2b4b0845c09d..a493961ae56e 100644 --- a/libs/coin-tester-modules/coin-tester-cardano/src/scenarii/cardanoTokenYaci.ts +++ b/libs/coin-tester-modules/coin-tester-cardano/src/scenarii/cardanoTokenYaci.ts @@ -4,6 +4,7 @@ import type { Scenario } from "@ledgerhq/coin-tester/main"; import type { GenericTransaction } from "@ledgerhq/live-common/bridge/generic-coin-framework/types"; import { encodeTokenAccountId } from "@ledgerhq/ledger-wallet-framework/account"; import type { TokenCurrency } from "@ledgerhq/ledger-wallet-framework/types"; +import { TokenCurrencyIdSchema } from "@ledgerhq/ledger-wallet-framework/types"; import type { Account, TokenAccount } from "@ledgerhq/types-live"; import BigNumber from "bignumber.js"; import { CARDANO_TESTNET, FRESH_ADDRESS_PATH, makeAccount } from "../fixtures"; @@ -62,7 +63,7 @@ export const scenarioCardanoTokenYaci: Scenario = { owner = address; const token: TokenCurrency = { type: "TokenCurrency", - id: `cardano_testnet/native/${assetReference}`, + id: TokenCurrencyIdSchema.parse(`cardano_testnet/native/${assetReference}`), contractAddress: assetReference, parentCurrencyId: CARDANO_TESTNET.id, tokenType: "native", diff --git a/libs/coin-tester-modules/coin-tester-solana/src/fixtures.ts b/libs/coin-tester-modules/coin-tester-solana/src/fixtures.ts index 2f3850147d09..a9ab535f144c 100644 --- a/libs/coin-tester-modules/coin-tester-solana/src/fixtures.ts +++ b/libs/coin-tester-modules/coin-tester-solana/src/fixtures.ts @@ -1,4 +1,5 @@ import type { CryptoCurrency, TokenCurrency } from "@ledgerhq/ledger-wallet-framework/types"; +import { TokenCurrencyIdSchema } from "@ledgerhq/ledger-wallet-framework/types"; import { decodeAccountId } from "@ledgerhq/ledger-wallet-framework/account"; import { getDerivationScheme, @@ -43,7 +44,7 @@ export const SOLANA_CWIF: TokenCurrency = { export const SOLANA_VIRTUAL: TokenCurrency = { type: "TokenCurrency", - id: "solana/spl/3iql8bfs2ve7mww4ehaqqhasbmrncrpxizwat2zfyr9y", + id: TokenCurrencyIdSchema.parse("solana/spl/3iql8bfs2ve7mww4ehaqqhasbmrncrpxizwat2zfyr9y"), name: "Virtual Protocol", ticker: "VIRTUAL", units: [{ name: "VIRTUAL", code: "VIRTUAL", magnitude: 9 }], @@ -56,7 +57,9 @@ export const SOLANA_VIRTUAL: TokenCurrency = { export const SOLANA_TSLAX: TokenCurrency = { type: "TokenCurrency", - id: "solana/spl/tesla_xstock_xsdovfqebukxuzhwhdvwhbhgehjgnst4mlodqsjhzob", + id: TokenCurrencyIdSchema.parse( + "solana/spl/tesla_xstock_xsdovfqebukxuzhwhdvwhbhgehjgnst4mlodqsjhzob", + ), contractAddress: "XsDoVfqeBukxuZHWhdvWHBhgEHjGNst4MLodqsJHzoB", parentCurrencyId: SOLANA.id, tokenType: "spl", diff --git a/libs/coin-tester-modules/coin-tester-stellar/src/fixtures.ts b/libs/coin-tester-modules/coin-tester-stellar/src/fixtures.ts index 4284ff49549d..814acac749f2 100644 --- a/libs/coin-tester-modules/coin-tester-stellar/src/fixtures.ts +++ b/libs/coin-tester-modules/coin-tester-stellar/src/fixtures.ts @@ -3,6 +3,10 @@ import { ed25519 } from "@noble/curves/ed25519"; import { StrKey } from "@stellar/stellar-sdk"; import { getCryptoCurrencyById } from "@ledgerhq/ledger-wallet-framework/currencies"; import type { TokenCurrency } from "@ledgerhq/ledger-wallet-framework/types"; +import { + CryptoCurrencyIdSchema, + TokenCurrencyIdSchema, +} from "@ledgerhq/ledger-wallet-framework/types"; import { getDerivationScheme, runDerivationScheme, @@ -62,9 +66,9 @@ const USDC_ASSET_MAGNITUDE = 7; export const USDC_TOKEN: TokenCurrency = { type: "TokenCurrency", - id: `stellar/asset/${USDC_ASSET_CODE}:${ISSUER_ADDRESS}`, + id: TokenCurrencyIdSchema.parse(`stellar/asset/${USDC_ASSET_CODE}:${ISSUER_ADDRESS}`), contractAddress: ISSUER_ADDRESS, - parentCurrencyId: "stellar", + parentCurrencyId: CryptoCurrencyIdSchema.parse("stellar"), tokenType: "stellar", name: USDC_ASSET_CODE, ticker: USDC_ASSET_CODE, diff --git a/libs/ledger-live-common/.oxlintrc.json b/libs/ledger-live-common/.oxlintrc.json index ac61f3cd44a3..c79d4abccd94 100644 --- a/libs/ledger-live-common/.oxlintrc.json +++ b/libs/ledger-live-common/.oxlintrc.json @@ -19,21 +19,8 @@ "suspicious": "warn", "pedantic": "off" }, - "plugins": [ - "eslint", - "import", - "oxc", - "unicorn", - "typescript", - "react", - "jest", - "jsx-a11y" - ], - "ignorePatterns": [ - "*.min.js", - "src/families/*/types.js", - "src/load/tokens/**" - ], + "plugins": ["eslint", "import", "oxc", "unicorn", "typescript", "react", "jest", "jsx-a11y"], + "ignorePatterns": ["*.min.js", "src/families/*/types.js", "src/load/tokens/**"], "rules": { "eslint/no-unused-vars": "warn", "eslint/no-empty-pattern": "warn", @@ -59,7 +46,11 @@ "Currency", "Unit", "FiatCurrency", - "ExplorerView" + "ExplorerView", + "CryptoCurrencyId", + "TokenCurrencyId", + "CryptoCurrencyIdSchema", + "TokenCurrencyIdSchema" ], "message": "Wallet-framework currency types are for coin-modules. Import from @domain/entity-currency-* (unions from @domain/entity-currency)." }, @@ -71,17 +62,18 @@ "Currency", "Unit", "FiatCurrency", - "ExplorerView" + "ExplorerView", + "CryptoCurrencyId", + "TokenCurrencyId", + "CryptoCurrencyIdSchema", + "TokenCurrencyIdSchema" ], "message": "Wallet-framework currency types are for coin-modules. Import from @domain/entity-currency-* (unions from @domain/entity-currency)." } ], "patterns": [ { - "group": [ - "@ledgerhq/live-common/lib/**", - "@ledgerhq/live-common/lib-es/**" - ], + "group": ["@ledgerhq/live-common/lib/**", "@ledgerhq/live-common/lib-es/**"], "message": "Please remove the /lib import from live-common import." }, { @@ -150,10 +142,7 @@ } }, { - "files": [ - "**/*.test.{ts,tsx}", - "**/__tests__/**" - ], + "files": ["**/*.test.{ts,tsx}", "**/__tests__/**"], "env": { "jest": true }, diff --git a/libs/ledger-live-common/src/account/helpers.test.ts b/libs/ledger-live-common/src/account/helpers.test.ts index 0565584c5238..dd7ca07d1efa 100644 --- a/libs/ledger-live-common/src/account/helpers.test.ts +++ b/libs/ledger-live-common/src/account/helpers.test.ts @@ -89,7 +89,7 @@ describe("filterAccountsExcludingBlacklisted", () => { const btcAccount = genAccount("btc", { currency: { ...mockEthereumCurrency, - id: "bitcoin", + id: CryptoCurrencyIdSchema.parse("bitcoin"), name: "Bitcoin", ticker: "BTC", type: "CryptoCurrency", diff --git a/libs/ledger-live-common/src/exchange/swap/hooks/useFromState.test.ts b/libs/ledger-live-common/src/exchange/swap/hooks/useFromState.test.ts index b33d802ba80e..5df0d24b0c61 100644 --- a/libs/ledger-live-common/src/exchange/swap/hooks/useFromState.test.ts +++ b/libs/ledger-live-common/src/exchange/swap/hooks/useFromState.test.ts @@ -3,7 +3,8 @@ */ import "../../../__tests__/test-helpers/dom-polyfill"; import React from "react"; -import { getCryptoCurrencyById } from "@domain/entity-currency-crypto"; +import { CryptoCurrencyIdSchema, getCryptoCurrencyById } from "@domain/entity-currency-crypto"; +import { TokenCurrencyIdSchema } from "@domain/entity-currency-token"; import { Account } from "@ledgerhq/types-live"; import { renderHook, act } from "@testing-library/react"; import BigNumber from "bignumber.js"; @@ -41,12 +42,12 @@ LiveConfig.setConfig({ }); const USDT = { type: "TokenCurrency" as const, - id: "ethereum/erc20/usd_tether__erc20_", + id: TokenCurrencyIdSchema.parse("ethereum/erc20/usd_tether__erc20_"), name: "Tether USD (ERC-20)", ticker: "USDT", units: [{ name: "Tether USD", code: "USDT", magnitude: 6 }], contractAddress: "0xdac17f958d2ee523a2206206994597c13d831ec7", - parentCurrencyId: "ethereum", + parentCurrencyId: CryptoCurrencyIdSchema.parse("ethereum"), tokenType: "erc20" as const, }; diff --git a/libs/ledger-live-common/src/exchange/swap/hooks/useUpdateMaxAmount.test.ts b/libs/ledger-live-common/src/exchange/swap/hooks/useUpdateMaxAmount.test.ts index 88856e201c1b..b062eda30898 100644 --- a/libs/ledger-live-common/src/exchange/swap/hooks/useUpdateMaxAmount.test.ts +++ b/libs/ledger-live-common/src/exchange/swap/hooks/useUpdateMaxAmount.test.ts @@ -2,7 +2,8 @@ * @jest-environment jsdom */ import "../../../__tests__/test-helpers/dom-polyfill"; -import { getCryptoCurrencyById } from "@domain/entity-currency-crypto"; +import { CryptoCurrencyIdSchema, getCryptoCurrencyById } from "@domain/entity-currency-crypto"; +import { TokenCurrencyIdSchema } from "@domain/entity-currency-token"; import { act, renderHook } from "@testing-library/react"; import BigNumber from "bignumber.js"; import { checkAccountSupported } from "../../../account/index"; @@ -21,12 +22,12 @@ const mockedEstimateMaxSpendable = jest.mocked(ethBridge.accountBridge.estimateM const ETH = getCryptoCurrencyById("ethereum"); const USDT = { type: "TokenCurrency" as const, - id: "ethereum/erc20/usd_tether__erc20_", + id: TokenCurrencyIdSchema.parse("ethereum/erc20/usd_tether__erc20_"), name: "Tether USD (ERC-20)", ticker: "USDT", units: [{ name: "Tether USD", code: "USDT", magnitude: 6 }], contractAddress: "0xdac17f958d2ee523a2206206994597c13d831ec7", - parentCurrencyId: "ethereum", + parentCurrencyId: CryptoCurrencyIdSchema.parse("ethereum"), tokenType: "erc20" as const, }; diff --git a/libs/ledger-live-common/src/families/evm/bridge/api.test.ts b/libs/ledger-live-common/src/families/evm/bridge/api.test.ts index 688616aa1d58..86238f819fb9 100644 --- a/libs/ledger-live-common/src/families/evm/bridge/api.test.ts +++ b/libs/ledger-live-common/src/families/evm/bridge/api.test.ts @@ -30,9 +30,9 @@ describe("evm bridge", () => { ) { return { type: "TokenCurrency", - id: "ethereum/erc20/usd__coin", + id: TokenCurrencyIdSchema.parse("ethereum/erc20/usd__coin"), contractAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", - parentCurrencyId: "ethereum", + parentCurrencyId: CryptoCurrencyIdSchema.parse("ethereum"), tokenType: "erc20", name: "USD Coin", ticker: "USDC", @@ -48,9 +48,11 @@ describe("evm bridge", () => { ) { return { type: "TokenCurrency", - id: "sonic/erc20/bridged_usdc_sonic_labs_0x29219dd400f2bf60e5a23d13be72b486d4038894", + id: TokenCurrencyIdSchema.parse( + "sonic/erc20/bridged_usdc_sonic_labs_0x29219dd400f2bf60e5a23d13be72b486d4038894", + ), contractAddress: "0x29219dd400f2Bf60E5a23d13Be72B486D4038894", - parentCurrencyId: "sonic", + parentCurrencyId: CryptoCurrencyIdSchema.parse("sonic"), tokenType: "erc20", name: "Bridged USDC (Sonic Labs)", ticker: "USDC", diff --git a/libs/ledger-wallet-framework/package.json b/libs/ledger-wallet-framework/package.json index db2bf6ee4f6c..d6165367aa87 100644 --- a/libs/ledger-wallet-framework/package.json +++ b/libs/ledger-wallet-framework/package.json @@ -115,7 +115,8 @@ "lodash": "^4.17.21", "prando": "^6.0.1", "rxjs": "catalog:", - "uuid": "11.1.0" + "uuid": "11.1.0", + "zod": "catalog:" }, "devDependencies": { "@domain/entity-currency-crypto": "workspace:^", diff --git a/libs/ledger-wallet-framework/src/account/index.test.ts b/libs/ledger-wallet-framework/src/account/index.test.ts index 7de9fa641f6a..9728c3ed5da7 100644 --- a/libs/ledger-wallet-framework/src/account/index.test.ts +++ b/libs/ledger-wallet-framework/src/account/index.test.ts @@ -12,6 +12,7 @@ import { genAccount } from "../mocks/account"; import "../test-helpers/staticTime"; import tokenData from "./__fixtures__/ethereum-erc20-0x_project.json"; import type { CryptoCurrency, TokenCurrency } from "../types"; +import { TokenCurrencyIdSchema } from "../types"; // oxlint-disable-next-line typescript/consistent-type-assertions const TOKEN = tokenData as TokenCurrency; @@ -154,7 +155,7 @@ test("accountWithMandatoryTokens ethereum", () => { .fill(null) .map((_, i) => ({ type: "TokenCurrency" as const, - id: `${currency.id}/erc20/mock_token_${i}`, + id: TokenCurrencyIdSchema.parse(`${currency.id}/erc20/mock_token_${i}`), contractAddress: `0x${i.toString(16).padStart(40, "0")}`, parentCurrencyId: currency.id, tokenType: "erc20" as const, diff --git a/libs/ledger-wallet-framework/src/derivation.ts b/libs/ledger-wallet-framework/src/derivation.ts index 073438618eab..63bac8810aeb 100644 --- a/libs/ledger-wallet-framework/src/derivation.ts +++ b/libs/ledger-wallet-framework/src/derivation.ts @@ -229,7 +229,7 @@ const modes: Readonly> = Object.freeze({ // modes[mode] = spec; // } -const legacyDerivations: Partial> = { +const legacyDerivations: Partial> = { aeternity: ["aeternity"], bitcoin_cash: [], tezos: ["galleonL", "tezboxL", "tezosSecp256k1", "tezosbip44h", "tezbox"], diff --git a/libs/ledger-wallet-framework/src/types.ts b/libs/ledger-wallet-framework/src/types.ts index 73a1493136ba..a688f5ecd1f4 100644 --- a/libs/ledger-wallet-framework/src/types.ts +++ b/libs/ledger-wallet-framework/src/types.ts @@ -1,4 +1,12 @@ -export type CryptoCurrencyId = string; +import { z } from "zod"; + +/** Opaque identifier for a crypto currency (e.g. `"bitcoin"`, `"ethereum"`). Non-empty string. */ +export const CryptoCurrencyIdSchema = z.string().min(1).brand<"CryptoCurrencyId">(); +export type CryptoCurrencyId = z.infer; + +/** Opaque identifier for a token (e.g. `"ethereum/erc20/usd-tether"`). Non-empty string. */ +export const TokenCurrencyIdSchema = z.string().min(1).brand<"TokenCurrencyId">(); +export type TokenCurrencyId = z.infer; export type LedgerExplorerId = string; @@ -20,7 +28,7 @@ export interface ExplorerView { export interface CryptoCurrency { type: "CryptoCurrency"; - id: any; + id: CryptoCurrencyId; name: string; ticker: string; deviceTicker?: string; @@ -52,11 +60,11 @@ export interface CryptoCurrency { export interface TokenCurrency { type: "TokenCurrency"; - id: any; + id: TokenCurrencyId; name: string; ticker: string; contractAddress: string; - parentCurrencyId: any; + parentCurrencyId: CryptoCurrencyId; units: Unit[]; tokenType: string; delisted?: boolean; diff --git a/libs/live-countervalues-react/src/react.test.ts b/libs/live-countervalues-react/src/react.test.ts index 07916f455595..607d815f9d06 100644 --- a/libs/live-countervalues-react/src/react.test.ts +++ b/libs/live-countervalues-react/src/react.test.ts @@ -17,6 +17,10 @@ import type { FiatCurrency, TokenCurrency, } from "@ledgerhq/ledger-wallet-framework/types"; +import { + CryptoCurrencyIdSchema, + TokenCurrencyIdSchema, +} from "@ledgerhq/ledger-wallet-framework/types"; jest.mock("@ledgerhq/live-countervalues/logic", () => ({ ...jest.requireActual("@ledgerhq/live-countervalues/logic"), @@ -151,9 +155,11 @@ describe("CountervaluesProvider", () => { const bitcoin = genAccount("bitcoin").currency; const unsupportedToken: TokenCurrency = { type: "TokenCurrency", - id: "ethereum/erc20/lc_staked_shared_eth_0xc4dcb059dd98b45b090da8982234c61d0b9e84f9", + id: TokenCurrencyIdSchema.parse( + "ethereum/erc20/lc_staked_shared_eth_0xc4dcb059dd98b45b090da8982234c61d0b9e84f9", + ), contractAddress: "0xc4dcb059dd98b45b090da8982234c61d0b9e84f9", - parentCurrencyId: "ethereum", + parentCurrencyId: CryptoCurrencyIdSchema.parse("ethereum"), tokenType: "erc20", name: "Ledger Staked Shared ETH", ticker: "osETH", diff --git a/libs/live-countervalues/src/logic.test.ts b/libs/live-countervalues/src/logic.test.ts index 1cfb880fe9fd..7f126b5e26b5 100644 --- a/libs/live-countervalues/src/logic.test.ts +++ b/libs/live-countervalues/src/logic.test.ts @@ -16,6 +16,10 @@ import type { Currency, TokenCurrency, } from "@ledgerhq/ledger-wallet-framework/types"; +import { + CryptoCurrencyIdSchema, + TokenCurrencyIdSchema, +} from "@ledgerhq/ledger-wallet-framework/types"; describe("inferTrackingPairForAccounts", () => { const accounts = Array(20) @@ -50,9 +54,11 @@ describe("filterSupportedTrackingPairs", () => { const usd = getFiatCurrencyByTicker("USD"); const unsupportedToken: TokenCurrency = { type: "TokenCurrency", - id: "ethereum/erc20/lc_staked_shared_eth_0xc4dcb059dd98b45b090da8982234c61d0b9e84f9", + id: TokenCurrencyIdSchema.parse( + "ethereum/erc20/lc_staked_shared_eth_0xc4dcb059dd98b45b090da8982234c61d0b9e84f9", + ), contractAddress: "0xc4dcb059dd98b45b090da8982234c61d0b9e84f9", - parentCurrencyId: "ethereum", + parentCurrencyId: CryptoCurrencyIdSchema.parse("ethereum"), tokenType: "erc20", name: "Ledger Staked Shared ETH", ticker: "osETH", @@ -62,7 +68,7 @@ describe("filterSupportedTrackingPairs", () => { }; const assetHubPolkadot: CryptoCurrency = { ...ethereum, - id: "assethub_polkadot", + id: CryptoCurrencyIdSchema.parse("assethub_polkadot"), name: "Asset Hub Polkadot", ticker: "DOT", }; diff --git a/libs/live-countervalues/src/tests/currencies.ts b/libs/live-countervalues/src/tests/currencies.ts index af0eb3c738c9..484b00d1d084 100644 --- a/libs/live-countervalues/src/tests/currencies.ts +++ b/libs/live-countervalues/src/tests/currencies.ts @@ -1,11 +1,12 @@ import type { CryptoCurrency, FiatCurrency } from "@ledgerhq/ledger-wallet-framework/types"; +import { CryptoCurrencyIdSchema } from "@ledgerhq/ledger-wallet-framework/types"; // Minimal currency fixtures so tests don't pull the full currency registry. // Only the fields consumed by the countervalues logic and the account mocks are populated. const bitcoin: CryptoCurrency = { type: "CryptoCurrency", - id: "bitcoin", + id: CryptoCurrencyIdSchema.parse("bitcoin"), name: "Bitcoin", ticker: "BTC", managerAppName: "Bitcoin", @@ -22,7 +23,7 @@ const bitcoin: CryptoCurrency = { const ethereum: CryptoCurrency = { type: "CryptoCurrency", - id: "ethereum", + id: CryptoCurrencyIdSchema.parse("ethereum"), name: "Ethereum", ticker: "ETH", managerAppName: "Ethereum", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d6554d264324..06d478468063 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9934,6 +9934,9 @@ importers: uuid: specifier: 11.1.0 version: 11.1.0 + zod: + specifier: 'catalog:' + version: 4.3.6 devDependencies: '@domain/entity-currency-crypto': specifier: workspace:^