Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[bug] WalletConnect Transaction promises not returning #116

Closed
1 task done
critesjosh opened this issue Jan 28, 2022 · 55 comments
Closed
1 task done

[bug] WalletConnect Transaction promises not returning #116

critesjosh opened this issue Jan 28, 2022 · 55 comments

Comments

@critesjosh
Copy link

Is there an existing issue for this?

  • I have searched the existing issues

Package Version

0.2.1

Current Behavior

I am using the package in my next.js application.

When I send transactions to a wallet connected with WalletConnect, the transaction promise never returns.

In the following code snippet, the transaction is picked up by the wallet and will successfully send, but the notifications aren't displayed and the receipt isn't logged.

I tried this with multiple wallets (Metamask and Valora) and neither of them work. Metamask works as expected.

  const setStorage = async (values) => {
    let tx = await contract.store(values.number);

    notification.open({
      message: "Updating Storage",
      description: `Contract storage updating to: ${values.number}`,
    });

    let receipt = await tx.wait();
    console.log("receipt", receipt);
}

Expected Behavior

I expect the transaction promise to resolve when it is sent by the wallet.

Steps To Reproduce

No response

Anything else?

No response

@tmm
Copy link
Member

tmm commented Jan 28, 2022

@critesjosh any chance you can create a basic CodeSandbox to help with debugging?

You can fork this template to get started.

@critesjosh
Copy link
Author

Yea I will work on adding the code there. In the meantime, I narrowed down the problem a bit. It has to do with the WalletConnectConnector rpc options. The dapp seems to connect to the RPC network at 1 initially be default, even when I scan the QR code and log in with my wallet that is connecting to network with id 44787 (Celo alfajores testnet). If I manually refresh the page, the WalletConnect provider updates the correct one (http endpoint defined in the options at 44787). If I set the http endpoint for network id 1 as the endpoint for my desired network, it works as expected (see the screenshot).

Screen Shot 2022-01-29 at 12 40 36 PM

Interestingly, when I associate the http endpoint for the alfajores testnet network in the rpc options at position 1, the transaction receipts are returned as expected. When the dapp is connected to the alfajores testnet properly via WC at rpc option 44787, the transaction receipts are not returned.

