Skip to content

Commit 5482a43

Browse files
committed
[CORE-683] SDK: automatically sign message for SIWE in connect UI for Ecosystem wallets
1 parent f323f7c commit 5482a43

File tree

3 files changed

+153
-126
lines changed

3 files changed

+153
-126
lines changed

.changeset/six-snails-reflect.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"thirdweb": patch
3+
---
4+
5+
Do not prompt user for signing message for SIWE auth in Connect UI for Ecosystem wallets

packages/thirdweb/src/react/web/ui/ConnectWallet/screens/SignatureScreen.test.tsx

Lines changed: 136 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -148,140 +148,153 @@ describe("SignatureScreen", () => {
148148
});
149149

150150
describe("HeadlessSignIn", () => {
151-
const mockWallet = createWallet("inApp");
152-
beforeEach(() => {
153-
vi.mocked(useActiveWallet).mockReturnValue(mockWallet);
154-
});
155-
156-
it("automatically triggers sign in on mount", async () => {
157-
render(
158-
<SignatureScreen
159-
onDone={() => {}}
160-
modalSize="wide"
161-
connectLocale={mockConnectLocale}
162-
client={TEST_CLIENT}
163-
auth={mockAuth}
164-
/>,
165-
{ setConnectedWallet: true },
166-
);
167-
168-
await waitFor(() => {
169-
expect(mockAuth.doLogin).toHaveBeenCalledTimes(1);
151+
function headlessTests() {
152+
it("automatically triggers sign in on mount", async () => {
153+
render(
154+
<SignatureScreen
155+
onDone={() => {}}
156+
modalSize="wide"
157+
connectLocale={mockConnectLocale}
158+
client={TEST_CLIENT}
159+
auth={mockAuth}
160+
/>,
161+
{ setConnectedWallet: true },
162+
);
163+
164+
await waitFor(() => {
165+
expect(mockAuth.doLogin).toHaveBeenCalledTimes(1);
166+
});
170167
});
171-
});
172168

173-
it("shows signing message during signing state", async () => {
174-
const { getByText } = render(
175-
<SignatureScreen
176-
onDone={() => {}}
177-
modalSize="wide"
178-
connectLocale={mockConnectLocale}
179-
client={TEST_CLIENT}
180-
auth={mockAuth}
181-
/>,
182-
{ setConnectedWallet: true },
183-
);
184-
185-
await waitFor(() => {
186-
expect(getByText("Signing")).toBeInTheDocument();
169+
it("shows signing message during signing state", async () => {
170+
const { getByText } = render(
171+
<SignatureScreen
172+
onDone={() => {}}
173+
modalSize="wide"
174+
connectLocale={mockConnectLocale}
175+
client={TEST_CLIENT}
176+
auth={mockAuth}
177+
/>,
178+
{ setConnectedWallet: true },
179+
);
180+
181+
await waitFor(() => {
182+
expect(getByText("Signing")).toBeInTheDocument();
183+
});
187184
});
188-
});
189185

190-
it("shows error and retry button when signing fails", async () => {
191-
mockAuth.doLogin.mockRejectedValueOnce(
192-
new Error("Headless signing failed"),
193-
);
194-
195-
const { getByText, getByRole } = render(
196-
<SignatureScreen
197-
onDone={() => {}}
198-
modalSize="wide"
199-
connectLocale={mockConnectLocale}
200-
client={TEST_CLIENT}
201-
auth={mockAuth}
202-
/>,
203-
{ setConnectedWallet: true },
204-
);
205-
206-
await waitFor(
207-
() => {
208-
expect(getByText("Headless signing failed")).toBeInTheDocument();
209-
expect(
210-
getByRole("button", { name: "Try Again" }),
211-
).toBeInTheDocument();
212-
},
213-
{ timeout: 2000 },
214-
);
215-
});
186+
it("shows error and retry button when signing fails", async () => {
187+
mockAuth.doLogin.mockRejectedValueOnce(
188+
new Error("Headless signing failed"),
189+
);
190+
191+
const { getByText, getByRole } = render(
192+
<SignatureScreen
193+
onDone={() => {}}
194+
modalSize="wide"
195+
connectLocale={mockConnectLocale}
196+
client={TEST_CLIENT}
197+
auth={mockAuth}
198+
/>,
199+
{ setConnectedWallet: true },
200+
);
201+
202+
await waitFor(
203+
() => {
204+
expect(getByText("Headless signing failed")).toBeInTheDocument();
205+
expect(
206+
getByRole("button", { name: "Try Again" }),
207+
).toBeInTheDocument();
208+
},
209+
{ timeout: 2000 },
210+
);
211+
});
216212

217-
it("allows retry after failure", async () => {
218-
mockAuth.doLogin
219-
.mockRejectedValueOnce(new Error("Failed first time"))
220-
.mockResolvedValueOnce(undefined);
221-
222-
const { getByRole, getByText } = render(
223-
<SignatureScreen
224-
onDone={() => {}}
225-
modalSize="wide"
226-
connectLocale={mockConnectLocale}
227-
client={TEST_CLIENT}
228-
auth={mockAuth}
229-
/>,
230-
{ setConnectedWallet: true },
231-
);
232-
233-
// Wait for initial failure
234-
await waitFor(
235-
() => {
236-
expect(getByText("Failed first time")).toBeInTheDocument();
237-
},
238-
{ timeout: 2000 },
239-
);
240-
241-
// Click retry
242-
const retryButton = getByRole("button", { name: "Try Again" });
243-
await userEvent.click(retryButton);
244-
245-
// Should show loading again
246-
await waitFor(() => {
247-
expect(getByText("Signing")).toBeInTheDocument();
213+
it("allows retry after failure", async () => {
214+
mockAuth.doLogin
215+
.mockRejectedValueOnce(new Error("Failed first time"))
216+
.mockResolvedValueOnce(undefined);
217+
218+
const { getByRole, getByText } = render(
219+
<SignatureScreen
220+
onDone={() => {}}
221+
modalSize="wide"
222+
connectLocale={mockConnectLocale}
223+
client={TEST_CLIENT}
224+
auth={mockAuth}
225+
/>,
226+
{ setConnectedWallet: true },
227+
);
228+
229+
// Wait for initial failure
230+
await waitFor(
231+
() => {
232+
expect(getByText("Failed first time")).toBeInTheDocument();
233+
},
234+
{ timeout: 2000 },
235+
);
236+
237+
// Click retry
238+
const retryButton = getByRole("button", { name: "Try Again" });
239+
await userEvent.click(retryButton);
240+
241+
// Should show loading again
242+
await waitFor(() => {
243+
expect(getByText("Signing")).toBeInTheDocument();
244+
});
245+
246+
// Should have called login twice
247+
expect(mockAuth.doLogin).toHaveBeenCalledTimes(2);
248248
});
249249

250-
// Should have called login twice
251-
expect(mockAuth.doLogin).toHaveBeenCalledTimes(2);
252-
});
250+
it("allows disconnecting wallet after failure", async () => {
251+
const mockDisconnect = vi.fn().mockResolvedValue(undefined);
252+
mockAuth.doLogin.mockRejectedValueOnce(new Error("Failed"));
253+
vi.mocked(useActiveWallet).mockReturnValueOnce({
254+
...createWallet("io.metamask"),
255+
disconnect: mockDisconnect,
256+
});
257+
258+
const { getByTestId } = render(
259+
<SignatureScreen
260+
onDone={() => {}}
261+
modalSize="wide"
262+
connectLocale={mockConnectLocale}
263+
client={TEST_CLIENT}
264+
auth={mockAuth}
265+
/>,
266+
{ setConnectedWallet: true },
267+
);
268+
269+
// Wait for failure and click disconnect
270+
await waitFor(
271+
() => {
272+
return getByTestId("disconnect-button");
273+
},
274+
{ timeout: 2000 },
275+
).then((button) => userEvent.click(button));
276+
277+
// Should have attempted to disconnect
278+
await waitFor(() => {
279+
expect(mockDisconnect).toHaveBeenCalled();
280+
});
281+
});
282+
}
253283

254-
it("allows disconnecting wallet after failure", async () => {
255-
const mockDisconnect = vi.fn().mockResolvedValue(undefined);
256-
mockAuth.doLogin.mockRejectedValueOnce(new Error("Failed"));
257-
vi.mocked(useActiveWallet).mockReturnValueOnce({
258-
...createWallet("io.metamask"),
259-
disconnect: mockDisconnect,
284+
describe("inApp wallet", () => {
285+
const mockWallet = createWallet("inApp");
286+
beforeEach(() => {
287+
vi.mocked(useActiveWallet).mockReturnValue(mockWallet);
260288
});
289+
headlessTests();
290+
});
261291

262-
const { getByTestId } = render(
263-
<SignatureScreen
264-
onDone={() => {}}
265-
modalSize="wide"
266-
connectLocale={mockConnectLocale}
267-
client={TEST_CLIENT}
268-
auth={mockAuth}
269-
/>,
270-
{ setConnectedWallet: true },
271-
);
272-
273-
// Wait for failure and click disconnect
274-
await waitFor(
275-
() => {
276-
return getByTestId("disconnect-button");
277-
},
278-
{ timeout: 2000 },
279-
).then((button) => userEvent.click(button));
280-
281-
// Should have attempted to disconnect
282-
await waitFor(() => {
283-
expect(mockDisconnect).toHaveBeenCalled();
292+
describe("Ecosystem wallet", () => {
293+
const mockWallet = createWallet("ecosystem.foo");
294+
beforeEach(() => {
295+
vi.mocked(useActiveWallet).mockReturnValue(mockWallet);
284296
});
297+
headlessTests();
285298
});
286299
});
287300
});

packages/thirdweb/src/react/web/ui/ConnectWallet/screens/SignatureScreen.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,10 @@ export const SignatureScreen: React.FC<{
7474
}
7575

7676
if (
77-
wallet.id === "inApp" ||
78-
wallet.id === "embedded" ||
79-
(wallet.id === "smart" && adminWallet?.id === "inApp")
77+
isHeadlessSignSupported(wallet.id) ||
78+
(wallet.id === "smart" &&
79+
adminWallet &&
80+
isHeadlessSignSupported(adminWallet.id))
8081
) {
8182
return (
8283
<HeadlessSignIn
@@ -227,6 +228,14 @@ export const SignatureScreen: React.FC<{
227228
);
228229
};
229230

231+
function isHeadlessSignSupported(walletId: Wallet["id"]) {
232+
return (
233+
walletId === "inApp" ||
234+
walletId === "embedded" ||
235+
walletId.startsWith("ecosystem")
236+
);
237+
}
238+
230239
function HeadlessSignIn({
231240
signIn,
232241
error,

0 commit comments

Comments
 (0)