@ledgerhq/cryptoassets 13.32.0-nightly.2 → 13.32.0-nightly.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,33 +1,5 @@
1
1
  import type { TokenCurrency } from "@ledgerhq/types-cryptoassets";
2
- import {
3
- convertERC20,
4
- convertSplTokens,
5
- convertJettonToken,
6
- convertAlgorandASATokens,
7
- convertVechainToken,
8
- convertTRONTokens,
9
- convertMultiversXESDTTokens,
10
- convertCardanoNativeTokens,
11
- convertStellarTokens,
12
- convertSuiTokens,
13
- convertAptCoinTokens,
14
- convertAptFaTokens,
15
- } from "./legacy/legacy-utils";
16
- import {
17
- AlgorandASAToken,
18
- CardanoNativeToken,
19
- ERC20Token,
20
- MultiversXESDTToken,
21
- StellarToken,
22
- TRC10Token,
23
- TRC20Token,
24
- } from "./types";
25
- import type { AptosToken } from "./data/apt_coin";
26
- import type { AptosToken as AptosFAToken } from "./data/apt_fungible_asset";
27
- import type { SuiToken } from "./data/sui";
28
- import type { Vip180Token } from "./data/vip180";
29
- import type { TonJettonToken } from "./data/ton-jetton";
30
- import type { SPLToken } from "./data/spl";
2
+ import { findCryptoCurrencyById } from "./currencies";
31
3
 