If I omit WC rpc option 1 altogether (which is what I want, I don't want to connect to ETH mainnet), I see the following error when trying to read contract data.
Screen Shot 2022-01-29 at 12 49 12 PM

@tmm
Copy link
Member

tmm commented Jan 30, 2022

What does your ether.js provider setup look like?

@critesjosh
Copy link
Author

Here are the connectors and the root component.

const connectors = [
  new InjectedConnector({ chains: [Celo, Alfajores, Localhost] }),
  new WalletConnectConnector({
    chains: [Celo, Alfajores, Localhost],
    options: {
      qrcode: true,
      rpc: {
        // There is a bug where on the first connection the provider URL defaults to network id 1 (ETH mainnet).
        // Set the RPC endpoint of your default network of choice as the #1
        // 1: "https://alfajores-forno.celo-testnet.org",
        44787: "https://alfajores-forno.celo-testnet.org",
        42220: "https://forno.celo.org",
      },
    },
  }),
];

function MyApp({ Component, pageProps }) {
  return (
    <>
      <Head>
        <title>Celo DApp Starter</title>
        <meta name="description" content="Celo DApp Starter" />
      </Head>
      <Provider connectors={connectors}>
        <Component {...pageProps} />
      </Provider>
    </>
  );
}

@critesjosh
Copy link
Author

I've been trying to update the codesandbox, but the site won't save my changes. 🤷

@tmm
Copy link
Member

tmm commented Jan 31, 2022

You might need to fork it or sign in.

@critesjosh
Copy link
Author

ok i got it. you can view the example here: https://codesandbox.io/s/staging-tree-kotvr?file=/src/index.tsx

try connecting to the dapp using WalletConnect with a wallet that is not connected to mainnet. the app will log the http connection of theSigner. It will show a connection to infura at first:
Screen Shot 2022-01-31 at 3 05 14 PM

and if you refresh the page, it should update to the correct endpoint.
Screen Shot 2022-01-31 at 3 07 02 PM

@tmm
Copy link
Member

tmm commented Jan 31, 2022

Thanks! Will check out the CodeSandbox when I have a moment.

In the meantime, I would try updating the connectors function to use the chainId. Maybe something like this:

import { getNetwork } from '@ethersproject/providers'
import { providers } from 'ethers'

const infuraId = 'Your Infura API Key'
const chains = [Celo, Alfajores]

type ConnectorsConfig = { chainId?: number };
const connectors = (_config: ConnectorsConfig) => {
  const network = getNetwork(chainId ?? defaultChain.id)
  const infuraRpcUrl = providers.InfuraProvider.getUrl(network, infuraId).url
  return [
    new InjectedConnector({ chains }),
    new WalletConnectConnector({
      chains,
      options: {
        infuraId,
        qrcode: true,
        rpc: {
          [`${network.chainId}`]: infuraRpcUrl,
        },
      },
    }),
  ]
}

@critesjosh
Copy link
Author

Unfortunately Infura doesn't support Celo yet.

@tmm
Copy link
Member

tmm commented Feb 1, 2022

Oh that was just a convenience method to get the RPC URL. You can swap that with this:

const rpcMap = {
  44787: "https://alfajores-forno.celo-testnet.org",
  42220: "https://forno.celo.org",
}

const connectors = (_config: ConnectorsConfig) => {
  const rpcUrl = rpcMap[chainId]
  return [
    new InjectedConnector({ chains }),
    new WalletConnectConnector({
      chains,
      options: {
        qrcode: true,
        rpc: {
          [`${chainId}`]: rpcUrl,
        },
      },
    }),
  ]
}

@critesjosh
Copy link
Author

just tried the updates you suggested, still no luck

https://codesandbox.io/s/staging-tree-kotvr?file=/src/index.tsx:432-433

@critesjosh
Copy link
Author

critesjosh commented Feb 2, 2022

Perhaps this is a bug with the useSigner hook? When I login with wallet connect, it shows the correct address from useAccount and the correct network from useNetwork. The problem is when I try to read the provider info associated with the signer. The http connection is trying to connect to https://mainnet.infura.io/v3/undefined instead of the provided url.

Update: When I log the connector returned by useConnect, it prints output when the WalletConnect modal pops up, before I scan the QR code. The default http connection is to ETH mainnet via infura. When I scan the QR code, the network and account data updates, but the http connection info does not update. The RPC provider associated with WalletConnect does update. So the RPC and signer connection info in the provider is correct, but the http connection info is not. Does the WalletConnect connector connect via http or rpc or both?

@critesjosh
Copy link
Author

critesjosh commented Feb 2, 2022

Just curious why wagmi uses @walletconnect/ethereum-provider (here) instead of @walletconnect/web3-provider?

web3-provider works for me as expected.

@pyk
Copy link

pyk commented Feb 3, 2022

currently I stumbled upon this problem.

Can confirm that somehow useSigner() returns the signer with mainnet rpc by default. The app need to be reloaded first after connecting via WalletConnect.

The next problem is when I send the transaction using the following code:

const vaultContract = new ethers.Contract(metadata.vaultAddress, VaultABI, signer);
const result = await vaultContract.mint(address, { value: ethers.utils.parseUnits(mintState.amount ? mintState.amount.toString() : "0", metadata.collateralDecimals) });

Request to confirm the tx is appear on the wallet.
when transaction is confirmed via the wallet, transaction succeed but the promise is never return.

I tried to use useContractWrite but got no response as well. It only doesn't work when user is connected via Walletconnect.

I tried to create and sign tx manually but error due to signer.sign is not supported:

const unsignedTx = await vaultContract.populateTransaction.mint(address, { value: ethers.utils.parseUnits(mintState.amount ? mintState.amount.toString() : "0", metadata.collateralDecimals) });
const signedTx = await signer.signTransaction(unsignedTx);

@critesjosh Would u mind to share ur solution using @walletconnect/web3-provider? Ty!

@critesjosh
Copy link
Author

critesjosh commented Feb 3, 2022

I was testing another web3-provider with another repo. it doesn't actually fix the problem sorry. I pulled wagmi and tested it locally with @walletconnect/web3-provider instead of @walletconnect/ethereum-provider and it still isn't working.

I think it may be a problem with ethers wrapping the WalletConnectProvider. For some reason the http connection in the ethers Web3Provider doesn't update when the connection to the mobile wallet is made. The signer on the WalletConnectProvider does update as expected.

@gitcoinbot
Copy link

Issue Status: 1. Open 2. Started 3. Submitted 4. Done


This issue now has a funding of 250.0 cUSD (249.76 USD @ $1.0/cUSD) attached to it.

@gitcoinbot
Copy link

gitcoinbot commented Feb 4, 2022

Issue Status: 1. Open 2. Started 3. Submitted 4. Done


Work has been started.

These users each claimed they can complete the work by 264 years, 9 months from now.
Please review their action plans below:

1) maxx6262 has been approved to start work.

