thirdweb 5.52.0-nightly-3a32b11a80cb28f22575219ab8f80e703793ec10-20240906000338 → 5.52.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/exports/react.js +4 -1
- package/dist/cjs/exports/react.js.map +1 -1
- package/dist/cjs/exports/social.js +6 -0
- package/dist/cjs/exports/social.js.map +1 -0
- package/dist/cjs/react/core/hooks/transaction/useSendTransaction.js.map +1 -1
- package/dist/cjs/react/core/providers/thirdweb-provider.js +2 -0
- package/dist/cjs/react/core/providers/thirdweb-provider.js.map +1 -1
- package/dist/cjs/react/core/social/useSocialProfiles.js +37 -0
- package/dist/cjs/react/core/social/useSocialProfiles.js.map +1 -0
- package/dist/cjs/react/core/utils/structuralSharing.js +54 -0
- package/dist/cjs/react/core/utils/structuralSharing.js.map +1 -0
- package/dist/cjs/react/core/utils/wallet.js +24 -0
- package/dist/cjs/react/core/utils/wallet.js.map +1 -1
- package/dist/cjs/react/native/ui/components/WalletImage.js +3 -3
- package/dist/cjs/react/native/ui/components/WalletImage.js.map +1 -1
- package/dist/cjs/react/native/ui/connect/ConnectedButton.js +3 -3
- package/dist/cjs/react/native/ui/connect/ConnectedButton.js.map +1 -1
- package/dist/cjs/react/native/ui/connect/ConnectedModal.js +2 -2
- package/dist/cjs/react/native/ui/connect/ConnectedModal.js.map +1 -1
- package/dist/cjs/react/web/ui/ConnectWallet/ConnectButton.js +0 -3
- package/dist/cjs/react/web/ui/ConnectWallet/ConnectButton.js.map +1 -1
- package/dist/cjs/react/web/ui/ConnectWallet/Details.js +9 -6
- package/dist/cjs/react/web/ui/ConnectWallet/Details.js.map +1 -1
- package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js +4 -1
- package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js.map +1 -1
- package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/main/useUISelectionStates.js +2 -1
- package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/main/useUISelectionStates.js.map +1 -1
- package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/useSwapSupportedChains.js +4 -4
- package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/useSwapSupportedChains.js.map +1 -1
- package/dist/cjs/social/profiles.js +38 -0
- package/dist/cjs/social/profiles.js.map +1 -0
- package/dist/cjs/social/types.js +3 -0
- package/dist/cjs/social/types.js.map +1 -0
- package/dist/cjs/utils/domains.js +3 -0
- package/dist/cjs/utils/domains.js.map +1 -1
- package/dist/cjs/utils/function-id.js +3 -5
- package/dist/cjs/utils/function-id.js.map +1 -1
- package/dist/cjs/utils/ipfs.js +19 -10
- package/dist/cjs/utils/ipfs.js.map +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/version.js.map +1 -1
- package/dist/cjs/wallets/smart/lib/userop.js +2 -1
- package/dist/cjs/wallets/smart/lib/userop.js.map +1 -1
- package/dist/esm/exports/react.js +2 -0
- package/dist/esm/exports/react.js.map +1 -1
- package/dist/esm/exports/social.js +3 -0
- package/dist/esm/exports/social.js.map +1 -0
- package/dist/esm/react/core/hooks/transaction/useSendTransaction.js.map +1 -1
- package/dist/esm/react/core/providers/thirdweb-provider.js +2 -0
- package/dist/esm/react/core/providers/thirdweb-provider.js.map +1 -1
- package/dist/esm/react/core/social/useSocialProfiles.js +34 -0
- package/dist/esm/react/core/social/useSocialProfiles.js.map +1 -0
- package/dist/esm/react/core/utils/structuralSharing.js +50 -0
- package/dist/esm/react/core/utils/structuralSharing.js.map +1 -0
- package/dist/esm/react/core/utils/wallet.js +24 -0
- package/dist/esm/react/core/utils/wallet.js.map +1 -1
- package/dist/esm/react/native/ui/components/WalletImage.js +3 -3
- package/dist/esm/react/native/ui/components/WalletImage.js.map +1 -1
- package/dist/esm/react/native/ui/connect/ConnectedButton.js +3 -3
- package/dist/esm/react/native/ui/connect/ConnectedButton.js.map +1 -1
- package/dist/esm/react/native/ui/connect/ConnectedModal.js +2 -2
- package/dist/esm/react/native/ui/connect/ConnectedModal.js.map +1 -1
- package/dist/esm/react/web/ui/ConnectWallet/ConnectButton.js +0 -3
- package/dist/esm/react/web/ui/ConnectWallet/ConnectButton.js.map +1 -1
- package/dist/esm/react/web/ui/ConnectWallet/Details.js +9 -6
- package/dist/esm/react/web/ui/ConnectWallet/Details.js.map +1 -1
- package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js +4 -1
- package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js.map +1 -1
- package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/main/useUISelectionStates.js +2 -1
- package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/main/useUISelectionStates.js.map +1 -1
- package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/useSwapSupportedChains.js +4 -4
- package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/useSwapSupportedChains.js.map +1 -1
- package/dist/esm/social/profiles.js +35 -0
- package/dist/esm/social/profiles.js.map +1 -0
- package/dist/esm/social/types.js +2 -0
- package/dist/esm/social/types.js.map +1 -0
- package/dist/esm/utils/domains.js +3 -0
- package/dist/esm/utils/domains.js.map +1 -1
- package/dist/esm/utils/function-id.js +3 -5
- package/dist/esm/utils/function-id.js.map +1 -1
- package/dist/esm/utils/ipfs.js +19 -10
- package/dist/esm/utils/ipfs.js.map +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/esm/version.js.map +1 -1
- package/dist/esm/wallets/smart/lib/userop.js +2 -1
- package/dist/esm/wallets/smart/lib/userop.js.map +1 -1
- package/dist/types/exports/react.d.ts +1 -0
- package/dist/types/exports/react.d.ts.map +1 -1
- package/dist/types/exports/social.d.ts +3 -0
- package/dist/types/exports/social.d.ts.map +1 -0
- package/dist/types/react/core/hooks/connection/ConnectButtonProps.d.ts +1 -0
- package/dist/types/react/core/hooks/connection/ConnectButtonProps.d.ts.map +1 -1
- package/dist/types/react/core/hooks/transaction/useSendTransaction.d.ts +3 -1
- package/dist/types/react/core/hooks/transaction/useSendTransaction.d.ts.map +1 -1
- package/dist/types/react/core/providers/thirdweb-provider.d.ts.map +1 -1
- package/dist/types/react/core/social/useSocialProfiles.d.ts +23 -0
- package/dist/types/react/core/social/useSocialProfiles.d.ts.map +1 -0
- package/dist/types/react/core/utils/structuralSharing.d.ts +4 -0
- package/dist/types/react/core/utils/structuralSharing.d.ts.map +1 -0
- package/dist/types/react/core/utils/wallet.d.ts +3 -0
- package/dist/types/react/core/utils/wallet.d.ts.map +1 -1
- package/dist/types/react/native/ui/components/WalletImage.d.ts +1 -1
- package/dist/types/react/native/ui/components/WalletImage.d.ts.map +1 -1
- package/dist/types/react/native/ui/connect/ConnectedButton.d.ts.map +1 -1
- package/dist/types/react/web/ui/ConnectWallet/Details.d.ts +18 -3
- package/dist/types/react/web/ui/ConnectWallet/Details.d.ts.map +1 -1
- package/dist/types/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.d.ts.map +1 -1
- package/dist/types/react/web/ui/ConnectWallet/screens/Buy/main/useUISelectionStates.d.ts.map +1 -1
- package/dist/types/react/web/ui/ConnectWallet/screens/Buy/swap/useSwapSupportedChains.d.ts +2 -2
- package/dist/types/react/web/ui/ConnectWallet/screens/Buy/swap/useSwapSupportedChains.d.ts.map +1 -1
- package/dist/types/social/profiles.d.ts +24 -0
- package/dist/types/social/profiles.d.ts.map +1 -0
- package/dist/types/social/types.d.ts +41 -0
- package/dist/types/social/types.d.ts.map +1 -0
- package/dist/types/utils/domains.d.ts +6 -0
- package/dist/types/utils/domains.d.ts.map +1 -1
- package/dist/types/utils/function-id.d.ts.map +1 -1
- package/dist/types/utils/ipfs.d.ts.map +1 -1
- package/dist/types/version.d.ts +1 -1
- package/dist/types/version.d.ts.map +1 -1
- package/dist/types/wallets/smart/lib/userop.d.ts +2 -1
- package/dist/types/wallets/smart/lib/userop.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/exports/react.ts +3 -0
- package/src/exports/social.ts +2 -0
- package/src/react/core/hooks/connection/ConnectButtonProps.ts +1 -0
- package/src/react/core/hooks/transaction/useSendTransaction.ts +5 -1
- package/src/react/core/providers/thirdweb-provider.tsx +2 -0
- package/src/react/core/social/useSocialProfiles.ts +40 -0
- package/src/react/core/utils/structuralSharing.ts +53 -0
- package/src/react/core/utils/wallet.ts +27 -0
- package/src/react/native/ui/components/WalletImage.tsx +4 -4
- package/src/react/native/ui/connect/ConnectedButton.tsx +8 -14
- package/src/react/native/ui/connect/ConnectedModal.tsx +8 -14
- package/src/react/web/ui/ConnectWallet/ConnectButton.tsx +0 -3
- package/src/react/web/ui/ConnectWallet/Details.tsx +40 -23
- package/src/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.tsx +7 -1
- package/src/react/web/ui/ConnectWallet/screens/Buy/main/useUISelectionStates.ts +2 -1
- package/src/react/web/ui/ConnectWallet/screens/Buy/swap/useSwapSupportedChains.ts +9 -3
- package/src/social/profiles.ts +46 -0
- package/src/social/types.ts +43 -0
- package/src/utils/domains.ts +8 -0
- package/src/utils/function-id.ts +3 -5
- package/src/utils/ipfs.test.ts +57 -1
- package/src/utils/ipfs.ts +22 -14
- package/src/version.ts +1 -1
- package/src/wallets/smart/lib/userop.ts +2 -1
@@ -0,0 +1,53 @@
|
|
1
|
+
import { replaceEqualDeep } from "@tanstack/react-query";
|
2
|
+
|
3
|
+
/** Forked from https://github.com/epoberezkin/fast-deep-equal */
|
4
|
+
// biome-ignore lint/suspicious/noExplicitAny: This function by nature takes any object
|
5
|
+
export function deepEqual(a: any, b: any) {
|
6
|
+
if (a === b) return true;
|
7
|
+
|
8
|
+
if (a && b && typeof a === "object" && typeof b === "object") {
|
9
|
+
if (a.constructor !== b.constructor) return false;
|
10
|
+
|
11
|
+
let length: number;
|
12
|
+
let i: number;
|
13
|
+
|
14
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
15
|
+
length = a.length;
|
16
|
+
if (length !== b.length) return false;
|
17
|
+
for (i = length; i-- !== 0; ) if (!deepEqual(a[i], b[i])) return false;
|
18
|
+
return true;
|
19
|
+
}
|
20
|
+
|
21
|
+
if (a.valueOf !== Object.prototype.valueOf)
|
22
|
+
return a.valueOf() === b.valueOf();
|
23
|
+
if (a.toString !== Object.prototype.toString)
|
24
|
+
return a.toString() === b.toString();
|
25
|
+
|
26
|
+
const keys = Object.keys(a);
|
27
|
+
length = keys.length;
|
28
|
+
if (length !== Object.keys(b).length) return false;
|
29
|
+
|
30
|
+
for (i = length; i-- !== 0; )
|
31
|
+
// biome-ignore lint/style/noNonNullAssertion: We know its there
|
32
|
+
if (!Object.prototype.hasOwnProperty.call(b, keys[i]!)) return false;
|
33
|
+
|
34
|
+
for (i = length; i-- !== 0; ) {
|
35
|
+
const key = keys[i];
|
36
|
+
|
37
|
+
if (key && !deepEqual(a[key], b[key])) return false;
|
38
|
+
}
|
39
|
+
|
40
|
+
return true;
|
41
|
+
}
|
42
|
+
|
43
|
+
// true if both NaN, false otherwise
|
44
|
+
// biome-ignore lint/suspicious/noSelfCompare: <explanation>
|
45
|
+
return a !== a && b !== b;
|
46
|
+
}
|
47
|
+
|
48
|
+
export function structuralSharing<T>(oldData: T | undefined, newData: T) {
|
49
|
+
if (deepEqual(oldData, newData)) {
|
50
|
+
return oldData as T;
|
51
|
+
}
|
52
|
+
return replaceEqualDeep(oldData, newData) as T;
|
53
|
+
}
|
@@ -5,11 +5,13 @@ import type { ThirdwebClient } from "../../../client/client.js";
|
|
5
5
|
import { resolveAvatar } from "../../../extensions/ens/resolve-avatar.js";
|
6
6
|
import { resolveName } from "../../../extensions/ens/resolve-name.js";
|
7
7
|
import { shortenAddress } from "../../../utils/address.js";
|
8
|
+
import { parseAvatarRecord } from "../../../utils/ens/avatar.js";
|
8
9
|
import { getWalletInfo } from "../../../wallets/__generated__/getWalletInfo.js";
|
9
10
|
import type { Account, Wallet } from "../../../wallets/interfaces/wallet.js";
|
10
11
|
import type { WalletInfo } from "../../../wallets/wallet-info.js";
|
11
12
|
import type { WalletId } from "../../../wallets/wallet-types.js";
|
12
13
|
import { useWalletBalance } from "../hooks/others/useWalletBalance.js";
|
14
|
+
import { useSocialProfiles } from "../social/useSocialProfiles.js";
|
13
15
|
|
14
16
|
/**
|
15
17
|
* Get the ENS name and avatar for an address
|
@@ -98,6 +100,11 @@ export function useConnectedWalletDetails(
|
|
98
100
|
ensName: ensNameQuery.data,
|
99
101
|
});
|
100
102
|
|
103
|
+
const socialProfileQuery = useSocialProfiles({
|
104
|
+
client,
|
105
|
+
address: activeAccount?.address,
|
106
|
+
});
|
107
|
+
|
101
108
|
const shortAddress = activeAccount?.address
|
102
109
|
? shortenAddress(activeAccount.address, 4)
|
103
110
|
: "";
|
@@ -110,11 +117,31 @@ export function useConnectedWalletDetails(
|
|
110
117
|
});
|
111
118
|
|
112
119
|
const addressOrENS = ensNameQuery.data || shortAddress;
|
120
|
+
const pfpUnresolved = socialProfileQuery.data?.filter((p) => p.avatar)[0]
|
121
|
+
?.avatar;
|
122
|
+
|
123
|
+
const { data: pfp } = useQuery({
|
124
|
+
queryKey: ["ens-avatar", pfpUnresolved],
|
125
|
+
queryFn: async () => {
|
126
|
+
if (!pfpUnresolved) {
|
127
|
+
return undefined;
|
128
|
+
}
|
129
|
+
return parseAvatarRecord({ client, uri: pfpUnresolved });
|
130
|
+
},
|
131
|
+
enabled: !!pfpUnresolved,
|
132
|
+
refetchOnWindowFocus: false,
|
133
|
+
refetchOnMount: false,
|
134
|
+
});
|
135
|
+
const name =
|
136
|
+
socialProfileQuery.data?.filter((p) => p.name)[0]?.name || addressOrENS;
|
113
137
|
|
114
138
|
return {
|
139
|
+
socialProfileQuery,
|
115
140
|
ensNameQuery,
|
116
141
|
ensAvatarQuery,
|
117
142
|
addressOrENS,
|
143
|
+
pfp,
|
144
|
+
name,
|
118
145
|
shortAddress,
|
119
146
|
balanceQuery,
|
120
147
|
};
|
@@ -21,9 +21,9 @@ export const WalletImage = (props: {
|
|
21
21
|
theme: Theme;
|
22
22
|
wallet: Wallet;
|
23
23
|
size: number;
|
24
|
-
|
24
|
+
avatar?: string | null;
|
25
25
|
}) => {
|
26
|
-
const { wallet,
|
26
|
+
const { wallet, avatar, size } = props;
|
27
27
|
|
28
28
|
const { data: imageData } = useQuery({
|
29
29
|
queryKey: ["wallet-image", wallet.id, wallet.getAccount()?.address],
|
@@ -56,10 +56,10 @@ export const WalletImage = (props: {
|
|
56
56
|
|
57
57
|
return WALLET_ICON;
|
58
58
|
},
|
59
|
-
enabled: !
|
59
|
+
enabled: !avatar,
|
60
60
|
});
|
61
61
|
|
62
|
-
const data =
|
62
|
+
const data = avatar || imageData || WALLET_ICON;
|
63
63
|
return <RNImage theme={props.theme} data={data} size={size} />;
|
64
64
|
};
|
65
65
|
|
@@ -22,13 +22,12 @@ export function ConnectedButton(
|
|
22
22
|
const theme = parseTheme(props.theme);
|
23
23
|
const { account, wallet } = props;
|
24
24
|
const walletChain = useActiveWalletChain();
|
25
|
-
const {
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
);
|
25
|
+
const { pfp, name, balanceQuery } = useConnectedWalletDetails(
|
26
|
+
props.client,
|
27
|
+
walletChain,
|
28
|
+
account,
|
29
|
+
props.detailsButton?.displayBalanceToken,
|
30
|
+
);
|
32
31
|
return (
|
33
32
|
<ThemedButton
|
34
33
|
theme={theme}
|
@@ -41,12 +40,7 @@ export function ConnectedButton(
|
|
41
40
|
}}
|
42
41
|
>
|
43
42
|
<View style={styles.row}>
|
44
|
-
<WalletImage
|
45
|
-
theme={theme}
|
46
|
-
size={40}
|
47
|
-
wallet={wallet}
|
48
|
-
ensAvatar={ensAvatarQuery.data}
|
49
|
-
/>
|
43
|
+
<WalletImage theme={theme} size={40} wallet={wallet} avatar={pfp} />
|
50
44
|
<View style={styles.col}>
|
51
45
|
<ThemedText
|
52
46
|
theme={theme}
|
@@ -55,7 +49,7 @@ export function ConnectedButton(
|
|
55
49
|
color: theme.colors.primaryButtonText,
|
56
50
|
}}
|
57
51
|
>
|
58
|
-
{
|
52
|
+
{name}
|
59
53
|
</ThemedText>
|
60
54
|
{balanceQuery.data ? (
|
61
55
|
<ThemedText
|
@@ -163,24 +163,18 @@ export function ConnectedModal(props: ConnectedModalProps) {
|
|
163
163
|
const AccountHeader = (props: ConnectedModalProps) => {
|
164
164
|
const { account, wallet, theme } = props;
|
165
165
|
const walletChain = useActiveWalletChain();
|
166
|
-
const {
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
);
|
166
|
+
const { pfp, name, balanceQuery } = useConnectedWalletDetails(
|
167
|
+
props.client,
|
168
|
+
walletChain,
|
169
|
+
account,
|
170
|
+
props.detailsButton?.displayBalanceToken,
|
171
|
+
);
|
173
172
|
return (
|
174
173
|
<View style={styles.accountHeaderContainer}>
|
175
|
-
<WalletImage
|
176
|
-
theme={theme}
|
177
|
-
size={70}
|
178
|
-
wallet={wallet}
|
179
|
-
ensAvatar={ensAvatarQuery.data}
|
180
|
-
/>
|
174
|
+
<WalletImage theme={theme} size={70} wallet={wallet} avatar={pfp} />
|
181
175
|
<SmartAccountBadge client={props.client} theme={theme} />
|
182
176
|
<Spacer size="smd" />
|
183
|
-
<Address account={account} theme={theme} addressOrENS={
|
177
|
+
<Address account={account} theme={theme} addressOrENS={name} />
|
184
178
|
<Spacer size="xxs" />
|
185
179
|
{balanceQuery.data ? (
|
186
180
|
<ThemedText
|
@@ -544,9 +544,6 @@ function ConnectButtonInner(
|
|
544
544
|
showAllWallets: props.showAllWallets,
|
545
545
|
walletConnect: props.walletConnect,
|
546
546
|
wallets: props.wallets,
|
547
|
-
hideReceiveFunds: props.detailsModal?.hideReceiveFunds,
|
548
|
-
hideSendFunds: props.detailsModal?.hideSendFunds,
|
549
|
-
hideBuyFunds: props.detailsModal?.hideBuyFunds,
|
550
547
|
}}
|
551
548
|
/>
|
552
549
|
);
|
@@ -131,13 +131,12 @@ export const ConnectedWalletDetails: React.FC<{
|
|
131
131
|
const activeAccount = useActiveAccount();
|
132
132
|
const walletChain = useActiveWalletChain();
|
133
133
|
|
134
|
-
const {
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
);
|
134
|
+
const { pfp, name, balanceQuery } = useConnectedWalletDetails(
|
135
|
+
client,
|
136
|
+
walletChain,
|
137
|
+
activeAccount,
|
138
|
+
props.detailsButton?.displayBalanceToken,
|
139
|
+
);
|
141
140
|
|
142
141
|
function closeModal() {
|
143
142
|
setRootEl(null);
|
@@ -185,8 +184,7 @@ export const ConnectedWalletDetails: React.FC<{
|
|
185
184
|
);
|
186
185
|
}
|
187
186
|
|
188
|
-
const avatarSrc =
|
189
|
-
props.detailsButton?.connectedAccountAvatarUrl ?? ensAvatarQuery.data;
|
187
|
+
const avatarSrc = props.detailsButton?.connectedAccountAvatarUrl || pfp;
|
190
188
|
|
191
189
|
return (
|
192
190
|
<WalletInfoButton
|
@@ -235,7 +233,7 @@ export const ConnectedWalletDetails: React.FC<{
|
|
235
233
|
weight={500}
|
236
234
|
className={`${TW_CONNECTED_WALLET}__address`}
|
237
235
|
>
|
238
|
-
{props.detailsButton?.connectedAccountName ??
|
236
|
+
{props.detailsButton?.connectedAccountName ?? name}
|
239
237
|
</Text>
|
240
238
|
|
241
239
|
{/* Balance */}
|
@@ -280,13 +278,12 @@ function DetailsModal(props: {
|
|
280
278
|
const { client, locale } = props;
|
281
279
|
const walletChain = useActiveWalletChain();
|
282
280
|
const activeAccount = useActiveAccount();
|
283
|
-
const {
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
);
|
281
|
+
const { pfp, name, balanceQuery } = useConnectedWalletDetails(
|
282
|
+
client,
|
283
|
+
walletChain,
|
284
|
+
activeAccount,
|
285
|
+
props.displayBalanceToken,
|
286
|
+
);
|
290
287
|
const theme = parseTheme(props.theme);
|
291
288
|
|
292
289
|
const activeWallet = useActiveWallet();
|
@@ -370,8 +367,7 @@ function DetailsModal(props: {
|
|
370
367
|
</MenuButton>
|
371
368
|
);
|
372
369
|
|
373
|
-
const avatarSrc =
|
374
|
-
props.detailsModal?.connectedAccountAvatarUrl ?? ensAvatarQuery.data;
|
370
|
+
const avatarSrc = props.detailsModal?.connectedAccountAvatarUrl ?? pfp;
|
375
371
|
|
376
372
|
const { hideSendFunds, hideReceiveFunds, hideBuyFunds } =
|
377
373
|
props.detailsModal || {};
|
@@ -483,7 +479,7 @@ function DetailsModal(props: {
|
|
483
479
|
}}
|
484
480
|
>
|
485
481
|
<Text color="primaryText" weight={500} size="md">
|
486
|
-
{props.detailsModal?.connectedAccountName ??
|
482
|
+
{props.detailsModal?.connectedAccountName ?? name}
|
487
483
|
</Text>
|
488
484
|
<IconButton>
|
489
485
|
<CopyIcon
|
@@ -1154,9 +1150,6 @@ export type DetailsModalConnectOptions = {
|
|
1154
1150
|
chains?: Chain[];
|
1155
1151
|
recommendedWallets?: Wallet[];
|
1156
1152
|
showAllWallets?: boolean;
|
1157
|
-
hideSendFunds?: boolean;
|
1158
|
-
hideReceiveFunds?: boolean;
|
1159
|
-
hideBuyFunds?: boolean;
|
1160
1153
|
};
|
1161
1154
|
|
1162
1155
|
export type UseWalletDetailsModalOptions = {
|
@@ -1380,6 +1373,27 @@ export type UseWalletDetailsModalOptions = {
|
|
1380
1373
|
* Use custom avatar URL for the connected wallet image in the `ConnectButton` Details Modal, overriding ENS avatar or Blobbie icon.
|
1381
1374
|
*/
|
1382
1375
|
connectedAccountAvatarUrl?: string;
|
1376
|
+
|
1377
|
+
/**
|
1378
|
+
* Hide the "Send Funds" button in the Details Modal.
|
1379
|
+
*
|
1380
|
+
* By default the "Send Funds" button is shown.
|
1381
|
+
*/
|
1382
|
+
hideSendFunds?: boolean;
|
1383
|
+
|
1384
|
+
/**
|
1385
|
+
* Hide the "Receive Funds" button in the Details Modal.
|
1386
|
+
*
|
1387
|
+
* By default the "Receive Funds" button is shown.
|
1388
|
+
*/
|
1389
|
+
hideReceiveFunds?: boolean;
|
1390
|
+
|
1391
|
+
/**
|
1392
|
+
* Hide the "Buy Funds" button in the Details Modal.
|
1393
|
+
*
|
1394
|
+
* By default the "Buy Funds" button is shown.
|
1395
|
+
*/
|
1396
|
+
hideBuyFunds?: boolean;
|
1383
1397
|
};
|
1384
1398
|
|
1385
1399
|
/**
|
@@ -1434,6 +1448,9 @@ export function useWalletDetailsModal() {
|
|
1434
1448
|
showTestnetFaucet: props.showTestnetFaucet,
|
1435
1449
|
connectedAccountName: props.connectedAccountName,
|
1436
1450
|
connectedAccountAvatarUrl: props.connectedAccountAvatarUrl,
|
1451
|
+
hideBuyFunds: props.hideBuyFunds,
|
1452
|
+
hideReceiveFunds: props.hideReceiveFunds,
|
1453
|
+
hideSendFunds: props.hideSendFunds,
|
1437
1454
|
}}
|
1438
1455
|
displayBalanceToken={props.displayBalanceToken}
|
1439
1456
|
theme={props.theme || "dark"}
|
@@ -97,7 +97,13 @@ export type BuyScreenProps = {
|
|
97
97
|
* @internal
|
98
98
|
*/
|
99
99
|
export default function BuyScreen(props: BuyScreenProps) {
|
100
|
-
const
|
100
|
+
const isTestMode = props.payOptions.buyWithCrypto
|
101
|
+
? props.payOptions.buyWithCrypto.testMode
|
102
|
+
: undefined;
|
103
|
+
const supportedDestinationsQuery = useBuySupportedDestinations(
|
104
|
+
props.client,
|
105
|
+
isTestMode,
|
106
|
+
);
|
101
107
|
|
102
108
|
if (!supportedDestinationsQuery.data) {
|
103
109
|
return <LoadingScreen />;
|
@@ -50,7 +50,8 @@ export function useToTokenSelectionStates(options: {
|
|
50
50
|
// use active chain if its supported as destination
|
51
51
|
supportedDestinations.find((x) => x.chain.id === activeChain?.id)
|
52
52
|
?.chain ||
|
53
|
-
// default to polygon
|
53
|
+
// default to the first chain in supportedDestinations, or polygon if nothing is found at all
|
54
|
+
supportedDestinations[0]?.chain ||
|
54
55
|
polygon,
|
55
56
|
);
|
56
57
|
|
@@ -36,11 +36,14 @@ export type SupportedChainAndTokens = Array<{
|
|
36
36
|
|
37
37
|
export async function fetchBuySupportedDestinations(
|
38
38
|
client: ThirdwebClient,
|
39
|
+
isTestMode?: boolean,
|
39
40
|
): Promise<SupportedChainAndTokens> {
|
40
41
|
return withCache(
|
41
42
|
async () => {
|
42
43
|
const fetchWithHeaders = getClientFetch(client);
|
43
|
-
const res = await fetchWithHeaders(
|
44
|
+
const res = await fetchWithHeaders(
|
45
|
+
`${getPaySupportedDestinations()}?isTestMode=${isTestMode}`,
|
46
|
+
);
|
44
47
|
const data = (await res.json()) as Response;
|
45
48
|
return data.result.map((item) => ({
|
46
49
|
chain: defineChain({
|
@@ -59,11 +62,14 @@ export async function fetchBuySupportedDestinations(
|
|
59
62
|
/**
|
60
63
|
* @internal
|
61
64
|
*/
|
62
|
-
export function useBuySupportedDestinations(
|
65
|
+
export function useBuySupportedDestinations(
|
66
|
+
client: ThirdwebClient,
|
67
|
+
isTestMode?: boolean,
|
68
|
+
) {
|
63
69
|
return useQuery({
|
64
70
|
queryKey: ["destination-tokens", client],
|
65
71
|
queryFn: async () => {
|
66
|
-
return fetchBuySupportedDestinations(client);
|
72
|
+
return fetchBuySupportedDestinations(client, isTestMode);
|
67
73
|
},
|
68
74
|
});
|
69
75
|
}
|
@@ -0,0 +1,46 @@
|
|
1
|
+
import type { ThirdwebClient } from "../client/client.js";
|
2
|
+
import { getThirdwebBaseUrl } from "../utils/domains.js";
|
3
|
+
import { getClientFetch } from "../utils/fetch.js";
|
4
|
+
import type { SocialProfiles } from "./types.js";
|
5
|
+
|
6
|
+
/**
|
7
|
+
* Fetches the wallet's available social profiles.
|
8
|
+
* @param args - The arguments to use when fetching the social profiles.
|
9
|
+
* @param args.address - The wallet address to fetch the social profiles for.
|
10
|
+
* @param args.client - The Thirdweb client.
|
11
|
+
* @returns A promise resolving to the retrieved social profiles for different protocols. If a profile is not available for a protocol, the value will be `null`.
|
12
|
+
*
|
13
|
+
* @example
|
14
|
+
* ```ts
|
15
|
+
* import { getProfiles } from "thirdweb/social";
|
16
|
+
* const profiles = await getProfiles({
|
17
|
+
* address: "0x...",
|
18
|
+
* client,
|
19
|
+
* });
|
20
|
+
* ```
|
21
|
+
* @beta
|
22
|
+
*/
|
23
|
+
export async function getSocialProfiles(args: {
|
24
|
+
address: string;
|
25
|
+
client: ThirdwebClient;
|
26
|
+
}): Promise<SocialProfiles> {
|
27
|
+
const { address, client } = args;
|
28
|
+
|
29
|
+
const clientFetch = getClientFetch(client);
|
30
|
+
const response = await clientFetch(
|
31
|
+
`${getThirdwebBaseUrl("social")}/v1/profiles/${address}`,
|
32
|
+
);
|
33
|
+
|
34
|
+
if (response.status !== 200) {
|
35
|
+
try {
|
36
|
+
const errorBody = await response.json();
|
37
|
+
throw new Error(`Failed to fetch profile: ${errorBody.message}`);
|
38
|
+
} catch {
|
39
|
+
throw new Error(
|
40
|
+
`Failed to fetch profile: ${response.status}\n${await response.text()}`,
|
41
|
+
);
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
return (await response.json()).data as SocialProfiles;
|
46
|
+
}
|
@@ -0,0 +1,43 @@
|
|
1
|
+
export type FarcasterProfile = {
|
2
|
+
fid?: number;
|
3
|
+
bio?: string;
|
4
|
+
pfp?: string;
|
5
|
+
display?: string;
|
6
|
+
username?: string;
|
7
|
+
custodyAddress?: string;
|
8
|
+
addresses?: string[];
|
9
|
+
};
|
10
|
+
|
11
|
+
export type LensProfile = {
|
12
|
+
name?: string;
|
13
|
+
bio?: string;
|
14
|
+
picture?: string;
|
15
|
+
coverPicture?: string;
|
16
|
+
};
|
17
|
+
|
18
|
+
export type EnsProfile = {
|
19
|
+
name?: string;
|
20
|
+
address?: string;
|
21
|
+
avatar?: string;
|
22
|
+
display?: string;
|
23
|
+
description?: string;
|
24
|
+
keywords?: string[];
|
25
|
+
email?: string;
|
26
|
+
mail?: string;
|
27
|
+
notice?: string;
|
28
|
+
location?: string;
|
29
|
+
phone?: string;
|
30
|
+
url?: string;
|
31
|
+
twitter?: string;
|
32
|
+
github?: string;
|
33
|
+
discord?: string;
|
34
|
+
telegram?: string;
|
35
|
+
};
|
36
|
+
|
37
|
+
export type SocialProfiles = {
|
38
|
+
type: "farcaster" | "lens" | "ens";
|
39
|
+
name?: string;
|
40
|
+
avatar?: string;
|
41
|
+
bio?: string;
|
42
|
+
metadata?: FarcasterProfile | LensProfile | EnsProfile;
|
43
|
+
}[];
|
package/src/utils/domains.ts
CHANGED
@@ -4,6 +4,11 @@ type DomainOverrides = {
|
|
4
4
|
* @default "rpc.thirdweb.com"
|
5
5
|
*/
|
6
6
|
rpc?: string;
|
7
|
+
/**
|
8
|
+
* The base URL for the social service.
|
9
|
+
* @default "social.thirdweb.com"
|
10
|
+
*/
|
11
|
+
social?: string;
|
7
12
|
/**
|
8
13
|
* The base URL for the in-app wallet service
|
9
14
|
* @default "embedded-wallet.thirdweb.com"
|
@@ -28,6 +33,7 @@ type DomainOverrides = {
|
|
28
33
|
|
29
34
|
export const DEFAULT_RPC_URL = "rpc.thirdweb.com";
|
30
35
|
const DEFAULT_IN_APP_WALLET_URL = "embedded-wallet.thirdweb.com";
|
36
|
+
const DEFAULT_SOCIAL_URL = "social.thirdweb.com";
|
31
37
|
const DEFAULT_PAY_URL = "pay.thirdweb.com";
|
32
38
|
const DEFAULT_STORAGE_URL = "storage.thirdweb.com";
|
33
39
|
const DEFAULT_BUNDLER_URL = "bundler.thirdweb.com";
|
@@ -35,6 +41,7 @@ const DEFAULT_BUNDLER_URL = "bundler.thirdweb.com";
|
|
35
41
|
let domains: { [k in keyof DomainOverrides]-?: string } = {
|
36
42
|
rpc: DEFAULT_RPC_URL,
|
37
43
|
inAppWallet: DEFAULT_IN_APP_WALLET_URL,
|
44
|
+
social: DEFAULT_SOCIAL_URL,
|
38
45
|
pay: DEFAULT_PAY_URL,
|
39
46
|
storage: DEFAULT_STORAGE_URL,
|
40
47
|
bundler: DEFAULT_BUNDLER_URL,
|
@@ -47,6 +54,7 @@ export const setThirdwebDomains = (DomainOverrides: DomainOverrides) => {
|
|
47
54
|
domains = {
|
48
55
|
rpc: DomainOverrides.rpc ?? DEFAULT_RPC_URL,
|
49
56
|
inAppWallet: DomainOverrides.inAppWallet ?? DEFAULT_IN_APP_WALLET_URL,
|
57
|
+
social: DomainOverrides.social ?? DEFAULT_SOCIAL_URL,
|
50
58
|
pay: DomainOverrides.pay ?? DEFAULT_PAY_URL,
|
51
59
|
storage: DomainOverrides.storage ?? DEFAULT_STORAGE_URL,
|
52
60
|
bundler: DomainOverrides.bundler ?? DEFAULT_BUNDLER_URL,
|
package/src/utils/function-id.ts
CHANGED
@@ -1,11 +1,9 @@
|
|
1
|
-
import {
|
2
|
-
import { uint8ArrayToHex } from "./encoding/hex.js";
|
1
|
+
import { randomBytesHex } from "./random.js";
|
3
2
|
|
4
3
|
// biome-ignore lint/suspicious/noExplicitAny: the whoel point here is to accept anything
|
5
4
|
type AnyFunction = (...args: any[]) => any;
|
6
5
|
|
7
|
-
|
8
|
-
const functionIdCache = new WeakMap<AnyFunction, string>();
|
6
|
+
const functionIdCache = new Map<AnyFunction, string>();
|
9
7
|
|
10
8
|
/**
|
11
9
|
* Retrieves the unique identifier for a given function.
|
@@ -20,7 +18,7 @@ export function getFunctionId(fn: AnyFunction) {
|
|
20
18
|
// biome-ignore lint/style/noNonNullAssertion: the `has` above ensures that this will always be set
|
21
19
|
return functionIdCache.get(fn)!;
|
22
20
|
}
|
23
|
-
const id =
|
21
|
+
const id = randomBytesHex();
|
24
22
|
functionIdCache.set(fn, id);
|
25
23
|
return id;
|
26
24
|
}
|
package/src/utils/ipfs.test.ts
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
2
2
|
import { createThirdwebClient } from "../client/client.js";
|
3
|
-
import {
|
3
|
+
import {
|
4
|
+
findIPFSCidFromUri,
|
5
|
+
getBaseUriFromBatch,
|
6
|
+
resolveScheme,
|
7
|
+
} from "./ipfs.js";
|
4
8
|
|
5
9
|
describe("resolveScheme", () => {
|
6
10
|
it("should resolve ipfs scheme when not passing a gateway override", () => {
|
@@ -70,3 +74,55 @@ describe("resolveScheme", () => {
|
|
70
74
|
expect(findIPFSCidFromUri(uri)).toBe(cid);
|
71
75
|
});
|
72
76
|
});
|
77
|
+
|
78
|
+
describe("getBaseUriFromBatch", () => {
|
79
|
+
it("should return the base uri", () => {
|
80
|
+
const batchOfUris = ["ipfs://Qm.../0", "ipfs://Qm.../1", "ipfs://Qm.../2"];
|
81
|
+
const baseUri = getBaseUriFromBatch(batchOfUris);
|
82
|
+
expect(baseUri).toMatchInlineSnapshot(`"ipfs://Qm.../"`);
|
83
|
+
});
|
84
|
+
it("should throw if the batch is empty", () => {
|
85
|
+
expect(() => getBaseUriFromBatch([])).toThrowErrorMatchingInlineSnapshot(
|
86
|
+
"[Error: Batch of URIs is empty]",
|
87
|
+
);
|
88
|
+
});
|
89
|
+
|
90
|
+
it("should throw if an element of the array does not have the same base", () => {
|
91
|
+
const batchOfUris = ["ipfs://Qm.../0", "ipfs://Qm.../1", "ipfs://Qm2.../2"];
|
92
|
+
expect(() =>
|
93
|
+
getBaseUriFromBatch(batchOfUris),
|
94
|
+
).toThrowErrorMatchingInlineSnapshot(
|
95
|
+
"[Error: All URIs in the batch must have the same base URI]",
|
96
|
+
);
|
97
|
+
});
|
98
|
+
|
99
|
+
it("should work with a custom domain", () => {
|
100
|
+
const batchOfUris = [
|
101
|
+
"https://example.com/0",
|
102
|
+
"https://example.com/1",
|
103
|
+
"https://example.com/2",
|
104
|
+
];
|
105
|
+
const baseUri = getBaseUriFromBatch(batchOfUris);
|
106
|
+
expect(baseUri).toMatchInlineSnapshot(`"https://example.com/"`);
|
107
|
+
});
|
108
|
+
|
109
|
+
it("should work with a custom domain and path", () => {
|
110
|
+
const batchOfUris = [
|
111
|
+
"https://example.com/path/0",
|
112
|
+
"https://example.com/path/1",
|
113
|
+
"https://example.com/path/2",
|
114
|
+
];
|
115
|
+
const baseUri = getBaseUriFromBatch(batchOfUris);
|
116
|
+
expect(baseUri).toMatchInlineSnapshot(`"https://example.com/path/"`);
|
117
|
+
});
|
118
|
+
|
119
|
+
it("should work with a custom domain and path with trailing slash", () => {
|
120
|
+
const batchOfUris = [
|
121
|
+
"https://example.com/path/0/",
|
122
|
+
"https://example.com/path/1/",
|
123
|
+
"https://example.com/path/2/",
|
124
|
+
];
|
125
|
+
const baseUri = getBaseUriFromBatch(batchOfUris);
|
126
|
+
expect(baseUri).toMatchInlineSnapshot(`"https://example.com/path/"`);
|
127
|
+
});
|
128
|
+
});
|
package/src/utils/ipfs.ts
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
import type { ThirdwebClient } from "../client/client.js";
|
2
|
-
|
3
2
|
import type { FileOrBufferOrString } from "../storage/upload/types.js";
|
4
3
|
|
5
4
|
export type ResolveSchemeOptions = {
|
@@ -109,23 +108,32 @@ export async function uploadOrExtractURIs<
|
|
109
108
|
* @internal
|
110
109
|
*/
|
111
110
|
export function getBaseUriFromBatch(uris: string[]): string {
|
112
|
-
const
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
111
|
+
const [base, ...rest] = uris.map((uri) => {
|
112
|
+
// remove query parameters
|
113
|
+
// biome-ignore lint/style/noParameterAssign: lemme do my stuff
|
114
|
+
[uri] = uri.split("?") as [string];
|
115
|
+
// remove fragments
|
116
|
+
// biome-ignore lint/style/noParameterAssign: lemme do my stuff
|
117
|
+
[uri] = uri.split("#") as [string];
|
118
|
+
|
119
|
+
// if the URI ends with a `/`, remove it
|
120
|
+
if (uri.endsWith("/")) {
|
121
|
+
// biome-ignore lint/style/noParameterAssign: lemme do my stuff
|
122
|
+
uri = uri.slice(0, -1);
|
120
123
|
}
|
121
|
-
}
|
122
124
|
|
123
|
-
|
124
|
-
|
125
|
+
// remove the last part of the URI & add the trailing `/`
|
126
|
+
return `${uri.split("/").slice(0, -1).join("/")}/`;
|
127
|
+
});
|
128
|
+
|
129
|
+
if (!base) {
|
130
|
+
throw new Error("Batch of URIs is empty");
|
125
131
|
}
|
126
132
|
|
127
|
-
|
128
|
-
|
133
|
+
if (rest.some((uri) => uri !== base)) {
|
134
|
+
throw new Error("All URIs in the batch must have the same base URI");
|
135
|
+
}
|
136
|
+
return base;
|
129
137
|
}
|
130
138
|
|
131
139
|
function isUriList<T extends FileOrBufferOrString | Record<string, unknown>>(
|