@b3dotfun/sdk 0.1.70-alpha.18 → 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/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/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/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/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/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,212 @@
|
|
|
1
|
+
import type { NFT, SimpleHashNFTResponse } from "@b3dotfun/sdk/global-account/types/simplehash.types";
|
|
2
|
+
import { zerionSlugToChainId } from "@b3dotfun/sdk/shared/utils/zerionPositions";
|
|
3
|
+
import { useQuery } from "@tanstack/react-query";
|
|
4
|
+
|
|
5
|
+
const PORTFOLIO_API_BASE_URL = "https://portfolio-api.b3.fun";
|
|
6
|
+
|
|
7
|
+
interface ZerionNftPosition {
|
|
8
|
+
id?: string;
|
|
9
|
+
attributes?: {
|
|
10
|
+
amount?: string;
|
|
11
|
+
changed_at?: string;
|
|
12
|
+
nft_info?: {
|
|
13
|
+
contract_address?: string;
|
|
14
|
+
token_id?: string;
|
|
15
|
+
name?: string;
|
|
16
|
+
interface?: string;
|
|
17
|
+
content?: { preview?: { url?: string }; detail?: { url?: string } };
|
|
18
|
+
flags?: { is_spam?: boolean };
|
|
19
|
+
};
|
|
20
|
+
collection_info?: {
|
|
21
|
+
name?: string;
|
|
22
|
+
description?: string;
|
|
23
|
+
content?: { icon?: { url?: string } };
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
relationships?: { chain?: { data?: { id?: string } } };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface ZerionNftPositionsResponse {
|
|
30
|
+
data?: ZerionNftPosition[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Caps an ERC-1155 balance string at MAX_SAFE_INTEGER so a huge supply cannot overflow. */
|
|
34
|
+
function safeParseBalance(balance: string | undefined): number {
|
|
35
|
+
if (!balance) return 1;
|
|
36
|
+
const parsed = parseInt(balance, 10);
|
|
37
|
+
if (Number.isNaN(parsed)) return 1;
|
|
38
|
+
return Math.min(parsed, Number.MAX_SAFE_INTEGER);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Reshape one Zerion NFT position into the SimpleHash record `AccountAssets` renders.
|
|
43
|
+
*
|
|
44
|
+
* Fields Zerion does not carry — traits, rarity, royalties, sale history — stay empty rather than
|
|
45
|
+
* being synthesised from something adjacent. In particular the position's `price` is a current
|
|
46
|
+
* estimate, not a sale, so it must not be written into `last_sale`.
|
|
47
|
+
*/
|
|
48
|
+
function toSimpleHashNft(position: ZerionNftPosition, ownerAddress: string): NFT | null {
|
|
49
|
+
const attributes = position.attributes ?? {};
|
|
50
|
+
const nftInfo = attributes.nft_info;
|
|
51
|
+
const slug = position.relationships?.chain?.data?.id;
|
|
52
|
+
if (!nftInfo?.contract_address || !nftInfo.token_id || !slug) return null;
|
|
53
|
+
|
|
54
|
+
const imageUrl = nftInfo.content?.detail?.url ?? nftInfo.content?.preview?.url ?? "";
|
|
55
|
+
const collectionInfo = attributes.collection_info ?? {};
|
|
56
|
+
const acquiredAt = attributes.changed_at ?? "";
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
nft_id: `${slug}.${nftInfo.contract_address}.${nftInfo.token_id}`,
|
|
60
|
+
chain: slug,
|
|
61
|
+
contract_address: nftInfo.contract_address,
|
|
62
|
+
token_id: nftInfo.token_id,
|
|
63
|
+
name: nftInfo.name || "",
|
|
64
|
+
description: collectionInfo.description || "",
|
|
65
|
+
previews: {
|
|
66
|
+
image_small_url: nftInfo.content?.preview?.url ?? imageUrl,
|
|
67
|
+
image_medium_url: imageUrl,
|
|
68
|
+
image_large_url: imageUrl,
|
|
69
|
+
image_opengraph_url: imageUrl,
|
|
70
|
+
blurhash: "",
|
|
71
|
+
predominant_color: "",
|
|
72
|
+
},
|
|
73
|
+
image_url: imageUrl,
|
|
74
|
+
image_properties: { width: 0, height: 0, size: 0, mime_type: "", exif_orientation: null },
|
|
75
|
+
video_url: null,
|
|
76
|
+
video_properties: null,
|
|
77
|
+
audio_url: null,
|
|
78
|
+
audio_properties: null,
|
|
79
|
+
model_url: null,
|
|
80
|
+
model_properties: null,
|
|
81
|
+
other_url: null,
|
|
82
|
+
other_properties: null,
|
|
83
|
+
background_color: null,
|
|
84
|
+
external_url: null,
|
|
85
|
+
created_date: "",
|
|
86
|
+
status: "minted",
|
|
87
|
+
token_count: 1,
|
|
88
|
+
owner_count: 1,
|
|
89
|
+
owners: [
|
|
90
|
+
{
|
|
91
|
+
owner_address: ownerAddress,
|
|
92
|
+
quantity: safeParseBalance(attributes.amount),
|
|
93
|
+
quantity_string: attributes.amount || "1",
|
|
94
|
+
first_acquired_date: acquiredAt,
|
|
95
|
+
last_acquired_date: acquiredAt,
|
|
96
|
+
},
|
|
97
|
+
],
|
|
98
|
+
contract: {
|
|
99
|
+
type: nftInfo.interface === "ERC1155" ? "ERC1155" : "ERC721",
|
|
100
|
+
name: collectionInfo.name || "",
|
|
101
|
+
symbol: null,
|
|
102
|
+
deployed_by: "",
|
|
103
|
+
deployed_via_contract: "",
|
|
104
|
+
owned_by: "",
|
|
105
|
+
has_multiple_collections: false,
|
|
106
|
+
},
|
|
107
|
+
collection: {
|
|
108
|
+
collection_id: nftInfo.contract_address,
|
|
109
|
+
name: collectionInfo.name || "Unknown Collection",
|
|
110
|
+
description: collectionInfo.description ?? null,
|
|
111
|
+
image_url: collectionInfo.content?.icon?.url ?? "",
|
|
112
|
+
image_properties: { width: 0, height: 0, mime_type: "" },
|
|
113
|
+
banner_image_url: null,
|
|
114
|
+
category: null,
|
|
115
|
+
is_nsfw: null,
|
|
116
|
+
external_url: null,
|
|
117
|
+
twitter_username: null,
|
|
118
|
+
discord_url: null,
|
|
119
|
+
instagram_username: null,
|
|
120
|
+
medium_username: null,
|
|
121
|
+
telegram_url: null,
|
|
122
|
+
marketplace_pages: [],
|
|
123
|
+
metaplex_mint: null,
|
|
124
|
+
metaplex_candy_machine: null,
|
|
125
|
+
metaplex_first_verified_creator: null,
|
|
126
|
+
floor_prices: [],
|
|
127
|
+
top_bids: [],
|
|
128
|
+
distinct_owner_count: 0,
|
|
129
|
+
distinct_nft_count: 0,
|
|
130
|
+
total_quantity: 0,
|
|
131
|
+
chains: [slug],
|
|
132
|
+
top_contracts: [nftInfo.contract_address],
|
|
133
|
+
collection_royalties: [],
|
|
134
|
+
},
|
|
135
|
+
last_sale: null,
|
|
136
|
+
primary_sale: null,
|
|
137
|
+
first_created: {
|
|
138
|
+
minted_to: ownerAddress,
|
|
139
|
+
quantity: 1,
|
|
140
|
+
quantity_string: "1",
|
|
141
|
+
timestamp: "",
|
|
142
|
+
block_number: 0,
|
|
143
|
+
transaction: "",
|
|
144
|
+
transaction_initiator: "",
|
|
145
|
+
},
|
|
146
|
+
rarity: { rank: null, score: null, unique_attributes: null },
|
|
147
|
+
royalty: [],
|
|
148
|
+
extra_metadata: {
|
|
149
|
+
attributes: [],
|
|
150
|
+
image_original_url: imageUrl,
|
|
151
|
+
animation_original_url: null,
|
|
152
|
+
metadata_original_url: "",
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* NFTs held by a wallet, in the SimpleHash shape `AccountAssets` already renders.
|
|
159
|
+
*
|
|
160
|
+
* Chain narrowing happens here rather than in the request: the upstream rejects some valid chain
|
|
161
|
+
* slugs outright and fails the whole request when one is present, so asking for a subset can cost
|
|
162
|
+
* you the whole answer.
|
|
163
|
+
*/
|
|
164
|
+
export function usePortfolioCollectibles(
|
|
165
|
+
address?: string,
|
|
166
|
+
chainIds?: number[],
|
|
167
|
+
options?: { limit?: number; filterSpam?: boolean },
|
|
168
|
+
) {
|
|
169
|
+
const limit = options?.limit;
|
|
170
|
+
const filterSpam = options?.filterSpam;
|
|
171
|
+
const wantedChainIds = chainIds && chainIds.length > 0 ? chainIds : undefined;
|
|
172
|
+
|
|
173
|
+
return useQuery({
|
|
174
|
+
queryKey: ["walletCollectibles", address, limit, filterSpam],
|
|
175
|
+
queryFn: async (): Promise<SimpleHashNFTResponse> => {
|
|
176
|
+
if (!address) throw new Error("Address is required");
|
|
177
|
+
|
|
178
|
+
const params = new URLSearchParams();
|
|
179
|
+
if (limit) params.set("page[size]", String(limit));
|
|
180
|
+
const query = params.toString();
|
|
181
|
+
const url = `${PORTFOLIO_API_BASE_URL}/v1/wallets/${encodeURIComponent(address)}/nft-positions/${query ? `?${query}` : ""}`;
|
|
182
|
+
|
|
183
|
+
const response = await fetch(url, { headers: { Accept: "application/json" } });
|
|
184
|
+
if (!response.ok) {
|
|
185
|
+
throw new Error(`Failed to fetch collectibles: ${response.status} ${response.statusText}`);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const body = (await response.json()) as ZerionNftPositionsResponse;
|
|
189
|
+
// Spam is dropped here, not in `select`: the flag lives on the raw position and the
|
|
190
|
+
// SimpleHash shape has nowhere to carry it downstream.
|
|
191
|
+
const nfts = (body.data ?? [])
|
|
192
|
+
.filter(position => !(filterSpam && position.attributes?.nft_info?.flags?.is_spam === true))
|
|
193
|
+
.map(position => toSimpleHashNft(position, address))
|
|
194
|
+
.filter((nft): nft is NFT => nft !== null);
|
|
195
|
+
|
|
196
|
+
return { next_cursor: null, next: null, previous: null, nfts };
|
|
197
|
+
},
|
|
198
|
+
enabled: Boolean(address),
|
|
199
|
+
staleTime: 30 * 1000,
|
|
200
|
+
gcTime: 5 * 60 * 1000,
|
|
201
|
+
select: (data: SimpleHashNFTResponse) => {
|
|
202
|
+
if (!wantedChainIds) return data;
|
|
203
|
+
|
|
204
|
+
const all = data.nfts ?? [];
|
|
205
|
+
const nfts = all.filter(nft => {
|
|
206
|
+
const chainId = zerionSlugToChainId(nft.chain);
|
|
207
|
+
return chainId !== undefined && wantedChainIds.includes(chainId);
|
|
208
|
+
});
|
|
209
|
+
return nfts.length === all.length ? data : { ...data, nfts };
|
|
210
|
+
},
|
|
211
|
+
});
|
|
212
|
+
}
|
|
@@ -675,8 +675,6 @@ export interface AnySpendDepositModalProps extends BaseModalProps {
|
|
|
675
675
|
showChainSelection?: boolean;
|
|
676
676
|
/** Whether to show the "Fund with Fiat" option in the deposit options list. Defaults to true */
|
|
677
677
|
showFiatOption?: boolean;
|
|
678
|
-
/** Minimum pool size for filtering tokens (default: 1,000,000) */
|
|
679
|
-
minPoolSize?: number;
|
|
680
678
|
/** Custom title for chain selection step */
|
|
681
679
|
chainSelectionTitle?: string;
|
|
682
680
|
/** Custom description for chain selection step */
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { Wallet } from "thirdweb/wallets";
|
|
2
|
+
|
|
1
3
|
export * from "./currency";
|
|
2
4
|
|
|
3
5
|
export const siteURL = "https://basement.fun";
|
|
@@ -8,6 +10,12 @@ export const ecosystemWalletId = (process.env.NEXT_PUBLIC_THIRDWEB_ECOSYSTEM_ID
|
|
|
8
10
|
process.env.EXPO_PUBLIC_THIRDWEB_ECOSYSTEM_ID ||
|
|
9
11
|
"ecosystem.b3-open-gaming") as `ecosystem.${string}`; // Fallback to prod key lookup
|
|
10
12
|
|
|
13
|
+
// Portable equivalent of thirdweb's `EcosystemWallet`, which thirdweb does not export
|
|
14
|
+
// from any public entry point — declaration emit cannot name the internal type (TS2742).
|
|
15
|
+
export type EcosystemWallet = Wallet<`ecosystem.${string}`> & {
|
|
16
|
+
getAuthToken: () => string | null;
|
|
17
|
+
};
|
|
18
|
+
|
|
11
19
|
export const tokenIcons = {
|
|
12
20
|
ETH: "https://cdn.b3.fun/ethereum.svg",
|
|
13
21
|
WETH: "https://cdn.b3.fun/wrapped-ethereum.svg",
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
adaptZerionPositions,
|
|
4
|
+
chainIdToZerionSlug,
|
|
5
|
+
EVM_NATIVE_TOKEN_ADDRESS,
|
|
6
|
+
zerionSlugToChainId,
|
|
7
|
+
type ZerionPositionLike,
|
|
8
|
+
} from "../zerionPositions";
|
|
9
|
+
|
|
10
|
+
// Slugs and ids below are shaped after live Zerion responses.
|
|
11
|
+
const SLUG_TO_CHAIN_ID: Record<string, number> = {
|
|
12
|
+
ethereum: 1,
|
|
13
|
+
base: 8453,
|
|
14
|
+
polygon: 137,
|
|
15
|
+
celo: 42220,
|
|
16
|
+
hyperevm: 999,
|
|
17
|
+
};
|
|
18
|
+
const slugToChainId = (slug: string) => SLUG_TO_CHAIN_ID[slug];
|
|
19
|
+
|
|
20
|
+
function position(overrides: {
|
|
21
|
+
id: string;
|
|
22
|
+
slug: string;
|
|
23
|
+
symbol: string;
|
|
24
|
+
implAddress?: string | null;
|
|
25
|
+
implDecimals?: number;
|
|
26
|
+
quantityDecimals?: number;
|
|
27
|
+
int?: string;
|
|
28
|
+
}): ZerionPositionLike {
|
|
29
|
+
const { id, slug, symbol, implAddress = null, implDecimals = 18, quantityDecimals = 18, int = "1000" } = overrides;
|
|
30
|
+
return {
|
|
31
|
+
id,
|
|
32
|
+
attributes: {
|
|
33
|
+
quantity: { int, decimals: quantityDecimals },
|
|
34
|
+
fungible_info: {
|
|
35
|
+
symbol,
|
|
36
|
+
implementations: [{ chain_id: slug, address: implAddress, decimals: implDecimals }],
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
relationships: { chain: { data: { id: slug } } },
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
describe("adaptZerionPositions native detection", () => {
|
|
44
|
+
it("treats a null implementation address as the chain's native coin", () => {
|
|
45
|
+
const [row] = adaptZerionPositions(
|
|
46
|
+
[position({ id: "base-base-asset-asset", slug: "base", symbol: "ETH" })],
|
|
47
|
+
slugToChainId,
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
expect(row.is_native).toBe(true);
|
|
51
|
+
expect(row.address).toBe(EVM_NATIVE_TOKEN_ADDRESS);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("treats Polygon's native coin as native despite its system-contract address", () => {
|
|
55
|
+
const [row] = adaptZerionPositions(
|
|
56
|
+
[
|
|
57
|
+
position({
|
|
58
|
+
id: "base-polygon-asset-asset",
|
|
59
|
+
slug: "polygon",
|
|
60
|
+
symbol: "POL",
|
|
61
|
+
implAddress: "0x0000000000000000000000000000000000001010",
|
|
62
|
+
}),
|
|
63
|
+
],
|
|
64
|
+
slugToChainId,
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
expect(row.is_native).toBe(true);
|
|
68
|
+
expect(row.address).toBe(EVM_NATIVE_TOKEN_ADDRESS);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("treats Celo's native coin as native despite its ERC-20 address", () => {
|
|
72
|
+
const [row] = adaptZerionPositions(
|
|
73
|
+
[
|
|
74
|
+
position({
|
|
75
|
+
id: "base-celo-asset-asset",
|
|
76
|
+
slug: "celo",
|
|
77
|
+
symbol: "celo",
|
|
78
|
+
implAddress: "0x471ece3750da237f93b8e339c536989b8978a438",
|
|
79
|
+
}),
|
|
80
|
+
],
|
|
81
|
+
slugToChainId,
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
expect(row.is_native).toBe(true);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("keeps a same-symbol non-native fungible distinct from the native coin", () => {
|
|
88
|
+
const rows = adaptZerionPositions(
|
|
89
|
+
[
|
|
90
|
+
position({
|
|
91
|
+
id: "base-polygon-asset-asset",
|
|
92
|
+
slug: "polygon",
|
|
93
|
+
symbol: "POL",
|
|
94
|
+
implAddress: "0x0000000000000000000000000000000000001010",
|
|
95
|
+
}),
|
|
96
|
+
position({
|
|
97
|
+
id: "0x89299a4c719ebe9fe6018aed81eb1d48b4f78d56-polygon-asset-asset",
|
|
98
|
+
slug: "polygon",
|
|
99
|
+
symbol: "POL",
|
|
100
|
+
implAddress: "0x89299a4c719ebe9fe6018aed81eb1d48b4f78d56",
|
|
101
|
+
}),
|
|
102
|
+
],
|
|
103
|
+
slugToChainId,
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
expect(rows.map(r => r.is_native)).toEqual([true, false]);
|
|
107
|
+
expect(rows[1].address).toBe("0x89299a4c719ebe9fe6018aed81eb1d48b4f78d56");
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
describe("adaptZerionPositions row filtering", () => {
|
|
112
|
+
it("drops a row whose chain is unmapped", () => {
|
|
113
|
+
const rows = adaptZerionPositions(
|
|
114
|
+
[position({ id: "base-unknownchain-asset-asset", slug: "unknownchain", symbol: "???" })],
|
|
115
|
+
slugToChainId,
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
expect(rows).toEqual([]);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("drops a row whose fungible has no implementation on its chain, rather than calling it native", () => {
|
|
122
|
+
const rows = adaptZerionPositions(
|
|
123
|
+
[
|
|
124
|
+
{
|
|
125
|
+
id: "0xabc-ethereum-asset-asset",
|
|
126
|
+
attributes: {
|
|
127
|
+
quantity: { int: "1000", decimals: 18 },
|
|
128
|
+
fungible_info: {
|
|
129
|
+
symbol: "ORPHAN",
|
|
130
|
+
// implementations exist, but none for the position's own chain
|
|
131
|
+
implementations: [{ chain_id: "polygon", address: "0xabc", decimals: 18 }],
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
relationships: { chain: { data: { id: "ethereum" } } },
|
|
135
|
+
},
|
|
136
|
+
],
|
|
137
|
+
slugToChainId,
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
expect(rows).toEqual([]);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it("drops a row that carries no quantity rather than reporting a zero balance", () => {
|
|
144
|
+
const rows = adaptZerionPositions(
|
|
145
|
+
[
|
|
146
|
+
{
|
|
147
|
+
id: "base-base-asset-asset",
|
|
148
|
+
attributes: {
|
|
149
|
+
quantity: { decimals: 18 },
|
|
150
|
+
fungible_info: { symbol: "ETH", implementations: [{ chain_id: "base", address: null, decimals: 18 }] },
|
|
151
|
+
},
|
|
152
|
+
relationships: { chain: { data: { id: "base" } } },
|
|
153
|
+
},
|
|
154
|
+
],
|
|
155
|
+
slugToChainId,
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
expect(rows).toEqual([]);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it("drops a row that carries no decimals rather than guessing a scale", () => {
|
|
162
|
+
const rows = adaptZerionPositions(
|
|
163
|
+
[
|
|
164
|
+
{
|
|
165
|
+
id: "0xabc-ethereum-asset-asset",
|
|
166
|
+
attributes: {
|
|
167
|
+
quantity: { int: "1000" },
|
|
168
|
+
fungible_info: { symbol: "MYSTERY", implementations: [{ chain_id: "ethereum", address: "0xabc" }] },
|
|
169
|
+
},
|
|
170
|
+
relationships: { chain: { data: { id: "ethereum" } } },
|
|
171
|
+
},
|
|
172
|
+
],
|
|
173
|
+
slugToChainId,
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
expect(rows).toEqual([]);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it("drops trash and non-displayable rows", () => {
|
|
180
|
+
const base = position({ id: "0xspam-ethereum-asset-asset", slug: "ethereum", symbol: "SPAM" });
|
|
181
|
+
const spam: ZerionPositionLike = { ...base, attributes: { ...base.attributes, flags: { is_trash: true } } };
|
|
182
|
+
const hidden: ZerionPositionLike = {
|
|
183
|
+
...base,
|
|
184
|
+
attributes: { ...base.attributes, flags: { displayable: false } },
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
expect(adaptZerionPositions([spam, hidden], slugToChainId)).toEqual([]);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it("drops any quantity that is not a base-10 integer, since all of them format to NaN", () => {
|
|
191
|
+
const rows = adaptZerionPositions(
|
|
192
|
+
[
|
|
193
|
+
position({ id: "0xa-ethereum-asset-asset", slug: "ethereum", symbol: "A", int: "" }),
|
|
194
|
+
position({ id: "0xb-ethereum-asset-asset", slug: "ethereum", symbol: "B", int: null as unknown as string }),
|
|
195
|
+
position({ id: "0xc-ethereum-asset-asset", slug: "ethereum", symbol: "C", int: "not-a-number" }),
|
|
196
|
+
position({ id: "0xd-ethereum-asset-asset", slug: "ethereum", symbol: "D", int: "0x1f" }),
|
|
197
|
+
position({ id: "0xe-ethereum-asset-asset", slug: "ethereum", symbol: "E", int: "1.5" }),
|
|
198
|
+
],
|
|
199
|
+
slugToChainId,
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
expect(rows).toEqual([]);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it("keeps a genuine zero balance", () => {
|
|
206
|
+
const [row] = adaptZerionPositions(
|
|
207
|
+
[position({ id: "base-ethereum-asset-asset", slug: "ethereum", symbol: "ETH", int: "0" })],
|
|
208
|
+
slugToChainId,
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
expect(row.amount).toBe("0");
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
describe("zerionSlugToChainId", () => {
|
|
216
|
+
it("reports an inherited object key as an unknown chain", () => {
|
|
217
|
+
// Slugs come off the wire; an object lookup would answer `constructor` with a function.
|
|
218
|
+
expect(zerionSlugToChainId("constructor")).toBeUndefined();
|
|
219
|
+
expect(zerionSlugToChainId("toString")).toBeUndefined();
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it("still resolves a real slug", () => {
|
|
223
|
+
expect(zerionSlugToChainId("ethereum")).toBe(1);
|
|
224
|
+
expect(chainIdToZerionSlug(8453)).toBe("base");
|
|
225
|
+
});
|
|
226
|
+
});
|