I think with use of try/catch block (and debug with full verbose run) we would find that makes this issue making no return from your promise.
2) mauricelc92 has been approved to start work.

I believe this has to do with the poor support for promises in the Web3 library itself and not WalletConnect for the sending of transactions.

I implemented this at my work for our Wallet and ran into a similar issue.

My action plan would be to try out the event subscriptions to see if that works as that's the recommended way in my experience. I have a decent amount of experience integrating WalletConnect as I did it for my company. I should be able to debug it for you.
3) wartstone has been approved to start work.

  1. I am a senior full stack blockchain developer
  2. I've loaded a demo with similar situation with you. I have a solution for this bug.

Learn more on the Gitcoin Issue Details page.

@tmm
Copy link
Member

tmm commented Feb 6, 2022

@critesjosh what wallet are you using? Standard Celo?

@critesjosh
Copy link
Author

@critesjosh what wallet are you using? Standard Celo?

The Valora wallets (celo mobile wallets) for android, testnet and mainnet.

@maxx6262
Copy link

maxx6262 commented Feb 7, 2022

@critesjosh I tried to connect both with Valora (mainnet) and testnet app (on alfalojes) but it souds also app can't match QR code...
I tried with Trust Wallet with Celo wallet and I get error message.
With multiple wallet, I get only ethereum mainnet able to connect, isn't it ?

@critesjosh
Copy link
Author

@maxx6262 i am able to connect using the testnet wallet and Valora. I am testing on this site

@maxx6262
Copy link

maxx6262 commented Feb 7, 2022

That's right, I'm now also connected . Thank you ;)

@maxx6262
Copy link

maxx6262 commented Feb 8, 2022

Did anyone find anything more than @critesjosh ?

I stayed tonight on This issue but the lonely one way to use promise is when I use others web3 library I already used.

Now all sign transactions are ok, I'm trying to make the more log I'm able and to switch any piece at each step to get point when issue would appear....

@maxx6262
Copy link

maxx6262 commented Feb 8, 2022

Does anyone get an error due to bad privider we can't use for Celo ?

@maxx6262
Copy link

maxx6262 commented Feb 8, 2022

I'm going to make clean repo to submit you @critesjosh .
I've got each time Promise return both on success and returned transactions with a simple storage contract I deployed on Alfajoles.. To be sure about that, Iadded logs on console but also alert messages with TX on fullfilled transactions and error messages on returned o returned/wrongs.
I've deleted all Web3 and others library to just keep etherjs, ans wagmi hooks to interact on chain. I 've linked Alfajoles wallet and I' now getting all Promise's retuns as expected.
Please let me touch in case you'd to be still in troubles with this.
Here is codesandbox repo I worked on

@gitcoinbot
Copy link

Issue Status: 1. Open 2. Started 3. Submitted 4. Done


Work for 250.0 cUSD (248.6 USD @ $0.99/cUSD) has been submitted by:

  1. @maxx6262

@ericnakagawa please take a look at the submitted work:


@maxx6262
Copy link

maxx6262 commented Feb 9, 2022

@critesjosh I know, but you didn't get Promise return when calling 'store' function isn't ?
Isn't it because you tried to call function by calling 'contract.store(values.number)' instead of using 'useContractWrite' hook inside your code as I maked on my submission ?

@maxx6262
Copy link

maxx6262 commented Feb 9, 2022

