I’ve been encountering an issue with the signing process using web3auth
in combination with Metamask, particularly on mobile platforms. Here’s some context:
I’m using web3auth
to manage wallet connections, and ethers.js
to handle signing. On a desktop platform, everything works smoothly: upon clicking the Metamask icon in the web3auth modal, provider.getSigner()
gets resolved successfully.
However, when testing the same flow on mobile, the process isn’t as seamless. When the ‘Open in Metamask Wallet’ modal appears and I choose to continue, I’m redirected to the Metamask app where it requests to connect to the wallet. Once I approve the connection, the app redirects me back to my application, but, without initiating the sign message process. The web3auth.on(ADAPTER_EVENTS.CONNECTED)
event also fires at this step whereas on desktop it
For my app to function correctly, the sign message process should ideally take place immediately after the wallet connection. However, I’m currently having to manually navigate back to Metamask, initiate the signing process by clicking ‘Sign’, and then return to my application.
I attempted to circumvent this by splitting the wallet connection and message signing into two separate buttons. Unfortunately, the signer.signMessage
function doesn’t prompt a redirection to Metamask, unlike signer.getAddress
.
This is also causing my transactions to fail even after i sign the message. Social auth works great though.
Using @web3auth/modal
Here is some code:
const signMessage = async (
signer: any,
address: string
): Promise<{ signature: string; message: SiweMessage }> => {
const message = new SiweMessage({
domain: window.location.host,
address: address,
statement: "Sign in with Ethereum to appName",
uri: window.location.origin,
version: "1",
chainId: CHAIN_ID,
nonce: await getCsrfToken(),
});
console.log("message", message);
console.log("message.nonce", message.nonce);
const preparedMessage = message.prepareMessage();
console.log("preparedMessage", preparedMessage);
setWalletConnected(true);
const signature = await signer.signMessage(preparedMessage);
console.log("signature", signature);
return { signature, message };
};
const handleSignIn = async (): Promise<boolean> => {
const web3authProvider = await web3auth?.connect();
const provider = new ethers.providers.Web3Provider(web3authProvider as any); //fix
const signer = provider.getSigner();
console.log("signer", signer);
const address = await signer.getAddress();
console.log("address", address);
// on mobile, success event is triggered here - too early
try {
const callbackUrl = "/protected";
const response = await signMessage(signer, address);
const { signature, message } = response; // signature
const signInRes = await signIn("credentials", {
message: JSON.stringify(message),
redirect: false,
signature,
callbackUrl,
});
console.log("signInRes", signInRes);
toast.success("Successfully connected.");
return true;
} catch (error) {
if (error["type"] === "failure") {
toast.error(error.result.message);
return false;
}
toast.error("An error occurred trying to connect user.");
return false;
}
};
const subscribeAuthEvents = async (web3auth: Web3Auth) => {
// Can subscribe to all ADAPTER_EVENTS and LOGIN_MODAL_EVENTS
web3auth.on(ADAPTER_EVENTS.CONNECTED, (data: unknown) => {
console.log("Yeah!, you are successfully logged in", data);
// setUser(data);
// setWalletProvider(web3auth.provider!);
});
web3auth.on(ADAPTER_EVENTS.CONNECTING, () => {
console.log("connecting");
});
web3auth.on(ADAPTER_EVENTS.DISCONNECTED, () => {
console.log("disconnected");
// setUser(null);
});
web3auth.on(ADAPTER_EVENTS.ERRORED, (error) => {
console.error("some error or user has cancelled login request", error);
});
};
Hoping to find a solution for this! Thanks