@b3dotfun/sdk 0.1.70-alpha.17 → 0.1.70-alpha.19
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/README.md +3 -3
- package/dist/cjs/anyspend/constants/rpc.d.ts +1 -0
- package/dist/cjs/anyspend/constants/rpc.js +3 -1
- package/dist/cjs/anyspend/react/components/AnySpendDeposit.d.ts +1 -3
- package/dist/cjs/anyspend/react/components/AnySpendDeposit.js +14 -12
- package/dist/cjs/anyspend/react/components/AnySpendStakeB3.js +32 -13
- package/dist/cjs/anyspend/react/components/AnySpendStakeB3ExactIn.js +32 -10
- package/dist/cjs/anyspend/react/components/checkout/CryptoPayPanel.js +16 -8
- package/dist/cjs/anyspend/react/components/common/TokenBalance.js +4 -5
- package/dist/cjs/anyspend/react/hooks/useSigMint.d.ts +1 -1
- package/dist/cjs/anyspend/utils/chain.d.ts +45 -0
- package/dist/cjs/anyspend/utils/chain.js +51 -2
- package/dist/cjs/global-account/react/components/B3Provider/B3Provider.d.ts +1 -2
- package/dist/cjs/global-account/react/components/B3Provider/B3Provider.js +2 -2
- package/dist/cjs/global-account/react/components/B3Provider/RelayKitProviderWrapper.d.ts +1 -2
- package/dist/cjs/global-account/react/components/B3Provider/RelayKitProviderWrapper.js +4 -5
- package/dist/cjs/global-account/react/components/ManageAccount/ContentTokens.js +23 -15
- package/dist/cjs/global-account/react/components/ManageAccount/NFTContent.js +2 -2
- package/dist/cjs/global-account/react/components/ManageAccount/ProfileSection.js +8 -6
- package/dist/cjs/global-account/react/components/ManageAccount/TokenContent.js +17 -8
- package/dist/cjs/global-account/react/components/Send/Send.js +15 -11
- package/dist/cjs/global-account/react/hooks/index.d.ts +2 -2
- package/dist/cjs/global-account/react/hooks/index.js +7 -8
- package/dist/cjs/global-account/react/hooks/useAuth.d.ts +2 -1
- package/dist/cjs/global-account/react/hooks/useAuth.js +1 -0
- package/dist/cjs/global-account/react/hooks/useAuthentication.d.ts +2 -1
- package/dist/cjs/global-account/react/hooks/useAuthentication.js +1 -0
- package/dist/cjs/global-account/react/hooks/useFirstEOA.d.ts +4 -7666
- package/dist/cjs/global-account/react/hooks/useFirstEOA.js +1 -0
- package/dist/cjs/global-account/react/hooks/usePortfolioBalance.d.ts +15 -0
- package/dist/cjs/global-account/react/hooks/usePortfolioBalance.js +76 -0
- package/dist/cjs/global-account/react/hooks/usePortfolioCollectibles.d.ts +12 -0
- package/dist/cjs/global-account/react/hooks/usePortfolioCollectibles.js +178 -0
- package/dist/cjs/global-account/react/hooks/useUnifiedChainSwitchAndExecute.d.ts +1 -0
- package/dist/cjs/global-account/react/hooks/useUnifiedChainSwitchAndExecute.js +18 -11
- package/dist/cjs/global-account/react/stores/useModalStore.d.ts +0 -2
- package/dist/cjs/global-account/react/utils/createWagmiConfig.d.ts +2 -2
- package/dist/cjs/shared/constants/chains/b3Chain.d.ts +24 -0
- package/dist/cjs/shared/constants/chains/supported.d.ts +4 -4
- package/dist/cjs/shared/constants/index.d.ts +4 -0
- package/dist/cjs/shared/utils/zerionPositions.d.ts +96 -0
- package/dist/cjs/shared/utils/zerionPositions.js +186 -0
- package/dist/cjs/wallet/utils/createWalletConfig.d.ts +2 -2
- package/dist/esm/anyspend/constants/rpc.d.ts +1 -0
- package/dist/esm/anyspend/constants/rpc.js +2 -0
- package/dist/esm/anyspend/react/components/AnySpendDeposit.d.ts +1 -3
- package/dist/esm/anyspend/react/components/AnySpendDeposit.js +15 -13
- package/dist/esm/anyspend/react/components/AnySpendStakeB3.js +33 -14
- package/dist/esm/anyspend/react/components/AnySpendStakeB3ExactIn.js +33 -11
- package/dist/esm/anyspend/react/components/checkout/CryptoPayPanel.js +18 -10
- package/dist/esm/anyspend/react/components/common/TokenBalance.js +6 -7
- package/dist/esm/anyspend/react/hooks/useSigMint.d.ts +1 -1
- package/dist/esm/anyspend/utils/chain.d.ts +45 -0
- package/dist/esm/anyspend/utils/chain.js +50 -3
- package/dist/esm/global-account/react/components/B3Provider/B3Provider.d.ts +1 -2
- package/dist/esm/global-account/react/components/B3Provider/B3Provider.js +2 -2
- package/dist/esm/global-account/react/components/B3Provider/RelayKitProviderWrapper.d.ts +1 -2
- package/dist/esm/global-account/react/components/B3Provider/RelayKitProviderWrapper.js +4 -5
- package/dist/esm/global-account/react/components/ManageAccount/ContentTokens.js +24 -16
- package/dist/esm/global-account/react/components/ManageAccount/NFTContent.js +3 -3
- package/dist/esm/global-account/react/components/ManageAccount/ProfileSection.js +9 -7
- package/dist/esm/global-account/react/components/ManageAccount/TokenContent.js +18 -9
- package/dist/esm/global-account/react/components/Send/Send.js +16 -12
- package/dist/esm/global-account/react/hooks/index.d.ts +2 -2
- package/dist/esm/global-account/react/hooks/index.js +2 -2
- package/dist/esm/global-account/react/hooks/useAuth.d.ts +2 -1
- package/dist/esm/global-account/react/hooks/useAuth.js +1 -0
- package/dist/esm/global-account/react/hooks/useAuthentication.d.ts +2 -1
- package/dist/esm/global-account/react/hooks/useAuthentication.js +1 -0
- package/dist/esm/global-account/react/hooks/useFirstEOA.d.ts +4 -7666
- package/dist/esm/global-account/react/hooks/useFirstEOA.js +1 -0
- package/dist/esm/global-account/react/hooks/usePortfolioBalance.d.ts +15 -0
- package/dist/esm/global-account/react/hooks/usePortfolioBalance.js +72 -0
- package/dist/esm/global-account/react/hooks/usePortfolioCollectibles.d.ts +12 -0
- package/dist/esm/global-account/react/hooks/usePortfolioCollectibles.js +175 -0
- package/dist/esm/global-account/react/hooks/useUnifiedChainSwitchAndExecute.d.ts +1 -0
- package/dist/esm/global-account/react/hooks/useUnifiedChainSwitchAndExecute.js +18 -11
- package/dist/esm/global-account/react/stores/useModalStore.d.ts +0 -2
- package/dist/esm/global-account/react/utils/createWagmiConfig.d.ts +2 -2
- package/dist/esm/shared/constants/chains/b3Chain.d.ts +24 -0
- package/dist/esm/shared/constants/chains/supported.d.ts +4 -4
- package/dist/esm/shared/constants/index.d.ts +4 -0
- package/dist/esm/shared/utils/zerionPositions.d.ts +96 -0
- package/dist/esm/shared/utils/zerionPositions.js +178 -0
- package/dist/esm/wallet/utils/createWalletConfig.d.ts +2 -2
- package/dist/types/anyspend/constants/rpc.d.ts +1 -0
- package/dist/types/anyspend/react/components/AnySpendDeposit.d.ts +1 -3
- package/dist/types/anyspend/react/hooks/useSigMint.d.ts +1 -1
- package/dist/types/anyspend/utils/chain.d.ts +45 -0
- package/dist/types/global-account/react/components/B3Provider/B3Provider.d.ts +1 -2
- package/dist/types/global-account/react/components/B3Provider/RelayKitProviderWrapper.d.ts +1 -2
- package/dist/types/global-account/react/hooks/index.d.ts +2 -2
- package/dist/types/global-account/react/hooks/useAuth.d.ts +2 -1
- package/dist/types/global-account/react/hooks/useAuthentication.d.ts +2 -1
- package/dist/types/global-account/react/hooks/useFirstEOA.d.ts +4 -7666
- package/dist/types/global-account/react/hooks/usePortfolioBalance.d.ts +15 -0
- package/dist/types/global-account/react/hooks/usePortfolioCollectibles.d.ts +12 -0
- package/dist/types/global-account/react/hooks/useUnifiedChainSwitchAndExecute.d.ts +1 -0
- package/dist/types/global-account/react/stores/useModalStore.d.ts +0 -2
- package/dist/types/global-account/react/utils/createWagmiConfig.d.ts +2 -2
- package/dist/types/shared/constants/chains/b3Chain.d.ts +24 -0
- package/dist/types/shared/constants/chains/supported.d.ts +4 -4
- package/dist/types/shared/constants/index.d.ts +4 -0
- package/dist/types/shared/utils/zerionPositions.d.ts +96 -0
- package/dist/types/wallet/utils/createWalletConfig.d.ts +2 -2
- package/node_modules/@b3/chain-registry/chains.json +29 -1
- package/node_modules/@b3/chain-registry/package.json +18 -2
- package/package.json +2 -2
- package/src/anyspend/README.md +2 -2
- package/src/anyspend/constants/rpc.ts +2 -0
- package/src/anyspend/docs/components.md +6 -6
- package/src/anyspend/docs/contributing.md +1 -1
- package/src/anyspend/docs/hooks.md +3 -3
- package/src/anyspend/docs/installation.md +2 -2
- package/src/anyspend/react/components/AnySpendDeposit.tsx +26 -19
- package/src/anyspend/react/components/AnySpendStakeB3.tsx +55 -14
- package/src/anyspend/react/components/AnySpendStakeB3ExactIn.tsx +55 -11
- package/src/anyspend/react/components/__tests__/QRDeposit.test.tsx +3 -4
- package/src/anyspend/react/components/checkout/CryptoPayPanel.tsx +25 -12
- package/src/anyspend/react/components/common/TokenBalance.tsx +10 -7
- package/src/anyspend/utils/__tests__/deprecatedChains.test.ts +44 -0
- package/src/anyspend/utils/__tests__/toRegistryChainId.test.ts +17 -0
- package/src/anyspend/utils/chain.ts +53 -2
- package/src/global-account/react/components/B3Provider/B3Provider.tsx +1 -3
- package/src/global-account/react/components/B3Provider/RelayKitProviderWrapper.tsx +4 -11
- package/src/global-account/react/components/ManageAccount/ContentTokens.tsx +50 -21
- package/src/global-account/react/components/ManageAccount/NFTContent.tsx +5 -3
- package/src/global-account/react/components/ManageAccount/ProfileSection.tsx +10 -6
- package/src/global-account/react/components/ManageAccount/TokenContent.tsx +22 -9
- package/src/global-account/react/components/Send/Send.tsx +39 -15
- package/src/global-account/react/hooks/__tests__/useUnifiedChainSwitchAndExecute.test.tsx +156 -0
- package/src/global-account/react/hooks/index.ts +2 -2
- package/src/global-account/react/hooks/useAuth.ts +3 -2
- package/src/global-account/react/hooks/useAuthentication.ts +3 -2
- package/src/global-account/react/hooks/useFirstEOA.tsx +9 -2
- package/src/global-account/react/hooks/usePortfolioBalance.ts +89 -0
- package/src/global-account/react/hooks/usePortfolioCollectibles.ts +212 -0
- package/src/global-account/react/hooks/useUnifiedChainSwitchAndExecute.ts +26 -12
- package/src/global-account/react/stores/useModalStore.ts +0 -2
- package/src/shared/constants/index.ts +8 -0
- package/src/shared/utils/__tests__/zerionPositions.test.ts +226 -0
- package/src/shared/utils/zerionPositions.ts +244 -0
- package/dist/cjs/global-account/react/hooks/useSimBalance.d.ts +0 -59
- package/dist/cjs/global-account/react/hooks/useSimBalance.js +0 -98
- package/dist/cjs/global-account/react/hooks/useSimCollectibles.d.ts +0 -45
- package/dist/cjs/global-account/react/hooks/useSimCollectibles.js +0 -190
- package/dist/cjs/global-account/react/utils/simdune.d.ts +0 -7
- package/dist/cjs/global-account/react/utils/simdune.js +0 -21
- package/dist/esm/global-account/react/hooks/useSimBalance.d.ts +0 -59
- package/dist/esm/global-account/react/hooks/useSimBalance.js +0 -93
- package/dist/esm/global-account/react/hooks/useSimCollectibles.d.ts +0 -45
- package/dist/esm/global-account/react/hooks/useSimCollectibles.js +0 -187
- package/dist/esm/global-account/react/utils/simdune.d.ts +0 -7
- package/dist/esm/global-account/react/utils/simdune.js +0 -17
- package/dist/types/global-account/react/hooks/useSimBalance.d.ts +0 -59
- package/dist/types/global-account/react/hooks/useSimCollectibles.d.ts +0 -45
- package/dist/types/global-account/react/utils/simdune.d.ts +0 -7
- package/node_modules/@b3/chain-registry/src/index.ts +0 -169
- package/node_modules/@b3/chain-registry/tsconfig.json +0 -16
- package/src/global-account/react/hooks/useSimBalance.ts +0 -164
- package/src/global-account/react/hooks/useSimCollectibles.ts +0 -238
- package/src/global-account/react/utils/simdune.ts +0 -20
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { getNativeRequired } from "../../../../anyspend/utils/chain.js";
|
|
2
|
+
import { getNativeRequired, toRegistryChainId } from "../../../../anyspend/utils/chain.js";
|
|
3
3
|
import { isNativeToken } from "../../../../anyspend/utils/token.js";
|
|
4
|
-
import {
|
|
4
|
+
import { usePortfolioTokenBalance } from "../../../../global-account/react/index.js";
|
|
5
5
|
import { formatTokenAmount } from "../../../../shared/utils/number.js";
|
|
6
6
|
import { useMemo } from "react";
|
|
7
7
|
import { formatUnits } from "viem";
|
|
8
8
|
export function TokenBalance({ token, walletAddress, onChangeInput, }) {
|
|
9
|
-
|
|
10
|
-
const { data, isLoading } =
|
|
9
|
+
// `token.chainId` is Relay-numbered; balance rows are keyed by the chain registry's id.
|
|
10
|
+
const { data: balance, isLoading, isError, } = usePortfolioTokenBalance(walletAddress, token.address, toRegistryChainId(token.chainId));
|
|
11
11
|
const { rawBalance, formattedBalance } = useMemo(() => {
|
|
12
|
-
const balance = data?.balances?.[0];
|
|
13
12
|
if (!balance?.amount) {
|
|
14
13
|
return { rawBalance: null, formattedBalance: "0" };
|
|
15
14
|
}
|
|
@@ -18,7 +17,7 @@ export function TokenBalance({ token, walletAddress, onChangeInput, }) {
|
|
|
18
17
|
rawBalance: raw,
|
|
19
18
|
formattedBalance: formatTokenAmount(raw, balance.decimals),
|
|
20
19
|
};
|
|
21
|
-
}, [
|
|
20
|
+
}, [balance]);
|
|
22
21
|
const handlePercentageClick = (percentage) => {
|
|
23
22
|
if (!rawBalance)
|
|
24
23
|
return;
|
|
@@ -42,5 +41,5 @@ export function TokenBalance({ token, walletAddress, onChangeInput, }) {
|
|
|
42
41
|
}
|
|
43
42
|
onChangeInput(formatUnits(amount, token.decimals));
|
|
44
43
|
};
|
|
45
|
-
return (_jsx("div", { className: "flex h-7 items-center justify-end gap-1", children: !isLoading && (_jsxs(_Fragment, { children: [_jsx("div", { className: "text-as-primary/50 inline-flex rounded-lg text-sm", children: rawBalance ? `Balance: ${formattedBalance}` : `Balance: 0` }), !!rawBalance && (_jsx(_Fragment, { children: _jsx("button", { onClick: () => handlePercentageClick(100), className: "text-as-primary/50 bg-as-on-surface-2 hover:bg-as-on-surface-3 inline-flex cursor-pointer rounded-lg px-2 py-1 text-xs transition-colors", children: "MAX" }) }))] })) }, `balance-${token.address}-${token.chainId}`));
|
|
44
|
+
return (_jsx("div", { className: "flex h-7 items-center justify-end gap-1", children: !isLoading && (_jsxs(_Fragment, { children: [_jsx("div", { className: "text-as-primary/50 inline-flex rounded-lg text-sm", children: isError ? "Balance: —" : rawBalance ? `Balance: ${formattedBalance}` : `Balance: 0` }), !!rawBalance && (_jsx(_Fragment, { children: _jsx("button", { onClick: () => handlePercentageClick(100), className: "text-as-primary/50 bg-as-on-surface-2 hover:bg-as-on-surface-3 inline-flex cursor-pointer rounded-lg px-2 py-1 text-xs transition-colors", children: "MAX" }) }))] })) }, `balance-${token.address}-${token.chainId}`));
|
|
46
45
|
}
|
|
@@ -10,9 +10,9 @@ export declare const useGenerateSigMintData: ({ recipientAddress, contractAddres
|
|
|
10
10
|
description?: string | undefined;
|
|
11
11
|
status?: "ACTIVE" | "INACTIVE" | "DRAFT" | undefined;
|
|
12
12
|
metadata?: {} | undefined;
|
|
13
|
+
logoURI?: string | undefined;
|
|
13
14
|
createdAt?: string | undefined;
|
|
14
15
|
updatedAt?: string | undefined;
|
|
15
|
-
logoURI?: string | undefined;
|
|
16
16
|
creator?: string | undefined;
|
|
17
17
|
signatureRequestBody?: {
|
|
18
18
|
currency?: string | undefined;
|
|
@@ -56,11 +56,23 @@ export declare const hyperEVM: {
|
|
|
56
56
|
};
|
|
57
57
|
};
|
|
58
58
|
sourceId?: number | undefined | undefined;
|
|
59
|
+
supportsTransactionReplacementDetection?: boolean | undefined | undefined;
|
|
59
60
|
testnet?: boolean | undefined | undefined;
|
|
60
61
|
custom?: Record<string, unknown> | undefined;
|
|
62
|
+
extendSchema?: Record<string, unknown> | undefined;
|
|
61
63
|
fees?: import("viem").ChainFees<undefined> | undefined;
|
|
62
64
|
formatters?: undefined;
|
|
65
|
+
prepareTransactionRequest?: ((args: import("viem").PrepareTransactionRequestParameters, options: {
|
|
66
|
+
client: import("viem").Client;
|
|
67
|
+
phase: "beforeFillTransaction" | "beforeFillParameters" | "afterFillParameters";
|
|
68
|
+
}) => Promise<import("viem").PrepareTransactionRequestParameters>) | [fn: ((args: import("viem").PrepareTransactionRequestParameters, options: {
|
|
69
|
+
client: import("viem").Client;
|
|
70
|
+
phase: "beforeFillTransaction" | "beforeFillParameters" | "afterFillParameters";
|
|
71
|
+
}) => Promise<import("viem").PrepareTransactionRequestParameters>) | undefined, options: {
|
|
72
|
+
runAt: readonly ("beforeFillTransaction" | "beforeFillParameters" | "afterFillParameters")[];
|
|
73
|
+
}] | undefined;
|
|
63
74
|
serializers?: import("viem").ChainSerializers<undefined, import("viem").TransactionSerializable> | undefined;
|
|
75
|
+
verifyHash?: ((client: import("viem").Client, parameters: import("viem").VerifyHashActionParameters) => Promise<import("viem").VerifyHashActionReturnType>) | undefined;
|
|
64
76
|
};
|
|
65
77
|
export declare const plume: {
|
|
66
78
|
blockExplorers: {
|
|
@@ -94,11 +106,23 @@ export declare const plume: {
|
|
|
94
106
|
};
|
|
95
107
|
};
|
|
96
108
|
sourceId?: number | undefined | undefined;
|
|
109
|
+
supportsTransactionReplacementDetection?: boolean | undefined | undefined;
|
|
97
110
|
testnet?: boolean | undefined | undefined;
|
|
98
111
|
custom?: Record<string, unknown> | undefined;
|
|
112
|
+
extendSchema?: Record<string, unknown> | undefined;
|
|
99
113
|
fees?: import("viem").ChainFees<undefined> | undefined;
|
|
100
114
|
formatters?: undefined;
|
|
115
|
+
prepareTransactionRequest?: ((args: import("viem").PrepareTransactionRequestParameters, options: {
|
|
116
|
+
client: import("viem").Client;
|
|
117
|
+
phase: "beforeFillTransaction" | "beforeFillParameters" | "afterFillParameters";
|
|
118
|
+
}) => Promise<import("viem").PrepareTransactionRequestParameters>) | [fn: ((args: import("viem").PrepareTransactionRequestParameters, options: {
|
|
119
|
+
client: import("viem").Client;
|
|
120
|
+
phase: "beforeFillTransaction" | "beforeFillParameters" | "afterFillParameters";
|
|
121
|
+
}) => Promise<import("viem").PrepareTransactionRequestParameters>) | undefined, options: {
|
|
122
|
+
runAt: readonly ("beforeFillTransaction" | "beforeFillParameters" | "afterFillParameters")[];
|
|
123
|
+
}] | undefined;
|
|
101
124
|
serializers?: import("viem").ChainSerializers<undefined, import("viem").TransactionSerializable> | undefined;
|
|
125
|
+
verifyHash?: ((client: import("viem").Client, parameters: import("viem").VerifyHashActionParameters) => Promise<import("viem").VerifyHashActionReturnType>) | undefined;
|
|
102
126
|
};
|
|
103
127
|
export declare const EVM_MAINNET: Record<number, IEVMChain>;
|
|
104
128
|
export declare const EVM_TESTNET: Record<number, IEVMChain>;
|
|
@@ -106,6 +130,14 @@ export declare const SOLANA_MAINNET: ISolanaChain;
|
|
|
106
130
|
export declare const HYPERLIQUID_MAINNET: IHyperliquidChain;
|
|
107
131
|
export declare const EVM_CHAINS: Record<number, IEVMChain>;
|
|
108
132
|
export declare const SOLANA_CHAINS: Record<number, ISolanaChain>;
|
|
133
|
+
/**
|
|
134
|
+
* Translate a Relay-numbered chain id into the id the chain registry uses.
|
|
135
|
+
*
|
|
136
|
+
* Relay numbers Solana 792703809; every other chain shares the universal EVM id. Balance rows are
|
|
137
|
+
* keyed by the registry's id, so handing Relay's number to a balance lookup matches nothing at all
|
|
138
|
+
* — and a funded Solana wallet then reads as empty rather than as unreadable.
|
|
139
|
+
*/
|
|
140
|
+
export declare function toRegistryChainId(chainId: number): number;
|
|
109
141
|
export declare const HYPERLIQUID_CHAINS: Record<number, IHyperliquidChain>;
|
|
110
142
|
export declare const ALL_CHAINS: Record<number, IBaseChain>;
|
|
111
143
|
export declare function getSolanaChains(network: "mainnet" | "testnet"): ISolanaChain;
|
|
@@ -128,6 +160,19 @@ export declare function getNativeToken(chainId: number): components["schemas"]["
|
|
|
128
160
|
export declare function isEvmChain(chainId: number): boolean;
|
|
129
161
|
export declare function isHyperliquidChain(chainId: number): boolean;
|
|
130
162
|
export declare function getHyperliquidChain(chainId: number): IHyperliquidChain;
|
|
163
|
+
/**
|
|
164
|
+
* Chains AnySpend no longer accepts orders on, as either source or destination.
|
|
165
|
+
*
|
|
166
|
+
* They stay in ALL_CHAINS on purpose. That map answers "what is this chain" — name, logo, token,
|
|
167
|
+
* decimals — which every order that ever existed still needs in order to render; removing an entry
|
|
168
|
+
* would make getChainName and friends throw on historical rows. Whether new orders are accepted is
|
|
169
|
+
* this separate question.
|
|
170
|
+
*
|
|
171
|
+
* anyspend-service imports this list rather than keeping its own, so the API and the chain picker
|
|
172
|
+
* can never disagree about what is on offer.
|
|
173
|
+
*/
|
|
174
|
+
export declare const DEPRECATED_CHAIN_IDS: readonly number[];
|
|
175
|
+
export declare function isDeprecatedChain(chainId?: number): boolean;
|
|
131
176
|
/**
|
|
132
177
|
* Get available chain IDs for AnySpend based on context (source or destination).
|
|
133
178
|
* Filters out chains that shouldn't be available for the given context.
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { RELAY_SOLANA_MAINNET_CHAIN_ID } from "../../anyspend/constants/index.js";
|
|
2
|
-
import {
|
|
2
|
+
import { SOLANA_CHAIN_ID } from "../../shared/utils/zerionPositions.js";
|
|
3
|
+
import { ABSTRACT_PUBLIC_RPC, ARBITRUM_PUBLIC_RPC, AVALANCHE_PUBLIC_RPC, BASE_PUBLIC_RPC, BSC_PUBLIC_RPC, ETHEREUM_PUBLIC_RPC, HYPEREVM_PUBLIC_RPC, OPTIMISM_PUBLIC_RPC, PLUME_PUBLIC_RPC, POLYGON_PUBLIC_RPC, ROBINHOOD_PUBLIC_RPC, } from "../../anyspend/constants/rpc.js";
|
|
3
4
|
import { b3Viem } from "../../shared/constants/chains/b3Viem.js";
|
|
4
5
|
import invariant from "invariant";
|
|
5
6
|
import { createPublicClient, createWalletClient, defineChain, http, parseEther, } from "viem";
|
|
6
|
-
import { abstract, arbitrum, avalanche, base, bsc, mainnet, optimism, polygon } from "viem/chains";
|
|
7
|
+
import { abstract, arbitrum, avalanche, base, bsc, mainnet, optimism, polygon, robinhood } from "viem/chains";
|
|
7
8
|
import { ChainType } from "../types/chain.js";
|
|
8
9
|
import { getAvaxToken, getBnbToken, getEthToken, getHyperEVMNativeToken, getHyperliquidUSDCToken, getPlumeNativeToken, getPolToken, getSolanaToken, HYPEREVM_CHAIN_ID, HYPERLIQUID_CHAIN_ID, PLUME_CHAIN_ID, } from "./token.js";
|
|
9
10
|
function getCustomEvmChain(chain, rpcUrl) {
|
|
@@ -228,6 +229,20 @@ export const EVM_MAINNET = {
|
|
|
228
229
|
coingeckoName: "plume-network",
|
|
229
230
|
wethAddress: "0xea237441c92cae6fc17caaf9a7acb3f953be4bd1", // WPLUME (wrapped native)
|
|
230
231
|
},
|
|
232
|
+
[robinhood.id]: {
|
|
233
|
+
id: robinhood.id,
|
|
234
|
+
name: robinhood.name,
|
|
235
|
+
logoUrl: "https://assets.relay.link/icons/square/4663/light.png",
|
|
236
|
+
type: ChainType.EVM,
|
|
237
|
+
nativeRequired: parseEther("0.0001"),
|
|
238
|
+
canDepositNative: true,
|
|
239
|
+
defaultToken: getEthToken(robinhood.id),
|
|
240
|
+
nativeToken: getEthToken(robinhood.id),
|
|
241
|
+
viem: getCustomEvmChain(robinhood, ROBINHOOD_PUBLIC_RPC),
|
|
242
|
+
pollingInterval: 1000, // 1 second for Robinhood Chain (Arbitrum Orbit fast blocks)
|
|
243
|
+
coingeckoName: "robinhood",
|
|
244
|
+
wethAddress: "0x0bd7d308f8e1639fab988df18a8011f41eacad73", // wrapped native ETH (registry wrappedNative)
|
|
245
|
+
},
|
|
231
246
|
};
|
|
232
247
|
export const EVM_TESTNET = {
|
|
233
248
|
// [sepolia.id]: {
|
|
@@ -306,6 +321,16 @@ export const HYPERLIQUID_MAINNET = {
|
|
|
306
321
|
};
|
|
307
322
|
export const EVM_CHAINS = { ...EVM_MAINNET, ...EVM_TESTNET };
|
|
308
323
|
export const SOLANA_CHAINS = { [RELAY_SOLANA_MAINNET_CHAIN_ID]: SOLANA_MAINNET };
|
|
324
|
+
/**
|
|
325
|
+
* Translate a Relay-numbered chain id into the id the chain registry uses.
|
|
326
|
+
*
|
|
327
|
+
* Relay numbers Solana 792703809; every other chain shares the universal EVM id. Balance rows are
|
|
328
|
+
* keyed by the registry's id, so handing Relay's number to a balance lookup matches nothing at all
|
|
329
|
+
* — and a funded Solana wallet then reads as empty rather than as unreadable.
|
|
330
|
+
*/
|
|
331
|
+
export function toRegistryChainId(chainId) {
|
|
332
|
+
return chainId === RELAY_SOLANA_MAINNET_CHAIN_ID ? SOLANA_CHAIN_ID : chainId;
|
|
333
|
+
}
|
|
309
334
|
export const HYPERLIQUID_CHAINS = {
|
|
310
335
|
[HYPERLIQUID_CHAIN_ID]: HYPERLIQUID_MAINNET,
|
|
311
336
|
};
|
|
@@ -582,6 +607,24 @@ export function getHyperliquidChain(chainId) {
|
|
|
582
607
|
invariant(HYPERLIQUID_CHAINS[chainId], `Chain ${chainId} is not a Hyperliquid chain`);
|
|
583
608
|
return HYPERLIQUID_CHAINS[chainId];
|
|
584
609
|
}
|
|
610
|
+
/**
|
|
611
|
+
* Chains AnySpend no longer accepts orders on, as either source or destination.
|
|
612
|
+
*
|
|
613
|
+
* They stay in ALL_CHAINS on purpose. That map answers "what is this chain" — name, logo, token,
|
|
614
|
+
* decimals — which every order that ever existed still needs in order to render; removing an entry
|
|
615
|
+
* would make getChainName and friends throw on historical rows. Whether new orders are accepted is
|
|
616
|
+
* this separate question.
|
|
617
|
+
*
|
|
618
|
+
* anyspend-service imports this list rather than keeping its own, so the API and the chain picker
|
|
619
|
+
* can never disagree about what is on offer.
|
|
620
|
+
*/
|
|
621
|
+
export const DEPRECATED_CHAIN_IDS = [
|
|
622
|
+
8333, // B3
|
|
623
|
+
98866, // Plume
|
|
624
|
+
];
|
|
625
|
+
export function isDeprecatedChain(chainId) {
|
|
626
|
+
return chainId !== undefined && DEPRECATED_CHAIN_IDS.includes(chainId);
|
|
627
|
+
}
|
|
585
628
|
/**
|
|
586
629
|
* Get available chain IDs for AnySpend based on context (source or destination).
|
|
587
630
|
* Filters out chains that shouldn't be available for the given context.
|
|
@@ -597,7 +640,11 @@ export function getHyperliquidChain(chainId) {
|
|
|
597
640
|
* const destChains = getAvailableChainIds("to") // [1, 8453, 137, ..., 1337]
|
|
598
641
|
*/
|
|
599
642
|
export function getAvailableChainIds(context) {
|
|
600
|
-
|
|
643
|
+
// Deprecated chains are excluded from both directions: the API rejects them, so offering them in
|
|
644
|
+
// a picker would let a user select something that then fails at order creation.
|
|
645
|
+
const allChainIds = Object.values(ALL_CHAINS)
|
|
646
|
+
.map(chain => chain.id)
|
|
647
|
+
.filter(chainId => !isDeprecatedChain(chainId));
|
|
601
648
|
if (context === "from") {
|
|
602
649
|
// Hyperliquid is only supported as destination chain, not source chain
|
|
603
650
|
return allChainIds.filter(chainId => chainId !== HYPERLIQUID_CHAIN_ID);
|
|
@@ -10,7 +10,7 @@ import { ClientType } from "../../../client-manager";
|
|
|
10
10
|
/**
|
|
11
11
|
* Main B3Provider component
|
|
12
12
|
*/
|
|
13
|
-
export declare function B3Provider({ theme, children, accountOverride, environment, automaticallySetFirstEoa, defaultEoaProvider,
|
|
13
|
+
export declare function B3Provider({ theme, children, accountOverride, environment, automaticallySetFirstEoa, defaultEoaProvider, toaster: _toaster, clientType, rpcUrls, partnerId, stripePublishableKey, onConnect, onLogout, connectors, overrideDefaultConnectors, createClientReferenceId, defaultPermissions, disableBSMNTAuthentication, queryClient, authStrategy, apiUrl, notificationsApiUrl, }: {
|
|
14
14
|
theme: "light" | "dark";
|
|
15
15
|
children: React.ReactNode;
|
|
16
16
|
accountOverride?: Account;
|
|
@@ -18,7 +18,6 @@ export declare function B3Provider({ theme, children, accountOverride, environme
|
|
|
18
18
|
automaticallySetFirstEoa?: boolean;
|
|
19
19
|
/** EIP-1193 provider to auto-connect as the default EOA wallet (e.g., Farcaster frame wallet) */
|
|
20
20
|
defaultEoaProvider?: EIP1193.EIP1193Provider;
|
|
21
|
-
simDuneApiKey?: string;
|
|
22
21
|
toaster?: {
|
|
23
22
|
position?: "top-center" | "top-right" | "bottom-center" | "bottom-right";
|
|
24
23
|
style?: React.CSSProperties;
|
|
@@ -22,7 +22,7 @@ const NOTIFICATIONS_URL_BY_ENV = {
|
|
|
22
22
|
/**
|
|
23
23
|
* Main B3Provider component
|
|
24
24
|
*/
|
|
25
|
-
export function B3Provider({ theme = "light", children, accountOverride, environment, automaticallySetFirstEoa, defaultEoaProvider,
|
|
25
|
+
export function B3Provider({ theme = "light", children, accountOverride, environment, automaticallySetFirstEoa, defaultEoaProvider,
|
|
26
26
|
// deprecated since v0.0.87
|
|
27
27
|
toaster: _toaster, clientType = "rest", rpcUrls, partnerId, stripePublishableKey, onConnect, onLogout, connectors, overrideDefaultConnectors = false, createClientReferenceId, defaultPermissions, disableBSMNTAuthentication = false, queryClient, authStrategy = "thirdweb", apiUrl, notificationsApiUrl, }) {
|
|
28
28
|
// Override the B3 API URL when the `apiUrl` prop is provided.
|
|
@@ -49,7 +49,7 @@ toaster: _toaster, clientType = "rest", rpcUrls, partnerId, stripePublishableKey
|
|
|
49
49
|
setClientType(clientType);
|
|
50
50
|
}, [clientType]);
|
|
51
51
|
const wagmiConfig = useMemo(() => createWagmiConfig({ partnerId, rpcUrls, connectors, overrideDefaultConnectors }), [partnerId, rpcUrls, connectors, overrideDefaultConnectors]);
|
|
52
|
-
return (_jsx(WalletProvider, { wagmiConfig: wagmiConfig, queryClient: queryClient, children: _jsx(TooltipProvider, { children: _jsx(ToastProvider, { children: _jsx(LocalSDKProvider, { onConnectCallback: onConnect, onLogoutCallback: onLogout, disableBSMNTAuthentication: disableBSMNTAuthentication, children: _jsxs(B3ConfigProvider, { accountOverride: accountOverride, environment: environment, automaticallySetFirstEoa: !!automaticallySetFirstEoa, theme: theme, clientType: clientType, partnerId: partnerId, stripePublishableKey: stripePublishableKey, createClientReferenceId: createClientReferenceId, defaultPermissions: defaultPermissions, authStrategy: authStrategy, children: [_jsx(ToastContextConnector, {}), _jsxs(RelayKitProviderWrapper, {
|
|
52
|
+
return (_jsx(WalletProvider, { wagmiConfig: wagmiConfig, queryClient: queryClient, children: _jsx(TooltipProvider, { children: _jsx(ToastProvider, { children: _jsx(LocalSDKProvider, { onConnectCallback: onConnect, onLogoutCallback: onLogout, disableBSMNTAuthentication: disableBSMNTAuthentication, children: _jsxs(B3ConfigProvider, { accountOverride: accountOverride, environment: environment, automaticallySetFirstEoa: !!automaticallySetFirstEoa, theme: theme, clientType: clientType, partnerId: partnerId, stripePublishableKey: stripePublishableKey, createClientReferenceId: createClientReferenceId, defaultPermissions: defaultPermissions, authStrategy: authStrategy, children: [_jsx(ToastContextConnector, {}), _jsxs(RelayKitProviderWrapper, { children: [children, _jsx(StyleRoot, { id: "b3-root" })] }), authStrategy === "better-auth" ? (_jsx(BetterAuthProvider, { partnerId: partnerId })) : (_jsx(AuthenticationProvider, { partnerId: partnerId, automaticallySetFirstEoa: !!automaticallySetFirstEoa, defaultEoaProvider: defaultEoaProvider }))] }) }) }) }) }));
|
|
53
53
|
}
|
|
54
54
|
/**
|
|
55
55
|
* Component to connect the toast context to the global toast API
|
|
@@ -2,7 +2,7 @@ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { RelayKitProvider } from "@relayprotocol/relay-kit-ui";
|
|
3
3
|
import { fetchChainConfigs, MAINNET_RELAY_API } from "@relayprotocol/relay-sdk";
|
|
4
4
|
import { useEffect, useState } from "react";
|
|
5
|
-
export function RelayKitProviderWrapper({ children
|
|
5
|
+
export function RelayKitProviderWrapper({ children }) {
|
|
6
6
|
const [relayChains, setRelayChains] = useState([]);
|
|
7
7
|
useEffect(() => {
|
|
8
8
|
const fetchChains = async () => {
|
|
@@ -11,13 +11,12 @@ export function RelayKitProviderWrapper({ children, simDuneApiKey, }) {
|
|
|
11
11
|
};
|
|
12
12
|
fetchChains();
|
|
13
13
|
}, []);
|
|
14
|
+
// No balance provider is configured for Relay's own token selector. Relay reads balances through
|
|
15
|
+
// its Dune integration, which we no longer hold a key for, and it accepts no substitute — so the
|
|
16
|
+
// selector lists tokens without balances rather than showing figures nothing can refresh.
|
|
14
17
|
return (_jsx(RelayKitProvider, { options: {
|
|
15
18
|
baseApiUrl: MAINNET_RELAY_API,
|
|
16
19
|
source: "anyspend",
|
|
17
|
-
duneConfig: {
|
|
18
|
-
apiKey: simDuneApiKey,
|
|
19
|
-
apiBaseUrl: "https://api.sim.dune.com",
|
|
20
|
-
},
|
|
21
20
|
chains: relayChains,
|
|
22
21
|
privateChainIds: undefined,
|
|
23
22
|
appName: "AnySpend",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { ALL_CHAINS, getExplorerTxUrl } from "../../../../anyspend/index.js";
|
|
3
3
|
import { ChainTokenIcon } from "../../../../anyspend/react/components/common/ChainTokenIcon.js";
|
|
4
|
-
import { Button, toast, TransitionPanel, useAnalytics,
|
|
4
|
+
import { Button, toast, TransitionPanel, useAnalytics, usePortfolioBalance, useUnifiedChainSwitchAndExecute, } from "../../../../global-account/react/index.js";
|
|
5
5
|
import { formatDisplayNumber, formatTokenAmount } from "../../../../shared/utils/number.js";
|
|
6
6
|
import invariant from "invariant";
|
|
7
7
|
import { ArrowLeft, CircleHelp, Copy, Loader2, Send } from "lucide-react";
|
|
@@ -41,7 +41,7 @@ export function ContentTokens({ activeTab }) {
|
|
|
41
41
|
const animationDirection = useRef(null);
|
|
42
42
|
// === DATA FETCHING ===
|
|
43
43
|
const account = useActiveAccount();
|
|
44
|
-
const { data:
|
|
44
|
+
const { data: balances, refetch: refetchBalances, isLoading: isLoadingBalance, isError: isBalanceError, } = usePortfolioBalance(account?.address);
|
|
45
45
|
// === BLOCKCHAIN INTERACTION ===
|
|
46
46
|
const { switchChainAndExecute } = useUnifiedChainSwitchAndExecute();
|
|
47
47
|
// === ANALYTICS ===
|
|
@@ -75,13 +75,13 @@ export function ContentTokens({ activeTab }) {
|
|
|
75
75
|
// === HELPER FUNCTION ===
|
|
76
76
|
// Get current version of selected token from fresh balance data
|
|
77
77
|
// 🔧 FIX: Prevents auto-navigation back to token list when balance refreshes
|
|
78
|
-
// The
|
|
78
|
+
// The balance hook refreshes data, creating new token object references
|
|
79
79
|
// This helper ensures we always get the fresh token data instead of stale references
|
|
80
80
|
const getCurrentSelectedToken = () => {
|
|
81
|
-
if (!selectedToken || !
|
|
81
|
+
if (!selectedToken || !balances) {
|
|
82
82
|
return null;
|
|
83
83
|
}
|
|
84
|
-
const found =
|
|
84
|
+
const found = balances.find(token => token.chain_id === selectedToken.chain_id && token.address === selectedToken.address);
|
|
85
85
|
return found || null;
|
|
86
86
|
};
|
|
87
87
|
// ==================================================================================
|
|
@@ -147,11 +147,13 @@ export function ContentTokens({ activeTab }) {
|
|
|
147
147
|
functionName: "transfer",
|
|
148
148
|
args: [recipientAddress, amountInWei],
|
|
149
149
|
});
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
150
|
+
// A native send carries value and no calldata; an ERC-20 send carries calldata and no
|
|
151
|
+
// value. Branch on the explicit flag, never on the address: the native sentinel is a
|
|
152
|
+
// display detail, and taking the ERC-20 path for a native coin spends gas without moving
|
|
153
|
+
// anything.
|
|
154
|
+
const tx = await switchChainAndExecute(displayToken.chain_id, displayToken.is_native
|
|
155
|
+
? { to: recipientAddress, value: amountInWei }
|
|
156
|
+
: { to: displayToken.address, data: sendTokenData, value: BigInt(0) });
|
|
155
157
|
if (tx) {
|
|
156
158
|
// Track successful send
|
|
157
159
|
sendAnalyticsEvent("send_token_button_click", {
|
|
@@ -177,7 +179,7 @@ export function ContentTokens({ activeTab }) {
|
|
|
177
179
|
// Wait 1 second to make sure the tx is indexed on sim api.
|
|
178
180
|
setTimeout(async () => {
|
|
179
181
|
// Force refetch to bypass cache and get fresh balance data
|
|
180
|
-
await
|
|
182
|
+
await refetchBalances();
|
|
181
183
|
}, 1000);
|
|
182
184
|
setIsSending(false);
|
|
183
185
|
}
|
|
@@ -211,21 +213,27 @@ export function ContentTokens({ activeTab }) {
|
|
|
211
213
|
if (isLoadingBalance) {
|
|
212
214
|
return _jsx(LoadingIndicator, {});
|
|
213
215
|
}
|
|
214
|
-
//
|
|
215
|
-
|
|
216
|
+
// A wallet IS connected here — only the read failed. Prompting the user to connect would send
|
|
217
|
+
// them to fix something that is not broken.
|
|
218
|
+
// `isBalanceError` as well as the absent list: after a first success a later refetch failure
|
|
219
|
+
// keeps `data` populated, so `!balances` alone would show stale numbers as if they were fresh.
|
|
220
|
+
if (account?.address && (isBalanceError || !balances)) {
|
|
221
|
+
return (_jsxs("div", { className: "flex flex-col items-center justify-center py-12 text-center", children: [_jsx("div", { className: "bg-b3-line/50 mb-4 rounded-full p-4", children: _jsx(Loader2, { className: "text-b3-foreground-muted h-8 w-8" }) }), _jsx("h3", { className: "text-b3-grey font-neue-montreal-semibold mb-2", children: "Couldn't load your tokens" }), _jsx("button", { onClick: () => refetchBalances(), className: "text-b3-foreground-muted font-neue-montreal-medium text-sm underline", children: "Try again" })] }));
|
|
222
|
+
}
|
|
223
|
+
if (!account?.address) {
|
|
216
224
|
return (_jsxs("div", { className: "flex flex-col items-center justify-center py-12 text-center", children: [_jsx("div", { className: "bg-b3-line/50 mb-4 rounded-full p-4", children: _jsx(Loader2, { className: "text-b3-foreground-muted h-8 w-8" }) }), _jsx("h3", { className: "text-b3-grey font-neue-montreal-semibold mb-2", children: "No wallet connected" }), _jsx("p", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "Connect your wallet to view token balances" })] }));
|
|
217
225
|
}
|
|
218
226
|
// === SMART FILTERING LOGIC ===
|
|
219
227
|
// Filter tokens with value >= $1 to reduce noise from dust tokens
|
|
220
|
-
const filteredTokens =
|
|
228
|
+
const filteredTokens = balances?.filter(token => token.value_usd !== undefined && token.value_usd >= 1) || [];
|
|
221
229
|
// 🧠 INTELLIGENT DISPLAY LOGIC:
|
|
222
230
|
// Show all tokens automatically when filtering would be unhelpful:
|
|
223
231
|
// 1. User explicitly requested to show all, OR
|
|
224
232
|
// 2. No tokens with value >= $1 (user has only dust), OR
|
|
225
233
|
// 3. 5 or fewer tokens with value >= $1 (not enough to warrant filtering)
|
|
226
234
|
const shouldShowAllTokens = showAllTokens || filteredTokens.length === 0 || filteredTokens.length <= 5;
|
|
227
|
-
const tokensToShow = shouldShowAllTokens ?
|
|
228
|
-
const hasHiddenTokens = !shouldShowAllTokens && (
|
|
235
|
+
const tokensToShow = shouldShowAllTokens ? balances || [] : filteredTokens;
|
|
236
|
+
const hasHiddenTokens = !shouldShowAllTokens && (balances?.length || 0) > filteredTokens.length;
|
|
229
237
|
// Handle token selection and navigate to send form
|
|
230
238
|
const handleTokenClick = (token) => {
|
|
231
239
|
setSelectedToken(token);
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useActiveWallet } from "thirdweb/react";
|
|
3
3
|
import { AccountAssets } from "..";
|
|
4
|
-
import {
|
|
4
|
+
import { usePortfolioCollectibles } from "../../hooks/index.js";
|
|
5
5
|
const NFTContent = () => {
|
|
6
6
|
// Get active wallet state
|
|
7
7
|
const activeWallet = useActiveWallet();
|
|
8
8
|
const activeAccount = activeWallet?.getAccount();
|
|
9
9
|
const activeAddress = activeAccount?.address;
|
|
10
|
-
const { data: nfts, isLoading } =
|
|
11
|
-
return (_jsx("div", { style: { minHeight: "100px" }, children: nfts ? (_jsx(AccountAssets, { nfts: nfts, isLoading: isLoading })) : (_jsx("div", { className: "py-12 text-center text-gray-500", children: "No NFTs found" })) }));
|
|
10
|
+
const { data: nfts, isLoading, isError } = usePortfolioCollectibles(activeAddress, [1, 8453], { filterSpam: true });
|
|
11
|
+
return (_jsx("div", { style: { minHeight: "100px" }, children: isError ? (_jsx("div", { className: "py-12 text-center text-gray-500", children: "Couldn't load your NFTs" })) : nfts ? (_jsx(AccountAssets, { nfts: nfts, isLoading: isLoading })) : (_jsx("div", { className: "py-12 text-center text-gray-500", children: "No NFTs found" })) }));
|
|
12
12
|
};
|
|
13
13
|
export default NFTContent;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useAccountWallet, useB3Config, useModalStore, useProfile,
|
|
2
|
+
import { useAccountWallet, useB3Config, useModalStore, useProfile, usePortfolioBalance, useUser, } from "../../../../global-account/react/index.js";
|
|
3
3
|
import { validateImageUrl } from "../../../../global-account/react/utils/profileDisplay.js";
|
|
4
4
|
import { AVATAR_COLORS } from "../../../../shared/constants/index.js";
|
|
5
5
|
import { formatUsername } from "../../../../shared/utils/index.js";
|
|
@@ -24,14 +24,16 @@ const ProfileSection = () => {
|
|
|
24
24
|
const setB3ModalOpen = useModalStore(state => state.setB3ModalOpen);
|
|
25
25
|
const setB3ModalContentType = useModalStore(state => state.setB3ModalContentType);
|
|
26
26
|
const navigateBack = useModalStore(state => state.navigateBack);
|
|
27
|
-
const { data:
|
|
27
|
+
const { data: balances, isError: isBalanceError } = usePortfolioBalance(smartWalletAddress);
|
|
28
28
|
const [imgError, setImgError] = useState(false);
|
|
29
29
|
const handleImgError = useCallback(() => setImgError(true), []);
|
|
30
|
+
// Null while the holdings are unknown. Summing an absent list to $0.00 would report an empty
|
|
31
|
+
// portfolio to someone whose balances merely failed to load.
|
|
30
32
|
const totalBalanceUsd = useMemo(() => {
|
|
31
|
-
if (!
|
|
32
|
-
return
|
|
33
|
-
return
|
|
34
|
-
}, [
|
|
33
|
+
if (isBalanceError || !balances)
|
|
34
|
+
return null;
|
|
35
|
+
return balances.reduce((sum, token) => sum + (token.value_usd || 0), 0);
|
|
36
|
+
}, [balances, isBalanceError]);
|
|
35
37
|
const handleEditAvatar = () => {
|
|
36
38
|
setB3ModalOpen(true);
|
|
37
39
|
setB3ModalContentType({
|
|
@@ -48,6 +50,6 @@ const ProfileSection = () => {
|
|
|
48
50
|
}, [avatarSrc]);
|
|
49
51
|
const currentUsername = user?.username || profile?.displayName || formatUsername(profile?.name || "");
|
|
50
52
|
const avatarSeed = eoaAddress || account?.address || smartWalletAddress || currentUsername || user?.email || "user";
|
|
51
|
-
return (_jsx("div", { className: "flex items-center justify-between px-5 py-6", children: _jsxs("div", { className: "global-account-profile flex items-center gap-4", children: [_jsxs("div", { className: "global-account-profile-avatar relative", children: [_jsx("div", { className: "border-b3-line border-1 bg-b3-primary-wash size-14 overflow-hidden rounded-full border", children: avatarSrc && !imgError ? (_jsx(IPFSMediaRenderer, { src: avatarSrc, alt: "Profile Avatar", className: "h-full w-full object-cover", onError: handleImgError })) : (_jsx(Avatar, { name: avatarSeed, variant: "beam", size: 56, colors: AVATAR_COLORS })) }), _jsx("button", { onClick: handleEditAvatar, className: "border-b3-background hover:bg-b3-grey/80 absolute -bottom-1 -right-1 flex size-6 items-center justify-center rounded-full border-4 bg-[#a0a0ab] transition-colors", children: _jsx(Pencil, { size: 10, className: "text-b3-background" }) })] }), _jsxs("div", { className: "global-account-profile-info flex flex-col gap-1", children: [!isBetterAuth && (_jsxs("h2", { className: "text-b3-grey font-neue-montreal-semibold flex h-[38px] items-center gap-1 text-xl", children: [_jsx("div", { className: "text-b3-foreground-muted", children: " $" }), _jsx("div", { className: "text-[30px]", children: formatDisplayNumber(totalBalanceUsd, { fractionDigits: 2 }) })] })), _jsx("div", { className: "b3-modal-username font-neue-montreal-semibold text-base leading-none text-[#0B57C2]", children: currentUsername }), isBetterAuth && user?.email && (_jsx("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: user.email }))] })] }) }));
|
|
53
|
+
return (_jsx("div", { className: "flex items-center justify-between px-5 py-6", children: _jsxs("div", { className: "global-account-profile flex items-center gap-4", children: [_jsxs("div", { className: "global-account-profile-avatar relative", children: [_jsx("div", { className: "border-b3-line border-1 bg-b3-primary-wash size-14 overflow-hidden rounded-full border", children: avatarSrc && !imgError ? (_jsx(IPFSMediaRenderer, { src: avatarSrc, alt: "Profile Avatar", className: "h-full w-full object-cover", onError: handleImgError })) : (_jsx(Avatar, { name: avatarSeed, variant: "beam", size: 56, colors: AVATAR_COLORS })) }), _jsx("button", { onClick: handleEditAvatar, className: "border-b3-background hover:bg-b3-grey/80 absolute -bottom-1 -right-1 flex size-6 items-center justify-center rounded-full border-4 bg-[#a0a0ab] transition-colors", children: _jsx(Pencil, { size: 10, className: "text-b3-background" }) })] }), _jsxs("div", { className: "global-account-profile-info flex flex-col gap-1", children: [!isBetterAuth && (_jsxs("h2", { className: "text-b3-grey font-neue-montreal-semibold flex h-[38px] items-center gap-1 text-xl", children: [_jsx("div", { className: "text-b3-foreground-muted", children: " $" }), _jsx("div", { className: "text-[30px]", children: totalBalanceUsd === null ? "—" : formatDisplayNumber(totalBalanceUsd, { fractionDigits: 2 }) })] })), _jsx("div", { className: "b3-modal-username font-neue-montreal-semibold text-base leading-none text-[#0B57C2]", children: currentUsername }), isBetterAuth && user?.email && (_jsx("div", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: user.email }))] })] }) }));
|
|
52
54
|
};
|
|
53
55
|
export default ProfileSection;
|
|
@@ -1,25 +1,34 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { usePortfolioBalance } from "../../../../global-account/react/index.js";
|
|
3
3
|
import { getChainLogo } from "../../../../shared/constants/chains/supported.js";
|
|
4
4
|
import { useActiveWallet } from "thirdweb/react";
|
|
5
5
|
import { TokenBalanceRow } from "./TokenBalanceRow.js";
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
const ETHEREUM_CHAIN_ID = 1;
|
|
7
|
+
// Chain logo URLs, keyed by chain id. Built with Object.fromEntries rather than `.map()`: an array
|
|
8
|
+
// satisfies Record<number, string> for the type checker while indexing by 0,1,2 at runtime, so
|
|
9
|
+
// every lookup by a real chain id would miss.
|
|
10
|
+
const CHAIN_LOGOS = Object.fromEntries([ETHEREUM_CHAIN_ID, 8453, 8333].map(chainId => [chainId, getChainLogo(chainId)]));
|
|
8
11
|
const TokenContent = () => {
|
|
9
12
|
// Get active wallet state
|
|
10
13
|
const activeWallet = useActiveWallet();
|
|
11
14
|
const activeAccount = activeWallet?.getAccount();
|
|
12
15
|
const activeAddress = activeAccount?.address;
|
|
13
|
-
|
|
14
|
-
|
|
16
|
+
// Base and Ethereum only. B3 (8333) is deliberately absent: the portfolio provider does not index
|
|
17
|
+
// it, so asking for it returns nothing and reads as a coverage gap rather than a choice. Restoring
|
|
18
|
+
// B3 needs a non-provider source, the way HyperEVM and Plume are served on-chain in b3os-web.
|
|
19
|
+
const { data: balances, isError: isBalanceError } = usePortfolioBalance(activeAddress, [8453, ETHEREUM_CHAIN_ID]);
|
|
15
20
|
if (!activeAddress) {
|
|
16
21
|
return _jsx("div", { className: "col-span-3 py-12 text-center text-gray-500", children: "No tokens found" });
|
|
17
22
|
}
|
|
18
|
-
|
|
23
|
+
// "Couldn't load" and "holds nothing" are different answers and must not share a message.
|
|
24
|
+
if (isBalanceError) {
|
|
25
|
+
return _jsx("div", { className: "col-span-3 py-12 text-center text-gray-500", children: "Couldn't load your tokens" });
|
|
26
|
+
}
|
|
27
|
+
if (!balances || balances.length === 0) {
|
|
19
28
|
return _jsx("div", { className: "col-span-3 py-12 text-center text-gray-500", children: "No tokens found" });
|
|
20
29
|
}
|
|
21
30
|
// Sort by USD value descending
|
|
22
|
-
const sortedBalances = [...
|
|
31
|
+
const sortedBalances = [...balances].sort((a, b) => {
|
|
23
32
|
const valueA = a.value_usd || 0;
|
|
24
33
|
const valueB = b.value_usd || 0;
|
|
25
34
|
return valueB - valueA;
|
|
@@ -33,8 +42,8 @@ const TokenContent = () => {
|
|
|
33
42
|
// Determine token logo
|
|
34
43
|
// For native tokens, use ETH logo instead of chain logo
|
|
35
44
|
let tokenLogo = token.token_metadata?.logo || "";
|
|
36
|
-
if (token.
|
|
37
|
-
tokenLogo = CHAIN_LOGOS[
|
|
45
|
+
if (token.is_native && token.symbol === "ETH") {
|
|
46
|
+
tokenLogo = CHAIN_LOGOS[ETHEREUM_CHAIN_ID];
|
|
38
47
|
}
|
|
39
48
|
return (_jsx(TokenBalanceRow, { tokenLogo: tokenLogo, chainLogo: CHAIN_LOGOS[token.chain_id] || "", name: token.name || token.symbol, balance: `${balance} ${token.symbol}`, usdValue: usdValue, priceChange: priceChange }, `${token.chain_id}-${token.address}-${index}`));
|
|
40
49
|
}) }));
|