You have to define Hook before rendering function 👍 const [ { data, nberror, nbloading }, write ] = useContractWrite( { addressOrName: StorageContractAddressTestnet, contractInterface: StorageAbi, }, 'store', { args: '9', } );
and you get Promise return inside button tag :
<button onClick={ async function() { write() .then( (rep) => { if (!rep.ok) { alert(rep.error); console.error({ "message": rep.error }) } else { notification.open({ "tx": rep.hash , "rep": rep }) }}) .catch(err => console.error({ "message": err })) }}>SetStorage </button>

@wartstone
Copy link

I though it would be something related with walletconnect. I switched to other networks(like matic or rinkeby) and providers also didn't get updated. good to see @maxx6262 solved this.

@zxqx
Copy link
Contributor

zxqx commented Feb 9, 2022

@maxx6262 Not able to run this app (either locally or in CodeSandbox) without compile errors.

@critesjosh
Copy link
Author

@critesjosh I know, but you didn't get Promise return when calling 'store' function isn't ? Isn't it because you tried to call function by calling 'contract.store(values.number)' instead of using 'useContractWrite' hook inside your code as I maked on my submission ?

This doesn't solve the original issue, it uses a different hook. You are correct in that I am using the useContract hook, but since it is creating an ethers.js Contract instance (described here) I would expect a function call to return the same data as the ethers contract.

@wartstone
Copy link

i'll try to check the walletconnect side since it seems it's not getting sovled yet

@zxqx
Copy link
Contributor

zxqx commented Feb 10, 2022

Might be worth taking a look at this issue in the @walletconnect monorepo: WalletConnect/walletconnect-monorepo#663.

It looks like it could be the same or a similar issue, and I was able to successfully use the workaround posted at the bottom of OP's post, although it only worked when executing a transaction right after connecting -- hard refreshing after connecting and executing a transaction did not work.

@maxx6262
Copy link

Sorry,
please try this opensandbox

I connect with Wallet Connect on Alfajores
I can read nb value (result on console)
I can confirm write transaction and get response (I display it into console)

Here is new Rep

@maxx6262
Copy link

maxx6262 commented Feb 10, 2022

You'll see below that I get

image

@critesjosh
Copy link
Author

@maxx6262 I am not getting any response in the console when sending the update transaction from your codesandbox. I am using the Valora Alfajores testnet wallet for Android connected via WalletConnect.

There is another issue, which is described above. The first time I log in to your app using wallet connect, I get an error when trying to send a transaction. Here is the error:

Screen Shot 2022-02-10 at 12 00 47 PM

If I refresh the UI, it works as expected. This just happens when the connection is first established.

@maxx6262
Copy link

maxx6262 commented Feb 10, 2022

Thanks @critesjosh ... unbelievable that I get returns and no other one...

That's why I keeped this one because it sounds having different comportment from my device and yours... (Did you also use Avast wich currently throw security alarm and disallowed me to reach any part of walletconnect as from siasky.net

I had same with Dacade projet last week

I'm now on this one getting back on first way : decompose wagmi write components and walletConnect Connector into all web3 steps from web3 and web3.eth (to try as I saw in official documentation when this bug appeared at version 1.3.0).
Maybe by calling full sending request from Web3, will we able to use all handlers ? as .on("transactionHash", callback()) or .on('receipt', callback()) ...

@maxx6262
Copy link

maxx6262 commented Feb 11, 2022

I attached Log file :

I see on this that the bug about first connection souds due to "Infura" provider being first loaded before next rendering call.
I'm trying to fix it by founding a way to set again provider as new connection being setted.

@critesjosh : When Connection is OK, you'll see that I get Promises return into console as requested, do you still have no returns from your device ?
On console :
image
image

he91x.csb.app-1644585291729.log

@maxx6262
Copy link

maxx6262 commented Feb 11, 2022

I just find how I succesfully get these returns within 3 steps to reproduce :

  1. I connect first time with Valora app (Alfajores testnet)
  2. I've to refresh page and click again on WalletConnect
  3. I disconnect from Valora app and click on "store" button and reconnect wallet with new QR code
    And then I get all returns without issue....

