thirdweb 5.116.0 → 5.116.2-nightly-151127d66825365cb0ed949ae28b9906ee4dfc8d-20251213000343
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/react/core/hooks/x402/useFetchWithPaymentCore.js +5 -1
- package/dist/cjs/react/core/hooks/x402/useFetchWithPaymentCore.js.map +1 -1
- package/dist/cjs/react/native/hooks/x402/useFetchWithPayment.js +6 -1
- package/dist/cjs/react/native/hooks/x402/useFetchWithPayment.js.map +1 -1
- package/dist/cjs/react/web/hooks/x402/useFetchWithPayment.js +7 -1
- package/dist/cjs/react/web/hooks/x402/useFetchWithPayment.js.map +1 -1
- package/dist/cjs/react/web/ui/Bridge/swap-widget/swap-ui.js +20 -0
- package/dist/cjs/react/web/ui/Bridge/swap-widget/swap-ui.js.map +1 -1
- package/dist/cjs/react/web/ui/Bridge/swap-widget/use-bridge-chains.js +15 -2
- package/dist/cjs/react/web/ui/Bridge/swap-widget/use-bridge-chains.js.map +1 -1
- package/dist/cjs/react/web/ui/ConnectWallet/WalletEntryButton.js +16 -2
- package/dist/cjs/react/web/ui/ConnectWallet/WalletEntryButton.js.map +1 -1
- package/dist/cjs/react/web/ui/ConnectWallet/icons/EmailIcon.js +1 -4
- package/dist/cjs/react/web/ui/ConnectWallet/icons/EmailIcon.js.map +1 -1
- package/dist/cjs/react/web/ui/ConnectWallet/icons/WalletDotIcon.js +1 -1
- package/dist/cjs/react/web/ui/ConnectWallet/icons/WalletDotIcon.js.map +1 -1
- package/dist/cjs/react/web/ui/ConnectWallet/in-app-wallet-icon.js +101 -0
- package/dist/cjs/react/web/ui/ConnectWallet/in-app-wallet-icon.js.map +1 -0
- package/dist/cjs/react/web/ui/components/Spinner.js +7 -7
- package/dist/cjs/react/web/ui/components/Spinner.js.map +1 -1
- package/dist/cjs/react/web/ui/design-system/elements.js +1 -2
- package/dist/cjs/react/web/ui/design-system/elements.js.map +1 -1
- package/dist/cjs/react/web/wallets/shared/ConnectWalletSocialOptions.js +4 -4
- package/dist/cjs/react/web/wallets/shared/ConnectWalletSocialOptions.js.map +1 -1
- package/dist/cjs/react/web/wallets/shared/OTPLoginUI.js +13 -7
- package/dist/cjs/react/web/wallets/shared/OTPLoginUI.js.map +1 -1
- package/dist/cjs/stories/ConnectEmbed.stories.js +34 -0
- package/dist/cjs/stories/ConnectEmbed.stories.js.map +1 -1
- package/dist/cjs/stories/in-app-wallet-icon.stories.js +59 -0
- package/dist/cjs/stories/in-app-wallet-icon.stories.js.map +1 -0
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/version.js.map +1 -1
- package/dist/cjs/wallets/in-app/web/lib/auth/otp.js +12 -1
- package/dist/cjs/wallets/in-app/web/lib/auth/otp.js.map +1 -1
- package/dist/cjs/x402/fetchWithPayment.js +13 -1
- package/dist/cjs/x402/fetchWithPayment.js.map +1 -1
- package/dist/cjs/x402/permitSignatureStorage.js +70 -0
- package/dist/cjs/x402/permitSignatureStorage.js.map +1 -0
- package/dist/cjs/x402/sign.js +51 -4
- package/dist/cjs/x402/sign.js.map +1 -1
- package/dist/esm/react/core/hooks/x402/useFetchWithPaymentCore.js +5 -1
- package/dist/esm/react/core/hooks/x402/useFetchWithPaymentCore.js.map +1 -1
- package/dist/esm/react/native/hooks/x402/useFetchWithPayment.js +6 -1
- package/dist/esm/react/native/hooks/x402/useFetchWithPayment.js.map +1 -1
- package/dist/esm/react/web/hooks/x402/useFetchWithPayment.js +8 -2
- package/dist/esm/react/web/hooks/x402/useFetchWithPayment.js.map +1 -1
- package/dist/esm/react/web/ui/Bridge/swap-widget/swap-ui.js +20 -0
- package/dist/esm/react/web/ui/Bridge/swap-widget/swap-ui.js.map +1 -1
- package/dist/esm/react/web/ui/Bridge/swap-widget/use-bridge-chains.js +15 -2
- package/dist/esm/react/web/ui/Bridge/swap-widget/use-bridge-chains.js.map +1 -1
- package/dist/esm/react/web/ui/ConnectWallet/WalletEntryButton.js +16 -2
- package/dist/esm/react/web/ui/ConnectWallet/WalletEntryButton.js.map +1 -1
- package/dist/esm/react/web/ui/ConnectWallet/icons/EmailIcon.js +1 -4
- package/dist/esm/react/web/ui/ConnectWallet/icons/EmailIcon.js.map +1 -1
- package/dist/esm/react/web/ui/ConnectWallet/icons/WalletDotIcon.js +1 -1
- package/dist/esm/react/web/ui/ConnectWallet/icons/WalletDotIcon.js.map +1 -1
- package/dist/esm/react/web/ui/ConnectWallet/in-app-wallet-icon.js +98 -0
- package/dist/esm/react/web/ui/ConnectWallet/in-app-wallet-icon.js.map +1 -0
- package/dist/esm/react/web/ui/components/Spinner.js +9 -9
- package/dist/esm/react/web/ui/components/Spinner.js.map +1 -1
- package/dist/esm/react/web/ui/design-system/elements.js +0 -1
- package/dist/esm/react/web/ui/design-system/elements.js.map +1 -1
- package/dist/esm/react/web/wallets/shared/ConnectWalletSocialOptions.js +1 -1
- package/dist/esm/react/web/wallets/shared/ConnectWalletSocialOptions.js.map +1 -1
- package/dist/esm/react/web/wallets/shared/OTPLoginUI.js +13 -7
- package/dist/esm/react/web/wallets/shared/OTPLoginUI.js.map +1 -1
- package/dist/esm/stories/ConnectEmbed.stories.js +31 -0
- package/dist/esm/stories/ConnectEmbed.stories.js.map +1 -1
- package/dist/esm/stories/in-app-wallet-icon.stories.js +55 -0
- package/dist/esm/stories/in-app-wallet-icon.stories.js.map +1 -0
- package/dist/esm/version.js +1 -1
- package/dist/esm/version.js.map +1 -1
- package/dist/esm/wallets/in-app/web/lib/auth/otp.js +12 -1
- package/dist/esm/wallets/in-app/web/lib/auth/otp.js.map +1 -1
- package/dist/esm/x402/fetchWithPayment.js +13 -1
- package/dist/esm/x402/fetchWithPayment.js.map +1 -1
- package/dist/esm/x402/permitSignatureStorage.js +65 -0
- package/dist/esm/x402/permitSignatureStorage.js.map +1 -0
- package/dist/esm/x402/sign.js +51 -4
- package/dist/esm/x402/sign.js.map +1 -1
- package/dist/scripts/bridge-widget.js +113 -112
- package/dist/types/react/core/hooks/x402/useFetchWithPaymentCore.d.ts +6 -0
- package/dist/types/react/core/hooks/x402/useFetchWithPaymentCore.d.ts.map +1 -1
- package/dist/types/react/native/hooks/x402/useFetchWithPayment.d.ts +1 -0
- package/dist/types/react/native/hooks/x402/useFetchWithPayment.d.ts.map +1 -1
- package/dist/types/react/web/hooks/x402/useFetchWithPayment.d.ts.map +1 -1
- package/dist/types/react/web/ui/Bridge/swap-widget/swap-ui.d.ts.map +1 -1
- package/dist/types/react/web/ui/Bridge/swap-widget/use-bridge-chains.d.ts +1 -2
- package/dist/types/react/web/ui/Bridge/swap-widget/use-bridge-chains.d.ts.map +1 -1
- package/dist/types/react/web/ui/ConnectWallet/WalletEntryButton.d.ts.map +1 -1
- package/dist/types/react/web/ui/ConnectWallet/icons/EmailIcon.d.ts +0 -3
- package/dist/types/react/web/ui/ConnectWallet/icons/EmailIcon.d.ts.map +1 -1
- package/dist/types/react/web/ui/ConnectWallet/icons/WalletDotIcon.d.ts.map +1 -1
- package/dist/types/react/web/ui/ConnectWallet/in-app-wallet-icon.d.ts +7 -0
- package/dist/types/react/web/ui/ConnectWallet/in-app-wallet-icon.d.ts.map +1 -0
- package/dist/types/react/web/ui/components/Spinner.d.ts.map +1 -1
- package/dist/types/react/web/ui/design-system/elements.d.ts +0 -4
- package/dist/types/react/web/ui/design-system/elements.d.ts.map +1 -1
- package/dist/types/react/web/wallets/shared/ConnectWalletSocialOptions.d.ts +2 -1
- package/dist/types/react/web/wallets/shared/ConnectWalletSocialOptions.d.ts.map +1 -1
- package/dist/types/react/web/wallets/shared/OTPLoginUI.d.ts.map +1 -1
- package/dist/types/stories/ConnectEmbed.stories.d.ts +3 -0
- package/dist/types/stories/ConnectEmbed.stories.d.ts.map +1 -1
- package/dist/types/stories/in-app-wallet-icon.stories.d.ts +10 -0
- package/dist/types/stories/in-app-wallet-icon.stories.d.ts.map +1 -0
- package/dist/types/version.d.ts +1 -1
- package/dist/types/version.d.ts.map +1 -1
- package/dist/types/wallets/in-app/web/lib/auth/otp.d.ts.map +1 -1
- package/dist/types/x402/fetchWithPayment.d.ts +6 -0
- package/dist/types/x402/fetchWithPayment.d.ts.map +1 -1
- package/dist/types/x402/permitSignatureStorage.d.ts +43 -0
- package/dist/types/x402/permitSignatureStorage.d.ts.map +1 -0
- package/dist/types/x402/sign.d.ts +3 -1
- package/dist/types/x402/sign.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/react/core/hooks/x402/useFetchWithPaymentCore.ts +11 -1
- package/src/react/native/hooks/x402/useFetchWithPayment.ts +6 -1
- package/src/react/web/hooks/x402/useFetchWithPayment.tsx +12 -2
- package/src/react/web/ui/Bridge/swap-widget/swap-ui.tsx +26 -0
- package/src/react/web/ui/Bridge/swap-widget/use-bridge-chains.ts +19 -2
- package/src/react/web/ui/ConnectWallet/WalletEntryButton.tsx +23 -2
- package/src/react/web/ui/ConnectWallet/icons/EmailIcon.tsx +12 -19
- package/src/react/web/ui/ConnectWallet/icons/WalletDotIcon.tsx +1 -0
- package/src/react/web/ui/ConnectWallet/in-app-wallet-icon.tsx +195 -0
- package/src/react/web/ui/components/Spinner.tsx +9 -9
- package/src/react/web/ui/design-system/elements.ts +0 -1
- package/src/react/web/wallets/shared/ConnectWalletSocialOptions.tsx +1 -1
- package/src/react/web/wallets/shared/OTPLoginUI.tsx +24 -11
- package/src/stories/ConnectEmbed.stories.tsx +55 -0
- package/src/stories/in-app-wallet-icon.stories.tsx +163 -0
- package/src/version.ts +1 -1
- package/src/wallets/in-app/web/lib/auth/otp.ts +11 -1
- package/src/x402/fetchWithPayment.ts +21 -0
- package/src/x402/permitSignatureStorage.ts +99 -0
- package/src/x402/sign.ts +76 -1
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import type { ThirdwebClient } from "../../../../client/client.js";
|
|
3
|
+
import type { Wallet } from "../../../../wallets/interfaces/wallet.js";
|
|
4
|
+
import type { AuthOption } from "../../../../wallets/types.js";
|
|
5
|
+
import { useCustomTheme } from "../../../core/design-system/CustomThemeProvider.js";
|
|
6
|
+
import {
|
|
7
|
+
iconSize,
|
|
8
|
+
radius,
|
|
9
|
+
spacing,
|
|
10
|
+
} from "../../../core/design-system/index.js";
|
|
11
|
+
import { socialIcons } from "../../../core/utils/walletIcon.js";
|
|
12
|
+
import { defaultAuthOptions } from "../../wallets/shared/ConnectWalletSocialOptions.js";
|
|
13
|
+
import { Img } from "../components/Img.js";
|
|
14
|
+
import { EmailIcon } from "./icons/EmailIcon.js";
|
|
15
|
+
import { FingerPrintIcon } from "./icons/FingerPrintIcon.js";
|
|
16
|
+
import { GuestIcon } from "./icons/GuestIcon.js";
|
|
17
|
+
import { PhoneIcon } from "./icons/PhoneIcon.js";
|
|
18
|
+
|
|
19
|
+
export function InAppWalletIcon(props: {
|
|
20
|
+
client: ThirdwebClient;
|
|
21
|
+
wallet: Wallet<"inApp">;
|
|
22
|
+
}) {
|
|
23
|
+
const enabledAuthMethods = (
|
|
24
|
+
props.wallet.getConfig()?.auth?.options || defaultAuthOptions
|
|
25
|
+
)
|
|
26
|
+
.slice() // clone
|
|
27
|
+
.sort((a, b) => {
|
|
28
|
+
if (a in socialIcons && !(b in socialIcons)) {
|
|
29
|
+
return -1;
|
|
30
|
+
}
|
|
31
|
+
if (!(a in socialIcons) && b in socialIcons) {
|
|
32
|
+
return 1;
|
|
33
|
+
}
|
|
34
|
+
return 0;
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const theme = useCustomTheme();
|
|
38
|
+
|
|
39
|
+
const firstMethod = enabledAuthMethods[0];
|
|
40
|
+
const secondMethod = enabledAuthMethods[1];
|
|
41
|
+
const thirdMethod = enabledAuthMethods[2];
|
|
42
|
+
const fourthMethod = enabledAuthMethods[3];
|
|
43
|
+
|
|
44
|
+
const offset = "4px";
|
|
45
|
+
const offset2 = "6px";
|
|
46
|
+
const smallIconSize = "20";
|
|
47
|
+
const extraIconSize = "12";
|
|
48
|
+
|
|
49
|
+
if (firstMethod && secondMethod) {
|
|
50
|
+
return (
|
|
51
|
+
<div
|
|
52
|
+
style={{
|
|
53
|
+
width: `${iconSize.xl}px`,
|
|
54
|
+
height: `${iconSize.xl}px`,
|
|
55
|
+
position: "relative",
|
|
56
|
+
gap: spacing["3xs"],
|
|
57
|
+
border: `1px solid ${theme.colors.borderColor}`,
|
|
58
|
+
borderRadius: radius.md,
|
|
59
|
+
backgroundColor: theme.colors.tertiaryBg,
|
|
60
|
+
}}
|
|
61
|
+
>
|
|
62
|
+
<div
|
|
63
|
+
style={{
|
|
64
|
+
position: "absolute",
|
|
65
|
+
top: offset,
|
|
66
|
+
left: offset,
|
|
67
|
+
display: "flex",
|
|
68
|
+
}}
|
|
69
|
+
>
|
|
70
|
+
<AuthOptionIcon
|
|
71
|
+
authOption={firstMethod}
|
|
72
|
+
client={props.client}
|
|
73
|
+
size={smallIconSize}
|
|
74
|
+
/>
|
|
75
|
+
</div>
|
|
76
|
+
|
|
77
|
+
<div
|
|
78
|
+
style={{
|
|
79
|
+
position: "absolute",
|
|
80
|
+
bottom: offset,
|
|
81
|
+
right: offset,
|
|
82
|
+
display: "flex",
|
|
83
|
+
}}
|
|
84
|
+
>
|
|
85
|
+
<AuthOptionIcon
|
|
86
|
+
authOption={secondMethod}
|
|
87
|
+
client={props.client}
|
|
88
|
+
size={smallIconSize}
|
|
89
|
+
/>
|
|
90
|
+
</div>
|
|
91
|
+
|
|
92
|
+
<div>
|
|
93
|
+
{thirdMethod && (
|
|
94
|
+
<div
|
|
95
|
+
style={{
|
|
96
|
+
position: "absolute",
|
|
97
|
+
top: offset2,
|
|
98
|
+
right: offset2,
|
|
99
|
+
display: "flex",
|
|
100
|
+
}}
|
|
101
|
+
>
|
|
102
|
+
<AuthOptionIcon
|
|
103
|
+
authOption={thirdMethod}
|
|
104
|
+
client={props.client}
|
|
105
|
+
size={extraIconSize}
|
|
106
|
+
/>
|
|
107
|
+
</div>
|
|
108
|
+
)}
|
|
109
|
+
|
|
110
|
+
{fourthMethod && (
|
|
111
|
+
<div
|
|
112
|
+
style={{
|
|
113
|
+
position: "absolute",
|
|
114
|
+
bottom: offset2,
|
|
115
|
+
left: offset2,
|
|
116
|
+
display: "flex",
|
|
117
|
+
}}
|
|
118
|
+
>
|
|
119
|
+
<AuthOptionIcon
|
|
120
|
+
authOption={fourthMethod}
|
|
121
|
+
client={props.client}
|
|
122
|
+
size={extraIconSize}
|
|
123
|
+
/>
|
|
124
|
+
</div>
|
|
125
|
+
)}
|
|
126
|
+
</div>
|
|
127
|
+
</div>
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (firstMethod) {
|
|
132
|
+
return (
|
|
133
|
+
<div
|
|
134
|
+
style={{
|
|
135
|
+
width: `${iconSize.xl}px`,
|
|
136
|
+
height: `${iconSize.xl}px`,
|
|
137
|
+
display: "flex",
|
|
138
|
+
justifyContent: "center",
|
|
139
|
+
alignItems: "center",
|
|
140
|
+
border: `1px solid ${theme.colors.borderColor}`,
|
|
141
|
+
borderRadius: radius.md,
|
|
142
|
+
backgroundColor: theme.colors.tertiaryBg,
|
|
143
|
+
}}
|
|
144
|
+
>
|
|
145
|
+
<AuthOptionIcon
|
|
146
|
+
authOption={firstMethod}
|
|
147
|
+
client={props.client}
|
|
148
|
+
key={firstMethod}
|
|
149
|
+
size={iconSize.lg}
|
|
150
|
+
/>
|
|
151
|
+
</div>
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function AuthOptionIcon(props: {
|
|
159
|
+
authOption: AuthOption;
|
|
160
|
+
client: ThirdwebClient;
|
|
161
|
+
size: string;
|
|
162
|
+
}) {
|
|
163
|
+
const theme = useCustomTheme();
|
|
164
|
+
if (props.authOption in socialIcons) {
|
|
165
|
+
const icon = socialIcons[props.authOption as keyof typeof socialIcons];
|
|
166
|
+
return (
|
|
167
|
+
<Img
|
|
168
|
+
src={icon}
|
|
169
|
+
width={props.size}
|
|
170
|
+
height={props.size}
|
|
171
|
+
client={props.client}
|
|
172
|
+
/>
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (props.authOption === "phone") {
|
|
177
|
+
return <PhoneIcon size={props.size} color={theme.colors.secondaryText} />;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (props.authOption === "email") {
|
|
181
|
+
return <EmailIcon size={props.size} color={theme.colors.secondaryText} />;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (props.authOption === "passkey") {
|
|
185
|
+
return (
|
|
186
|
+
<FingerPrintIcon size={props.size} color={theme.colors.secondaryText} />
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (props.authOption === "guest") {
|
|
191
|
+
return <GuestIcon size={props.size} color={theme.colors.secondaryText} />;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
@@ -3,7 +3,7 @@ import { keyframes } from "@emotion/react";
|
|
|
3
3
|
import { useCustomTheme } from "../../../core/design-system/CustomThemeProvider.js";
|
|
4
4
|
import type { Theme } from "../../../core/design-system/index.js";
|
|
5
5
|
import { iconSize } from "../../../core/design-system/index.js";
|
|
6
|
-
import {
|
|
6
|
+
import { StyledSvg } from "../design-system/elements.js";
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* @internal
|
|
@@ -24,20 +24,25 @@ export const Spinner: React.FC<{
|
|
|
24
24
|
viewBox="0 0 50 50"
|
|
25
25
|
className="tw-spinner"
|
|
26
26
|
>
|
|
27
|
-
<
|
|
27
|
+
<circle
|
|
28
28
|
cx="25"
|
|
29
29
|
cy="25"
|
|
30
30
|
fill="none"
|
|
31
31
|
r="20"
|
|
32
|
+
style={{
|
|
33
|
+
strokeLinecap: "round",
|
|
34
|
+
animation: `tw-spinner-circle-dash 1.5s ease-in-out infinite`,
|
|
35
|
+
}}
|
|
32
36
|
stroke={props.color ? theme.colors[props.color] : "currentColor"}
|
|
33
37
|
strokeWidth={Number(iconSize[props.size]) > 64 ? "2" : "4"}
|
|
34
38
|
/>
|
|
39
|
+
<style>{dashAnimation}</style>
|
|
35
40
|
</Svg>
|
|
36
41
|
);
|
|
37
42
|
};
|
|
38
|
-
|
|
39
43
|
// animations
|
|
40
|
-
const dashAnimation =
|
|
44
|
+
const dashAnimation = `
|
|
45
|
+
@keyframes tw-spinner-circle-dash {
|
|
41
46
|
0% {
|
|
42
47
|
stroke-dasharray: 1, 150;
|
|
43
48
|
stroke-dashoffset: 0;
|
|
@@ -63,8 +68,3 @@ const Svg = /* @__PURE__ */ StyledSvg({
|
|
|
63
68
|
height: "1em",
|
|
64
69
|
width: "1em",
|
|
65
70
|
});
|
|
66
|
-
|
|
67
|
-
const Circle = /* @__PURE__ */ StyledCircle({
|
|
68
|
-
animation: `${dashAnimation} 1.5s ease-in-out infinite`,
|
|
69
|
-
strokeLinecap: "round",
|
|
70
|
-
});
|
|
@@ -2,7 +2,6 @@ import styled from "@emotion/styled";
|
|
|
2
2
|
|
|
3
3
|
export const StyledDiv = /* @__PURE__ */ styled.div;
|
|
4
4
|
export const StyledSvg = /* @__PURE__ */ styled.svg;
|
|
5
|
-
export const StyledCircle = /* @__PURE__ */ styled.circle;
|
|
6
5
|
export const StyledSpan = /* @__PURE__ */ styled.span;
|
|
7
6
|
export const StyledAnchor = /* @__PURE__ */ styled.a;
|
|
8
7
|
export const StyledButton = /* @__PURE__ */ styled.button;
|
|
@@ -29,7 +29,10 @@ type VerificationStatus =
|
|
|
29
29
|
| "valid"
|
|
30
30
|
| "idle"
|
|
31
31
|
| "payment_required";
|
|
32
|
-
type AccountStatus =
|
|
32
|
+
type AccountStatus =
|
|
33
|
+
| { type: "sending" }
|
|
34
|
+
| { type: "sent" }
|
|
35
|
+
| { type: "error"; message: string | undefined };
|
|
33
36
|
type ScreenToShow = "base" | "enter-password-or-recovery-code";
|
|
34
37
|
|
|
35
38
|
/**
|
|
@@ -52,7 +55,9 @@ export function OTPLoginUI(props: {
|
|
|
52
55
|
const [otpInput, setOtpInput] = useState("");
|
|
53
56
|
const [verifyStatus, setVerifyStatus] = useState<VerificationStatus>("idle");
|
|
54
57
|
const [error, setError] = useState<string | undefined>();
|
|
55
|
-
const [accountStatus, setAccountStatus] = useState<AccountStatus>(
|
|
58
|
+
const [accountStatus, setAccountStatus] = useState<AccountStatus>({
|
|
59
|
+
type: "sending",
|
|
60
|
+
});
|
|
56
61
|
const [countdown, setCountdown] = useState(0);
|
|
57
62
|
const ecosystem = isEcosystemWallet(wallet)
|
|
58
63
|
? {
|
|
@@ -66,7 +71,7 @@ export function OTPLoginUI(props: {
|
|
|
66
71
|
const sendEmailOrSms = useCallback(async () => {
|
|
67
72
|
setOtpInput("");
|
|
68
73
|
setVerifyStatus("idle");
|
|
69
|
-
setAccountStatus("sending");
|
|
74
|
+
setAccountStatus({ type: "sending" });
|
|
70
75
|
|
|
71
76
|
try {
|
|
72
77
|
if ("email" in userInfo) {
|
|
@@ -76,7 +81,7 @@ export function OTPLoginUI(props: {
|
|
|
76
81
|
email: userInfo.email,
|
|
77
82
|
strategy: "email",
|
|
78
83
|
});
|
|
79
|
-
setAccountStatus("sent");
|
|
84
|
+
setAccountStatus({ type: "sent" });
|
|
80
85
|
setCountdown(60); // Start 60-second countdown
|
|
81
86
|
} else if ("phone" in userInfo) {
|
|
82
87
|
await preAuthenticate({
|
|
@@ -85,7 +90,7 @@ export function OTPLoginUI(props: {
|
|
|
85
90
|
phoneNumber: userInfo.phone,
|
|
86
91
|
strategy: "phone",
|
|
87
92
|
});
|
|
88
|
-
setAccountStatus("sent");
|
|
93
|
+
setAccountStatus({ type: "sent" });
|
|
89
94
|
setCountdown(60); // Start 60-second countdown
|
|
90
95
|
} else {
|
|
91
96
|
throw new Error("Invalid userInfo");
|
|
@@ -93,7 +98,10 @@ export function OTPLoginUI(props: {
|
|
|
93
98
|
} catch (e) {
|
|
94
99
|
console.error(e);
|
|
95
100
|
setVerifyStatus("idle");
|
|
96
|
-
setAccountStatus(
|
|
101
|
+
setAccountStatus({
|
|
102
|
+
type: "error",
|
|
103
|
+
message: e instanceof Error ? e.message : undefined,
|
|
104
|
+
});
|
|
97
105
|
}
|
|
98
106
|
}, [props.client, userInfo, ecosystem]);
|
|
99
107
|
|
|
@@ -317,19 +325,24 @@ export function OTPLoginUI(props: {
|
|
|
317
325
|
|
|
318
326
|
{!isWideModal && <Line />}
|
|
319
327
|
|
|
320
|
-
<Container
|
|
321
|
-
|
|
328
|
+
<Container
|
|
329
|
+
gap="sm"
|
|
330
|
+
p={isWideModal ? undefined : "lg"}
|
|
331
|
+
flex="column"
|
|
332
|
+
>
|
|
333
|
+
{accountStatus.type === "error" && (
|
|
322
334
|
<Text
|
|
323
335
|
center
|
|
324
336
|
color="danger"
|
|
325
337
|
size="sm"
|
|
326
338
|
className="tw-screen-error"
|
|
327
339
|
>
|
|
328
|
-
{
|
|
340
|
+
{accountStatus.message ||
|
|
341
|
+
locale.emailLoginScreen.failedToSendCode}
|
|
329
342
|
</Text>
|
|
330
343
|
)}
|
|
331
344
|
|
|
332
|
-
{accountStatus === "sending" && (
|
|
345
|
+
{accountStatus.type === "sending" && (
|
|
333
346
|
<Container
|
|
334
347
|
center="both"
|
|
335
348
|
flex="row"
|
|
@@ -343,7 +356,7 @@ export function OTPLoginUI(props: {
|
|
|
343
356
|
</Container>
|
|
344
357
|
)}
|
|
345
358
|
|
|
346
|
-
{accountStatus !== "sending" && (
|
|
359
|
+
{accountStatus.type !== "sending" && (
|
|
347
360
|
<LinkButton
|
|
348
361
|
onClick={countdown === 0 ? sendEmailOrSms : undefined}
|
|
349
362
|
style={{
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Meta } from "@storybook/react";
|
|
2
2
|
import { ConnectButton } from "../react/web/ui/ConnectWallet/ConnectButton.js";
|
|
3
3
|
import { ConnectEmbed } from "../react/web/ui/ConnectWallet/Modal/ConnectEmbed.js";
|
|
4
|
+
import { createWallet } from "../wallets/create-wallet.js";
|
|
4
5
|
import { ecosystemWallet } from "../wallets/in-app/web/ecosystem.js";
|
|
5
6
|
import { inAppWallet } from "../wallets/in-app/web/in-app.js";
|
|
6
7
|
import { storyClient } from "./utils.js";
|
|
@@ -110,6 +111,60 @@ export function AllInAppWalletAuthMethods() {
|
|
|
110
111
|
);
|
|
111
112
|
}
|
|
112
113
|
|
|
114
|
+
export function ConfiguredInAppWalletWideModal() {
|
|
115
|
+
return (
|
|
116
|
+
<ConnectEmbed
|
|
117
|
+
client={storyClient}
|
|
118
|
+
className="foo-bar"
|
|
119
|
+
modalSize="wide"
|
|
120
|
+
wallets={[
|
|
121
|
+
createWallet("io.metamask"),
|
|
122
|
+
inAppWallet({
|
|
123
|
+
auth: {
|
|
124
|
+
options: ["google", "github", "email"],
|
|
125
|
+
},
|
|
126
|
+
}),
|
|
127
|
+
]}
|
|
128
|
+
/>
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function GoogleLoginWideModal() {
|
|
133
|
+
return (
|
|
134
|
+
<ConnectEmbed
|
|
135
|
+
client={storyClient}
|
|
136
|
+
className="foo-bar"
|
|
137
|
+
modalSize="wide"
|
|
138
|
+
wallets={[
|
|
139
|
+
createWallet("io.metamask"),
|
|
140
|
+
inAppWallet({
|
|
141
|
+
auth: {
|
|
142
|
+
options: ["google"],
|
|
143
|
+
},
|
|
144
|
+
}),
|
|
145
|
+
]}
|
|
146
|
+
/>
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function GithubLoginWideModal() {
|
|
151
|
+
return (
|
|
152
|
+
<ConnectEmbed
|
|
153
|
+
client={storyClient}
|
|
154
|
+
className="foo-bar"
|
|
155
|
+
modalSize="wide"
|
|
156
|
+
wallets={[
|
|
157
|
+
createWallet("io.metamask"),
|
|
158
|
+
inAppWallet({
|
|
159
|
+
auth: {
|
|
160
|
+
options: ["github"],
|
|
161
|
+
},
|
|
162
|
+
}),
|
|
163
|
+
]}
|
|
164
|
+
/>
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
113
168
|
export function EcosystemWallet() {
|
|
114
169
|
return (
|
|
115
170
|
<ConnectEmbed
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import type { Meta } from "@storybook/react";
|
|
2
|
+
import {
|
|
3
|
+
CustomThemeProvider,
|
|
4
|
+
useCustomTheme,
|
|
5
|
+
} from "../react/core/design-system/CustomThemeProvider.js";
|
|
6
|
+
import { InAppWalletIcon } from "../react/web/ui/ConnectWallet/in-app-wallet-icon.js";
|
|
7
|
+
import { defaultAuthOptions } from "../react/web/wallets/shared/ConnectWalletSocialOptions.js";
|
|
8
|
+
import { inAppWallet } from "../wallets/in-app/web/in-app.js";
|
|
9
|
+
import type { AuthOption } from "../wallets/types.js";
|
|
10
|
+
import { storyClient } from "./utils.js";
|
|
11
|
+
|
|
12
|
+
const meta: Meta<typeof Variant> = {
|
|
13
|
+
title: "Components/in-app-wallet-icon",
|
|
14
|
+
decorators: [
|
|
15
|
+
(Story) => {
|
|
16
|
+
return (
|
|
17
|
+
<CustomThemeProvider theme="dark">
|
|
18
|
+
<Story />
|
|
19
|
+
</CustomThemeProvider>
|
|
20
|
+
);
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
};
|
|
24
|
+
export default meta;
|
|
25
|
+
|
|
26
|
+
function Variants() {
|
|
27
|
+
const theme = useCustomTheme();
|
|
28
|
+
return (
|
|
29
|
+
<div
|
|
30
|
+
style={{
|
|
31
|
+
backgroundColor: theme.colors.modalBg,
|
|
32
|
+
padding: "14px",
|
|
33
|
+
borderRadius: "10px",
|
|
34
|
+
display: "flex",
|
|
35
|
+
flexDirection: "column",
|
|
36
|
+
gap: "12px",
|
|
37
|
+
}}
|
|
38
|
+
>
|
|
39
|
+
<div>
|
|
40
|
+
<SectionTitle title="Default" />
|
|
41
|
+
<Variant authOptions={defaultAuthOptions} />
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
<div>
|
|
45
|
+
<SectionTitle title="Single method enabled" />
|
|
46
|
+
<div style={{ display: "flex", gap: "10px", flexWrap: "wrap" }}>
|
|
47
|
+
<Variant authOptions={["email"]} />
|
|
48
|
+
<Variant authOptions={["phone"]} />
|
|
49
|
+
<Variant authOptions={["passkey"]} />
|
|
50
|
+
<Variant authOptions={["guest"]} />
|
|
51
|
+
<Variant authOptions={["google"]} />
|
|
52
|
+
<Variant authOptions={["apple"]} />
|
|
53
|
+
<Variant authOptions={["facebook"]} />
|
|
54
|
+
<Variant authOptions={["discord"]} />
|
|
55
|
+
<Variant authOptions={["github"]} />
|
|
56
|
+
<Variant authOptions={["twitch"]} />
|
|
57
|
+
<Variant authOptions={["x"]} />
|
|
58
|
+
<Variant authOptions={["telegram"]} />
|
|
59
|
+
<Variant authOptions={["line"]} />
|
|
60
|
+
<Variant authOptions={["coinbase"]} />
|
|
61
|
+
<Variant authOptions={["epic"]} />
|
|
62
|
+
<Variant authOptions={["farcaster"]} />
|
|
63
|
+
<Variant authOptions={["tiktok"]} />
|
|
64
|
+
<Variant authOptions={["steam"]} />
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
<div>
|
|
69
|
+
<SectionTitle title="Two methods enabled" />
|
|
70
|
+
<div style={{ display: "flex", gap: "10px", flexWrap: "wrap" }}>
|
|
71
|
+
<Variant authOptions={["email", "phone"]} />
|
|
72
|
+
<Variant authOptions={["email", "passkey"]} />
|
|
73
|
+
<Variant authOptions={["email", "guest"]} />
|
|
74
|
+
<Variant authOptions={["email", "google"]} />
|
|
75
|
+
<Variant authOptions={["email", "apple"]} />
|
|
76
|
+
<Variant authOptions={["email", "facebook"]} />
|
|
77
|
+
<Variant authOptions={["google", "discord"]} />
|
|
78
|
+
<Variant authOptions={["google", "github"]} />
|
|
79
|
+
<Variant authOptions={["google", "twitch"]} />
|
|
80
|
+
<Variant authOptions={["google", "x"]} />
|
|
81
|
+
<Variant authOptions={["google", "telegram"]} />
|
|
82
|
+
<Variant authOptions={["google", "line"]} />
|
|
83
|
+
<Variant authOptions={["google", "coinbase"]} />
|
|
84
|
+
<Variant authOptions={["google", "epic"]} />
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
|
|
88
|
+
<div>
|
|
89
|
+
<SectionTitle title="Three methods enabled" />
|
|
90
|
+
<div style={{ display: "flex", gap: "10px", flexWrap: "wrap" }}>
|
|
91
|
+
<Variant authOptions={["google", "apple", "github"]} />
|
|
92
|
+
<Variant authOptions={["email", "phone", "guest"]} />
|
|
93
|
+
<Variant authOptions={["email", "phone", "google"]} />
|
|
94
|
+
<Variant authOptions={["email", "phone", "apple"]} />
|
|
95
|
+
<Variant authOptions={["email", "phone", "facebook"]} />
|
|
96
|
+
</div>
|
|
97
|
+
</div>
|
|
98
|
+
|
|
99
|
+
<div>
|
|
100
|
+
<SectionTitle title="Four or more methods enabled" />
|
|
101
|
+
<div style={{ display: "flex", gap: "10px", flexWrap: "wrap" }}>
|
|
102
|
+
<Variant
|
|
103
|
+
authOptions={["email", "phone", "google", "apple", "facebook"]}
|
|
104
|
+
/>
|
|
105
|
+
<Variant authOptions={["epic", "tiktok", "github", "email"]} />
|
|
106
|
+
<Variant
|
|
107
|
+
authOptions={["twitch", "tiktok", "epic", "email", "phone"]}
|
|
108
|
+
/>
|
|
109
|
+
<Variant authOptions={["email", "phone", "passkey", "guest"]} />
|
|
110
|
+
<Variant
|
|
111
|
+
authOptions={[
|
|
112
|
+
"google",
|
|
113
|
+
"apple",
|
|
114
|
+
"facebook",
|
|
115
|
+
"github",
|
|
116
|
+
"discord",
|
|
117
|
+
"twitch",
|
|
118
|
+
"x",
|
|
119
|
+
]}
|
|
120
|
+
/>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
</div>
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function LightTheme() {
|
|
128
|
+
return <ThemeSetup theme="light" />;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function DarkTheme() {
|
|
132
|
+
return <ThemeSetup theme="dark" />;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function ThemeSetup(props: { theme: "light" | "dark" }) {
|
|
136
|
+
return (
|
|
137
|
+
<CustomThemeProvider theme={props.theme}>
|
|
138
|
+
<Variants />
|
|
139
|
+
</CustomThemeProvider>
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function Variant(props: { authOptions: AuthOption[] }) {
|
|
144
|
+
return (
|
|
145
|
+
<InAppWalletIcon
|
|
146
|
+
client={storyClient}
|
|
147
|
+
wallet={inAppWallet({
|
|
148
|
+
auth: {
|
|
149
|
+
options: props.authOptions,
|
|
150
|
+
},
|
|
151
|
+
})}
|
|
152
|
+
/>
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function SectionTitle(props: { title: string }) {
|
|
157
|
+
const theme = useCustomTheme();
|
|
158
|
+
return (
|
|
159
|
+
<p style={{ color: theme.colors.secondaryText, fontSize: "14px" }}>
|
|
160
|
+
{props.title}
|
|
161
|
+
</p>
|
|
162
|
+
);
|
|
163
|
+
}
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = "5.116.
|
|
1
|
+
export const version = "5.116.2-nightly-151127d66825365cb0ed949ae28b9906ee4dfc8d-20251213000343";
|
|
@@ -51,7 +51,17 @@ export const sendOtp = async (args: PreAuthArgsType): Promise<void> => {
|
|
|
51
51
|
});
|
|
52
52
|
|
|
53
53
|
if (!response.ok) {
|
|
54
|
-
|
|
54
|
+
const raw = await response.text();
|
|
55
|
+
let message: string | undefined;
|
|
56
|
+
try {
|
|
57
|
+
const parsed = JSON.parse(raw);
|
|
58
|
+
if (parsed && typeof parsed.message === "string") {
|
|
59
|
+
message = parsed.message;
|
|
60
|
+
}
|
|
61
|
+
} catch {
|
|
62
|
+
// ignore parse errors
|
|
63
|
+
}
|
|
64
|
+
throw new Error(message || "Failed to send verification code");
|
|
55
65
|
}
|
|
56
66
|
|
|
57
67
|
return await response.json();
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { getCachedChain } from "../chains/utils.js";
|
|
2
2
|
import type { ThirdwebClient } from "../client/client.js";
|
|
3
|
+
import { getAddress } from "../utils/address.js";
|
|
4
|
+
import type { AsyncStorage } from "../utils/storage/AsyncStorage.js";
|
|
5
|
+
import { webLocalStorage } from "../utils/storage/webStorage.js";
|
|
3
6
|
import type { Wallet } from "../wallets/interfaces/wallet.js";
|
|
7
|
+
import { clearPermitSignatureFromCache } from "./permitSignatureStorage.js";
|
|
4
8
|
import {
|
|
5
9
|
extractEvmChainId,
|
|
6
10
|
networkToCaip2ChainId,
|
|
@@ -57,6 +61,11 @@ export function wrapFetchWithPayment(
|
|
|
57
61
|
paymentRequirementsSelector?: (
|
|
58
62
|
paymentRequirements: RequestedPaymentRequirements[],
|
|
59
63
|
) => RequestedPaymentRequirements | undefined;
|
|
64
|
+
/**
|
|
65
|
+
* Storage for caching permit signatures (for "upto" scheme).
|
|
66
|
+
* When provided, permit signatures will be cached and reused if the on-chain allowance is sufficient.
|
|
67
|
+
*/
|
|
68
|
+
storage?: AsyncStorage;
|
|
60
69
|
},
|
|
61
70
|
) {
|
|
62
71
|
return async (input: RequestInfo, init?: RequestInit) => {
|
|
@@ -131,6 +140,7 @@ export function wrapFetchWithPayment(
|
|
|
131
140
|
account,
|
|
132
141
|
selectedPaymentRequirements,
|
|
133
142
|
x402Version,
|
|
143
|
+
options?.storage ?? webLocalStorage,
|
|
134
144
|
);
|
|
135
145
|
|
|
136
146
|
const initParams = init || {};
|
|
@@ -150,6 +160,17 @@ export function wrapFetchWithPayment(
|
|
|
150
160
|
};
|
|
151
161
|
|
|
152
162
|
const secondResponse = await fetch(input, newInit);
|
|
163
|
+
|
|
164
|
+
// If payment was rejected (still 402), clear cached signature
|
|
165
|
+
if (secondResponse.status === 402 && options?.storage) {
|
|
166
|
+
await clearPermitSignatureFromCache(options.storage, {
|
|
167
|
+
chainId: paymentChainId,
|
|
168
|
+
asset: selectedPaymentRequirements.asset,
|
|
169
|
+
owner: getAddress(account.address),
|
|
170
|
+
spender: getAddress(selectedPaymentRequirements.payTo),
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
153
174
|
return secondResponse;
|
|
154
175
|
};
|
|
155
176
|
}
|