@vultisig/core-chain 5.2.0 → 5.3.0

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.
Files changed (74) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/dist/chains/solana/spl/verification.d.ts +38 -0
  3. package/dist/chains/solana/spl/verification.d.ts.map +1 -0
  4. package/dist/chains/solana/spl/verification.js +45 -0
  5. package/dist/chains/solana/spl/verification.js.map +1 -0
  6. package/dist/chains/solana/spl/verifiedRegistry.d.ts +34 -0
  7. package/dist/chains/solana/spl/verifiedRegistry.d.ts.map +1 -0
  8. package/dist/chains/solana/spl/verifiedRegistry.js +65 -0
  9. package/dist/chains/solana/spl/verifiedRegistry.js.map +1 -0
  10. package/dist/chains/ton/jetton/symbol.d.ts +3 -5
  11. package/dist/chains/ton/jetton/symbol.d.ts.map +1 -1
  12. package/dist/chains/ton/jetton/symbol.js +5 -58
  13. package/dist/chains/ton/jetton/symbol.js.map +1 -1
  14. package/dist/chains/ton/jetton/verification.d.ts +1 -1
  15. package/dist/chains/ton/jetton/verification.d.ts.map +1 -1
  16. package/dist/chains/ton/jetton/verification.js +3 -3
  17. package/dist/chains/ton/jetton/verification.js.map +1 -1
  18. package/dist/chains/ton/jetton/verifiedRegistry.d.ts +1 -1
  19. package/dist/chains/ton/jetton/verifiedRegistry.d.ts.map +1 -1
  20. package/dist/chains/ton/jetton/verifiedRegistry.js +3 -3
  21. package/dist/chains/ton/jetton/verifiedRegistry.js.map +1 -1
  22. package/dist/coin/coingecko/coingeckoToken.d.ts +11 -0
  23. package/dist/coin/coingecko/coingeckoToken.d.ts.map +1 -1
  24. package/dist/coin/coingecko/getCoingeckoId.d.ts +10 -0
  25. package/dist/coin/coingecko/getCoingeckoId.d.ts.map +1 -1
  26. package/dist/coin/coingecko/getCoingeckoId.js +30 -1
  27. package/dist/coin/coingecko/getCoingeckoId.js.map +1 -1
  28. package/dist/coin/find/resolvers/solana/index.d.ts +22 -1
  29. package/dist/coin/find/resolvers/solana/index.d.ts.map +1 -1
  30. package/dist/coin/find/resolvers/solana/index.js +79 -11
  31. package/dist/coin/find/resolvers/solana/index.js.map +1 -1
  32. package/dist/coin/jupiter/api.d.ts +18 -0
  33. package/dist/coin/jupiter/api.d.ts.map +1 -0
  34. package/dist/coin/jupiter/api.js +52 -0
  35. package/dist/coin/jupiter/api.js.map +1 -0
  36. package/dist/coin/jupiter/token.d.ts +4 -0
  37. package/dist/coin/jupiter/token.d.ts.map +1 -1
  38. package/dist/coin/jupiter/token.js.map +1 -1
  39. package/dist/coin/token/metadata/resolvers/solana.d.ts +3 -1
  40. package/dist/coin/token/metadata/resolvers/solana.d.ts.map +1 -1
  41. package/dist/coin/token/metadata/resolvers/solana.js +10 -6
  42. package/dist/coin/token/metadata/resolvers/solana.js.map +1 -1
  43. package/dist/coin/tokenSymbol.d.ts +10 -0
  44. package/dist/coin/tokenSymbol.d.ts.map +1 -0
  45. package/dist/coin/tokenSymbol.js +62 -0
  46. package/dist/coin/tokenSymbol.js.map +1 -0
  47. package/dist/security/blockaid/tx/simulation/api/core.d.ts +17 -0
  48. package/dist/security/blockaid/tx/simulation/api/core.d.ts.map +1 -1
  49. package/dist/security/blockaid/tx/simulation/api/core.js +58 -41
  50. package/dist/security/blockaid/tx/simulation/api/core.js.map +1 -1
  51. package/dist/swap/general/GeneralSwapQuote.d.ts +10 -0
  52. package/dist/swap/general/GeneralSwapQuote.d.ts.map +1 -1
  53. package/dist/swap/general/swapkit/api/getSwapKitQuote.d.ts.map +1 -1
  54. package/dist/swap/general/swapkit/api/getSwapKitQuote.js +40 -14
  55. package/dist/swap/general/swapkit/api/getSwapKitQuote.js.map +1 -1
  56. package/dist/swap/native/NativeSwapQuote.d.ts +6 -1
  57. package/dist/swap/native/NativeSwapQuote.d.ts.map +1 -1
  58. package/dist/tx/fee/evm/clampEvmPriorityFee.d.ts +10 -4
  59. package/dist/tx/fee/evm/clampEvmPriorityFee.d.ts.map +1 -1
  60. package/dist/tx/fee/evm/clampEvmPriorityFee.js +35 -14
  61. package/dist/tx/fee/evm/clampEvmPriorityFee.js.map +1 -1
  62. package/dist/tx/fee/evm/evmGasLimit.d.ts +29 -0
  63. package/dist/tx/fee/evm/evmGasLimit.d.ts.map +1 -1
  64. package/dist/tx/fee/evm/evmGasLimit.js +47 -17
  65. package/dist/tx/fee/evm/evmGasLimit.js.map +1 -1
  66. package/dist/tx/fee/evm/gasPrice.d.ts +4 -0
  67. package/dist/tx/fee/evm/gasPrice.d.ts.map +1 -0
  68. package/dist/tx/fee/evm/gasPrice.js +4 -0
  69. package/dist/tx/fee/evm/gasPrice.js.map +1 -0
  70. package/dist/tx/fee/evm/maxPriorityFeePerGas.d.ts +8 -0
  71. package/dist/tx/fee/evm/maxPriorityFeePerGas.d.ts.map +1 -1
  72. package/dist/tx/fee/evm/maxPriorityFeePerGas.js +30 -1
  73. package/dist/tx/fee/evm/maxPriorityFeePerGas.js.map +1 -1
  74. package/package.json +26 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,44 @@
1
1
  # @vultisig/core-chain
2
2
 
3
+ ## 5.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#2325](https://github.com/vultisig/vultisig-sdk/pull/2325) [`7c95286`](https://github.com/vultisig/vultisig-sdk/commit/7c9528622702a1e6f10cd5ff72017779d25e509a) Thanks [@Ehsan-saradar](https://github.com/Ehsan-saradar)! - EVM fee quotes now size the gas reserve from the transaction itself instead of a flat 600k floor. An aggregator swap is signed with the larger of the route's own gas and 1.5x its simulation (1.5x the 600k default when it cannot be simulated, e.g. a token route quoted before its allowance exists); a THORChain or Maya swap deposit (any transaction carrying the native swap payload) takes a fixed 120k; a plain transfer, including a memo-carrying vault deposit that carries no swap payload, takes its simulation raised to a per-chain floor with no inflation (when it cannot be simulated, that floor plus the intrinsic cost of its memo calldata); a dApp or other contract call keeps 1.5x headroom over its simulation. Base-fee headroom drops from 50% to 20% (32% for swaps), legacy-priced chains (BSC) are priced from `eth_gasPrice` with no tip, and the tip is the highest recent 5th-percentile reward from `eth_feeHistory`, capped at the gas price, with per-chain floors (1 gwei on tip-auction chains, 30 gwei on Polygon, 20 wei on OP-stack rollups) and a zero tip on Arbitrum, Mantle and Robinhood.
8
+
9
+ `getEvmFeeQuote`'s `minimumGasLimit` now only raises the value that stands in for a failed simulation and never a successful estimate. `getEvmTransferGasLimit`, `getEvmContractCallGasLimit` and `evmRouterDepositGasLimit` are exported from `@vultisig/core-chain/tx/fee/evm/evmGasLimit`, and `getEvmGasPrice` from `@vultisig/core-chain/tx/fee/evm/gasPrice`.
10
+
11
+ - [#2328](https://github.com/vultisig/vultisig-sdk/pull/2328) [`741272f`](https://github.com/vultisig/vultisig-sdk/commit/741272f8d3872afdf12d9487d2121dee04c2f363) Thanks [@Ehsan-saradar](https://github.com/Ehsan-saradar)! - Move `slippage_bps` on a native swap quote from the top level into `fees`, where THORChain and MayaChain actually send it.
12
+
13
+ `NativeSwapQuote.slippage_bps` was never populated: THORChain's `QuoteSwapResponse` has no such property, and its `QuoteFees` schema declares `slippage_bps` as a required integer. MayaChain's spec agrees. Because the field was optional, every consumer reading it silently got `undefined` rather than a compile error — which is how the price-impact row went missing in the desktop app and extension.
14
+
15
+ `NativeSwapFees` now carries `slippage_bps?: number`, and the phantom top-level field is gone so the wrong read cannot compile. This is a type-only change; `getNativeSwapQuote` already spreads the response through verbatim, so no runtime behavior changes.
16
+
17
+ Note that `slippage_bps` is the price impact alone and is not interchangeable with the neighbouring `total_bps`, which is the total fee relative to the amount out.
18
+
19
+ - [#2331](https://github.com/vultisig/vultisig-sdk/pull/2331) [`982d464`](https://github.com/vultisig/vultisig-sdk/commit/982d4645467272f32e33a2df20883c1a7171a7ee) Thanks [@Ehsan-saradar](https://github.com/Ehsan-saradar)! - Publish the SwapKit swap-fee work to the core packages that hold it. [#2315](https://github.com/vultisig/vultisig-sdk/issues/2315) landed
20
+ `swap_fee` on `SwapKitSwapPayload`, the `getKeysignSwapFeeFields` reader, and the
21
+ `sub_provider` route tag in `@vultisig/core-mpc`, plus the transfer-route fee
22
+ resolution in `@vultisig/core-chain` — but its changeset named only
23
+ `@vultisig/sdk`, so neither core package was versioned and the release skipped
24
+ both. Clients that consume `@vultisig/core-mpc` directly, rather than through
25
+ `@vultisig/sdk`, cannot reach the new fee group or its reader until these are
26
+ republished.
27
+
28
+ - [#2339](https://github.com/vultisig/vultisig-sdk/pull/2339) [`95cf397`](https://github.com/vultisig/vultisig-sdk/commit/95cf39722b8a4d3e197b26bcef9983ecef6c3703) Thanks [@Ehsan-saradar](https://github.com/Ehsan-saradar)! - feat(solana): verified / unverified / scam classification for SPL tokens, and verified-only discovery
29
+
30
+ Solana discovery kept a mint when a price id could be found for it. That hid legitimate tokens that simply had no CoinGecko listing, and did nothing about the airdropped counterfeits and zero-decimal spam a Solana wallet accumulates — a priced impostor was auto-added, an unpriced real token was not, and neither carried a label.
31
+
32
+ `findSolanaCoins` now returns **verified mints only**, priced or not, mirroring TON. Zero-balance token accounts are skipped, Jupiter's search endpoint answers for a hundred mints per call instead of one call per token, CoinGecko ids come from its on-chain multi-token endpoint thirty mints per call, decimals come from the token account itself, and curated metadata wins for tokens we ship ourselves. When Jupiter cannot be reached, listed mints are still discovered from the registry's metadata; a failed price-id lookup, by contrast, fails the round instead of saving the token without a price id for good. Unverified and scam mints can still be added by hand, where the UI labels them.
33
+
34
+ Verification lives in `@vultisig/core-chain/chains/solana/spl/verification`. The registry of verified mints (`chains/solana/spl/verifiedRegistry`) merges our curated Solana tokens with Jupiter's verified list, fetched once an hour and degrading to the curated list alone when unreachable. `resolveSolanaTokenVerification` is pure: a listed mint — or one Jupiter itself flags verified — is `verified`; an unlisted mint is `scam` when its symbol or name collapses onto a verified token's, and `unverified` otherwise. `getSolanaTokenVerification({ id, ticker })` is the one-call form for token rows and approval cards; a listed mint is answered from the registry alone, any other mint is judged by what it claims on Jupiter, falling back to the local ticker offline. The tiers are the chain-agnostic `TokenVerification` type.
35
+
36
+ The symbol normaliser behind the counterfeit heuristic moves to `@vultisig/core-chain/coin/tokenSymbol` as `normalizeTokenSymbol`; `chains/ton/jetton/symbol` keeps exporting `normalizeJettonSymbol` as an alias. `coin/jupiter/api` gains `getJupiterTokens` (batched, keyed by mint, filtered to the mints asked for) and `getJupiterVerifiedTokens`, `SolanaJupiterToken` carries Jupiter's `isVerified` flag and `tags`, and `coin/coingecko/getCoingeckoId` gains the batched `getSolanaCoingeckoIds`. `getSolanaTokenMetadata` now fails with a clear error for a mint Jupiter does not index instead of a `TypeError`.
37
+
38
+ ### Patch Changes
39
+
40
+ - [#2002](https://github.com/vultisig/vultisig-sdk/pull/2002) [`2e1ed70`](https://github.com/vultisig/vultisig-sdk/commit/2e1ed704ccd0a360eaf760f1258c7cd8a4401e22) Thanks [@gomesalexandre](https://github.com/gomesalexandre)! - Net Solana Blockaid simulation diffs by resolved mint (native SOL and the WSOL mint share a bucket) before classifying the result as a `swap` or `transfer`. The wrap-then-spend case previously surfaced as a bogus "SOL to WSOL swap" whose destination amount was only the token account's rent-exempt residual, at up to ~29x smaller than the amount actually leaving. The reverse unwrap/close-account case now rejects the receive-only result instead of inventing a transfer. The parser now nets same-mint legs and only classifies as a swap when two distinct mints remain.
41
+
3
42
  ## 5.2.0
4
43
 
5
44
  ### Minor Changes
@@ -0,0 +1,38 @@
1
+ import { TokenVerification } from '@vultisig/core-chain/coin/tokenVerification';
2
+ import { SolanaVerifiedTokenRegistry } from './verifiedRegistry.js';
3
+ type ResolveSolanaTokenVerificationInput = {
4
+ /** Mint address. */
5
+ address: string;
6
+ symbol?: string;
7
+ name?: string;
8
+ /** Jupiter's own verification flag for the mint, when known. */
9
+ isVerified?: boolean | null;
10
+ registry: SolanaVerifiedTokenRegistry;
11
+ };
12
+ /**
13
+ * Classifies a mint against the verified registry. A listed mint is `verified`
14
+ * whatever it calls itself, and so is one Jupiter itself marks verified — that
15
+ * covers a listing newer than the registry's hourly refresh and the degraded,
16
+ * curated-only registry. An unlisted mint is `scam` when its symbol or name
17
+ * collapses (see `normalizeTokenSymbol`) onto a verified token's symbol or
18
+ * name — the fake-USDT pattern, where the counterfeit is only distinguishable
19
+ * by address. Anything else is `unverified`.
20
+ */
21
+ export declare const resolveSolanaTokenVerification: ({ address, symbol, name, isVerified, registry, }: ResolveSolanaTokenVerificationInput) => TokenVerification;
22
+ type GetSolanaTokenVerificationInput = {
23
+ /** Mint address. */
24
+ id: string;
25
+ /** Ticker already known locally, used when Jupiter has no entry for the mint. */
26
+ ticker?: string;
27
+ };
28
+ /**
29
+ * Verification tier for one mint, for token rows and approval cards. A mint the
30
+ * registry lists is verified without any further lookup, so a token list full
31
+ * of legitimate tokens costs no Jupiter calls. For any other mint the symbol
32
+ * and name are read from Jupiter so a counterfeit is judged by what it actually
33
+ * claims to be, not by the ticker stored locally; falls back to that ticker
34
+ * when the lookup fails, so the label still renders offline.
35
+ */
36
+ export declare const getSolanaTokenVerification: ({ id, ticker, }: GetSolanaTokenVerificationInput) => Promise<TokenVerification>;
37
+ export {};
38
+ //# sourceMappingURL=verification.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verification.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/chain/chains/solana/spl/verification.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,6CAA6C,CAAA;AAG/E,OAAO,EAAkC,2BAA2B,EAAE,MAAM,oBAAoB,CAAA;AAEhG,KAAK,mCAAmC,GAAG;IACzC,oBAAoB;IACpB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,gEAAgE;IAChE,UAAU,CAAC,EAAE,OAAO,GAAG,IAAI,CAAA;IAC3B,QAAQ,EAAE,2BAA2B,CAAA;CACtC,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,8BAA8B,GAAI,kDAM5C,mCAAmC,KAAG,iBAUxC,CAAA;AAED,KAAK,+BAA+B,GAAG;IACrC,oBAAoB;IACpB,EAAE,EAAE,MAAM,CAAA;IACV,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,0BAA0B,GAAU,iBAG9C,+BAA+B,KAAG,OAAO,CAAC,iBAAiB,CAc7D,CAAA"}
@@ -0,0 +1,45 @@
1
+ import { getJupiterTokens } from '@vultisig/core-chain/coin/jupiter/api';
2
+ import { normalizeTokenSymbol } from '@vultisig/core-chain/coin/tokenSymbol';
3
+ import { attempt } from '@vultisig/lib-utils/attempt';
4
+ import { getSolanaVerifiedTokenRegistry } from './verifiedRegistry.js';
5
+ /**
6
+ * Classifies a mint against the verified registry. A listed mint is `verified`
7
+ * whatever it calls itself, and so is one Jupiter itself marks verified — that
8
+ * covers a listing newer than the registry's hourly refresh and the degraded,
9
+ * curated-only registry. An unlisted mint is `scam` when its symbol or name
10
+ * collapses (see `normalizeTokenSymbol`) onto a verified token's symbol or
11
+ * name — the fake-USDT pattern, where the counterfeit is only distinguishable
12
+ * by address. Anything else is `unverified`.
13
+ */
14
+ export const resolveSolanaTokenVerification = ({ address, symbol, name, isVerified, registry, }) => {
15
+ if (registry.byAddress[address] || isVerified)
16
+ return 'verified';
17
+ const impersonates = [symbol, name].some(label => {
18
+ const skeleton = label ? normalizeTokenSymbol(label) : '';
19
+ return !!skeleton && (registry.symbols.has(skeleton) || registry.names.has(skeleton));
20
+ });
21
+ return impersonates ? 'scam' : 'unverified';
22
+ };
23
+ /**
24
+ * Verification tier for one mint, for token rows and approval cards. A mint the
25
+ * registry lists is verified without any further lookup, so a token list full
26
+ * of legitimate tokens costs no Jupiter calls. For any other mint the symbol
27
+ * and name are read from Jupiter so a counterfeit is judged by what it actually
28
+ * claims to be, not by the ticker stored locally; falls back to that ticker
29
+ * when the lookup fails, so the label still renders offline.
30
+ */
31
+ export const getSolanaTokenVerification = async ({ id, ticker, }) => {
32
+ const registry = await getSolanaVerifiedTokenRegistry();
33
+ if (registry.byAddress[id])
34
+ return 'verified';
35
+ const tokens = await attempt(getJupiterTokens([id]));
36
+ const token = 'data' in tokens ? tokens.data?.[id] : undefined;
37
+ return resolveSolanaTokenVerification({
38
+ address: id,
39
+ symbol: token?.symbol ?? ticker,
40
+ name: token?.name,
41
+ isVerified: token?.isVerified,
42
+ registry,
43
+ });
44
+ };
45
+ //# sourceMappingURL=verification.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verification.js","sourceRoot":"","sources":["../../../../../../../packages/core/chain/chains/solana/spl/verification.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAA;AACxE,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAA;AAE5E,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAA;AAErD,OAAO,EAAE,8BAA8B,EAA+B,MAAM,oBAAoB,CAAA;AAYhG;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAAC,EAC7C,OAAO,EACP,MAAM,EACN,IAAI,EACJ,UAAU,EACV,QAAQ,GAC4B,EAAqB,EAAE;IAC3D,IAAI,QAAQ,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,UAAU;QAAE,OAAO,UAAU,CAAA;IAEhE,MAAM,YAAY,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;QAC/C,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;QAEzD,OAAO,CAAC,CAAC,QAAQ,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAA;IACvF,CAAC,CAAC,CAAA;IAEF,OAAO,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAA;AAC7C,CAAC,CAAA;AASD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,KAAK,EAAE,EAC/C,EAAE,EACF,MAAM,GAC0B,EAA8B,EAAE;IAChE,MAAM,QAAQ,GAAG,MAAM,8BAA8B,EAAE,CAAA;IACvD,IAAI,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QAAE,OAAO,UAAU,CAAA;IAE7C,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;IACpD,MAAM,KAAK,GAAG,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IAE9D,OAAO,8BAA8B,CAAC;QACpC,OAAO,EAAE,EAAE;QACX,MAAM,EAAE,KAAK,EAAE,MAAM,IAAI,MAAM;QAC/B,IAAI,EAAE,KAAK,EAAE,IAAI;QACjB,UAAU,EAAE,KAAK,EAAE,UAAU;QAC7B,QAAQ;KACT,CAAC,CAAA;AACJ,CAAC,CAAA"}
@@ -0,0 +1,34 @@
1
+ /** A mint we treat as legitimate, keyed by its exact base58 address. */
2
+ export type VerifiedSolanaToken = {
3
+ address: string;
4
+ symbol: string;
5
+ name?: string;
6
+ decimals?: number;
7
+ logo?: string;
8
+ };
9
+ /**
10
+ * Verified mints indexed for the two questions verification asks: "is this
11
+ * mint listed?" and "does this symbol or name belong to a listed token?".
12
+ * `symbols` and `names` hold `normalizeTokenSymbol` skeletons. Mints are
13
+ * case-sensitive base58, so `byAddress` is keyed exactly.
14
+ */
15
+ export type SolanaVerifiedTokenRegistry = {
16
+ byAddress: Record<string, VerifiedSolanaToken>;
17
+ symbols: Set<string>;
18
+ names: Set<string>;
19
+ };
20
+ /**
21
+ * Builds a registry from a list of verified tokens. On a mint collision the
22
+ * earlier entry's metadata is kept in `byAddress`, but every entry's symbol and
23
+ * name are indexed: two entries for one mint describe the same verified token,
24
+ * and a counterfeit may copy either spelling.
25
+ */
26
+ export declare const makeSolanaVerifiedTokenRegistry: (tokens: VerifiedSolanaToken[]) => SolanaVerifiedTokenRegistry;
27
+ /**
28
+ * The mints we consider verified: our own curated Solana tokens (which win, so
29
+ * their tickers and logos are kept) merged with Jupiter's verified list.
30
+ * Degrades to the curated list alone when Jupiter cannot be fetched, so
31
+ * discovery and labels keep working offline — with fewer tokens recognised.
32
+ */
33
+ export declare const getSolanaVerifiedTokenRegistry: () => Promise<SolanaVerifiedTokenRegistry>;
34
+ //# sourceMappingURL=verifiedRegistry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verifiedRegistry.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/chain/chains/solana/spl/verifiedRegistry.ts"],"names":[],"mappings":"AAQA,wEAAwE;AACxE,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,CAAA;AAED;;;;;GAKG;AACH,MAAM,MAAM,2BAA2B,GAAG;IACxC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAA;IAC9C,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IACpB,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CACnB,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,+BAA+B,GAAI,QAAQ,mBAAmB,EAAE,KAAG,2BAc/E,CAAA;AAwCD;;;;;GAKG;AACH,eAAO,MAAM,8BAA8B,QAAa,OAAO,CAAC,2BAA2B,CAO1F,CAAA"}
@@ -0,0 +1,65 @@
1
+ import { Chain } from '@vultisig/core-chain/Chain';
2
+ import { getJupiterVerifiedTokens } from '@vultisig/core-chain/coin/jupiter/api';
3
+ import { knownTokens } from '@vultisig/core-chain/coin/knownTokens';
4
+ import { normalizeTokenSymbol } from '@vultisig/core-chain/coin/tokenSymbol';
5
+ import { attempt } from '@vultisig/lib-utils/attempt';
6
+ import { memoizeAsync } from '@vultisig/lib-utils/memoizeAsync';
7
+ import { convertDuration } from '@vultisig/lib-utils/time/convertDuration';
8
+ /**
9
+ * Builds a registry from a list of verified tokens. On a mint collision the
10
+ * earlier entry's metadata is kept in `byAddress`, but every entry's symbol and
11
+ * name are indexed: two entries for one mint describe the same verified token,
12
+ * and a counterfeit may copy either spelling.
13
+ */
14
+ export const makeSolanaVerifiedTokenRegistry = (tokens) => {
15
+ const registry = { byAddress: {}, symbols: new Set(), names: new Set() };
16
+ for (const token of tokens) {
17
+ registry.byAddress[token.address] ??= token;
18
+ const symbol = normalizeTokenSymbol(token.symbol);
19
+ if (symbol)
20
+ registry.symbols.add(symbol);
21
+ const name = token.name ? normalizeTokenSymbol(token.name) : '';
22
+ if (name)
23
+ registry.names.add(name);
24
+ }
25
+ return registry;
26
+ };
27
+ const getCuratedTokens = () => knownTokens[Chain.Solana].flatMap(({ id, ticker, decimals, logo }) => id ? [{ address: id, symbol: ticker, decimals, logo }] : []);
28
+ const fetchJupiterVerifiedTokens = async () => (await getJupiterVerifiedTokens()).flatMap(({ id, symbol, name, decimals, icon }) => {
29
+ const ticker = symbol.trim();
30
+ if (!ticker)
31
+ return [];
32
+ return [
33
+ {
34
+ address: id,
35
+ symbol: ticker,
36
+ ...(name ? { name } : {}),
37
+ ...(typeof decimals === 'number' ? { decimals } : {}),
38
+ ...(icon ? { logo: icon } : {}),
39
+ },
40
+ ];
41
+ });
42
+ // Only a successful fetch is cached: a rejected promise is never stored, so an
43
+ // outage is retried on the next call instead of pinning the degraded registry.
44
+ const getFullRegistry = memoizeAsync(async () => makeSolanaVerifiedTokenRegistry([...getCuratedTokens(), ...(await fetchJupiterVerifiedTokens())]), { cacheTime: convertDuration(1, 'h', 'ms') });
45
+ let curatedRegistry;
46
+ const getCuratedRegistry = () => {
47
+ if (!curatedRegistry) {
48
+ curatedRegistry = makeSolanaVerifiedTokenRegistry(getCuratedTokens());
49
+ }
50
+ return curatedRegistry;
51
+ };
52
+ /**
53
+ * The mints we consider verified: our own curated Solana tokens (which win, so
54
+ * their tickers and logos are kept) merged with Jupiter's verified list.
55
+ * Degrades to the curated list alone when Jupiter cannot be fetched, so
56
+ * discovery and labels keep working offline — with fewer tokens recognised.
57
+ */
58
+ export const getSolanaVerifiedTokenRegistry = async () => {
59
+ const result = await attempt(getFullRegistry());
60
+ if ('data' in result && result.data)
61
+ return result.data;
62
+ console.warn('[solana] verified token list unavailable; using the curated list only', result.error);
63
+ return getCuratedRegistry();
64
+ };
65
+ //# sourceMappingURL=verifiedRegistry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verifiedRegistry.js","sourceRoot":"","sources":["../../../../../../../packages/core/chain/chains/solana/spl/verifiedRegistry.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,7 @@
1
1
  /**
2
- * Collapses a jetton symbol or name to the Latin skeleton a user perceives, so
3
- * `USD₮`, `UЅDT` (Cyrillic Ѕ), `$USĐ₮` and `usdt` all compare equal to `USDT`.
4
- * Compatibility decomposition folds full-width and mathematical letter forms,
5
- * diacritics are dropped, known homoglyphs are mapped, and everything that is
6
- * not `A–Z`/`0–9` is removed. Returns an empty string when nothing survives.
2
+ * Jetton-named alias of the chain-agnostic `normalizeTokenSymbol`, kept so
3
+ * importers of this subpath keep working. New code should import the shared
4
+ * normalizer from `coin/tokenSymbol` directly.
7
5
  */
8
6
  export declare const normalizeJettonSymbol: (value: string) => string;
9
7
  //# sourceMappingURL=symbol.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"symbol.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/chain/chains/ton/jetton/symbol.ts"],"names":[],"mappings":"AAmDA;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,GAAI,OAAO,MAAM,KAAG,MAIxB,CAAA"}
1
+ {"version":3,"file":"symbol.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/chain/chains/ton/jetton/symbol.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,2BAAuB,CAAA"}
@@ -1,61 +1,8 @@
1
+ import { normalizeTokenSymbol } from '@vultisig/core-chain/coin/tokenSymbol';
1
2
  /**
2
- * Homoglyphs scammers substitute into a jetton symbol so it *reads* like a
3
- * verified one while differing byte-for-byte: Cyrillic/Greek capitals that look
4
- * like Latin ones, the tugrik sign standing in for `T`, and stroked `D`s. Keys
5
- * are already upper-cased because the map is applied after `toUpperCase()`.
3
+ * Jetton-named alias of the chain-agnostic `normalizeTokenSymbol`, kept so
4
+ * importers of this subpath keep working. New code should import the shared
5
+ * normalizer from `coin/tokenSymbol` directly.
6
6
  */
7
- const confusables = {
8
- // Cyrillic
9
- А: 'A',
10
- В: 'B',
11
- Е: 'E',
12
- Ё: 'E',
13
- Ѕ: 'S',
14
- І: 'I',
15
- Ј: 'J',
16
- К: 'K',
17
- М: 'M',
18
- Н: 'H',
19
- О: 'O',
20
- Р: 'P',
21
- С: 'C',
22
- Т: 'T',
23
- У: 'Y',
24
- Х: 'X',
25
- Ԛ: 'Q',
26
- Ԝ: 'W',
27
- // Greek
28
- Α: 'A',
29
- Β: 'B',
30
- Ε: 'E',
31
- Ζ: 'Z',
32
- Η: 'H',
33
- Ι: 'I',
34
- Κ: 'K',
35
- Μ: 'M',
36
- Ν: 'N',
37
- Ο: 'O',
38
- Ρ: 'P',
39
- Τ: 'T',
40
- Υ: 'Y',
41
- Χ: 'X',
42
- // Currency and stroked letters
43
- '₮': 'T',
44
- Đ: 'D',
45
- Ð: 'D',
46
- Ɖ: 'D',
47
- Ŧ: 'T',
48
- };
49
- const combiningMarks = /[̀-ͯ]/g;
50
- /**
51
- * Collapses a jetton symbol or name to the Latin skeleton a user perceives, so
52
- * `USD₮`, `UЅDT` (Cyrillic Ѕ), `$USĐ₮` and `usdt` all compare equal to `USDT`.
53
- * Compatibility decomposition folds full-width and mathematical letter forms,
54
- * diacritics are dropped, known homoglyphs are mapped, and everything that is
55
- * not `A–Z`/`0–9` is removed. Returns an empty string when nothing survives.
56
- */
57
- export const normalizeJettonSymbol = (value) => Array.from(value.normalize('NFKD').replace(combiningMarks, '').toUpperCase())
58
- .map(char => confusables[char] ?? char)
59
- .join('')
60
- .replace(/[^A-Z0-9]/g, '');
7
+ export const normalizeJettonSymbol = normalizeTokenSymbol;
61
8
  //# sourceMappingURL=symbol.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"symbol.js","sourceRoot":"","sources":["../../../../../../../packages/core/chain/chains/ton/jetton/symbol.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,GAA2B;IAC1C,WAAW;IACX,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,QAAQ;IACR,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,+BAA+B;IAC/B,GAAG,EAAE,GAAG;IACR,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;CACP,CAAA;AAED,MAAM,cAAc,GAAG,QAAQ,CAAA;AAE/B;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,KAAa,EAAU,EAAE,CAC7D,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;KAC1E,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC;KACtC,IAAI,CAAC,EAAE,CAAC;KACR,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAA"}
1
+ {"version":3,"file":"symbol.js","sourceRoot":"","sources":["../../../../../../../packages/core/chain/chains/ton/jetton/symbol.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAA;AAE5E;;;;GAIG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,oBAAoB,CAAA"}
@@ -13,7 +13,7 @@ type ResolveTonJettonVerificationInput = {
13
13
  * Classifies a jetton against the verified registry. A listed address is
14
14
  * `verified` whatever it calls itself. An unlisted jetton is `scam` when the
15
15
  * indexer flags it or when its symbol or name collapses (see
16
- * `normalizeJettonSymbol`) onto a verified jetton's symbol or name — the
16
+ * `normalizeTokenSymbol`) onto a verified jetton's symbol or name — the
17
17
  * fake-USDT pattern, where the counterfeit is only distinguishable by address.
18
18
  * Anything else is `unverified`.
19
19
  */
@@ -1 +1 @@
1
- {"version":3,"file":"verification.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/chain/chains/ton/jetton/verification.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,6CAA6C,CAAA;AAI/E,OAAO,EAAgC,yBAAyB,EAAE,MAAM,oBAAoB,CAAA;AAE5F,KAAK,iCAAiC,GAAG;IACvC,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,4DAA4D;IAC5D,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,QAAQ,EAAE,yBAAyB,CAAA;CACpC,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,GAAI,qDAM1C,iCAAiC,KAAG,iBAYtC,CAAA;AAED,KAAK,6BAA6B,GAAG;IACnC,mDAAmD;IACnD,EAAE,EAAE,MAAM,CAAA;IACV,sFAAsF;IACtF,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,GAAU,iBAG5C,6BAA6B,KAAG,OAAO,CAAC,iBAAiB,CAe3D,CAAA"}
1
+ {"version":3,"file":"verification.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/chain/chains/ton/jetton/verification.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,6CAA6C,CAAA;AAG/E,OAAO,EAAgC,yBAAyB,EAAE,MAAM,oBAAoB,CAAA;AAE5F,KAAK,iCAAiC,GAAG;IACvC,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,4DAA4D;IAC5D,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,QAAQ,EAAE,yBAAyB,CAAA;CACpC,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,GAAI,qDAM1C,iCAAiC,KAAG,iBAYtC,CAAA;AAED,KAAK,6BAA6B,GAAG;IACnC,mDAAmD;IACnD,EAAE,EAAE,MAAM,CAAA;IACV,sFAAsF;IACtF,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,GAAU,iBAG5C,6BAA6B,KAAG,OAAO,CAAC,iBAAiB,CAe3D,CAAA"}
@@ -1,13 +1,13 @@
1
1
  import { tonAddressToRawKey } from '@vultisig/core-chain/chains/ton/address';
2
2
  import { getJettonMastersMetadata } from '@vultisig/core-chain/chains/ton/api';
3
+ import { normalizeTokenSymbol } from '@vultisig/core-chain/coin/tokenSymbol';
3
4
  import { attempt } from '@vultisig/lib-utils/attempt';
4
- import { normalizeJettonSymbol } from './symbol.js';
5
5
  import { getTonVerifiedJettonRegistry } from './verifiedRegistry.js';
6
6
  /**
7
7
  * Classifies a jetton against the verified registry. A listed address is
8
8
  * `verified` whatever it calls itself. An unlisted jetton is `scam` when the
9
9
  * indexer flags it or when its symbol or name collapses (see
10
- * `normalizeJettonSymbol`) onto a verified jetton's symbol or name — the
10
+ * `normalizeTokenSymbol`) onto a verified jetton's symbol or name — the
11
11
  * fake-USDT pattern, where the counterfeit is only distinguishable by address.
12
12
  * Anything else is `unverified`.
13
13
  */
@@ -17,7 +17,7 @@ export const resolveTonJettonVerification = ({ address, symbol, name, isFlaggedS
17
17
  if (isFlaggedScam)
18
18
  return 'scam';
19
19
  const impersonates = [symbol, name].some(label => {
20
- const skeleton = label ? normalizeJettonSymbol(label) : '';
20
+ const skeleton = label ? normalizeTokenSymbol(label) : '';
21
21
  return !!skeleton && (registry.symbols.has(skeleton) || registry.names.has(skeleton));
22
22
  });
23
23
  return impersonates ? 'scam' : 'unverified';
@@ -1 +1 @@
1
- {"version":3,"file":"verification.js","sourceRoot":"","sources":["../../../../../../../packages/core/chain/chains/ton/jetton/verification.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAA;AAC5E,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAA;AAE9E,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAA;AAErD,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAA;AAChD,OAAO,EAAE,4BAA4B,EAA6B,MAAM,oBAAoB,CAAA;AAY5F;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,EAC3C,OAAO,EACP,MAAM,EACN,IAAI,EACJ,aAAa,EACb,QAAQ,GAC0B,EAAqB,EAAE;IACzD,IAAI,QAAQ,CAAC,SAAS,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;QAAE,OAAO,UAAU,CAAA;IAEtE,IAAI,aAAa;QAAE,OAAO,MAAM,CAAA;IAEhC,MAAM,YAAY,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;QAC/C,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;QAE1D,OAAO,CAAC,CAAC,QAAQ,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAA;IACvF,CAAC,CAAC,CAAA;IAEF,OAAO,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAA;AAC7C,CAAC,CAAA;AASD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,KAAK,EAAE,EAC7C,EAAE,EACF,MAAM,GACwB,EAA8B,EAAE;IAC9D,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC7C,4BAA4B,EAAE;QAC9B,OAAO,CAAC,wBAAwB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;KACxC,CAAC,CAAA;IAEF,MAAM,MAAM,GAAG,MAAM,IAAI,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IAEvF,OAAO,4BAA4B,CAAC;QAClC,OAAO,EAAE,EAAE;QACX,MAAM,EAAE,MAAM,EAAE,MAAM,IAAI,MAAM;QAChC,IAAI,EAAE,MAAM,EAAE,IAAI;QAClB,aAAa,EAAE,MAAM,EAAE,aAAa;QACpC,QAAQ;KACT,CAAC,CAAA;AACJ,CAAC,CAAA"}
1
+ {"version":3,"file":"verification.js","sourceRoot":"","sources":["../../../../../../../packages/core/chain/chains/ton/jetton/verification.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAA;AAC5E,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAA;AAC9E,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAA;AAE5E,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAA;AAErD,OAAO,EAAE,4BAA4B,EAA6B,MAAM,oBAAoB,CAAA;AAY5F;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,EAC3C,OAAO,EACP,MAAM,EACN,IAAI,EACJ,aAAa,EACb,QAAQ,GAC0B,EAAqB,EAAE;IACzD,IAAI,QAAQ,CAAC,SAAS,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;QAAE,OAAO,UAAU,CAAA;IAEtE,IAAI,aAAa;QAAE,OAAO,MAAM,CAAA;IAEhC,MAAM,YAAY,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;QAC/C,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;QAEzD,OAAO,CAAC,CAAC,QAAQ,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAA;IACvF,CAAC,CAAC,CAAA;IAEF,OAAO,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAA;AAC7C,CAAC,CAAA;AASD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,KAAK,EAAE,EAC7C,EAAE,EACF,MAAM,GACwB,EAA8B,EAAE;IAC9D,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC7C,4BAA4B,EAAE;QAC9B,OAAO,CAAC,wBAAwB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;KACxC,CAAC,CAAA;IAEF,MAAM,MAAM,GAAG,MAAM,IAAI,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IAEvF,OAAO,4BAA4B,CAAC;QAClC,OAAO,EAAE,EAAE;QACX,MAAM,EAAE,MAAM,EAAE,MAAM,IAAI,MAAM;QAChC,IAAI,EAAE,MAAM,EAAE,IAAI;QAClB,aAAa,EAAE,MAAM,EAAE,aAAa;QACpC,QAAQ;KACT,CAAC,CAAA;AACJ,CAAC,CAAA"}
@@ -16,7 +16,7 @@ export type VerifiedJetton = {
16
16
  /**
17
17
  * Verified jettons indexed for the two questions verification asks: "is this
18
18
  * address listed?" and "does this symbol or name belong to a listed jetton?".
19
- * `symbols` and `names` hold `normalizeJettonSymbol` skeletons.
19
+ * `symbols` and `names` hold `normalizeTokenSymbol` skeletons.
20
20
  */
21
21
  export type TonVerifiedJettonRegistry = {
22
22
  byAddress: Record<string, VerifiedJetton>;
@@ -1 +1 @@
1
- {"version":3,"file":"verifiedRegistry.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/chain/chains/ton/jetton/verifiedRegistry.ts"],"names":[],"mappings":"AAUA;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,6EAA6E,CAAA;AAW7G,oFAAoF;AACpF,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB,CAAA;AAED;;;;GAIG;AACH,MAAM,MAAM,yBAAyB,GAAG;IACtC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;IACzC,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IACpB,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CACnB,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,6BAA6B,GAAI,SAAS,cAAc,EAAE,KAAG,yBAezE,CAAA;AA4DD;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,QAAa,OAAO,CAAC,yBAAyB,CAOtF,CAAA"}
1
+ {"version":3,"file":"verifiedRegistry.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/chain/chains/ton/jetton/verifiedRegistry.ts"],"names":[],"mappings":"AASA;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,6EAA6E,CAAA;AAW7G,oFAAoF;AACpF,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB,CAAA;AAED;;;;GAIG;AACH,MAAM,MAAM,yBAAyB,GAAG;IACtC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;IACzC,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IACpB,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CACnB,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,6BAA6B,GAAI,SAAS,cAAc,EAAE,KAAG,yBAezE,CAAA;AA4DD;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,QAAa,OAAO,CAAC,yBAAyB,CAOtF,CAAA"}
@@ -1,11 +1,11 @@
1
1
  import { Chain } from '@vultisig/core-chain/Chain';
2
2
  import { tonAddressToRawKey } from '@vultisig/core-chain/chains/ton/address';
3
3
  import { knownTokens } from '@vultisig/core-chain/coin/knownTokens';
4
+ import { normalizeTokenSymbol } from '@vultisig/core-chain/coin/tokenSymbol';
4
5
  import { attempt } from '@vultisig/lib-utils/attempt';
5
6
  import { memoizeAsync } from '@vultisig/lib-utils/memoizeAsync';
6
7
  import { queryUrl } from '@vultisig/lib-utils/query/queryUrl';
7
8
  import { convertDuration } from '@vultisig/lib-utils/time/convertDuration';
8
- import { normalizeJettonSymbol } from './symbol.js';
9
9
  /**
10
10
  * Tonkeeper's community-reviewed jetton whitelist, the list every major TON
11
11
  * wallet uses as its "verified" tier. Compiled from the repo's YAML sources on
@@ -26,10 +26,10 @@ export const makeTonVerifiedJettonRegistry = (jettons) => {
26
26
  for (const jetton of jettons) {
27
27
  const address = tonAddressToRawKey(jetton.address);
28
28
  registry.byAddress[address] ??= { ...jetton, address };
29
- const symbol = normalizeJettonSymbol(jetton.symbol);
29
+ const symbol = normalizeTokenSymbol(jetton.symbol);
30
30
  if (symbol)
31
31
  registry.symbols.add(symbol);
32
- const name = jetton.name ? normalizeJettonSymbol(jetton.name) : '';
32
+ const name = jetton.name ? normalizeTokenSymbol(jetton.name) : '';
33
33
  if (name)
34
34
  registry.names.add(name);
35
35
  }
@@ -1 +1 @@
1
- {"version":3,"file":"verifiedRegistry.js","sourceRoot":"","sources":["../../../../../../../packages/core/chain/chains/ton/jetton/verifiedRegistry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"verifiedRegistry.js","sourceRoot":"","sources":["../../../../../../../packages/core/chain/chains/ton/jetton/verifiedRegistry.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,17 @@ export type SolanaCoingeckoTokenResponse = {
7
7
  };
8
8
  };
9
9
  };
10
+ /** CoinGecko's on-chain multi-token lookup; a mint it does not index is simply missing from `data`. */
11
+ export type SolanaCoingeckoTokensResponse = {
12
+ data?: {
13
+ id: string;
14
+ type: 'token';
15
+ attributes?: {
16
+ address?: string;
17
+ coingecko_coin_id?: string | null;
18
+ };
19
+ }[];
20
+ };
10
21
  export type SolanaFmTokenResponse = {
11
22
  tokenList?: {
12
23
  extensions?: {
@@ -1 +1 @@
1
- {"version":3,"file":"coingeckoToken.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/chain/coin/coingecko/coingeckoToken.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,4BAA4B,GAAG;IACzC,IAAI,EAAE;QACJ,EAAE,EAAE,MAAM,CAAA;QACV,IAAI,EAAE,OAAO,CAAA;QACb,UAAU,EAAE;YACV,iBAAiB,EAAE,MAAM,CAAA;SAC1B,CAAA;KACF,CAAA;CACF,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,SAAS,CAAC,EAAE;QACV,UAAU,CAAC,EAAE;YACX,WAAW,CAAC,EAAE,MAAM,CAAA;SACrB,GAAG,IAAI,CAAA;KACT,GAAG,IAAI,CAAA;CACT,CAAA"}
1
+ {"version":3,"file":"coingeckoToken.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/chain/coin/coingecko/coingeckoToken.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,4BAA4B,GAAG;IACzC,IAAI,EAAE;QACJ,EAAE,EAAE,MAAM,CAAA;QACV,IAAI,EAAE,OAAO,CAAA;QACb,UAAU,EAAE;YACV,iBAAiB,EAAE,MAAM,CAAA;SAC1B,CAAA;KACF,CAAA;CACF,CAAA;AAED,uGAAuG;AACvG,MAAM,MAAM,6BAA6B,GAAG;IAC1C,IAAI,CAAC,EAAE;QACL,EAAE,EAAE,MAAM,CAAA;QACV,IAAI,EAAE,OAAO,CAAA;QACb,UAAU,CAAC,EAAE;YACX,OAAO,CAAC,EAAE,MAAM,CAAA;YAChB,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;SAClC,CAAA;KACF,EAAE,CAAA;CACJ,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,SAAS,CAAC,EAAE;QACV,UAAU,CAAC,EAAE;YACX,WAAW,CAAC,EAAE,MAAM,CAAA;SACrB,GAAG,IAAI,CAAA;KACT,GAAG,IAAI,CAAA;CACT,CAAA"}
@@ -1,4 +1,14 @@
1
1
  export declare const getSolanaCoingeckoId: ({ id }: {
2
2
  id: string;
3
3
  }) => Promise<string | undefined>;
4
+ /**
5
+ * CoinGecko ids for the given mints, keyed by mint, read from CoinGecko's
6
+ * on-chain index thirty mints per call. Mints are matched exactly: base58 is
7
+ * case-sensitive and CoinGecko echoes the on-chain spelling. A mint it does
8
+ * not index, or lists without a coin id, is absent from the result. A failed
9
+ * call propagates instead of degrading to "no id": a caller that persists the
10
+ * answer would otherwise store a priced token as unpriced for good, whereas a
11
+ * failed call can simply be retried.
12
+ */
13
+ export declare const getSolanaCoingeckoIds: (ids: string[]) => Promise<Record<string, string>>;
4
14
  //# sourceMappingURL=getCoingeckoId.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"getCoingeckoId.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/chain/coin/coingecko/getCoingeckoId.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,oBAAoB,GAAU,QAAQ;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,gCAgBhE,CAAA"}
1
+ {"version":3,"file":"getCoingeckoId.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/chain/coin/coingecko/getCoingeckoId.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,oBAAoB,GAAU,QAAQ;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,gCAchE,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,GAAU,KAAK,MAAM,EAAE,KAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAqBzF,CAAA"}
@@ -1,8 +1,13 @@
1
1
  import { rootApiUrl } from '@vultisig/core-config';
2
+ import { toBatches } from '@vultisig/lib-utils/array/toBatches';
3
+ import { withoutDuplicates } from '@vultisig/lib-utils/array/withoutDuplicates';
2
4
  import { attempt } from '@vultisig/lib-utils/attempt';
3
5
  import { queryUrl } from '@vultisig/lib-utils/query/queryUrl';
6
+ const onchainSolanaTokensUrl = `${rootApiUrl}/coingeicko/api/v3/onchain/networks/solana/tokens`;
7
+ /** CoinGecko documents up to thirty addresses per multi-token call. */
8
+ const mintsPerLookup = 30;
4
9
  export const getSolanaCoingeckoId = async ({ id }) => {
5
- const cgResult = await attempt(() => queryUrl(`${rootApiUrl}/coingeicko/api/v3/onchain/networks/solana/tokens/${id}`));
10
+ const cgResult = await attempt(() => queryUrl(`${onchainSolanaTokensUrl}/${id}`));
6
11
  if ('data' in cgResult) {
7
12
  const coingeckoId = cgResult.data?.data?.attributes?.coingecko_coin_id ?? undefined;
8
13
  if (coingeckoId)
@@ -16,4 +21,28 @@ export const getSolanaCoingeckoId = async ({ id }) => {
16
21
  }
17
22
  return undefined;
18
23
  };
24
+ /**
25
+ * CoinGecko ids for the given mints, keyed by mint, read from CoinGecko's
26
+ * on-chain index thirty mints per call. Mints are matched exactly: base58 is
27
+ * case-sensitive and CoinGecko echoes the on-chain spelling. A mint it does
28
+ * not index, or lists without a coin id, is absent from the result. A failed
29
+ * call propagates instead of degrading to "no id": a caller that persists the
30
+ * answer would otherwise store a priced token as unpriced for good, whereas a
31
+ * failed call can simply be retried.
32
+ */
33
+ export const getSolanaCoingeckoIds = async (ids) => {
34
+ const requested = withoutDuplicates(ids);
35
+ const wanted = new Set(requested);
36
+ const responses = await Promise.all(toBatches(requested, mintsPerLookup).map(batch => queryUrl(`${onchainSolanaTokensUrl}/multi/${batch.join(',')}`)));
37
+ const result = {};
38
+ for (const { data } of responses) {
39
+ for (const { attributes } of data ?? []) {
40
+ const address = attributes?.address;
41
+ if (address && wanted.has(address) && attributes.coingecko_coin_id) {
42
+ result[address] = attributes.coingecko_coin_id;
43
+ }
44
+ }
45
+ }
46
+ return result;
47
+ };
19
48
  //# sourceMappingURL=getCoingeckoId.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"getCoingeckoId.js","sourceRoot":"","sources":["../../../../../../packages/core/chain/coin/coingecko/getCoingeckoId.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAA;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,oCAAoC,CAAA;AAI7D,MAAM,CAAC,MAAM,oBAAoB,GAAG,KAAK,EAAE,EAAE,EAAE,EAAkB,EAAE,EAAE;IACnE,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,CAClC,QAAQ,CAA+B,GAAG,UAAU,qDAAqD,EAAE,EAAE,CAAC,CAC/G,CAAA;IACD,IAAI,MAAM,IAAI,QAAQ,EAAE,CAAC;QACvB,MAAM,WAAW,GAAG,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,iBAAiB,IAAI,SAAS,CAAA;QACnF,IAAI,WAAW;YAAE,OAAO,WAAW,CAAA;IACrC,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAwB,mCAAmC,EAAE,EAAE,CAAC,CAAC,CAAA;IAC9G,IAAI,MAAM,IAAI,QAAQ,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,CAAA;QAC9D,IAAI,IAAI;YAAE,OAAO,IAAI,CAAA;IACvB,CAAC;IAED,OAAO,SAAS,CAAA;AAClB,CAAC,CAAA"}
1
+ {"version":3,"file":"getCoingeckoId.js","sourceRoot":"","sources":["../../../../../../packages/core/chain/coin/coingecko/getCoingeckoId.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,qCAAqC,CAAA;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,6CAA6C,CAAA;AAC/E,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAA;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,oCAAoC,CAAA;AAI7D,MAAM,sBAAsB,GAAG,GAAG,UAAU,mDAAmD,CAAA;AAE/F,uEAAuE;AACvE,MAAM,cAAc,GAAG,EAAE,CAAA;AAEzB,MAAM,CAAC,MAAM,oBAAoB,GAAG,KAAK,EAAE,EAAE,EAAE,EAAkB,EAAE,EAAE;IACnE,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,CAAC,QAAQ,CAA+B,GAAG,sBAAsB,IAAI,EAAE,EAAE,CAAC,CAAC,CAAA;IAC/G,IAAI,MAAM,IAAI,QAAQ,EAAE,CAAC;QACvB,MAAM,WAAW,GAAG,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,iBAAiB,IAAI,SAAS,CAAA;QACnF,IAAI,WAAW;YAAE,OAAO,WAAW,CAAA;IACrC,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAwB,mCAAmC,EAAE,EAAE,CAAC,CAAC,CAAA;IAC9G,IAAI,MAAM,IAAI,QAAQ,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,CAAA;QAC9D,IAAI,IAAI;YAAE,OAAO,IAAI,CAAA;IACvB,CAAC;IAED,OAAO,SAAS,CAAA;AAClB,CAAC,CAAA;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,KAAK,EAAE,GAAa,EAAmC,EAAE;IAC5F,MAAM,SAAS,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAA;IACxC,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAA;IAEjC,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,GAAG,CACjC,SAAS,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAC/C,QAAQ,CAAgC,GAAG,sBAAsB,UAAU,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAC9F,CACF,CAAA;IAED,MAAM,MAAM,GAA2B,EAAE,CAAA;IACzC,KAAK,MAAM,EAAE,IAAI,EAAE,IAAI,SAAS,EAAE,CAAC;QACjC,KAAK,MAAM,EAAE,UAAU,EAAE,IAAI,IAAI,IAAI,EAAE,EAAE,CAAC;YACxC,MAAM,OAAO,GAAG,UAAU,EAAE,OAAO,CAAA;YACnC,IAAI,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,UAAU,CAAC,iBAAiB,EAAE,CAAC;gBACnE,MAAM,CAAC,OAAO,CAAC,GAAG,UAAU,CAAC,iBAAiB,CAAA;YAChD,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC,CAAA"}
@@ -1,3 +1,24 @@
1
+ import { OtherChain } from '@vultisig/core-chain/Chain';
1
2
  import { FindCoinsResolver } from '@vultisig/core-chain/coin/find/resolver';
2
- export declare const findSolanaCoins: FindCoinsResolver;
3
+ /**
4
+ * Discovers the SPL and Token-2022 holdings at `address` that pass verification.
5
+ *
6
+ * Only `verified` mints are returned. Solana wallets are carpet-bombed with
7
+ * airdropped counterfeits and zero-decimal spam, and auto-adding those to a
8
+ * vault would put a "USDT" balance on the home screen that the user never
9
+ * received. A verified token is returned whether or not a price id is known
10
+ * for it: gating on price hid legitimate unpriced tokens while letting priced
11
+ * scams through. Unverified and scam mints can still be added by hand, where
12
+ * the UI labels them.
13
+ *
14
+ * Jupiter answers for a hundred mints per call and CoinGecko for thirty, so a
15
+ * whole wallet costs a handful of calls; decimals come from the token account
16
+ * itself, and curated metadata wins for tokens we ship ourselves. When Jupiter
17
+ * cannot be reached, listed mints are still discovered from registry metadata
18
+ * and only a mint verified since the registry's last refresh waits for the
19
+ * next round. A failed price-id lookup, by contrast, fails the round: the
20
+ * caller persists the result, and a token saved without its price id would
21
+ * stay unpriced for good.
22
+ */
23
+ export declare const findSolanaCoins: FindCoinsResolver<OtherChain.Solana>;
3
24
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/coin/find/resolvers/solana/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,yCAAyC,CAAA;AAO3E,eAAO,MAAM,eAAe,EAAE,iBAiB7B,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/chain/coin/find/resolvers/solana/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AAMvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yCAAyC,CAAA;AAkB3E;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,eAAe,EAAE,iBAAiB,CAAC,UAAU,CAAC,MAAM,CAgEhE,CAAA"}