I'm searching what would be unreachable datas that get dapp on second connection, but I don't see at the moment why WalletConnect has this bug...

As you'll see above, it sounds as valora get connection out...

Record_2022-02-11-20-37-18.mp4

@maxx6262
Copy link

i'm currently testing on this dapp with traceable call requests.

@wartstone
Copy link

@maxx6262 ya,

  1. i think the "unexpected token i in json" problem is probably due to the useSigner() returns the signer with mainnet rpc.
  2. yes, it's related with walletconnect. i'm checking the relevant walletconnect logics as well.

@maxx6262
Copy link

.

Yes it first try to reach transaction request via Infura, despite I maked manually provider without it.

For the second issue, WalletConnect sounds unable to sync as UI being refreshed (new wctoken ?).

In same time, connector doesn't reach disconnection from wallet app....

@maxx6262
Copy link

I tried to make new Provider from WalletConnectProvider to overrice current one to see if it could fix it...
I returned this parsed into ethers.providers.Web3Provider and it just fix reading calll return but there is still same issue each 1 session from 2.... for I don't see full explanation at the moment... I had another enjoyment when I thought it was fixed (lol)
Here is new new Repo
and codeqsandbox

I'm now seeing to set good Signer to see if it would help, and then in case it would not fix it, I think I'll reach into Connector builders...

@rcstanciu
Copy link

As a workaround, I have set the chainId property to the working network id, in the options object when instantiating the WalletConnectConnector:

const connectors = ({ chainId }: { chainId?: number | undefined }) => {
  return [
    new WalletConnectConnector({
      chains,
      options: {
        qrcode: true,
        chainId: networkId,
        rpc: {
          [networkId]: alchemyApiUrl,
        },
      },
    }),
  ]
}