32
4
  export interface ApiTokenData {
33
5
  id: string;
@@ -39,121 +11,133 @@ export interface ApiTokenData {
39
11
  delisted?: boolean;
40
12
  disableCountervalue?: boolean;
41
13
  tokenIdentifier?: string;
14
+ ledgerSignature?: string;
42
15
  }
43
16
 
17
+ /**
18
+ * Transforms Ledger Live token ID to backend API format for querying
19
+ *
20
+ * This handles cases where LL uses different ID conventions than backend APIs.
21
+ * Applied BEFORE querying the API to ensure the request uses the correct format:
22
+ *
23
+ * - MultiversX: multiversx/esdt/* → elrond/esdt/* (API uses old name) [LIVE-22557]
24
+ * - Stellar: UPPERCASE → lowercase (API uses lowercase) [LIVE-22558]
25
+ *
26
+ * @param legacyId - Token ID in Ledger Live format
27
+ * @returns Token ID in backend API format
28
+ */
29
+ export function legacyIdToApiId(legacyId: string): string {
30
+ let apiId = legacyId;
31
+
32
+ // LIVE-22557: MultiversX - API uses old "elrond" name
33
+ if (apiId.startsWith("multiversx/esdt/")) {
34
+ apiId = apiId.replace("multiversx/esdt/", "elrond/esdt/");
35
+ }
36
+
37
+ // LIVE-22558: Stellar - API uses all lowercase (including the address part)
38
+ if (apiId.startsWith("stellar/asset/")) {
39
+ apiId = apiId.toLowerCase();
40
+ }
41
+
42
+ return apiId;
43
+ }
44
+
45
+ /**
46
+ * Converts API token data to Ledger Live TokenCurrency format
47
+ *
48
+ * This function applies client-side transformations to reconcile differences between
49
+ * backend APIs (CAL/DaDa) and Ledger Live's expected token format:
50
+ *
51
+ * - MultiversX: elrond/esdt/* → multiversx/esdt/* [LIVE-22557]
52
+ * - Stellar: Normalizes casing to stellar/asset/UPPERCASE_ADDRESS and tokenType asset → stellar [LIVE-22558]
53
+ * - Cardano: Reconstructs contractAddress from policyId + tokenIdentifier [LIVE-22559]
54
+ * - Sui: Transforms tokenType from "coin" to "sui" [LIVE-22560]
55
+ * - TON Jetton: Removes name prefix from ID (ton/jetton/name_address → ton/jetton/address) [LIVE-22561]
56
+ *
57
+ * @param apiToken - Token data from backend API
58
+ * @returns TokenCurrency object in Ledger Live format, or undefined if parent currency not found
59
+ */
44
60
  export function convertApiToken(apiToken: ApiTokenData): TokenCurrency | undefined {
45
- const { standard, id, contractAddress, name, ticker, units, delisted = false } = apiToken;
46
-
47
- const magnitude = units[0]?.magnitude || 0;
48
-
49
- switch (standard) {
50
- case "erc20":
51
- case "bep20": {
52
- const parentCurrencyId = id.split("/")[0];
53
- const tokenIdentifier = id.split("/")[2] || contractAddress;
54
- const erc20Data: ERC20Token = [
55
- parentCurrencyId,
56
- tokenIdentifier,
57
- ticker,
58
- magnitude,
59
- name,
60
- "",
61
- contractAddress,
62
- false,
63
- delisted,
64
- ];
65
- return convertERC20(erc20Data);
66
- }
67
- case "spl": {
68
- const parentCurrencyId = id.split("/")[0];
69
- const splData: SPLToken = [id, parentCurrencyId, name, ticker, contractAddress, magnitude];
70
- return convertSplTokens(splData);
71
- }
72
- case "jetton": {
73
- const jettonData: TonJettonToken = [contractAddress, name, ticker, magnitude, delisted];
74
- return convertJettonToken(jettonData);
75
- }
76
- case "asa": {
77
- const tokenId = id.split("/")[2] || contractAddress;
78
- const asaData: AlgorandASAToken = [tokenId, ticker, name, contractAddress, magnitude];
79
- return convertAlgorandASATokens(asaData);
80
- }
81
- case "esdt": {
82
- const tokenIdentifier = id.split("/")[2] || contractAddress;
83
- const esdtData: MultiversXESDTToken = [ticker, tokenIdentifier, magnitude, "", name];
84
- return convertMultiversXESDTTokens(esdtData);
85
- }
86
- case "trc10": {
87
- const tokenId = parseInt(id.split("/")[2] || contractAddress);
88
- const trc10Data: TRC10Token = [
89
- tokenId,
90
- ticker,
91
- name,
92
- contractAddress,
93
- magnitude,
94
- delisted,
95
- "",
96
- ];
97
- return convertTRONTokens("trc10")(trc10Data);
98
- }
99
- case "trc20": {
100
- const tokenId = id.split("/")[2] || contractAddress;
101
- const trc20Data: TRC20Token = [
102
- tokenId,
103
- ticker,
104
- name,
105
- contractAddress,
106
- magnitude,
107
- delisted,
108
- "",
109
- ];
110
- return convertTRONTokens("trc20")(trc20Data);
111
- }
112
- case "vip180": {
113
- const tokenIdentifier = id.split("/")[2] || contractAddress;
114
- const vip180Data: Vip180Token = [tokenIdentifier, ticker, name, contractAddress, magnitude];
115
- return convertVechainToken(vip180Data);
116
- }
117
- case "native": {
118
- const parentCurrencyId = id.split("/")[0];
119
- if (parentCurrencyId !== "cardano") return undefined;
120
-
121
- const tokenIdentifier = id.split("/")[2] || contractAddress;
122
- const parts = tokenIdentifier.split(".");
123
- const [policyId, assetName = ""] = parts;
124
-
125
- const cardanoData: CardanoNativeToken = [
126
- "cardano",
127
- policyId,
128
- assetName,
129
- name,
130
- ticker,
131
- magnitude,
132
- delisted,
133
- ];
134
- return convertCardanoNativeTokens(cardanoData);
135
- }
136
- case "stellar": {
137
- const parts = contractAddress.split(":");
138
- const assetCode = parts[0] || ticker;
139
- const assetIssuer = parts[1] || contractAddress;
61
+ const {
62
+ standard,
63
+ id,
64
+ contractAddress,
65
+ name,
66
+ ticker,
67
+ units,
68
+ delisted = false,
69
+ tokenIdentifier,
70
+ ledgerSignature,
71
+ } = apiToken;
140
72
 
141
- const stellarData: StellarToken = [assetCode, assetIssuer, "stellar", name, magnitude];
142
- return convertStellarTokens(stellarData);
143
- }
144
- case "coin": {
145
- const aptCoinData: AptosToken = [id, ticker, name, contractAddress, magnitude, delisted];
146
- return convertAptCoinTokens(aptCoinData);
147
- }
148
- case "fungible_asset": {
149
- const aptFaData: AptosFAToken = [id, ticker, name, contractAddress, magnitude, delisted];
150
- return convertAptFaTokens(aptFaData);
151
- }
152
- case "sui": {
153
- const suiData: SuiToken = [id, name, ticker, contractAddress, magnitude, ""];
154
- return convertSuiTokens(suiData);
73
+ // Apply client-side patches to reconcile CAL format with LL format
74
+ let patchedId = id;
75
+ let patchedContractAddress = contractAddress;
76
+ let patchedStandard = standard;
77
+
78
+ // Get parent currency from the ORIGINAL ID (before transformation)
79
+ // This is important for currencies that changed names (elrond -> multiversx)
80
+ const parentCurrencyId = id.split("/")[0];
81
+ const parentCurrency = findCryptoCurrencyById(parentCurrencyId);
82
+
83
+ if (!parentCurrency) {
84
+ return undefined;
85
+ }
86
+
87
+ // LIVE-22557: MultiversX - Transform elrond/* to multiversx/*
88
+ if (patchedId.startsWith("elrond/esdt/")) {
89
+ patchedId = patchedId.replace("elrond/esdt/", "multiversx/esdt/");
90
+ }
91
+
92
+ // LIVE-22558: Stellar - Transform to LL mixed-case format: stellar/asset/ + UPPERCASE_REST
93
+ // Also fix tokenType: API returns "asset", LL expects "stellar"
94
+ const stellarPrefix = "stellar/asset/";
95
+ if (patchedId.toLowerCase().startsWith(stellarPrefix)) {
96
+ const rest = patchedId.substring(stellarPrefix.length);
97
+ patchedId = stellarPrefix + rest.toUpperCase();
98
+ patchedStandard = patchedStandard === "asset" ? "stellar" : patchedStandard;
99
+ }
100
+
101
+ // LIVE-22559: Cardano - Reconstruct full assetId (policyId + assetName)
102
+ if (standard === "native" && tokenIdentifier) {
103
+ patchedContractAddress = contractAddress + tokenIdentifier;
104
+ }
105
+
106
+ // LIVE-22560: Sui - Transform "coin" standard to "sui" tokenType (LL format)
107
+ if (standard === "coin" && patchedId.startsWith("sui/")) {
108
+ patchedStandard = "sui";
109
+ }
110
+
111
+ // LIVE-22561: TON Jetton - Remove name prefix from ID (API: ton/jetton/name_address -> LL: ton/jetton/address)
112
+ if (patchedId.startsWith("ton/jetton/") && patchedId.indexOf("_") > 0) {
113
+ const parts = patchedId.split("_");
114
+ if (parts.length === 2) {
115
+ patchedId = "ton/jetton/" + parts[1];
155
116
  }
156
- default:
157
- return undefined;
158
117
  }
118
+
119
+ // Construct TokenCurrency directly from API data
120
+ const tokenCurrency: TokenCurrency = {
121
+ type: "TokenCurrency",
122
+ id: patchedId,
123
+ contractAddress: patchedContractAddress,
124
+ parentCurrency,
125
+ tokenType: patchedStandard,
126
+ name,
127
+ ticker,
128
+ delisted,
129
+ disableCountervalue: !!parentCurrency.isTestnetFor || !!apiToken.disableCountervalue,
130
+ units: units.map(unit => ({
131
+ name: unit.name,
132
+ code: unit.code,
133
+ magnitude: unit.magnitude,
134
+ })),
135
+ };
136
+
137
+ // Add ledgerSignature if present
138
+ if (ledgerSignature) {
139
+ tokenCurrency.ledgerSignature = ledgerSignature;
140
+ }
141
+
142
+ return tokenCurrency;
159
143
  }
@@ -45,7 +45,7 @@ export const ApiTokenResponseSchema = z.object({
45
45
  /** Chain ID */
46
46
  chain_id: z.string(),
47
47
  /** Token identifier */
48
- token_identifier: z.string(),
48
+ token_identifier: z.string().optional(),
49
49
  /** Network type */
50
50
  network_type: z.string(),
51
51
  /** Meta currency ID */
@@ -53,7 +53,7 @@ export const ApiTokenResponseSchema = z.object({
53
53
  /** Blockchain name */
54
54
  blockchain_name: z.string(),
55
55
  /** Live signature */
56
- live_signature: z.string(),
56
+ live_signature: z.string().optional(),
57
57
  });
58
58
 
59
59
  export type ApiTokenResponse = z.infer<typeof ApiTokenResponseSchema>;
@@ -4,7 +4,7 @@ import { getEnv } from "@ledgerhq/live-env";
4
4
  import { GetTokensDataParams, PageParam, TokensDataTags, TokensDataWithPagination } from "./types";
5
5
  import { TOKEN_OUTPUT_FIELDS } from "./fields";
6
6
  import { TokenCurrency } from "@ledgerhq/types-cryptoassets";
7
- import { findCryptoCurrencyById } from "../../currencies";
7
+ import { convertApiToken } from "../../api-token-converter";
8
8
 
9
9
  function transformTokensResponse(
10
10
  response: ApiTokenResponse[],
@@ -24,28 +24,28 @@ function transformTokensResponse(
24
24
  }
25
25
 
26
26
  function transformApiTokenToTokenCurrency(token: ApiTokenResponse): TokenCurrency | undefined {
27
- const parentCurrency = findCryptoCurrencyById(token.network);
28
- if (!parentCurrency) {
29
- return undefined;
30
- }
31
-
32
- return {
33
- type: "TokenCurrency",
27
+ // convertApiToken handles all format reconciliation internally
28
+ const result = convertApiToken({
34
29
  id: token.id,
35
- ledgerSignature: token.live_signature,
36
30
  contractAddress: token.contract_address,
37
- parentCurrency,
38
- tokenType: token.standard,
39
31
  name: token.name,
40
32
  ticker: token.ticker,
41
- units: token.units.map(unit => ({
42
- code: unit.code,
43
- name: unit.name,
44
- magnitude: unit.magnitude,
45
- })),
33
+ units: token.units,
34
+ standard: token.standard,
35
+ tokenIdentifier: token.token_identifier,
46
36
  delisted: token.delisted,
47
- symbol: token.symbol,
48
- };
37
+ ledgerSignature: token.live_signature,
38
+ });
39
+
40
+ // Add symbol if result exists
41
+ if (result && token.symbol) {
42
+ return {
43
+ ...result,
44
+ symbol: token.symbol,
45
+ };
46
+ }
47
+
48
+ return result;
49
49
  }
50
50
 
51
51
  export const cryptoAssetsApi = createApi({