@embarkai/ui-kit 0.4.13 → 0.4.17
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.
- package/dist/iframe/index.html +1 -1
- package/dist/iframe/main.js +3 -3
- package/dist/index.cjs +78 -21
- package/dist/index.d.cts +22 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +78 -21
- package/package.json +2 -2
package/dist/iframe/index.html
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
<meta http-equiv="X-Content-Type-Options" content="nosniff" />
|
|
16
16
|
<meta http-equiv="Referrer-Policy" content="strict-origin-when-cross-origin" />
|
|
17
17
|
|
|
18
|
-
<title>EmbarkAI Secure Wallet - iframe version 0.4.
|
|
18
|
+
<title>EmbarkAI Secure Wallet - iframe version 0.4.17</title>
|
|
19
19
|
|
|
20
20
|
<!-- Styles will be injected by build process -->
|
|
21
21
|
<style>
|
package/dist/iframe/main.js
CHANGED
|
@@ -4592,7 +4592,7 @@ var BinanceOnrampAPI = class {
|
|
|
4592
4592
|
this.disconnectSse();
|
|
4593
4593
|
const controller = new AbortController();
|
|
4594
4594
|
this.sseAbortController = controller;
|
|
4595
|
-
const url = `${API_DOMAIN}/sse/
|
|
4595
|
+
const url = `${API_DOMAIN}/sse/events?walletAddress=${encodeURIComponent(walletAddress)}`;
|
|
4596
4596
|
const start = async () => {
|
|
4597
4597
|
try {
|
|
4598
4598
|
const response = await fetch(url, {
|
|
@@ -4780,7 +4780,7 @@ var FinchPayRampAPI = class {
|
|
|
4780
4780
|
this.disconnectSse();
|
|
4781
4781
|
const controller = new AbortController();
|
|
4782
4782
|
this.sseAbortController = controller;
|
|
4783
|
-
const url = `${API_DOMAIN2}/sse/
|
|
4783
|
+
const url = `${API_DOMAIN2}/sse/events?walletAddress=${encodeURIComponent(walletAddress)}`;
|
|
4784
4784
|
const start = async () => {
|
|
4785
4785
|
try {
|
|
4786
4786
|
const response = await fetch(url, {
|
|
@@ -6262,7 +6262,7 @@ var SigningManager = class extends TokenRefreshApiClient {
|
|
|
6262
6262
|
};
|
|
6263
6263
|
|
|
6264
6264
|
// src/iframe/main.ts
|
|
6265
|
-
var IFRAME_VERSION = "0.4.
|
|
6265
|
+
var IFRAME_VERSION = "0.4.17";
|
|
6266
6266
|
var IframeWallet = class {
|
|
6267
6267
|
constructor() {
|
|
6268
6268
|
console.log("=".repeat(60));
|
package/dist/index.cjs
CHANGED
|
@@ -15170,6 +15170,7 @@ function useWatchTokens(options) {
|
|
|
15170
15170
|
// 30 seconds
|
|
15171
15171
|
gcTime: 5 * 60 * 1e3,
|
|
15172
15172
|
// 5 minutes
|
|
15173
|
+
refetchOnMount: "always",
|
|
15173
15174
|
retry: 2,
|
|
15174
15175
|
retryDelay: 1e3
|
|
15175
15176
|
});
|
|
@@ -15235,6 +15236,7 @@ function mapBlockscoutToAsset(balance) {
|
|
|
15235
15236
|
balance: value,
|
|
15236
15237
|
formattedBalance,
|
|
15237
15238
|
decimals,
|
|
15239
|
+
exchangeRateUsd: token.exchange_rate || void 0,
|
|
15238
15240
|
logo: token.icon_url || void 0
|
|
15239
15241
|
};
|
|
15240
15242
|
if (type === "erc721" || type === "erc1155") {
|
|
@@ -15320,6 +15322,9 @@ function useBlockscoutAssets(options) {
|
|
|
15320
15322
|
const publicClient = useSession((st) => st.publicClient);
|
|
15321
15323
|
const activeChainId = useSession((st) => st.activeChainId);
|
|
15322
15324
|
const chainConfig = useSession((st) => st.chainConfig);
|
|
15325
|
+
const portfolioConfig = useProviderConfig().config.current.portfolio;
|
|
15326
|
+
const customTokenBalancesQuery = portfolioConfig?.tokenBalancesQuery;
|
|
15327
|
+
const customTokenBalancesQueryKey = portfolioConfig?.tokenBalancesQueryKey;
|
|
15323
15328
|
const blockscoutApiUrl = getBlockscoutApiUrl(chainConfig);
|
|
15324
15329
|
const blockscoutClient = (0, import_react57.useMemo)(
|
|
15325
15330
|
() => blockscoutApiUrl ? (0, import_clients2.createBlockscoutClient)({ baseUrl: blockscoutApiUrl }) : null,
|
|
@@ -15350,8 +15355,9 @@ function useBlockscoutAssets(options) {
|
|
|
15350
15355
|
enabled: !!publicClient && !!address && enabled,
|
|
15351
15356
|
staleTime: 30 * 1e3,
|
|
15352
15357
|
// 30 seconds
|
|
15353
|
-
gcTime: 5 * 60 * 1e3
|
|
15358
|
+
gcTime: 5 * 60 * 1e3,
|
|
15354
15359
|
// 5 minutes
|
|
15360
|
+
refetchOnMount: "always"
|
|
15355
15361
|
});
|
|
15356
15362
|
const {
|
|
15357
15363
|
data: tokenBalances,
|
|
@@ -15360,11 +15366,22 @@ function useBlockscoutAssets(options) {
|
|
|
15360
15366
|
refetch: refetchTokens,
|
|
15361
15367
|
dataUpdatedAt
|
|
15362
15368
|
} = (0, import_react_query39.useQuery)({
|
|
15363
|
-
queryKey: [BLOCKSCOUT_QUERY_KEY, address, blockscoutApiUrl],
|
|
15364
|
-
queryFn: () =>
|
|
15365
|
-
|
|
15366
|
-
|
|
15369
|
+
queryKey: [BLOCKSCOUT_QUERY_KEY, address, blockscoutApiUrl, customTokenBalancesQueryKey],
|
|
15370
|
+
queryFn: async () => {
|
|
15371
|
+
if (customTokenBalancesQuery) {
|
|
15372
|
+
try {
|
|
15373
|
+
return await customTokenBalancesQuery(address);
|
|
15374
|
+
} catch (error2) {
|
|
15375
|
+
console.warn("[useBlockscoutAssets] Custom token balances query failed:", error2);
|
|
15376
|
+
if (!blockscoutClient) throw error2;
|
|
15377
|
+
}
|
|
15378
|
+
}
|
|
15379
|
+
return await blockscoutClient.getTokenBalances(address);
|
|
15380
|
+
},
|
|
15381
|
+
enabled: !!address && enabled && (!!customTokenBalancesQuery || !!blockscoutClient),
|
|
15382
|
+
staleTime: 0,
|
|
15367
15383
|
gcTime: BLOCKSCOUT_QUERY_GC_TIME,
|
|
15384
|
+
refetchOnMount: "always",
|
|
15368
15385
|
retry: 2,
|
|
15369
15386
|
retryDelay: 1e3
|
|
15370
15387
|
});
|
|
@@ -15378,6 +15395,7 @@ function useBlockscoutAssets(options) {
|
|
|
15378
15395
|
enabled: !!address && enabled && !!blockscoutClient,
|
|
15379
15396
|
staleTime: BLOCKSCOUT_QUERY_STALE_TIME,
|
|
15380
15397
|
gcTime: BLOCKSCOUT_QUERY_GC_TIME,
|
|
15398
|
+
refetchOnMount: "always",
|
|
15381
15399
|
retry: 2,
|
|
15382
15400
|
retryDelay: 1e3
|
|
15383
15401
|
});
|
|
@@ -15512,6 +15530,7 @@ function useBlockscoutAssets(options) {
|
|
|
15512
15530
|
var import_clients2, import_react_query39, import_react57, import_viem7, BLOCKSCOUT_QUERY_KEY, ERC3643_DETECTION_QUERY_KEY, ERC3643_ABI;
|
|
15513
15531
|
var init_useBlockscoutAssets = __esm({
|
|
15514
15532
|
"src/internal/hooks/useBlockscoutAssets.ts"() {
|
|
15533
|
+
init_ProviderContext();
|
|
15515
15534
|
init_SessionContext();
|
|
15516
15535
|
import_clients2 = require("@embarkai/core/clients");
|
|
15517
15536
|
import_react_query39 = require("@tanstack/react-query");
|
|
@@ -15614,6 +15633,21 @@ async function getAssetRate2(symbol) {
|
|
|
15614
15633
|
const response = await fetch(assetURL);
|
|
15615
15634
|
return await response.json();
|
|
15616
15635
|
}
|
|
15636
|
+
async function resolveAssetRate(symbol, address, customAssetRateQuery) {
|
|
15637
|
+
if (customAssetRateQuery) {
|
|
15638
|
+
try {
|
|
15639
|
+
const customRate = await customAssetRateQuery({ symbol, address });
|
|
15640
|
+
const numeric = Number(customRate?.price || 0);
|
|
15641
|
+
if (customRate && Number.isFinite(numeric) && numeric > 0) {
|
|
15642
|
+
return customRate;
|
|
15643
|
+
}
|
|
15644
|
+
} catch (error) {
|
|
15645
|
+
console.warn("[PortfolioItem] Custom asset rate query failed:", error);
|
|
15646
|
+
}
|
|
15647
|
+
}
|
|
15648
|
+
if (!isAssetRateAvailable(symbol)) return null;
|
|
15649
|
+
return getAssetRate2(symbol);
|
|
15650
|
+
}
|
|
15617
15651
|
function PortfolioItemImage(props) {
|
|
15618
15652
|
const { asset } = props;
|
|
15619
15653
|
const [nftImageError, setNftImageError] = (0, import_react58.useState)(false);
|
|
@@ -15660,22 +15694,29 @@ function PortfolioItemImage(props) {
|
|
|
15660
15694
|
}
|
|
15661
15695
|
function PortfolioItem(props) {
|
|
15662
15696
|
const { address, asset, isProjectAsset } = props;
|
|
15663
|
-
const
|
|
15697
|
+
const providerConfig = useProviderConfig().config.current;
|
|
15698
|
+
const { assets: projectAssets, showBalanceAs: showBalanceAsSymbol } = providerConfig.projectAssets || {};
|
|
15699
|
+
const customAssetRateQuery = providerConfig.portfolio?.assetRateQuery;
|
|
15700
|
+
const customAssetRateQueryKey = providerConfig.portfolio?.assetRateQueryKey;
|
|
15664
15701
|
const qc = (0, import_react_query40.useQueryClient)();
|
|
15665
15702
|
const { balanceQueryKey } = projectAssets?.find((a) => a.symbol === showBalanceAsSymbol) || {};
|
|
15666
15703
|
const projectAssetBalance = !!balanceQueryKey ? qc.getQueryData(balanceQueryKey) : null;
|
|
15667
15704
|
const isNft = isNftAsset(asset);
|
|
15668
15705
|
const isSecurity = isSecurityToken(asset);
|
|
15706
|
+
const embeddedRate = Number(asset.exchangeRateUsd || 0);
|
|
15707
|
+
const hasEmbeddedRate = Number.isFinite(embeddedRate) && embeddedRate > 0;
|
|
15669
15708
|
const { data: assetRate, isLoading: isRateLoading } = (0, import_react_query40.useQuery)({
|
|
15670
15709
|
retry: false,
|
|
15671
15710
|
staleTime: 4 * 60 * 1e3,
|
|
15672
|
-
enabled: !!address &&
|
|
15673
|
-
queryKey: [ASSETS_RATES_QUERY_KEY, address, asset.symbol],
|
|
15674
|
-
queryFn: async () => await
|
|
15711
|
+
enabled: !!address && !hasEmbeddedRate && !isProjectAsset && !isNft && !isSecurity && (!!customAssetRateQuery || !!isAssetRateAvailable(asset.symbol)),
|
|
15712
|
+
queryKey: [ASSETS_RATES_QUERY_KEY, address, asset.address, asset.symbol, customAssetRateQueryKey],
|
|
15713
|
+
queryFn: async () => await resolveAssetRate(asset.symbol, asset.address, customAssetRateQuery)
|
|
15675
15714
|
});
|
|
15676
15715
|
const showProjectFiatBalance = isProjectAsset && !!projectAssetBalance?.fiatFormatted;
|
|
15677
15716
|
const renderBalance = showProjectFiatBalance ? projectAssetBalance?.fiatFormatted || 0 : Number((0, import_viem9.formatUnits)(BigInt(asset?.balance || "0"), asset?.decimals || 18));
|
|
15678
|
-
const
|
|
15717
|
+
const resolvedRate = hasEmbeddedRate ? embeddedRate : Number(assetRate?.price || 0);
|
|
15718
|
+
const usdRenderBalance = resolvedRate > 0 ? renderBalance * resolvedRate : 0;
|
|
15719
|
+
const shortContractAddress = asset.address ? truncateMiddle(asset.address, 6, 4) : null;
|
|
15679
15720
|
return /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)(
|
|
15680
15721
|
"div",
|
|
15681
15722
|
{
|
|
@@ -15689,15 +15730,22 @@ function PortfolioItem(props) {
|
|
|
15689
15730
|
children: [
|
|
15690
15731
|
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)(PortfolioItemImage, { asset }),
|
|
15691
15732
|
/* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "w-full flex-1", children: [
|
|
15692
|
-
/* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "w-full flex items-center justify-between text-xs", children: [
|
|
15693
|
-
/* @__PURE__ */ (0, import_jsx_runtime80.
|
|
15694
|
-
|
|
15695
|
-
|
|
15696
|
-
|
|
15697
|
-
|
|
15698
|
-
|
|
15699
|
-
|
|
15700
|
-
|
|
15733
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "w-full flex items-center justify-between text-xs gap-2", children: [
|
|
15734
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("div", { className: "min-w-0 flex flex-col", children: [
|
|
15735
|
+
/* @__PURE__ */ (0, import_jsx_runtime80.jsx)(
|
|
15736
|
+
"span",
|
|
15737
|
+
{
|
|
15738
|
+
className: "truncate max-w-[150px]",
|
|
15739
|
+
title: isNft ? asset.nftMetadata?.collectionName || asset.name : asset.name,
|
|
15740
|
+
children: isNft ? asset.nftMetadata?.collectionName || asset.name || shortContractAddress || "Unknown" : asset.name || shortContractAddress || "Unknown"
|
|
15741
|
+
}
|
|
15742
|
+
),
|
|
15743
|
+
!isNft && shortContractAddress && /* @__PURE__ */ (0, import_jsx_runtime80.jsxs)("span", { className: "text-[10px] text-[var(--ui-kit-fg-muted)] font-mono truncate", title: asset.address, children: [
|
|
15744
|
+
asset.symbol,
|
|
15745
|
+
" \xB7 ",
|
|
15746
|
+
shortContractAddress
|
|
15747
|
+
] })
|
|
15748
|
+
] }),
|
|
15701
15749
|
!!usdRenderBalance && !isProjectAsset && !isNft && !isSecurity && /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "text-[var(--ui-kit-fg-muted)]", children: "USD" }),
|
|
15702
15750
|
!isSecurity && isNft && "type" in asset && /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "uppercase text-[10px] px-1 bg-[var(--ui-kit-bg-info)] rounded-full", children: asset.type === "erc721" ? "ERC-721" : "ERC-1155" }),
|
|
15703
15751
|
isSecurity && /* @__PURE__ */ (0, import_jsx_runtime80.jsx)("span", { className: "uppercase text-[10px] px-1 bg-[var(--ui-kit-bg-warning)] rounded-full", children: "Security Token" })
|
|
@@ -15741,6 +15789,7 @@ var init_PortfolioItem = __esm({
|
|
|
15741
15789
|
init_base();
|
|
15742
15790
|
init_priceFormatter();
|
|
15743
15791
|
init_utils2();
|
|
15792
|
+
init_truncateMiddle();
|
|
15744
15793
|
init_BalanceView2();
|
|
15745
15794
|
import_jsx_runtime80 = require("react/jsx-runtime");
|
|
15746
15795
|
SKIP_SYMBOLS2 = ["TEST"];
|
|
@@ -16982,6 +17031,11 @@ function AssetListItem(props) {
|
|
|
16982
17031
|
/* @__PURE__ */ (0, import_jsx_runtime91.jsx)(AssetInputIcon, { asset, size: "large" }),
|
|
16983
17032
|
/* @__PURE__ */ (0, import_jsx_runtime91.jsxs)("div", { className: "flex-1 flex flex-col items-start", children: [
|
|
16984
17033
|
/* @__PURE__ */ (0, import_jsx_runtime91.jsx)("div", { className: "text-[10px] truncate leading-4", children: isNft ? asset.nftMetadata?.name || asset.name : asset.name }),
|
|
17034
|
+
!isNft && asset.address && /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)("div", { className: "text-[10px] text-[var(--ui-kit-fg-muted)] font-mono truncate leading-4", title: asset.address, children: [
|
|
17035
|
+
asset.symbol,
|
|
17036
|
+
" \xB7 ",
|
|
17037
|
+
truncateMiddle(asset.address, 6, 4)
|
|
17038
|
+
] }),
|
|
16985
17039
|
/* @__PURE__ */ (0, import_jsx_runtime91.jsx)("span", { className: "block text-lg font-bold", children: isNft ? /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(import_jsx_runtime91.Fragment, { children: [
|
|
16986
17040
|
asset.symbol,
|
|
16987
17041
|
asset.tokenId && /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)("span", { className: "ml-1", children: [
|
|
@@ -17039,6 +17093,7 @@ var init_AssetList = __esm({
|
|
|
17039
17093
|
import_viem13 = require("viem");
|
|
17040
17094
|
init_priceFormatter();
|
|
17041
17095
|
init_utils2();
|
|
17096
|
+
init_truncateMiddle();
|
|
17042
17097
|
init_BalanceView2();
|
|
17043
17098
|
init_useSendStore();
|
|
17044
17099
|
init_utils8();
|
|
@@ -19296,7 +19351,7 @@ var init_package = __esm({
|
|
|
19296
19351
|
"package.json"() {
|
|
19297
19352
|
package_default = {
|
|
19298
19353
|
name: "@embarkai/ui-kit",
|
|
19299
|
-
version: "0.4.
|
|
19354
|
+
version: "0.4.17",
|
|
19300
19355
|
description: "React UI components and hooks for EmbarkAI authentication and Account Abstraction",
|
|
19301
19356
|
type: "module",
|
|
19302
19357
|
main: "./dist/index.cjs",
|
|
@@ -19312,8 +19367,9 @@ var init_package = __esm({
|
|
|
19312
19367
|
clean: "rm -rf dist",
|
|
19313
19368
|
"build:css": "tailwindcss -c tailwind.config.cjs -i src/styles/index.css -o src/styles/built.css --minify",
|
|
19314
19369
|
"build:iframe-html": "node scripts/copy-iframe-html.js",
|
|
19315
|
-
"build:copy-css": "
|
|
19370
|
+
"build:copy-css": "node scripts/copy-styles-css.js",
|
|
19316
19371
|
build: "pnpm build:css && tsup && pnpm build:iframe-html && pnpm build:copy-css",
|
|
19372
|
+
prepack: "pnpm build",
|
|
19317
19373
|
dev: "pnpm build:css && tsup --watch",
|
|
19318
19374
|
"dev:iframe": "vite --config iframe/vite.config.ts",
|
|
19319
19375
|
csv: "npx tsx src/i18n/utils/prepareCsvProofread.ts --origin en --target zh",
|
|
@@ -23285,6 +23341,7 @@ function Provider(props) {
|
|
|
23285
23341
|
if (updates.warnings) next.warnings = { ...next.warnings, ...updates.warnings };
|
|
23286
23342
|
if (updates.kyc) next.kyc = { ...next.kyc, ...updates.kyc };
|
|
23287
23343
|
if (updates.watchTokens) next.watchTokens = { ...next.watchTokens, ...updates.watchTokens };
|
|
23344
|
+
if (updates.portfolio) next.portfolio = { ...next.portfolio, ...updates.portfolio };
|
|
23288
23345
|
if (updates.services && typeof window !== "undefined") {
|
|
23289
23346
|
try {
|
|
23290
23347
|
window.__EMBARK_SERVICES__ = next.services;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import * as React$1 from 'react';
|
|
3
3
|
import React__default, { ReactNode, MutableRefObject, FC, HTMLAttributes, ButtonHTMLAttributes } from 'react';
|
|
4
|
+
import { BlockscoutTokenBalance } from '@embarkai/core/clients';
|
|
4
5
|
import * as viem from 'viem';
|
|
5
6
|
import { Address as Address$1, Hex, PublicClient, Chain, Hash as Hash$1, TransactionReceipt } from 'viem';
|
|
6
7
|
import * as _tanstack_react_query from '@tanstack/react-query';
|
|
@@ -89,6 +90,8 @@ interface Asset {
|
|
|
89
90
|
formattedBalance: string;
|
|
90
91
|
/** Decimal precision (undefined for NFTs) */
|
|
91
92
|
decimals?: number;
|
|
93
|
+
/** USD rate reported by explorer when available */
|
|
94
|
+
exchangeRateUsd?: string;
|
|
92
95
|
/** NFT token ID (only for ERC721/ERC1155) */
|
|
93
96
|
tokenId?: string;
|
|
94
97
|
/** Token logo URL */
|
|
@@ -178,6 +181,14 @@ interface ProjectAsset extends Omit<Asset, 'type'> {
|
|
|
178
181
|
}>;
|
|
179
182
|
hideInPortfolio?: boolean;
|
|
180
183
|
}
|
|
184
|
+
interface AssetRateQueryInput {
|
|
185
|
+
symbol: string;
|
|
186
|
+
address?: `0x${string}`;
|
|
187
|
+
}
|
|
188
|
+
interface AssetRateQueryResult {
|
|
189
|
+
symbol: string;
|
|
190
|
+
price: string;
|
|
191
|
+
}
|
|
181
192
|
/**
|
|
182
193
|
* Token configuration for custom token watching.
|
|
183
194
|
* Used when chain doesn't have Blockscout API or for project-specific tokens.
|
|
@@ -228,6 +239,17 @@ interface ProviderConfig {
|
|
|
228
239
|
assets: ProjectAsset[];
|
|
229
240
|
showBalanceAs?: ProjectAsset['symbol'];
|
|
230
241
|
};
|
|
242
|
+
/**
|
|
243
|
+
* Host-provided portfolio data overrides.
|
|
244
|
+
* If tokenBalancesQuery is provided, SDK uses it instead of Blockscout
|
|
245
|
+
* for ERC-20 portfolio balances and keeps the legacy Blockscout path as fallback.
|
|
246
|
+
*/
|
|
247
|
+
portfolio?: {
|
|
248
|
+
tokenBalancesQuery?: (address: `0x${string}`) => Promise<BlockscoutTokenBalance[]>;
|
|
249
|
+
tokenBalancesQueryKey?: readonly unknown[];
|
|
250
|
+
assetRateQuery?: (input: AssetRateQueryInput) => Promise<AssetRateQueryResult | null>;
|
|
251
|
+
assetRateQueryKey?: readonly unknown[];
|
|
252
|
+
};
|
|
231
253
|
/**
|
|
232
254
|
* Custom tokens to monitor per chain.
|
|
233
255
|
* SDK will fetch balances via RPC multicall.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import * as React$1 from 'react';
|
|
3
3
|
import React__default, { ReactNode, MutableRefObject, FC, HTMLAttributes, ButtonHTMLAttributes } from 'react';
|
|
4
|
+
import { BlockscoutTokenBalance } from '@embarkai/core/clients';
|
|
4
5
|
import * as viem from 'viem';
|
|
5
6
|
import { Address as Address$1, Hex, PublicClient, Chain, Hash as Hash$1, TransactionReceipt } from 'viem';
|
|
6
7
|
import * as _tanstack_react_query from '@tanstack/react-query';
|
|
@@ -89,6 +90,8 @@ interface Asset {
|
|
|
89
90
|
formattedBalance: string;
|
|
90
91
|
/** Decimal precision (undefined for NFTs) */
|
|
91
92
|
decimals?: number;
|
|
93
|
+
/** USD rate reported by explorer when available */
|
|
94
|
+
exchangeRateUsd?: string;
|
|
92
95
|
/** NFT token ID (only for ERC721/ERC1155) */
|
|
93
96
|
tokenId?: string;
|
|
94
97
|
/** Token logo URL */
|
|
@@ -178,6 +181,14 @@ interface ProjectAsset extends Omit<Asset, 'type'> {
|
|
|
178
181
|
}>;
|
|
179
182
|
hideInPortfolio?: boolean;
|
|
180
183
|
}
|
|
184
|
+
interface AssetRateQueryInput {
|
|
185
|
+
symbol: string;
|
|
186
|
+
address?: `0x${string}`;
|
|
187
|
+
}
|
|
188
|
+
interface AssetRateQueryResult {
|
|
189
|
+
symbol: string;
|
|
190
|
+
price: string;
|
|
191
|
+
}
|
|
181
192
|
/**
|
|
182
193
|
* Token configuration for custom token watching.
|
|
183
194
|
* Used when chain doesn't have Blockscout API or for project-specific tokens.
|
|
@@ -228,6 +239,17 @@ interface ProviderConfig {
|
|
|
228
239
|
assets: ProjectAsset[];
|
|
229
240
|
showBalanceAs?: ProjectAsset['symbol'];
|
|
230
241
|
};
|
|
242
|
+
/**
|
|
243
|
+
* Host-provided portfolio data overrides.
|
|
244
|
+
* If tokenBalancesQuery is provided, SDK uses it instead of Blockscout
|
|
245
|
+
* for ERC-20 portfolio balances and keeps the legacy Blockscout path as fallback.
|
|
246
|
+
*/
|
|
247
|
+
portfolio?: {
|
|
248
|
+
tokenBalancesQuery?: (address: `0x${string}`) => Promise<BlockscoutTokenBalance[]>;
|
|
249
|
+
tokenBalancesQueryKey?: readonly unknown[];
|
|
250
|
+
assetRateQuery?: (input: AssetRateQueryInput) => Promise<AssetRateQueryResult | null>;
|
|
251
|
+
assetRateQueryKey?: readonly unknown[];
|
|
252
|
+
};
|
|
231
253
|
/**
|
|
232
254
|
* Custom tokens to monitor per chain.
|
|
233
255
|
* SDK will fetch balances via RPC multicall.
|
package/dist/index.js
CHANGED
|
@@ -15106,6 +15106,7 @@ function useWatchTokens(options) {
|
|
|
15106
15106
|
// 30 seconds
|
|
15107
15107
|
gcTime: 5 * 60 * 1e3,
|
|
15108
15108
|
// 5 minutes
|
|
15109
|
+
refetchOnMount: "always",
|
|
15109
15110
|
retry: 2,
|
|
15110
15111
|
retryDelay: 1e3
|
|
15111
15112
|
});
|
|
@@ -15172,6 +15173,7 @@ function mapBlockscoutToAsset(balance) {
|
|
|
15172
15173
|
balance: value,
|
|
15173
15174
|
formattedBalance,
|
|
15174
15175
|
decimals,
|
|
15176
|
+
exchangeRateUsd: token.exchange_rate || void 0,
|
|
15175
15177
|
logo: token.icon_url || void 0
|
|
15176
15178
|
};
|
|
15177
15179
|
if (type === "erc721" || type === "erc1155") {
|
|
@@ -15257,6 +15259,9 @@ function useBlockscoutAssets(options) {
|
|
|
15257
15259
|
const publicClient = useSession((st) => st.publicClient);
|
|
15258
15260
|
const activeChainId = useSession((st) => st.activeChainId);
|
|
15259
15261
|
const chainConfig = useSession((st) => st.chainConfig);
|
|
15262
|
+
const portfolioConfig = useProviderConfig().config.current.portfolio;
|
|
15263
|
+
const customTokenBalancesQuery = portfolioConfig?.tokenBalancesQuery;
|
|
15264
|
+
const customTokenBalancesQueryKey = portfolioConfig?.tokenBalancesQueryKey;
|
|
15260
15265
|
const blockscoutApiUrl = getBlockscoutApiUrl(chainConfig);
|
|
15261
15266
|
const blockscoutClient = useMemo5(
|
|
15262
15267
|
() => blockscoutApiUrl ? createBlockscoutClient({ baseUrl: blockscoutApiUrl }) : null,
|
|
@@ -15287,8 +15292,9 @@ function useBlockscoutAssets(options) {
|
|
|
15287
15292
|
enabled: !!publicClient && !!address && enabled,
|
|
15288
15293
|
staleTime: 30 * 1e3,
|
|
15289
15294
|
// 30 seconds
|
|
15290
|
-
gcTime: 5 * 60 * 1e3
|
|
15295
|
+
gcTime: 5 * 60 * 1e3,
|
|
15291
15296
|
// 5 minutes
|
|
15297
|
+
refetchOnMount: "always"
|
|
15292
15298
|
});
|
|
15293
15299
|
const {
|
|
15294
15300
|
data: tokenBalances,
|
|
@@ -15297,11 +15303,22 @@ function useBlockscoutAssets(options) {
|
|
|
15297
15303
|
refetch: refetchTokens,
|
|
15298
15304
|
dataUpdatedAt
|
|
15299
15305
|
} = useQuery16({
|
|
15300
|
-
queryKey: [BLOCKSCOUT_QUERY_KEY, address, blockscoutApiUrl],
|
|
15301
|
-
queryFn: () =>
|
|
15302
|
-
|
|
15303
|
-
|
|
15306
|
+
queryKey: [BLOCKSCOUT_QUERY_KEY, address, blockscoutApiUrl, customTokenBalancesQueryKey],
|
|
15307
|
+
queryFn: async () => {
|
|
15308
|
+
if (customTokenBalancesQuery) {
|
|
15309
|
+
try {
|
|
15310
|
+
return await customTokenBalancesQuery(address);
|
|
15311
|
+
} catch (error2) {
|
|
15312
|
+
console.warn("[useBlockscoutAssets] Custom token balances query failed:", error2);
|
|
15313
|
+
if (!blockscoutClient) throw error2;
|
|
15314
|
+
}
|
|
15315
|
+
}
|
|
15316
|
+
return await blockscoutClient.getTokenBalances(address);
|
|
15317
|
+
},
|
|
15318
|
+
enabled: !!address && enabled && (!!customTokenBalancesQuery || !!blockscoutClient),
|
|
15319
|
+
staleTime: 0,
|
|
15304
15320
|
gcTime: BLOCKSCOUT_QUERY_GC_TIME,
|
|
15321
|
+
refetchOnMount: "always",
|
|
15305
15322
|
retry: 2,
|
|
15306
15323
|
retryDelay: 1e3
|
|
15307
15324
|
});
|
|
@@ -15315,6 +15332,7 @@ function useBlockscoutAssets(options) {
|
|
|
15315
15332
|
enabled: !!address && enabled && !!blockscoutClient,
|
|
15316
15333
|
staleTime: BLOCKSCOUT_QUERY_STALE_TIME,
|
|
15317
15334
|
gcTime: BLOCKSCOUT_QUERY_GC_TIME,
|
|
15335
|
+
refetchOnMount: "always",
|
|
15318
15336
|
retry: 2,
|
|
15319
15337
|
retryDelay: 1e3
|
|
15320
15338
|
});
|
|
@@ -15449,6 +15467,7 @@ function useBlockscoutAssets(options) {
|
|
|
15449
15467
|
var BLOCKSCOUT_QUERY_KEY, ERC3643_DETECTION_QUERY_KEY, ERC3643_ABI;
|
|
15450
15468
|
var init_useBlockscoutAssets = __esm({
|
|
15451
15469
|
"src/internal/hooks/useBlockscoutAssets.ts"() {
|
|
15470
|
+
init_ProviderContext();
|
|
15452
15471
|
init_SessionContext();
|
|
15453
15472
|
init_initial();
|
|
15454
15473
|
init_constants();
|
|
@@ -15552,6 +15571,21 @@ async function getAssetRate2(symbol) {
|
|
|
15552
15571
|
const response = await fetch(assetURL);
|
|
15553
15572
|
return await response.json();
|
|
15554
15573
|
}
|
|
15574
|
+
async function resolveAssetRate(symbol, address, customAssetRateQuery) {
|
|
15575
|
+
if (customAssetRateQuery) {
|
|
15576
|
+
try {
|
|
15577
|
+
const customRate = await customAssetRateQuery({ symbol, address });
|
|
15578
|
+
const numeric = Number(customRate?.price || 0);
|
|
15579
|
+
if (customRate && Number.isFinite(numeric) && numeric > 0) {
|
|
15580
|
+
return customRate;
|
|
15581
|
+
}
|
|
15582
|
+
} catch (error) {
|
|
15583
|
+
console.warn("[PortfolioItem] Custom asset rate query failed:", error);
|
|
15584
|
+
}
|
|
15585
|
+
}
|
|
15586
|
+
if (!isAssetRateAvailable(symbol)) return null;
|
|
15587
|
+
return getAssetRate2(symbol);
|
|
15588
|
+
}
|
|
15555
15589
|
function PortfolioItemImage(props) {
|
|
15556
15590
|
const { asset } = props;
|
|
15557
15591
|
const [nftImageError, setNftImageError] = useState22(false);
|
|
@@ -15598,22 +15632,29 @@ function PortfolioItemImage(props) {
|
|
|
15598
15632
|
}
|
|
15599
15633
|
function PortfolioItem(props) {
|
|
15600
15634
|
const { address, asset, isProjectAsset } = props;
|
|
15601
|
-
const
|
|
15635
|
+
const providerConfig = useProviderConfig().config.current;
|
|
15636
|
+
const { assets: projectAssets, showBalanceAs: showBalanceAsSymbol } = providerConfig.projectAssets || {};
|
|
15637
|
+
const customAssetRateQuery = providerConfig.portfolio?.assetRateQuery;
|
|
15638
|
+
const customAssetRateQueryKey = providerConfig.portfolio?.assetRateQueryKey;
|
|
15602
15639
|
const qc = useQueryClient20();
|
|
15603
15640
|
const { balanceQueryKey } = projectAssets?.find((a) => a.symbol === showBalanceAsSymbol) || {};
|
|
15604
15641
|
const projectAssetBalance = !!balanceQueryKey ? qc.getQueryData(balanceQueryKey) : null;
|
|
15605
15642
|
const isNft = isNftAsset(asset);
|
|
15606
15643
|
const isSecurity = isSecurityToken(asset);
|
|
15644
|
+
const embeddedRate = Number(asset.exchangeRateUsd || 0);
|
|
15645
|
+
const hasEmbeddedRate = Number.isFinite(embeddedRate) && embeddedRate > 0;
|
|
15607
15646
|
const { data: assetRate, isLoading: isRateLoading } = useQuery17({
|
|
15608
15647
|
retry: false,
|
|
15609
15648
|
staleTime: 4 * 60 * 1e3,
|
|
15610
|
-
enabled: !!address &&
|
|
15611
|
-
queryKey: [ASSETS_RATES_QUERY_KEY, address, asset.symbol],
|
|
15612
|
-
queryFn: async () => await
|
|
15649
|
+
enabled: !!address && !hasEmbeddedRate && !isProjectAsset && !isNft && !isSecurity && (!!customAssetRateQuery || !!isAssetRateAvailable(asset.symbol)),
|
|
15650
|
+
queryKey: [ASSETS_RATES_QUERY_KEY, address, asset.address, asset.symbol, customAssetRateQueryKey],
|
|
15651
|
+
queryFn: async () => await resolveAssetRate(asset.symbol, asset.address, customAssetRateQuery)
|
|
15613
15652
|
});
|
|
15614
15653
|
const showProjectFiatBalance = isProjectAsset && !!projectAssetBalance?.fiatFormatted;
|
|
15615
15654
|
const renderBalance = showProjectFiatBalance ? projectAssetBalance?.fiatFormatted || 0 : Number(formatUnits5(BigInt(asset?.balance || "0"), asset?.decimals || 18));
|
|
15616
|
-
const
|
|
15655
|
+
const resolvedRate = hasEmbeddedRate ? embeddedRate : Number(assetRate?.price || 0);
|
|
15656
|
+
const usdRenderBalance = resolvedRate > 0 ? renderBalance * resolvedRate : 0;
|
|
15657
|
+
const shortContractAddress = asset.address ? truncateMiddle(asset.address, 6, 4) : null;
|
|
15617
15658
|
return /* @__PURE__ */ jsxs73(
|
|
15618
15659
|
"div",
|
|
15619
15660
|
{
|
|
@@ -15627,15 +15668,22 @@ function PortfolioItem(props) {
|
|
|
15627
15668
|
children: [
|
|
15628
15669
|
/* @__PURE__ */ jsx80(PortfolioItemImage, { asset }),
|
|
15629
15670
|
/* @__PURE__ */ jsxs73("div", { className: "w-full flex-1", children: [
|
|
15630
|
-
/* @__PURE__ */ jsxs73("div", { className: "w-full flex items-center justify-between text-xs", children: [
|
|
15631
|
-
/* @__PURE__ */
|
|
15632
|
-
|
|
15633
|
-
|
|
15634
|
-
|
|
15635
|
-
|
|
15636
|
-
|
|
15637
|
-
|
|
15638
|
-
|
|
15671
|
+
/* @__PURE__ */ jsxs73("div", { className: "w-full flex items-center justify-between text-xs gap-2", children: [
|
|
15672
|
+
/* @__PURE__ */ jsxs73("div", { className: "min-w-0 flex flex-col", children: [
|
|
15673
|
+
/* @__PURE__ */ jsx80(
|
|
15674
|
+
"span",
|
|
15675
|
+
{
|
|
15676
|
+
className: "truncate max-w-[150px]",
|
|
15677
|
+
title: isNft ? asset.nftMetadata?.collectionName || asset.name : asset.name,
|
|
15678
|
+
children: isNft ? asset.nftMetadata?.collectionName || asset.name || shortContractAddress || "Unknown" : asset.name || shortContractAddress || "Unknown"
|
|
15679
|
+
}
|
|
15680
|
+
),
|
|
15681
|
+
!isNft && shortContractAddress && /* @__PURE__ */ jsxs73("span", { className: "text-[10px] text-[var(--ui-kit-fg-muted)] font-mono truncate", title: asset.address, children: [
|
|
15682
|
+
asset.symbol,
|
|
15683
|
+
" \xB7 ",
|
|
15684
|
+
shortContractAddress
|
|
15685
|
+
] })
|
|
15686
|
+
] }),
|
|
15639
15687
|
!!usdRenderBalance && !isProjectAsset && !isNft && !isSecurity && /* @__PURE__ */ jsx80("span", { className: "text-[var(--ui-kit-fg-muted)]", children: "USD" }),
|
|
15640
15688
|
!isSecurity && isNft && "type" in asset && /* @__PURE__ */ jsx80("span", { className: "uppercase text-[10px] px-1 bg-[var(--ui-kit-bg-info)] rounded-full", children: asset.type === "erc721" ? "ERC-721" : "ERC-1155" }),
|
|
15641
15689
|
isSecurity && /* @__PURE__ */ jsx80("span", { className: "uppercase text-[10px] px-1 bg-[var(--ui-kit-bg-warning)] rounded-full", children: "Security Token" })
|
|
@@ -15675,6 +15723,7 @@ var init_PortfolioItem = __esm({
|
|
|
15675
15723
|
init_base();
|
|
15676
15724
|
init_priceFormatter();
|
|
15677
15725
|
init_utils2();
|
|
15726
|
+
init_truncateMiddle();
|
|
15678
15727
|
init_BalanceView2();
|
|
15679
15728
|
SKIP_SYMBOLS2 = ["TEST"];
|
|
15680
15729
|
ASSETS_RATES_QUERY_KEY = "lumia-passport-assets-rates-query-key";
|
|
@@ -16907,6 +16956,11 @@ function AssetListItem(props) {
|
|
|
16907
16956
|
/* @__PURE__ */ jsx91(AssetInputIcon, { asset, size: "large" }),
|
|
16908
16957
|
/* @__PURE__ */ jsxs84("div", { className: "flex-1 flex flex-col items-start", children: [
|
|
16909
16958
|
/* @__PURE__ */ jsx91("div", { className: "text-[10px] truncate leading-4", children: isNft ? asset.nftMetadata?.name || asset.name : asset.name }),
|
|
16959
|
+
!isNft && asset.address && /* @__PURE__ */ jsxs84("div", { className: "text-[10px] text-[var(--ui-kit-fg-muted)] font-mono truncate leading-4", title: asset.address, children: [
|
|
16960
|
+
asset.symbol,
|
|
16961
|
+
" \xB7 ",
|
|
16962
|
+
truncateMiddle(asset.address, 6, 4)
|
|
16963
|
+
] }),
|
|
16910
16964
|
/* @__PURE__ */ jsx91("span", { className: "block text-lg font-bold", children: isNft ? /* @__PURE__ */ jsxs84(Fragment35, { children: [
|
|
16911
16965
|
asset.symbol,
|
|
16912
16966
|
asset.tokenId && /* @__PURE__ */ jsxs84("span", { className: "ml-1", children: [
|
|
@@ -16962,6 +17016,7 @@ var init_AssetList = __esm({
|
|
|
16962
17016
|
"src/internal/components/SendRecieveMenu/components/AssetList.tsx"() {
|
|
16963
17017
|
init_priceFormatter();
|
|
16964
17018
|
init_utils2();
|
|
17019
|
+
init_truncateMiddle();
|
|
16965
17020
|
init_BalanceView2();
|
|
16966
17021
|
init_useSendStore();
|
|
16967
17022
|
init_utils8();
|
|
@@ -19214,7 +19269,7 @@ var init_package = __esm({
|
|
|
19214
19269
|
"package.json"() {
|
|
19215
19270
|
package_default = {
|
|
19216
19271
|
name: "@embarkai/ui-kit",
|
|
19217
|
-
version: "0.4.
|
|
19272
|
+
version: "0.4.17",
|
|
19218
19273
|
description: "React UI components and hooks for EmbarkAI authentication and Account Abstraction",
|
|
19219
19274
|
type: "module",
|
|
19220
19275
|
main: "./dist/index.cjs",
|
|
@@ -19230,8 +19285,9 @@ var init_package = __esm({
|
|
|
19230
19285
|
clean: "rm -rf dist",
|
|
19231
19286
|
"build:css": "tailwindcss -c tailwind.config.cjs -i src/styles/index.css -o src/styles/built.css --minify",
|
|
19232
19287
|
"build:iframe-html": "node scripts/copy-iframe-html.js",
|
|
19233
|
-
"build:copy-css": "
|
|
19288
|
+
"build:copy-css": "node scripts/copy-styles-css.js",
|
|
19234
19289
|
build: "pnpm build:css && tsup && pnpm build:iframe-html && pnpm build:copy-css",
|
|
19290
|
+
prepack: "pnpm build",
|
|
19235
19291
|
dev: "pnpm build:css && tsup --watch",
|
|
19236
19292
|
"dev:iframe": "vite --config iframe/vite.config.ts",
|
|
19237
19293
|
csv: "npx tsx src/i18n/utils/prepareCsvProofread.ts --origin en --target zh",
|
|
@@ -23228,6 +23284,7 @@ function Provider(props) {
|
|
|
23228
23284
|
if (updates.warnings) next.warnings = { ...next.warnings, ...updates.warnings };
|
|
23229
23285
|
if (updates.kyc) next.kyc = { ...next.kyc, ...updates.kyc };
|
|
23230
23286
|
if (updates.watchTokens) next.watchTokens = { ...next.watchTokens, ...updates.watchTokens };
|
|
23287
|
+
if (updates.portfolio) next.portfolio = { ...next.portfolio, ...updates.portfolio };
|
|
23231
23288
|
if (updates.services && typeof window !== "undefined") {
|
|
23232
23289
|
try {
|
|
23233
23290
|
window.__EMBARK_SERVICES__ = next.services;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@embarkai/ui-kit",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.17",
|
|
4
4
|
"description": "React UI components and hooks for EmbarkAI authentication and Account Abstraction",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"clean": "rm -rf dist",
|
|
88
88
|
"build:css": "tailwindcss -c tailwind.config.cjs -i src/styles/index.css -o src/styles/built.css --minify",
|
|
89
89
|
"build:iframe-html": "node scripts/copy-iframe-html.js",
|
|
90
|
-
"build:copy-css": "
|
|
90
|
+
"build:copy-css": "node scripts/copy-styles-css.js",
|
|
91
91
|
"build": "pnpm build:css && tsup && pnpm build:iframe-html && pnpm build:copy-css",
|
|
92
92
|
"dev": "pnpm build:css && tsup --watch",
|
|
93
93
|
"dev:iframe": "vite --config iframe/vite.config.ts",
|