As seen in the WalletConnect source code (https://github.com/WalletConnect/walletconnect-monorepo/blob/ad1670bff2186b6e0a1456fd3704c560edf11125/packages/ethereum-provider/src/index.ts#L88), if chainId is not provided, the default one is used in the constructor (Mainnet). Although it should update to the selected network, somehow it does not do that.

@maxx6262
Copy link

In fact I think due to Hook process, it needs first rendering without our settings before WalletConnect uses chainId as requested, that sounds why we've to make refresh and reconnect wallet to get this fully operational as attended...

@wartstone
Copy link

wartstone commented Feb 23, 2022

the workaround does work if we add the chainId in the EthereumProvider. it seems EthereumProvider does try to update when network connected or signer_events gets updated. I'm checking isCompatibleChainId method. EthereumProvider would first check whether isCompatibleChainId and then update the chainid. it could be the cause.

@neuroswish
Copy link

anyone find a solution to this? I agree with @maxx6262 that I think it's a hooks issue. On first mount for me (on mainnet), trying the useSigner hook doesn't return a promise properly. When I disconnect and reconnect my wallet, however, it works fine

@octavioamu
Copy link

octavioamu commented Apr 6, 2022

having a similar issue trying to listen an event "SignMsg" from contract, I need to reload after connect the wallet to be able to listen events, seems is looking on the wrong network.
What Im trying to do is login someone with gnosis (with walletconnect).
https://gallery.mirror.xyz/GzHNX1UvpNmBDQjQ0pQnE_wsdxoS0_yWocRGOssH4Xw

@tmm
Copy link
Member

tmm commented Apr 7, 2022

Check out the upcoming version of wagmi 0.3.0-next.13 (and corresponding docs). This might be solved there.

@octavioamu
Copy link

octavioamu commented Apr 7, 2022

@tmm I did the migration to the new version and sadly wasn't fixed. I will explain in case we are talking about different problems.
First I connect the wallet using walletconnect, pasting the code of qrcode in gnosis app metamask and gnosis on rinkeby.
The connections works fine but when I fire the signmessage method with a new signer (refetch old getSigner()) I console log the signer and get this:
Screen Shot 2022-04-07 at 14 06 45

If I just reload the page the signer now is rinkeby (the right one)
Screen Shot 2022-04-07 at 14 08 13

This is how my connectors is setup:

const infuraId = process.env.NEXT_PUBLIC_INFURA_ID
const chains = defaultChains
const defaultChain = chain.mainnet

const connectors = ({ chainId }) => {
  const chain = chains.find((x) => x.id === chainId) ?? defaultChain
  const rpcUrl = chain.rpcUrls.infura
      ? `${chain.rpcUrls.infura}/${infuraId}`
      : typeof chain.rpcUrls.default === 'string'
      ? chain.rpcUrls.default
      : chain.rpcUrls.default[0]

  return [
    new InjectedConnector({
      chains,
      options: { shimDisconnect: true },
    }),
    new WalletConnectConnector({
      options: {
        qrcode: true,
        rpc: {
          [chain.id]: rpcUrl,
        },
      },
    }),
    new CoinbaseWalletConnector({
      options: {
        appName: 'My wagmi app',
        chainId: chain.id,
        jsonRpcUrl: rpcUrl,
      },
    }),
  ]
}

export default connectors;

So seems the network by default is set to mainnet, then it change to the right one but doesn't change chainId on the connectors as the new WalletConnectConnector was already setup with defaultChain and that is chain.mainnet On solution I was thinking todo is to look the environment and check if it is "development" use defaultChain= chain.rinkeby but I was looking for a better and more dynamic solution.

Any ideas? Thanks in advance.

@tmm
Copy link
Member

tmm commented Apr 7, 2022

Got it. Thanks for the info. Don't be sad, the next version isn't out yet! Will look into this more.

Possible that there's a WalletConnect issue somewhere in the stack here, signer/connector is getting stale in wagmi, etc. (Would check out this one too since you are using gnosis. Just something to be aware of.)

@octavioamu
Copy link

octavioamu commented Apr 7, 2022

Maybe on connect need to update the hooks data?

connector.on("connect", (error, payload) => {
  if (error) {
    throw error;
  }

  // Get provided accounts and chainId
  const { accounts, chainId } = payload.params[0];
});

https://docs.walletconnect.com/quick-start/dapps/client

Just guessing but maybe something like

      provider.on('connect', this.onChainChanged)

in https://github.com/tmm/wagmi/blob/main/packages/core/src/connectors/walletConnect.ts#L34
to be sure the new network is changed when the wallet actually connect?

@octavioamu
Copy link

octavioamu commented Apr 7, 2022

Got it to work with chainId: chain.id in case somebody find it useful but still using env variable to force rinkeby
wagmi 0.3.0-next.13

import { chain, defaultChains } from 'wagmi'
import { InjectedConnector } from 'wagmi/connectors/injected'
import { WalletConnectConnector } from 'wagmi/connectors/walletConnect'
import { CoinbaseWalletConnector } from 'wagmi/connectors/coinbaseWallet'

const infuraId = process.env.NEXT_PUBLIC_INFURA_ID
const env = process.env.NODE_ENV
const chains = defaultChains
const defaultChain =  env === "development" ? chain.rinkeby : chain.mainnet

const connectors = ({ chainId }) => {
  const chain = chains.find((x) => x.id === chainId) ?? defaultChain
  const rpcUrl = chain.rpcUrls.infura
      ? `${chain.rpcUrls.infura}/${infuraId}`
      : typeof chain.rpcUrls.default === 'string'
      ? chain.rpcUrls.default
      : chain.rpcUrls.default[0]

  return [
    new InjectedConnector({
      chains,
      options: { shimDisconnect: true },
    }),
    new WalletConnectConnector({
      options: {
        qrcode: true,
        chainId: chain.id,
        rpc: {
          [chain.id]: rpcUrl,
        },
      },
    }),
    new CoinbaseWalletConnector({
      options: {
        appName: 'My wagmi app',
        chainId: chain.id,
        jsonRpcUrl: rpcUrl,
      },
    }),
  ]
}

export default connectors;

@tmm
Copy link
Member

tmm commented May 21, 2022

Closing as this is for an older version of wagmi. If this issue persists in current versions (now 0.4.x), please file a new issue.

Copy link
Contributor

This issue has been locked since it has been closed for more than 14 days.

If you found a concrete bug or regression related to it, please open a new bug report with a reproduction against the latest wagmi version. If you have any other comments you can create a new discussion.

@github-actions github-actions bot locked and limited conversation to collaborators Jan 18, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants