2

I work on a React (Next.js) web project which connects to a NestJS backend.

The process of wallet authentication on server is the following:

  1. wallet connects to our frontend app
  2. frontend sends the wallet address to our backend which generates a one time password for it
  3. wallet then signs a message (one time password)
  4. frontend sends the encoded signature back to backend
  5. backend verifies the message with wallets public key

I'm integrating my dApps with mobile libraries now and experiencing issues.

This is my handleConnectPress function for mobile handling of "Connect" button press:

    const { authorizeSession, selectedAccount } = useAuthorization();
    const [authorizationInProgress, setAuthorizationInProgress] = useState(false);
    const web3Auth = useWeb3Auth(http); // API requests for my backend service

    const handleConnectClick = useGuardedCallback(async () => {
        try {
            if (authorizationInProgress) {
                return;
            }
            setAuthorizationInProgress(true);
            await transact(async (wallet) => {
                const freshAccount = await authorizeSession(wallet);
                const account = selectedAccount ?? freshAccount;

                const oneTimePassword = await web3Auth.requestPassword(account.publicKey.toString());
                const message = new TextEncoder().encode(oneTimePassword);

                const [signedMessage] = await wallet.signMessages({
                    addresses: [account.address],
                    payloads: [message],
                });
                const signature = signedMessage.slice(-64);
                const encoding = bs58.encode(signature);
                await web3Auth.connectWallet(encoding, account.publicKey.toString()); // authenticates wallet on backend
            });
        } finally {
            setAuthorizationInProgress(false);
        }
    }, []);

NOTE: useAuthorization is reused from example-react-native-app

Below I'm attaching what I want to achieve. First example with the "Fake dApp" show that in a single click we can authorize the wallet, sign a message and have the connected state in the app (useWallet.wallet is not empty). Second example is my current implementation and it works with authorization and message signing, but wallet state is empty!

"Fake dApp" source code is located on this repo but I just fail at finding the correct code snippet from there which I could reuse...

enter image description here

4
  • I don't know enough about the Web3Auth SDK. Is there anything about that call to web3Auth.connectWallet() that would cause a React rerender? If not, it's likely that you're getting connected, but nothing actually triggers React to rerender with that new fact. Nov 1, 2022 at 0:49
  • That's my local hook with a bit confusing name but essentially it just calls an authenticated endpoint https://d-reader-backend.herokuapp.com/api#/Auth/AuthController_connect in order to obtain the access token. I don't believe it causes a rerender since it only updates the http.headers.default.authorization and stores the key in LS, but I have a feeling like I've had something else cause a rerender so it should all be there. I'll check now and update with a new comment Nov 1, 2022 at 0:57
  • 1
    No, web3Auth.connectWallet indeed doesn't rerender any of the components whilst a regular connect from useWallet does. I've forced a rerender on components like FundAccountButton.tsx but without luck. I'll troubleshoot a bit more before coming to some more meaningful conclusions Nov 1, 2022 at 1:22
  • 1
    I've figured out a solution but staying offline for a few days. Until I update the question with a proper answer (and a working code example!), anyone that has this same issue please feel free to drop me a message on discord "Josip Volarević#3099" so you don't have to wait for my update There is a somewhat complete working code here: github.com/open-sauce-labs/solomon/tree/master/src/components Nov 7, 2022 at 11:56

1 Answer 1

1

Detect if wallet adapter is a mobile one: wallet.adapter.name === 'Mobile Wallet Adapter' and if it is use one of the two approaches:

  1. use 2 separate buttons - one for connecting the wallet (authorizing your dApp within the mobile wallet) and one for signing the message
  2. have a single "authorize and sign" button with a custom transact implementation

Roughly something like the following:

await transact(async (mobileWallet) => {
  // authorizeSession prompts for authorizing your dApp within the wallet dApp
  const freshAccount = await authorizeSession(mobileWallet)
  if (typeof onAuthorize === 'function') {
    const account = selectedAccount ?? freshAccount
    // onAuthorize prompts for message signing under the hood
    await onAuthorize(mobileWallet, account)
  }
})

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.