@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
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Canonical browser-side translation of Zerion wallet positions into B3 balance rows.
|
|
4
|
+
*
|
|
5
|
+
* This lives in the published SDK because every browser consumer needs it — the apps in this repo
|
|
6
|
+
* and the sites that install `@b3dotfun/sdk` from npm — and the in-repo Zerion client is a private
|
|
7
|
+
* workspace package that a published package cannot depend on. Backend services keep their own
|
|
8
|
+
* translation: pulling a browser SDK into a Node service to share one function is a worse trade
|
|
9
|
+
* than the second copy.
|
|
10
|
+
*
|
|
11
|
+
* Only the HTTP layer differs between callers. The rules below — which row counts as the chain's
|
|
12
|
+
* native coin, and which rows have no usable identity — must not be re-derived anywhere else.
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.SOLANA_CHAIN_ID = exports.SOLANA_ZERION_SLUG = exports.SOLANA_NATIVE_TOKEN_ADDRESS = exports.EVM_NATIVE_TOKEN_ADDRESS = void 0;
|
|
16
|
+
exports.zerionSlugToChainId = zerionSlugToChainId;
|
|
17
|
+
exports.chainIdToZerionSlug = chainIdToZerionSlug;
|
|
18
|
+
exports.nativeTokenAddressForChain = nativeTokenAddressForChain;
|
|
19
|
+
exports.balanceMatchesToken = balanceMatchesToken;
|
|
20
|
+
exports.adaptZerionPositions = adaptZerionPositions;
|
|
21
|
+
/** Address B3 uses for a chain's native coin on EVM. Matches NATIVE_TOKEN_ADDRESSES. */
|
|
22
|
+
exports.EVM_NATIVE_TOKEN_ADDRESS = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
|
|
23
|
+
exports.SOLANA_NATIVE_TOKEN_ADDRESS = "So11111111111111111111111111111111111111112";
|
|
24
|
+
exports.SOLANA_ZERION_SLUG = "solana";
|
|
25
|
+
/** What Zerion's `quantity.int` is: a base-10 integer, unbounded in length. */
|
|
26
|
+
const DECIMAL_INTEGER_PATTERN = /^\d+$/;
|
|
27
|
+
/** Solana's chain id as the chain registry defines it — the id every balance row is keyed by. */
|
|
28
|
+
exports.SOLANA_CHAIN_ID = 7565164;
|
|
29
|
+
/**
|
|
30
|
+
* Zerion chain slug → numeric chain id. Slugs are Zerion's own vocabulary and do not always match
|
|
31
|
+
* the chain's common name — Gnosis is `xdai`, Metis is `metis-andromeda` — so an entry invented
|
|
32
|
+
* from the chain name silently drops every position on that chain, because the adapter skips any
|
|
33
|
+
* slug it cannot map. Every entry here is taken from Zerion's `GET /v1/chains/`.
|
|
34
|
+
*/
|
|
35
|
+
const ZERION_CHAIN_IDS = {
|
|
36
|
+
ethereum: 1,
|
|
37
|
+
optimism: 10,
|
|
38
|
+
"binance-smart-chain": 56,
|
|
39
|
+
xdai: 100,
|
|
40
|
+
unichain: 130,
|
|
41
|
+
polygon: 137,
|
|
42
|
+
sonic: 146,
|
|
43
|
+
fantom: 250,
|
|
44
|
+
"zksync-era": 324,
|
|
45
|
+
world: 480,
|
|
46
|
+
hyperevm: 999,
|
|
47
|
+
"metis-andromeda": 1088,
|
|
48
|
+
"polygon-zkevm": 1101,
|
|
49
|
+
soneium: 1868,
|
|
50
|
+
ronin: 2020,
|
|
51
|
+
abstract: 2741,
|
|
52
|
+
robinhood: 4663,
|
|
53
|
+
mantle: 5000,
|
|
54
|
+
base: 8453,
|
|
55
|
+
mode: 34443,
|
|
56
|
+
arbitrum: 42161,
|
|
57
|
+
celo: 42220,
|
|
58
|
+
avalanche: 43114,
|
|
59
|
+
linea: 59144,
|
|
60
|
+
berachain: 80094,
|
|
61
|
+
blast: 81457,
|
|
62
|
+
taiko: 167000,
|
|
63
|
+
scroll: 534352,
|
|
64
|
+
zora: 7777777,
|
|
65
|
+
degen: 666666666,
|
|
66
|
+
aurora: 1313161554,
|
|
67
|
+
[exports.SOLANA_ZERION_SLUG]: exports.SOLANA_CHAIN_ID,
|
|
68
|
+
};
|
|
69
|
+
// Maps rather than objects: a slug arrives straight off the wire, and an object lookup resolves an
|
|
70
|
+
// inherited key like `constructor` or `toString` to something truthy instead of reporting the chain
|
|
71
|
+
// as unknown — which would carry a row past the `=== undefined` guard with a function as its id.
|
|
72
|
+
const CHAIN_ID_BY_ZERION_SLUG = new Map(Object.entries(ZERION_CHAIN_IDS));
|
|
73
|
+
const ZERION_SLUG_BY_CHAIN_ID = new Map(Object.entries(ZERION_CHAIN_IDS).map(([slug, id]) => [id, slug]));
|
|
74
|
+
function zerionSlugToChainId(slug) {
|
|
75
|
+
return CHAIN_ID_BY_ZERION_SLUG.get(slug);
|
|
76
|
+
}
|
|
77
|
+
function chainIdToZerionSlug(chainId) {
|
|
78
|
+
return ZERION_SLUG_BY_CHAIN_ID.get(chainId);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Zerion encodes a position's asset in the first hyphen-delimited segment of its resource `id`
|
|
82
|
+
* (`<assetRef>-<chainSlug>-<positionType>-…`). A chain's native coin uses the literal `base`
|
|
83
|
+
* (`base-polygon-asset-asset`); ERC-20s use the contract address
|
|
84
|
+
* (`0x1dd17…-ethereum-asset-asset`).
|
|
85
|
+
*
|
|
86
|
+
* This is the only reliable native signal. A falsy per-chain `implementation.address` looks
|
|
87
|
+
* equivalent and is not: Zerion reports Polygon's native coin at its `0x…1010` system contract and
|
|
88
|
+
* Celo's at a real ERC-20 address, while Polygon simultaneously carries a non-native fungible with
|
|
89
|
+
* the same `POL` symbol. Keying on the address shape misclassifies both.
|
|
90
|
+
*/
|
|
91
|
+
function isNativePosition(id, impl) {
|
|
92
|
+
if (id?.startsWith("base-") === true)
|
|
93
|
+
return true;
|
|
94
|
+
// Second signal, for the chains that spell native as an absent address. It requires the
|
|
95
|
+
// implementation to EXIST: a fungible with no entry for this chain tells us nothing about what
|
|
96
|
+
// the row is, and calling that native would hand a value-bearing send an amount we cannot name.
|
|
97
|
+
return impl !== undefined && !impl.address;
|
|
98
|
+
}
|
|
99
|
+
function nativeTokenAddressForChain(slug) {
|
|
100
|
+
return slug === exports.SOLANA_ZERION_SLUG ? exports.SOLANA_NATIVE_TOKEN_ADDRESS : exports.EVM_NATIVE_TOKEN_ADDRESS;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Every spelling of "the chain's own coin" a caller might hold.
|
|
104
|
+
*
|
|
105
|
+
* A token record's address depends on where it came from — a quote provider, a token list, a URL
|
|
106
|
+
* parameter — and each source names the native coin differently. Matching a balance row against any
|
|
107
|
+
* single one of these silently fails for the others.
|
|
108
|
+
*/
|
|
109
|
+
const NATIVE_TOKEN_MARKERS = new Set([
|
|
110
|
+
"native",
|
|
111
|
+
"0x0000000000000000000000000000000000000000",
|
|
112
|
+
exports.EVM_NATIVE_TOKEN_ADDRESS,
|
|
113
|
+
exports.SOLANA_NATIVE_TOKEN_ADDRESS.toLowerCase(),
|
|
114
|
+
"11111111111111111111111111111111",
|
|
115
|
+
]);
|
|
116
|
+
/**
|
|
117
|
+
* Whether `balance` is the token identified by `tokenAddress`.
|
|
118
|
+
*
|
|
119
|
+
* Native coins are matched on the row's `is_native` flag rather than its printed address, because
|
|
120
|
+
* the caller and the adapter rarely spell the native coin the same way.
|
|
121
|
+
*/
|
|
122
|
+
function balanceMatchesToken(balance, tokenAddress) {
|
|
123
|
+
const wanted = tokenAddress.toLowerCase();
|
|
124
|
+
if (NATIVE_TOKEN_MARKERS.has(wanted))
|
|
125
|
+
return balance.is_native;
|
|
126
|
+
// Case-insensitive only for hex contract addresses. Solana mints are base58, where case is
|
|
127
|
+
// significant — lowercasing them would let two distinct mints compare equal.
|
|
128
|
+
if (balance.chain === exports.SOLANA_ZERION_SLUG)
|
|
129
|
+
return balance.address === tokenAddress;
|
|
130
|
+
return balance.address.toLowerCase() === wanted;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Adapt raw Zerion positions into balance rows, dropping any row we cannot describe honestly.
|
|
134
|
+
*
|
|
135
|
+
* A row is dropped when its chain slug is absent or unmapped, or when neither the quantity nor the
|
|
136
|
+
* chain implementation carries decimals — an amount rendered against a guessed scale is a wrong
|
|
137
|
+
* number presented as a real one, which is worse for the reader than a missing row.
|
|
138
|
+
*
|
|
139
|
+
* @param slugToChainId overrides slug resolution; return undefined to skip a chain entirely.
|
|
140
|
+
*/
|
|
141
|
+
function adaptZerionPositions(positions, slugToChainId = zerionSlugToChainId) {
|
|
142
|
+
const out = [];
|
|
143
|
+
for (const position of positions) {
|
|
144
|
+
const attributes = position.attributes ?? {};
|
|
145
|
+
const flags = attributes.flags;
|
|
146
|
+
if (flags && (flags.displayable === false || flags.is_trash === true))
|
|
147
|
+
continue;
|
|
148
|
+
const slug = position.relationships?.chain?.data?.id;
|
|
149
|
+
if (!slug)
|
|
150
|
+
continue;
|
|
151
|
+
const chainId = slugToChainId(slug);
|
|
152
|
+
if (chainId === undefined)
|
|
153
|
+
continue;
|
|
154
|
+
const fungibleInfo = attributes.fungible_info ?? {};
|
|
155
|
+
const implementation = (fungibleInfo.implementations ?? []).find(entry => entry.chain_id === slug);
|
|
156
|
+
const decimals = attributes.quantity?.decimals ?? implementation?.decimals;
|
|
157
|
+
if (decimals === undefined)
|
|
158
|
+
continue;
|
|
159
|
+
const isNative = isNativePosition(position.id, implementation);
|
|
160
|
+
// A non-native row with no contract address has no on-chain identity — drop it rather than
|
|
161
|
+
// render a holding nothing can name.
|
|
162
|
+
const address = isNative ? nativeTokenAddressForChain(slug) : implementation?.address;
|
|
163
|
+
if (!address)
|
|
164
|
+
continue;
|
|
165
|
+
// A quantity we cannot read is not a zero balance. Must be the base-10 integer `quantity.int`
|
|
166
|
+
// is: `null`, `""`, and any other unusable string all format to NaN, which callers coerce back
|
|
167
|
+
// to 0 and show as "holds none". `"0"` matches, so a real zero balance still comes through.
|
|
168
|
+
const amount = attributes.quantity?.int;
|
|
169
|
+
if (amount === undefined || !DECIMAL_INTEGER_PATTERN.test(amount))
|
|
170
|
+
continue;
|
|
171
|
+
out.push({
|
|
172
|
+
chain: slug,
|
|
173
|
+
chain_id: chainId,
|
|
174
|
+
address,
|
|
175
|
+
amount,
|
|
176
|
+
symbol: fungibleInfo.symbol ?? "",
|
|
177
|
+
decimals,
|
|
178
|
+
is_native: isNative,
|
|
179
|
+
name: fungibleInfo.name,
|
|
180
|
+
price_usd: attributes.price ?? undefined,
|
|
181
|
+
value_usd: attributes.value ?? undefined,
|
|
182
|
+
token_metadata: fungibleInfo.icon?.url ? { logo: fungibleInfo.icon.url } : undefined,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
return out;
|
|
186
|
+
}
|
|
@@ -16,6 +16,6 @@ export interface CreateWalletConfigOptions {
|
|
|
16
16
|
* Creates a generic wagmi config with sensible defaults.
|
|
17
17
|
* No ecosystem wallet, no B3-specific concerns.
|
|
18
18
|
*/
|
|
19
|
-
export declare function createWalletConfig(options?: CreateWalletConfigOptions): import("wagmi").Config<readonly [
|
|
20
|
-
[k: string]:
|
|
19
|
+
export declare function createWalletConfig(options?: CreateWalletConfigOptions): import("wagmi").Config<readonly [any, ...any[]], {
|
|
20
|
+
[k: string]: any;
|
|
21
21
|
}, CreateConnectorFn[]>;
|
|
@@ -17,6 +17,7 @@ export declare const B3_PUBLIC_RPC = "https://mainnet-rpc.b3.fun";
|
|
|
17
17
|
export declare const ABSTRACT_PUBLIC_RPC = "https://api.mainnet.abs.xyz";
|
|
18
18
|
export declare const HYPEREVM_PUBLIC_RPC = "https://rpc.hyperliquid.xyz/evm";
|
|
19
19
|
export declare const PLUME_PUBLIC_RPC = "https://rpc.plume.org";
|
|
20
|
+
export declare const ROBINHOOD_PUBLIC_RPC = "https://rpc.mainnet.chain.robinhood.com";
|
|
20
21
|
/**
|
|
21
22
|
* Map of chain IDs to their default public RPC URLs.
|
|
22
23
|
*/
|
|
@@ -19,6 +19,7 @@ export const B3_PUBLIC_RPC = "https://mainnet-rpc.b3.fun";
|
|
|
19
19
|
export const ABSTRACT_PUBLIC_RPC = "https://api.mainnet.abs.xyz";
|
|
20
20
|
export const HYPEREVM_PUBLIC_RPC = "https://rpc.hyperliquid.xyz/evm";
|
|
21
21
|
export const PLUME_PUBLIC_RPC = "https://rpc.plume.org";
|
|
22
|
+
export const ROBINHOOD_PUBLIC_RPC = "https://rpc.mainnet.chain.robinhood.com";
|
|
22
23
|
/**
|
|
23
24
|
* Map of chain IDs to their default public RPC URLs.
|
|
24
25
|
*/
|
|
@@ -34,4 +35,5 @@ export const PUBLIC_RPC_URLS = {
|
|
|
34
35
|
2741: ABSTRACT_PUBLIC_RPC, // Abstract
|
|
35
36
|
999: HYPEREVM_PUBLIC_RPC, // HyperEVM
|
|
36
37
|
98866: PLUME_PUBLIC_RPC, // Plume Network
|
|
38
|
+
4663: ROBINHOOD_PUBLIC_RPC, // Robinhood Chain
|
|
37
39
|
};
|
|
@@ -84,8 +84,6 @@ export interface AnySpendDepositProps {
|
|
|
84
84
|
showFiatOption?: boolean;
|
|
85
85
|
/** Custom list of supported chains. If not provided, uses default chains */
|
|
86
86
|
supportedChains?: ChainConfig[];
|
|
87
|
-
/** Minimum pool size for filtering tokens (default: 1,000,000) */
|
|
88
|
-
minPoolSize?: number;
|
|
89
87
|
/** Custom title for chain selection step */
|
|
90
88
|
chainSelectionTitle?: string;
|
|
91
89
|
/** Custom description for chain selection step */
|
|
@@ -164,4 +162,4 @@ export interface AnySpendDepositProps {
|
|
|
164
162
|
* onSuccess={(amount) => console.log(`Deposited ${amount}`)}
|
|
165
163
|
* />
|
|
166
164
|
*/
|
|
167
|
-
export declare function AnySpendDeposit({ loadOrder, mode, recipientAddress, paymentType: initialPaymentType, sourceTokenAddress, sourceTokenChainId: initialSourceChainId, destinationTokenAddress, destinationTokenChainId, lockDestinationToken, onSuccess, onOpenCustomModal, mainFooter, onTokenSelect, customUsdInputValues, preferEoa, minDestinationAmount, header, orderType, depositContractConfig, showChainSelection, showFiatOption, supportedChains,
|
|
165
|
+
export declare function AnySpendDeposit({ loadOrder, mode, recipientAddress, paymentType: initialPaymentType, sourceTokenAddress, sourceTokenChainId: initialSourceChainId, destinationTokenAddress, destinationTokenChainId, lockDestinationToken, onSuccess, onOpenCustomModal, mainFooter, onTokenSelect, customUsdInputValues, preferEoa, minDestinationAmount, header, orderType, depositContractConfig, showChainSelection, showFiatOption, supportedChains, topChainsCount, onClose, returnToHomeUrl, customRecipientLabel, returnHomeLabel, isCustomDeposit, classes, allowDirectTransfer, pureTransferOnly, destinationTokenAmount, callbackMetadata, senderAddress, slots, content, theme, }: AnySpendDepositProps): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { USDC_BASE } from "../../../anyspend/index.js";
|
|
3
|
-
import { Skeleton, useAccountWallet,
|
|
3
|
+
import { Skeleton, useAccountWallet, usePortfolioBalance, useTokenData } from "../../../global-account/react/index.js";
|
|
4
4
|
import { cn } from "../../../shared/utils/cn.js";
|
|
5
5
|
import { formatTokenAmount } from "../../../shared/utils/number.js";
|
|
6
6
|
import { NetworkArbitrumOne, NetworkBase, NetworkBinanceSmartChain, NetworkEthereum, NetworkOptimism, NetworkPolygonPos, } from "@web3icons/react";
|
|
@@ -21,8 +21,6 @@ const DEFAULT_SUPPORTED_CHAINS = [
|
|
|
21
21
|
{ id: 137, name: "Polygon" },
|
|
22
22
|
{ id: 56, name: "BNB Chain" },
|
|
23
23
|
];
|
|
24
|
-
// Minimum pool size to filter out low liquidity tokens
|
|
25
|
-
const DEFAULT_MIN_POOL_SIZE = 1000000;
|
|
26
24
|
/**
|
|
27
25
|
* Self-described fallback metadata for the default funding token(s), keyed by
|
|
28
26
|
* `${chainId}:${lowercased address}`. Used when `useTokenData` misses (returns
|
|
@@ -109,7 +107,7 @@ function ChainIcon({ chainId, className }) {
|
|
|
109
107
|
* onSuccess={(amount) => console.log(`Deposited ${amount}`)}
|
|
110
108
|
* />
|
|
111
109
|
*/
|
|
112
|
-
export function AnySpendDeposit({ loadOrder, mode = "modal", recipientAddress, paymentType: initialPaymentType, sourceTokenAddress, sourceTokenChainId: initialSourceChainId, destinationTokenAddress, destinationTokenChainId, lockDestinationToken = true, onSuccess, onOpenCustomModal, mainFooter, onTokenSelect, customUsdInputValues, preferEoa, minDestinationAmount, header, orderType, depositContractConfig, showChainSelection, showFiatOption = true, supportedChains = DEFAULT_SUPPORTED_CHAINS,
|
|
110
|
+
export function AnySpendDeposit({ loadOrder, mode = "modal", recipientAddress, paymentType: initialPaymentType, sourceTokenAddress, sourceTokenChainId: initialSourceChainId, destinationTokenAddress, destinationTokenChainId, lockDestinationToken = true, onSuccess, onOpenCustomModal, mainFooter, onTokenSelect, customUsdInputValues, preferEoa, minDestinationAmount, header, orderType, depositContractConfig, showChainSelection, showFiatOption = true, supportedChains = DEFAULT_SUPPORTED_CHAINS, topChainsCount = 3, onClose, returnToHomeUrl, customRecipientLabel, returnHomeLabel, isCustomDeposit = false, classes, allowDirectTransfer = false, pureTransferOnly = false, destinationTokenAmount, callbackMetadata, senderAddress, slots, content, theme, }) {
|
|
113
111
|
// Extract deposit-specific classes for convenience
|
|
114
112
|
const depositClasses = classes?.deposit;
|
|
115
113
|
const { connectedEOAWallet } = useAccountWallet();
|
|
@@ -144,13 +142,17 @@ export function AnySpendDeposit({ loadOrder, mode = "modal", recipientAddress, p
|
|
|
144
142
|
}, [destinationTokenAddress, destinationTokenChainId, destinationTokenData]);
|
|
145
143
|
// Fetch balances for EOA wallet (use senderAddress as fallback for pre-filled balance display)
|
|
146
144
|
const effectiveBalanceAddress = senderAddress || eoaAddress;
|
|
147
|
-
const { data:
|
|
148
|
-
// Group balances by chain and calculate total USD value per chain
|
|
145
|
+
const { data: balances, isLoading: isBalanceLoading, isError: isBalanceError, } = usePortfolioBalance(shouldShowChainSelection ? effectiveBalanceAddress : undefined, supportedChains.map(c => c.id));
|
|
146
|
+
// Group balances by chain and calculate total USD value per chain.
|
|
147
|
+
//
|
|
148
|
+
// There is deliberately no liquidity threshold here. The balance provider reports no pool size,
|
|
149
|
+
// so a `pool_size > n` test is false for every row and quietly reduces to "native only",
|
|
150
|
+
// erasing every ERC-20 the user holds from the chain summary. Spam filtering belongs to the
|
|
151
|
+
// token-filter service, which has the data to do it.
|
|
149
152
|
const chainBalances = useMemo(() => {
|
|
150
|
-
if (!
|
|
153
|
+
if (!balances)
|
|
151
154
|
return {};
|
|
152
|
-
|
|
153
|
-
return filteredBalances.reduce((acc, token) => {
|
|
155
|
+
return balances.reduce((acc, token) => {
|
|
154
156
|
const chainId = token.chain_id;
|
|
155
157
|
if (!acc[chainId]) {
|
|
156
158
|
acc[chainId] = {
|
|
@@ -164,7 +166,7 @@ export function AnySpendDeposit({ loadOrder, mode = "modal", recipientAddress, p
|
|
|
164
166
|
acc[chainId].tokenCount += 1;
|
|
165
167
|
return acc;
|
|
166
168
|
}, {});
|
|
167
|
-
}, [
|
|
169
|
+
}, [balances]);
|
|
168
170
|
// Sort chains by USD value (highest first)
|
|
169
171
|
const sortedChains = useMemo(() => {
|
|
170
172
|
return supportedChains
|
|
@@ -219,10 +221,10 @@ export function AnySpendDeposit({ loadOrder, mode = "modal", recipientAddress, p
|
|
|
219
221
|
if (step === "select-chain") {
|
|
220
222
|
return (_jsxs("div", { className: depositClasses?.chainSelection ||
|
|
221
223
|
cn("anyspend-deposit anyspend-deposit-chain-selection font-inter bg-as-surface-primary relative mx-auto w-full max-w-[460px]", mode === "page" && "border-as-border-secondary overflow-hidden rounded-2xl border shadow-xl"), children: [onClose && (_jsx("button", { onClick: onClose, className: depositClasses?.closeButton ||
|
|
222
|
-
"anyspend-deposit-close-button text-as-secondary hover:text-as-primary absolute right-4 top-4 z-10", children: _jsx("svg", { className: "h-6 w-6", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })), !isBalanceLoading && totalBalance > 0 && (_jsxs("div", { className: depositClasses?.balanceContainer || "anyspend-deposit-balance border-theme-border-secondary border-b p-5", children: [_jsx("p", { className: depositClasses?.balanceLabel || "anyspend-deposit-balance-label text-as-secondary text-sm", children: "Your Balance" }), _jsxs("p", { className: depositClasses?.balanceValue || "anyspend-deposit-balance-value text-as-primary text-3xl font-semibold", children: [formatDecimal(totalBalance), " ", _jsx("span", { className: "text-sm", children: "USD" })] })] })), _jsxs("div", { className: depositClasses?.optionsContainer || "anyspend-deposit-options flex flex-col gap-2 p-6", children: [isBalanceLoading && (_jsx("div", { className: depositClasses?.chainsSkeleton || "anyspend-deposit-chains-skeleton flex flex-col gap-2", children: [1, 2].map((_, i) => (_jsxs("div", { className: depositClasses?.skeletonItem ||
|
|
223
|
-
"border-border-primary flex items-center justify-between rounded-xl border p-4", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Skeleton, { className: "h-6 w-6 rounded-full" }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Skeleton, { className: "h-4 w-32" }), _jsx(Skeleton, { className: "h-3 w-20" })] })] }), _jsx(Skeleton, { className: "h-5 w-5" })] }, i))) })), topChainsWithBalance.length > 0 && (_jsx("div", { className: depositClasses?.chainsContainer || "anyspend-deposit-chains flex flex-col gap-2", children: topChainsWithBalance.map(chain => (_jsxs("button", { onClick: () => handleSelectChain(chain.id), className: depositClasses?.chainButton ||
|
|
224
|
+
"anyspend-deposit-close-button text-as-secondary hover:text-as-primary absolute right-4 top-4 z-10", children: _jsx("svg", { className: "h-6 w-6", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })), !isBalanceLoading && !isBalanceError && totalBalance > 0 && (_jsxs("div", { className: depositClasses?.balanceContainer || "anyspend-deposit-balance border-theme-border-secondary border-b p-5", children: [_jsx("p", { className: depositClasses?.balanceLabel || "anyspend-deposit-balance-label text-as-secondary text-sm", children: "Your Balance" }), _jsxs("p", { className: depositClasses?.balanceValue || "anyspend-deposit-balance-value text-as-primary text-3xl font-semibold", children: [formatDecimal(totalBalance), " ", _jsx("span", { className: "text-sm", children: "USD" })] })] })), _jsxs("div", { className: depositClasses?.optionsContainer || "anyspend-deposit-options flex flex-col gap-2 p-6", children: [isBalanceLoading && (_jsx("div", { className: depositClasses?.chainsSkeleton || "anyspend-deposit-chains-skeleton flex flex-col gap-2", children: [1, 2].map((_, i) => (_jsxs("div", { className: depositClasses?.skeletonItem ||
|
|
225
|
+
"border-border-primary flex items-center justify-between rounded-xl border p-4", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Skeleton, { className: "h-6 w-6 rounded-full" }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Skeleton, { className: "h-4 w-32" }), _jsx(Skeleton, { className: "h-3 w-20" })] })] }), _jsx(Skeleton, { className: "h-5 w-5" })] }, i))) })), isBalanceError && !isBalanceLoading && (_jsx("p", { className: "text-as-primary/50 px-1 py-2 text-sm", children: "We couldn't read your balances just now. You can still pick a chain below." })), !isBalanceError && topChainsWithBalance.length > 0 && (_jsx("div", { className: depositClasses?.chainsContainer || "anyspend-deposit-chains flex flex-col gap-2", children: topChainsWithBalance.map(chain => (_jsxs("button", { onClick: () => handleSelectChain(chain.id), className: depositClasses?.chainButton ||
|
|
224
226
|
"anyspend-deposit-chain-button border-border-primary hover:border-as-brand hover:bg-as-surface-secondary flex w-full items-center justify-between rounded-xl border p-4 text-left shadow-sm transition-all", children: [_jsx("div", { className: depositClasses?.chainContent || "anyspend-deposit-chain-content", children: _jsxs("div", { className: depositClasses?.chainInfo || "anyspend-deposit-chain-info", children: [_jsxs("span", { className: depositClasses?.chainName ||
|
|
225
|
-
"anyspend-deposit-chain-name text-as-primary flex items-center gap-1.5 font-medium", children: ["Deposit from ", chain.name, _jsx(ChainIcon, { chainId: chain.id, className: depositClasses?.chainIcon || "h-5 w-5" })] }),
|
|
227
|
+
"anyspend-deposit-chain-name text-as-primary flex items-center gap-1.5 font-medium", children: ["Deposit from ", chain.name, _jsx(ChainIcon, { chainId: chain.id, className: depositClasses?.chainIcon || "h-5 w-5" })] }), _jsx("p", { className: depositClasses?.chainBalance || "anyspend-deposit-chain-balance text-as-secondary text-xs", children: `${formatUsd(chain.balance)} available` })] }) }), _jsx(ChevronRight, { className: depositClasses?.chainChevron || "anyspend-deposit-chain-chevron text-as-secondary h-5 w-5" })] }, chain.id))) })), _jsxs("div", { className: depositClasses?.generalOptions || "anyspend-deposit-general-options flex flex-col gap-2", children: [_jsxs("button", { onClick: handleSelectCrypto, className: depositClasses?.cryptoButton ||
|
|
226
228
|
"anyspend-deposit-option-button anyspend-deposit-crypto-button border-border-primary hover:border-as-brand hover:bg-as-surface-secondary flex w-full items-center justify-between rounded-xl border p-4 text-left shadow-sm transition-all", children: [_jsx("div", { className: depositClasses?.optionContent || "anyspend-deposit-option-content", children: _jsxs("div", { className: depositClasses?.optionInfo || "anyspend-deposit-option-info", children: [_jsx("span", { className: depositClasses?.optionTitle || "anyspend-deposit-option-title text-as-primary font-medium", children: "Deposit Crypto" }), _jsx("p", { className: depositClasses?.optionDescription ||
|
|
227
229
|
"anyspend-deposit-option-description text-as-secondary text-xs", children: "Swap from any token on any chain" })] }) }), _jsx(ChevronRight, { className: depositClasses?.optionChevron || "anyspend-deposit-option-chevron text-as-secondary h-5 w-5" })] }), _jsxs("div", { className: depositClasses?.divider || "anyspend-deposit-divider flex items-center gap-3", children: [_jsx("div", { className: depositClasses?.dividerLine || "bg-as-stroke h-px flex-1" }), _jsx("span", { className: depositClasses?.dividerText || "anyspend-deposit-divider-text text-as-secondary text-sm", children: "More options" }), _jsx("div", { className: depositClasses?.dividerLine || "bg-as-stroke h-px flex-1" })] }), _jsxs("button", { onClick: handleSelectQrDeposit, className: depositClasses?.qrButton ||
|
|
228
230
|
"anyspend-deposit-option-button anyspend-deposit-qr-button border-border-primary hover:border-as-brand hover:bg-as-surface-secondary flex w-full items-center justify-between rounded-xl border p-4 text-left shadow-sm transition-all", children: [_jsxs("div", { className: depositClasses?.optionContent || "anyspend-deposit-option-content flex items-center gap-3", children: [_jsx(QrCodeIcon, { className: depositClasses?.optionIcon || "anyspend-deposit-option-icon h-10 w-10" }), _jsxs("div", { className: depositClasses?.optionInfo || "anyspend-deposit-option-info", children: [_jsx("span", { className: depositClasses?.optionTitle || "anyspend-deposit-option-title text-as-primary font-medium", children: "Deposit with QR Code" }), _jsx("p", { className: depositClasses?.optionDescription ||
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { ABI_ERC20_STAKING, B3_TOKEN, eqci, getExplorerTxUrl } from "../../../anyspend/index.js";
|
|
3
|
-
import { Button, GlareCardRounded, Input, StyleRoot, TextLoop, toast, useHasMounted, useModalStore,
|
|
3
|
+
import { Button, GlareCardRounded, Input, StyleRoot, TextLoop, toast, useHasMounted, useModalStore, usePortfolioBalance, useUnifiedChainSwitchAndExecute, } from "../../../global-account/react/index.js";
|
|
4
4
|
import { PUBLIC_BASE_RPC_URL } from "../../../shared/constants/index.js";
|
|
5
5
|
import { formatTokenAmount } from "../../../shared/utils/number.js";
|
|
6
6
|
import invariant from "invariant";
|
|
@@ -34,11 +34,25 @@ export function AnySpendStakeB3({ loadOrder, mode = "modal", recipientAddress, s
|
|
|
34
34
|
// Wagmi hooks for direct staking
|
|
35
35
|
const { address } = useAccount();
|
|
36
36
|
const { switchChainAndExecute, isSwitchingOrExecuting } = useUnifiedChainSwitchAndExecute();
|
|
37
|
-
// Fetch B3 token balance
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
// Fetch B3 token balance. `isBalanceUnknown` must gate every use of `b3RawBalance`: a failed read
|
|
38
|
+
// yields the same 0 as an empty wallet, and acting on it pushes a holder into the swap flow to
|
|
39
|
+
// buy a token they already have.
|
|
40
|
+
const { data: balances, isLoading: isBalanceLoading, isError: isBalanceError, refetch: refetchBalance, } = usePortfolioBalance(address, [base.id]);
|
|
41
|
+
// Guarded on `address`: with no wallet connected the query never runs, and a query that was
|
|
42
|
+
// never asked is not a query that failed. Without this the screen tells a visitor their
|
|
43
|
+
// balance is unavailable and refuses to continue, when they simply have not connected yet.
|
|
44
|
+
const isBalanceUnknown = Boolean(address) && (isBalanceError || (!isBalanceLoading && balances === undefined));
|
|
45
|
+
const b3RawBalanceStr = balances?.find(b => eqci(b.address, B3_TOKEN.address))?.amount || "0";
|
|
40
46
|
const b3RawBalance = BigInt(b3RawBalanceStr);
|
|
41
47
|
const b3Balance = formatTokenAmount(b3RawBalance, B3_TOKEN.decimals);
|
|
48
|
+
/**
|
|
49
|
+
* Whether the wallet demonstrably holds enough B3 to stake `amountRaw` directly.
|
|
50
|
+
*
|
|
51
|
+
* False while the balance is unknown — but callers must not read that as a shortfall. An unknown
|
|
52
|
+
* balance is neither enough nor short, and the two need different UI: a shortfall offers the swap
|
|
53
|
+
* flow, an unknown offers a retry. Check `isBalanceUnknown` first.
|
|
54
|
+
*/
|
|
55
|
+
const hasEnoughB3 = (amountRaw) => !isBalanceUnknown && BigInt(amountRaw || "0") <= b3RawBalance;
|
|
42
56
|
// State for direct staking flow
|
|
43
57
|
const [isStaking, setIsStaking] = useState(false);
|
|
44
58
|
const [stakingTxHash, setStakingTxHash] = useState("");
|
|
@@ -206,9 +220,11 @@ export function AnySpendStakeB3({ loadOrder, mode = "modal", recipientAddress, s
|
|
|
206
220
|
toast.error("Please enter a valid amount to stake");
|
|
207
221
|
return;
|
|
208
222
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
223
|
+
if (isBalanceUnknown) {
|
|
224
|
+
toast.error("Can't read your B3 balance right now. Please try again.");
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
if (hasEnoughB3(userStakeAmount)) {
|
|
212
228
|
// User has enough B3, proceed with direct staking
|
|
213
229
|
handleDirectStaking();
|
|
214
230
|
}
|
|
@@ -232,16 +248,19 @@ export function AnySpendStakeB3({ loadOrder, mode = "modal", recipientAddress, s
|
|
|
232
248
|
opacity: hasMounted ? 1 : 0,
|
|
233
249
|
y: hasMounted ? 0 : 20,
|
|
234
250
|
filter: hasMounted ? "blur(0px)" : "blur(10px)",
|
|
235
|
-
}, transition: { duration: 0.3, delay: 0.1, ease: "easeInOut" }, children: _jsx("h2", { className: "font-sf-rounded font-neue-montreal-medium mb-1 text-center text-2xl font-semibold", children: (
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
})() }) })] }), _jsxs(motion.div, { initial: false, animate: {
|
|
251
|
+
}, transition: { duration: 0.3, delay: 0.1, ease: "easeInOut" }, children: _jsx("h2", { className: "font-sf-rounded font-neue-montreal-medium mb-1 text-center text-2xl font-semibold", children: isBalanceUnknown || !debouncedAmount || hasEnoughB3(debouncedUserStakeAmount)
|
|
252
|
+
? "Stake B3"
|
|
253
|
+
: "Swap & Stake B3" }) })] }), _jsxs(motion.div, { initial: false, animate: {
|
|
239
254
|
opacity: hasMounted ? 1 : 0,
|
|
240
255
|
y: hasMounted ? 0 : 20,
|
|
241
256
|
filter: hasMounted ? "blur(0px)" : "blur(10px)",
|
|
242
|
-
}, transition: { duration: 0.3, delay: 0.2, ease: "easeInOut" }, className: "bg-b3-react-background w-full p-6", children: [_jsx("div", { className: "mb-2", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("p", { className: "text-as-primary/70 text-sm font-medium", children: "I want to stake" }), _jsxs("span", { className: "text-as-primary/50 flex items-center gap-1 text-sm", children: ["Available: ", isBalanceLoading ? _jsx(Loader2, { className: "h-3 w-3 animate-spin" }) : `${b3Balance} B3`] })] }) }), _jsxs("div", { className: "relative", children: [_jsx(Input, { onFocus: onFocusStakeAmountInput, type: "text", placeholder: "0.00", value: displayAmount, onChange: e => validateAndSetAmount(e.target.value), className: `h-14 px-4 text-lg ${!isAmountValid && displayAmount ? "border-as-red" : "border-b3-react-border"}` }), _jsx("div", { className: "font-pack absolute right-4 top-1/2 -translate-y-1/2 text-lg font-medium text-blue-500/70", children: "B3" })] }), !isAmountValid && displayAmount && _jsx("p", { className: "text-as-red mt-2 text-sm", children: validationError }), _jsx("div", { className: "mt-4", children: (() => {
|
|
243
|
-
|
|
244
|
-
|
|
257
|
+
}, transition: { duration: 0.3, delay: 0.2, ease: "easeInOut" }, className: "bg-b3-react-background w-full p-6", children: [_jsx("div", { className: "mb-2", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("p", { className: "text-as-primary/70 text-sm font-medium", children: "I want to stake" }), _jsxs("span", { className: "text-as-primary/50 flex items-center gap-1 text-sm", children: ["Available:", " ", isBalanceLoading ? (_jsx(Loader2, { className: "h-3 w-3 animate-spin" })) : isBalanceUnknown ? ("unavailable") : (`${b3Balance} B3`)] })] }) }), _jsxs("div", { className: "relative", children: [_jsx(Input, { onFocus: onFocusStakeAmountInput, type: "text", placeholder: "0.00", value: displayAmount, onChange: e => validateAndSetAmount(e.target.value), className: `h-14 px-4 text-lg ${!isAmountValid && displayAmount ? "border-as-red" : "border-b3-react-border"}` }), _jsx("div", { className: "font-pack absolute right-4 top-1/2 -translate-y-1/2 text-lg font-medium text-blue-500/70", children: "B3" })] }), !isAmountValid && displayAmount && _jsx("p", { className: "text-as-red mt-2 text-sm", children: validationError }), _jsx("div", { className: "mt-4", children: (() => {
|
|
258
|
+
// An unreadable balance is not a shortfall, so it must not open the swap upsell —
|
|
259
|
+
// that would sell a swap to someone who may already hold the tokens.
|
|
260
|
+
if (isBalanceUnknown) {
|
|
261
|
+
return (_jsxs("div", { className: "bg-as-brand/10 flex flex-col items-center gap-2 rounded-lg p-4 pb-5", children: [_jsx("p", { className: "text-as-primary/70 text-sm font-medium", children: "We couldn't read your B3 balance just now." }), _jsx(Button, { variant: "ghost", onClick: () => refetchBalance(), className: "text-as-primary text-sm", children: "Try again" })] }));
|
|
262
|
+
}
|
|
263
|
+
if (!hasEnoughB3(debouncedUserStakeAmount) || !debouncedAmount) {
|
|
245
264
|
return (_jsxs("div", { className: "bg-as-brand/10 flex flex-col items-center gap-2 rounded-lg p-4 pb-5", children: [_jsxs("div", { className: "flex items-center justify-center gap-2", children: [_jsx("span", { className: "text-as-primary text-sm font-semibold", children: "Swap & stake from any token" }), _jsxs(TextLoop, { children: [_jsx(EthIcon, { className: "h-8 w-8" }), _jsx(SolIcon, { className: "h-8 w-8" }), _jsx(UsdcIcon, { className: "h-8 w-8" })] }), _jsx(ArrowRight, { className: "text-as-primary h-4 w-4" }), _jsx("img", { src: "https://cdn.b3.fun/b3-coin-3d.png", className: "h-7 w-7", alt: "B3 Token" })] }), _jsx("p", { className: "text-as-primary/50 text-sm font-medium", children: debouncedAmount
|
|
246
265
|
? `No problem, we'll help you swap to ${debouncedAmount} B3!`
|
|
247
266
|
: "Not enough B3? We'll help you swap from other coins." })] }));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { ABI_ERC20_STAKING, B3_TOKEN, eqci, getExplorerTxUrl } from "../../../anyspend/index.js";
|
|
3
3
|
import { normalizeAddress } from "../../../anyspend/utils/index.js";
|
|
4
|
-
import { Button, GlareCardRounded, Input, StyleRoot, TextLoop, toast, useHasMounted, useModalStore,
|
|
4
|
+
import { Button, GlareCardRounded, Input, StyleRoot, TextLoop, toast, useHasMounted, useModalStore, usePortfolioBalance, useUnifiedChainSwitchAndExecute, } from "../../../global-account/react/index.js";
|
|
5
5
|
import { PUBLIC_BASE_RPC_URL } from "../../../shared/constants/index.js";
|
|
6
6
|
import { formatTokenAmount } from "../../../shared/utils/number.js";
|
|
7
7
|
import { ArrowRight, Loader2 } from "lucide-react";
|
|
@@ -37,11 +37,25 @@ export function AnySpendStakeB3ExactIn({ loadOrder, mode = "modal", sourceTokenA
|
|
|
37
37
|
// Wagmi hooks for direct staking
|
|
38
38
|
const { address } = useAccount();
|
|
39
39
|
const { switchChainAndExecute, isSwitchingOrExecuting } = useUnifiedChainSwitchAndExecute();
|
|
40
|
-
// Fetch B3 token balance
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
// Fetch B3 token balance. `isBalanceUnknown` must gate every use of `b3RawBalance`: a failed read
|
|
41
|
+
// yields the same 0 as an empty wallet, and acting on it pushes a holder into the swap flow to
|
|
42
|
+
// buy a token they already have.
|
|
43
|
+
const { data: balances, isLoading: isBalanceLoading, isError: isBalanceError, refetch: refetchBalance, } = usePortfolioBalance(address, [base.id]);
|
|
44
|
+
// Guarded on `address`: with no wallet connected the query never runs, and a query that was
|
|
45
|
+
// never asked is not a query that failed. Without this the screen tells a visitor their
|
|
46
|
+
// balance is unavailable and refuses to continue, when they simply have not connected yet.
|
|
47
|
+
const isBalanceUnknown = Boolean(address) && (isBalanceError || (!isBalanceLoading && balances === undefined));
|
|
48
|
+
const b3RawBalanceStr = balances?.find(b => eqci(b.address, B3_TOKEN.address))?.amount || "0";
|
|
43
49
|
const b3RawBalance = BigInt(b3RawBalanceStr);
|
|
44
50
|
const b3Balance = formatTokenAmount(b3RawBalance, B3_TOKEN.decimals);
|
|
51
|
+
/**
|
|
52
|
+
* Whether the wallet demonstrably holds enough B3 to stake `amountRaw` directly.
|
|
53
|
+
*
|
|
54
|
+
* False while the balance is unknown — but callers must not read that as a shortfall. An unknown
|
|
55
|
+
* balance is neither enough nor short, and the two need different UI: a shortfall offers the swap
|
|
56
|
+
* flow, an unknown offers a retry. Check `isBalanceUnknown` first.
|
|
57
|
+
*/
|
|
58
|
+
const hasEnoughB3 = (amountRaw) => !isBalanceUnknown && BigInt(amountRaw || "0") <= b3RawBalance;
|
|
45
59
|
// State for direct staking flow
|
|
46
60
|
const [isStaking, setIsStaking] = useState(false);
|
|
47
61
|
const [stakingTxHash, setStakingTxHash] = useState("");
|
|
@@ -212,8 +226,11 @@ export function AnySpendStakeB3ExactIn({ loadOrder, mode = "modal", sourceTokenA
|
|
|
212
226
|
return;
|
|
213
227
|
}
|
|
214
228
|
// Check if user has sufficient B3 balance for direct staking
|
|
215
|
-
|
|
216
|
-
|
|
229
|
+
if (isBalanceUnknown) {
|
|
230
|
+
toast.error("Can't read your B3 balance right now. Please try again.");
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
if (hasEnoughB3(userStakeAmount)) {
|
|
217
234
|
// User has enough B3, proceed with direct staking
|
|
218
235
|
handleDirectStaking();
|
|
219
236
|
}
|
|
@@ -246,15 +263,20 @@ export function AnySpendStakeB3ExactIn({ loadOrder, mode = "modal", sourceTokenA
|
|
|
246
263
|
y: hasMounted ? 0 : 20,
|
|
247
264
|
filter: hasMounted ? "blur(0px)" : "blur(10px)",
|
|
248
265
|
}, transition: { duration: 0.3, delay: 0.1, ease: "easeInOut" }, children: _jsx("h2", { className: "font-sf-rounded font-neue-montreal-medium mb-1 text-center text-2xl font-semibold", children: (() => {
|
|
249
|
-
|
|
250
|
-
|
|
266
|
+
return isBalanceUnknown || !debouncedAmount || hasEnoughB3(debouncedUserStakeAmount)
|
|
267
|
+
? "Stake B3"
|
|
268
|
+
: "Swap & Stake B3";
|
|
251
269
|
})() }) })] }), _jsxs(motion.div, { initial: false, animate: {
|
|
252
270
|
opacity: hasMounted ? 1 : 0,
|
|
253
271
|
y: hasMounted ? 0 : 20,
|
|
254
272
|
filter: hasMounted ? "blur(0px)" : "blur(10px)",
|
|
255
|
-
}, transition: { duration: 0.3, delay: 0.2, ease: "easeInOut" }, className: "bg-b3-react-background w-full p-6", children: [_jsx("div", { className: "mb-2", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("p", { className: "text-as-primary/70 text-sm font-medium", children: "I want to stake" }), _jsxs("span", { className: "text-as-primary/50 flex items-center gap-1 text-sm", children: ["Available: ", isBalanceLoading ? _jsx(Loader2, { className: "h-3 w-3 animate-spin" }) : `${b3Balance} B3`] })] }) }), _jsxs("div", { className: "relative", children: [_jsx(Input, { onFocus: onFocusStakeAmountInput, type: "text", placeholder: "0.00", value: displayAmount, onChange: e => validateAndSetAmount(e.target.value), className: `h-14 px-4 text-lg ${!isAmountValid && displayAmount ? "border-as-red" : "border-b3-react-border"}` }), _jsx("div", { className: "font-pack absolute right-4 top-1/2 -translate-y-1/2 text-lg font-medium text-blue-500/70", children: "B3" })] }), !isAmountValid && displayAmount && _jsx("p", { className: "text-as-red mt-2 text-sm", children: validationError }), _jsx("div", { className: "mt-4", children: (() => {
|
|
256
|
-
|
|
257
|
-
|
|
273
|
+
}, transition: { duration: 0.3, delay: 0.2, ease: "easeInOut" }, className: "bg-b3-react-background w-full p-6", children: [_jsx("div", { className: "mb-2", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("p", { className: "text-as-primary/70 text-sm font-medium", children: "I want to stake" }), _jsxs("span", { className: "text-as-primary/50 flex items-center gap-1 text-sm", children: ["Available:", " ", isBalanceLoading ? (_jsx(Loader2, { className: "h-3 w-3 animate-spin" })) : isBalanceUnknown ? ("unavailable") : (`${b3Balance} B3`)] })] }) }), _jsxs("div", { className: "relative", children: [_jsx(Input, { onFocus: onFocusStakeAmountInput, type: "text", placeholder: "0.00", value: displayAmount, onChange: e => validateAndSetAmount(e.target.value), className: `h-14 px-4 text-lg ${!isAmountValid && displayAmount ? "border-as-red" : "border-b3-react-border"}` }), _jsx("div", { className: "font-pack absolute right-4 top-1/2 -translate-y-1/2 text-lg font-medium text-blue-500/70", children: "B3" })] }), !isAmountValid && displayAmount && _jsx("p", { className: "text-as-red mt-2 text-sm", children: validationError }), _jsx("div", { className: "mt-4", children: (() => {
|
|
274
|
+
// An unreadable balance is not a shortfall, so it must not open the swap upsell —
|
|
275
|
+
// that would sell a swap to someone who may already hold the tokens.
|
|
276
|
+
if (isBalanceUnknown) {
|
|
277
|
+
return (_jsxs("div", { className: "bg-as-brand/10 flex flex-col items-center gap-2 rounded-lg p-4 pb-5", children: [_jsx("p", { className: "text-as-primary/70 text-sm font-medium", children: "We couldn't read your B3 balance just now." }), _jsx(Button, { variant: "ghost", onClick: () => refetchBalance(), className: "text-as-primary text-sm", children: "Try again" })] }));
|
|
278
|
+
}
|
|
279
|
+
if (!hasEnoughB3(debouncedUserStakeAmount) || !debouncedAmount) {
|
|
258
280
|
return (_jsxs("div", { className: "bg-as-brand/10 flex flex-col items-center gap-2 rounded-lg p-4 pb-5", children: [_jsxs("div", { className: "flex items-center justify-center gap-2", children: [_jsx("span", { className: "text-as-primary text-sm font-semibold", children: "Swap & stake from any token" }), _jsxs(TextLoop, { children: [_jsx(EthIcon, { className: "h-8 w-8" }), _jsx(SolIcon, { className: "h-8 w-8" }), _jsx(UsdcIcon, { className: "h-8 w-8" })] }), _jsx(ArrowRight, { className: "text-as-primary h-4 w-4" }), _jsx("img", { src: "https://cdn.b3.fun/b3-coin-3d.png", className: "h-7 w-7", alt: "B3 Token" })] }), _jsx("p", { className: "text-as-primary/50 text-sm font-medium", children: debouncedAmount
|
|
259
281
|
? `No problem, we'll help you swap to ${debouncedAmount} B3!`
|
|
260
282
|
: "Not enough B3? We'll help you swap from other coins." })] }));
|
|
@@ -6,9 +6,9 @@ import { useAnyspendOrderAndTransactions } from "../../../../anyspend/react/hook
|
|
|
6
6
|
import { useCreateDepositFirstOrder } from "../../../../anyspend/react/hooks/useCreateDepositFirstOrder.js";
|
|
7
7
|
import { useOnOrderSuccess } from "../../../../anyspend/react/hooks/useOnOrderSuccess.js";
|
|
8
8
|
import { ALL_CHAINS, RELAY_SOLANA_MAINNET_CHAIN_ID, getAvailableChainIds } from "../../../../anyspend/index.js";
|
|
9
|
-
import { getPaymentUrl } from "../../../../anyspend/utils/chain.js";
|
|
9
|
+
import { getPaymentUrl, toRegistryChainId } from "../../../../anyspend/utils/chain.js";
|
|
10
10
|
import { isNativeToken } from "../../../../anyspend/utils/token.js";
|
|
11
|
-
import { useAccountWallet, useIsMobile,
|
|
11
|
+
import { useAccountWallet, useIsMobile, usePortfolioTokenBalance, useTokenData, useUnifiedChainSwitchAndExecute, } from "../../../../global-account/react/index.js";
|
|
12
12
|
import { ShinyButton, TextShimmer } from "../../../../global-account/react/index.js";
|
|
13
13
|
import { formatTokenAmount } from "../../../../shared/utils/number.js";
|
|
14
14
|
import { cn } from "../../../../shared/utils/cn.js";
|
|
@@ -68,13 +68,17 @@ export function CryptoPayPanel({ recipientAddress, destinationTokenAddress, dest
|
|
|
68
68
|
? "native"
|
|
69
69
|
: selectedSrcToken.address
|
|
70
70
|
: undefined;
|
|
71
|
-
|
|
71
|
+
// `selectedSrcChainId` is Relay-numbered; balance rows are keyed by the chain registry's id.
|
|
72
|
+
const { data: balanceRow, isError: isBalanceError } = usePortfolioTokenBalance(effectiveAddress, tokenAddress, toRegistryChainId(selectedSrcChainId));
|
|
72
73
|
const balance = useMemo(() => {
|
|
73
|
-
|
|
74
|
-
if (!b?.amount)
|
|
74
|
+
if (!balanceRow?.amount)
|
|
75
75
|
return { raw: BigInt(0), formatted: "0", decimals: 18 };
|
|
76
|
-
return {
|
|
77
|
-
|
|
76
|
+
return {
|
|
77
|
+
raw: BigInt(balanceRow.amount),
|
|
78
|
+
formatted: formatTokenAmount(BigInt(balanceRow.amount), balanceRow.decimals),
|
|
79
|
+
decimals: balanceRow.decimals,
|
|
80
|
+
};
|
|
81
|
+
}, [balanceRow]);
|
|
78
82
|
const srcAmount = useMemo(() => {
|
|
79
83
|
if (isSameToken)
|
|
80
84
|
return totalAmount;
|
|
@@ -85,7 +89,9 @@ export function CryptoPayPanel({ recipientAddress, destinationTokenAddress, dest
|
|
|
85
89
|
return "0";
|
|
86
90
|
return formatTokenAmount(BigInt(srcAmount || "0"), selectedSrcToken.decimals || 18);
|
|
87
91
|
}, [srcAmount, selectedSrcToken]);
|
|
88
|
-
|
|
92
|
+
// A failed balance read must not masquerade as a shortfall: it would disable Pay and tell a
|
|
93
|
+
// funded user they are short. Unknown blocks auto-pay but leaves the manual path open.
|
|
94
|
+
const hasEnoughBalance = !isBalanceError && balance.raw >= BigInt(srcAmount || "0");
|
|
89
95
|
/* ------------------------------------------------------------------ */
|
|
90
96
|
/* Destination token object (shared by both flows) */
|
|
91
97
|
/* ------------------------------------------------------------------ */
|
|
@@ -314,7 +320,7 @@ export function CryptoPayPanel({ recipientAddress, destinationTokenAddress, dest
|
|
|
314
320
|
}, [shouldAutoPay, connectedAddress, selectedSrcToken, hasEnoughBalance, isLoadingAnyspendQuote, handleWalletPay]);
|
|
315
321
|
const isLoading = isLoadingAnyspendQuote;
|
|
316
322
|
const isPending = isCreatingSwapOrder || isSendingDeposit || isWaitingForExecution;
|
|
317
|
-
const canPay = connectedAddress && selectedSrcToken && hasEnoughBalance && !isLoading && !isPending;
|
|
323
|
+
const canPay = connectedAddress && selectedSrcToken && (hasEnoughBalance || isBalanceError) && !isLoading && !isPending;
|
|
318
324
|
const chainName = ALL_CHAINS[selectedSrcChainId]?.name || "the specified chain";
|
|
319
325
|
const chainLogoUrl = ALL_CHAINS[selectedSrcChainId]?.logoUrl;
|
|
320
326
|
// Collapse QR on mobile when a wallet connector is available
|
|
@@ -333,7 +339,9 @@ export function CryptoPayPanel({ recipientAddress, destinationTokenAddress, dest
|
|
|
333
339
|
name: token.name,
|
|
334
340
|
symbol: token.symbol,
|
|
335
341
|
});
|
|
336
|
-
}, supportedWalletVMs: ["evm", "svm"], token: undefined, trigger: _jsxs("button", { className: cn("flex w-full items-center justify-between rounded-xl border border-gray-200 bg-white px-4 py-3 transition-colors hover:border-gray-300 dark:border-neutral-700 dark:bg-neutral-800 dark:hover:border-neutral-600", classes?.tokenSelector), children: [selectedSrcToken ? (_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(ChainTokenIcon, { chainUrl: ALL_CHAINS[selectedSrcToken.chainId]?.logoUrl || "", tokenUrl: selectedSrcToken.metadata?.logoURI, className: "h-8 w-8" }), _jsxs("div", { className: "text-left", children: [_jsx("p", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: selectedSrcToken.symbol }), _jsxs("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: ["Balance: ", balance.formatted] })] })] })) : (_jsx("span", { className: "text-sm text-gray-400", children: "Select token" })), _jsx(ChevronsUpDown, { className: "h-4 w-4 text-gray-400" })] }) })] }), _jsx(motion.div, { initial: { opacity: 0, y: 6 }, animate: { opacity: 1, y: 0 }, transition: { duration: 0.25, ease: "easeOut" }, className: cn("rounded-xl border border-gray-200 bg-gray-50 px-4 py-3 dark:border-neutral-700 dark:bg-neutral-800/50", classes?.quoteDisplay), children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-sm text-gray-500 dark:text-gray-400", children: "You pay" }), _jsx(AnimatePresence, { mode: "wait", children: isLoadingAnyspendQuote ? (_jsx(motion.div, { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, transition: { duration: 0.15 }, children: _jsx(TextShimmer, { duration: 1, className: "text-sm", children: "Fetching quote..." }) }, "quote-loading")) : (_jsxs(motion.span, { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, transition: { duration: 0.15 }, className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: [srcAmountFormatted, " ", selectedSrcToken?.symbol || ""] }, "quote-amount")) })] }) }), _jsx(AnimatePresence, { children: connectedAddress && selectedSrcToken && !hasEnoughBalance && !isLoading && (
|
|
342
|
+
}, supportedWalletVMs: ["evm", "svm"], token: undefined, trigger: _jsxs("button", { className: cn("flex w-full items-center justify-between rounded-xl border border-gray-200 bg-white px-4 py-3 transition-colors hover:border-gray-300 dark:border-neutral-700 dark:bg-neutral-800 dark:hover:border-neutral-600", classes?.tokenSelector), children: [selectedSrcToken ? (_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(ChainTokenIcon, { chainUrl: ALL_CHAINS[selectedSrcToken.chainId]?.logoUrl || "", tokenUrl: selectedSrcToken.metadata?.logoURI, className: "h-8 w-8" }), _jsxs("div", { className: "text-left", children: [_jsx("p", { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: selectedSrcToken.symbol }), _jsxs("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: ["Balance: ", balance.formatted] })] })] })) : (_jsx("span", { className: "text-sm text-gray-400", children: "Select token" })), _jsx(ChevronsUpDown, { className: "h-4 w-4 text-gray-400" })] }) })] }), _jsx(motion.div, { initial: { opacity: 0, y: 6 }, animate: { opacity: 1, y: 0 }, transition: { duration: 0.25, ease: "easeOut" }, className: cn("rounded-xl border border-gray-200 bg-gray-50 px-4 py-3 dark:border-neutral-700 dark:bg-neutral-800/50", classes?.quoteDisplay), children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-sm text-gray-500 dark:text-gray-400", children: "You pay" }), _jsx(AnimatePresence, { mode: "wait", children: isLoadingAnyspendQuote ? (_jsx(motion.div, { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, transition: { duration: 0.15 }, children: _jsx(TextShimmer, { duration: 1, className: "text-sm", children: "Fetching quote..." }) }, "quote-loading")) : (_jsxs(motion.span, { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, transition: { duration: 0.15 }, className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: [srcAmountFormatted, " ", selectedSrcToken?.symbol || ""] }, "quote-amount")) })] }) }), _jsx(AnimatePresence, { children: connectedAddress && selectedSrcToken && !hasEnoughBalance && !isLoading && (_jsx(motion.p, { initial: { opacity: 0, height: 0 }, animate: { opacity: 1, height: "auto" }, exit: { opacity: 0, height: 0 }, transition: { duration: 0.2, ease: "easeOut" }, className: `text-center text-sm ${isBalanceError ? "text-as-primary/50" : "text-red-500"}`, children: isBalanceError
|
|
343
|
+
? `Couldn't check your ${selectedSrcToken.symbol} balance`
|
|
344
|
+
: `Insufficient ${selectedSrcToken.symbol} balance` }, "balance-warning")) }), !connectedAddress ? (_jsx(ShinyButton, { accentColor: themeColor || "hsl(var(--as-brand))", onClick: handleConnectWallet, className: cn("w-full", classes?.payButton), textClassName: "text-white", children: "Connect Wallet to Pay" })) : (_jsx(ShinyButton, { accentColor: themeColor || "hsl(var(--as-brand))", onClick: handleWalletPay, disabled: !canPay, className: cn("w-full", classes?.payButton), textClassName: cn(!canPay ? "text-as-secondary" : "text-white"), children: isPending ? (_jsxs("span", { className: "flex items-center justify-center gap-2", children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin" }), isCreatingSwapOrder
|
|
337
345
|
? "Creating order..."
|
|
338
346
|
: isSendingDeposit
|
|
339
347
|
? "Confirm in wallet..."
|