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

Uncatchable “missing v” when sending transaction #4513

Closed
ricmoo opened this issue Dec 16, 2023 · 63 comments
Closed

Uncatchable “missing v” when sending transaction #4513

ricmoo opened this issue Dec 16, 2023 · 63 comments
Assignees
Labels
bug Verified to be an issue. fixed/complete This Bug is fixed or Enhancement is complete and published. v6 Issues regarding v6

Comments

@ricmoo
Copy link
Member

ricmoo commented Dec 16, 2023

Ethers Version

6.9.0

Search Terms

Missing v, signature

Describe the Problem

This is related to two issues:

  1. An Ethers bug, related to fix: catch rejected promise #4512 where an error during sending a transaction is not catchable
  2. wallets not returning a v or yParity in the response to eth_getTransactionByHash.

I’m working on a fix for 1 (which is exposing some other possible oddity) and communicating with other groups for 2.

If you are experiencing this issue, ca you please let me know which wallet you are using? It seems like MetaMask through Wallet Connect is having this issue at least. Curious if there are others.

Code Snippet

No response

Contract ABI

No response

Errors

No response

Environment

No response

Environment (Other)

No response

@ricmoo ricmoo added bug Verified to be an issue. on-deck This Enhancement or Bug is currently being worked on. v6 Issues regarding v6 next-patch Issues scheduled for the next arch release. labels Dec 16, 2023
@ricmoo ricmoo self-assigned this Dec 16, 2023
@ricmoo
Copy link
Member Author

ricmoo commented Dec 16, 2023

It seems like this isn’t a WalletConnect issue, but maybe a MetaMask issue (for part 2). Still investigating.

I currently only have data points for MetaMask through WalletConnect. There is a “hacky” solution I can imagine if necessary. Since only the v is missing, what ethers could do for EIP-1559 transaction transactions, at least, is use ecrecover to compute from using a v of 27 and 28, if one of those match to tx, use it to fill in the transaction.

The doesn’t help for EIP-155 transactions though, unless the chain ID is incorporated, which starts feeling more hacky. I’d ether fix this upstream, as it seems like a wallet bug, but seeking feedback on some other ideas too. ;)

@llopez
Copy link

llopez commented Dec 16, 2023

I am using ethers v6.9.0 and web3modal v3.4.0 + metamask extension

@llopez
Copy link

llopez commented Dec 16, 2023

it happens after several times of sending a transaction.

code snippet:

  const provider = new BrowserProvider(walletProvider.value, 80001)
  const signer = await provider.getSigner()
  const admin  = await signer.getAddress();
  const contract = new ethers.Contract(CONTRACT_ADDRESS, ABI, signer);

  const r = await contract.votingEscrow();
  console.log(r);

  const tokenBptAddr = '0x975Ec7795F0Fbab6aF88C9C4228a46359165F3B0';
  const name = 'test'
  const symbol = 'test1'
  const maxLockTime = 60*60*24*7; // 1 week
  const now = new Date();
  const rewardDistributorStartTime = now.getTime() + (60 * 60);

  try {
    const tx = await contract.deploy(tokenBptAddr, name, symbol, maxLockTime, rewardDistributorStartTime, admin, admin)
    console.log('tx submitted', tx)
    const receipt = await tx.wait();
    console.log('tx success', receipt);
  } catch (error) {
    console.log('error', error);
  }

it never catches the error

@glitch-txs
Copy link

I'm not able to reproduce it, I was able to do txs with both MetaMask and Rabby.

it happens after several times of sending a transaction.

So does it mean it happens randomly?

@llopez
Copy link

llopez commented Dec 16, 2023

yes. It is a random error. I would be great at least if we can catch it.

@ricmoo
Copy link
Member Author

ricmoo commented Dec 16, 2023

Catching it is coming. :)

@WooMai
Copy link

WooMai commented Dec 16, 2023

Same error here (but transaction sent successfully), randomly happening about 90% of the time, using ethers.js 6.9.0 with @metamask/sdk-react-ui 0.14.1 and MetaMask Chrome Extension

async function mintToken() {
        const provider = new BrowserProvider(sdk!.getProvider());

        const contract = new Contract(tokenInfo!.address, [{
            "inputs": [
                {
                    "internalType": "uint256",
                    "name": "nonce",
                    "type": "uint256"
                }
            ],
            "name": "mint",
            "outputs": [],
            "stateMutability": "nonpayable",
            "type": "function"
        }], await provider.getSigner());
        const tx = await contract.mint(foundNonce!);  // this promise rejected
        console.log('mint tx', tx);
    }

the error message is

Uncaught (in promise) TypeError: missing v (argument="signature", value={ "accessList": null, "blockHash": null, "blockNumber": null, "from": "(sender address)", "gas": "0xf856", "gasPrice": "0x2540be400", "hash": "(removed)", "input": "(removed)", "maxFeePerGas": "0x2540be400", "maxPriorityFeePerGas": "0x2540be400", "nonce": "0x16", "r": "(removed)", "s": "(removed)", "to": "(removed)", "transactionIndex": null, "type": "0x2", "value": "0x0" }, code=INVALID_ARGUMENT, version=6.9.0)

just debugged for a couple hours for this problem until I saw this issue :´(

@llopez
Copy link

llopez commented Dec 16, 2023

I noticed that the error occurs when I send a transaction with the same data than the previous one. maybe the code does not regenerate the signature because the data is the same.. not sure

@llopez
Copy link

llopez commented Dec 16, 2023

yes. that is the way to reproduce the error. send the same transaction two times in a row

@glitch-txs
Copy link

@llopez awesome! Could you try with a different wallet? It would be nice to know if this is a MetaMask issue or the issue is somewhere else

@WWZ90
Copy link

WWZ90 commented Dec 17, 2023

I am experiencing the same problem now

Uncaught (in promise) TypeError: missing v (argument="signature", value={ "accessList": null, "blockHash": null,...

here:

try {
      await usdc.balanceOf(owner).then(async (balance) => {
        await usdc.approve(import.meta.env.VITE_OO_CONTRACT_ADDRESS, balance).then(async tx => {
          tx.wait();
          await usdc.balanceOf(owner).then(async (balance) => {

await usdc.approve when I click for Aproval on metamask, the error shows, and nothing more happens. waiting forever.
This is something that works a few days ago, and now is broken for some reason.

@elleria-bot
Copy link

elleria-bot commented Dec 17, 2023

Getting the same issue on Metamask v11.7.0 on Ethers v6.7.1
image

Some of our players are experiencing this as well, even on the first transaction (no need to do twice in a row).
Seems to be a relatively new issue, we only started getting stuck reports a day ago (16 December 12pm UTC)

@KukretiShubham
Copy link

KukretiShubham commented Dec 17, 2023

I just had this issue, was working fine till yesterday. Wallet: Metamask

@Anjan-poudel-1
Copy link

Anjan-poudel-1 commented Dec 17, 2023

image

had the same issue

using ethers 6.9 and metamask wallet.

same transaction works well with "web3" package

@hmMachghoul
Copy link

It appears that the issue I'm encountering is specific to MetaMask. When using other wallets like Coinbase, WalletConnect (WC), or Ruby, this problem does not occur. I've attempted using different RPC endpoints with MetaMask, but they all seem to fail, although occasionally it does work correctly. It's worth noting that my testing was exclusively on various testnets, including Ethereum's Sepolia, Binance Smart Chain's Testnet, and Mumbai.

@wenjoy
Copy link

wenjoy commented Dec 17, 2023

I get this error when I'm using ethers.js@6.8.1 with metamask@11.7.0 on testnet Sepolia.

P.S. I'm curious why here try to get signature from value, can anyone give me a clue about it?

result.signature = Signature.from(value);

@wenjoy
Copy link

wenjoy commented Dec 17, 2023

@ricmoo has mentioned why this happened at Describe the Problem, in case someone missing it at first glim like me, I paste here again #4512.

And as a temporary work around, you can handle it by window.onerror.

@kule1163
Copy link

Hello guys i have same issue i build a nft marketplace app about 1 month ago everything works fine but now i start to create new one i have this issue i test my old app my old app have the same issue. I realised that it gives error but smart contract funtions go on to work very fine. If i try to use transaction i randomly get this error but i remove transaction on my code just run smart contract function i dont have any problem about 24 hours i try to find a solution for it. Now i am happy i not alone. If i have a solution for it as soon as possible i will share with u. Have good a luck

@kule1163
Copy link

Hi again try to use coinbase wallet everything works fine till metamask solve this problem i will use coinbase

@ChristianGreinke
Copy link

ChristianGreinke commented Dec 17, 2023

We ran into the same issue when ethers is trying to resolve transaction data with metamask before metamask has received enough confirmations from the network. Apparently metamask returns the transaction without complete signature data.
Further the sendTransaction function handles that by reissuing checkTx if tx is null but the internal from(sig) function would just break out with an assertError in the case of missing v. I fixed the issue with the change to the sendTransaction function below. Obviously that would run into an endless loop for permanent missing v error. Feel free to adapt. For our test case that change is sufficient.

original

async sendTransaction(tx) {
        // This cannot be mined any earlier than any recent block
        const blockNumber = await this.provider.getBlockNumber();
        // Send the transaction
        const hash = await this.sendUncheckedTransaction(tx);
        // Unfortunately, JSON-RPC only provides and opaque transaction hash
        // for a response, and we need the actual transaction, so we poll
        // for it; it should show up very quickly
        return await (new Promise((resolve, reject) => {
            const timeouts = [1000, 100];
            const checkTx = async () => {
                // Try getting the transaction
                const tx = await this.provider.getTransaction(hash);
                if (tx != null) {
                    resolve(tx.replaceableTransaction(blockNumber));
                    return;
                }
                // Wait another 4 seconds
                this.provider._setTimeout(() => { checkTx(); }, timeouts.pop() || 4000);
            };
            checkTx();
        }));
    }

my change

async sendTransaction(tx) {
        // This cannot be mined any earlier than any recent block
        const blockNumber = await this.provider.getBlockNumber();
        // Send the transaction
        const hash = await this.sendUncheckedTransaction(tx);
        // Unfortunately, JSON-RPC only provides and opaque transaction hash
        // for a response, and we need the actual transaction, so we poll
        // for it; it should show up very quickly
        return await (new Promise((resolve, reject) => {
            const timeouts = [1000, 100];
            const checkTx = async () => {
                // Try getting the transaction
                try{
                    const tx = await this.provider.getTransaction(hash);
                    if (tx != null) {
                        resolve(tx.replaceableTransaction(blockNumber));
                        return;
                    }
                }catch(error){
                    if(error.toString().includes('missing v')){

                    }else{
                        reject(hash);
                    }
                }
                // Wait another 4 seconds
                this.provider._setTimeout(() => { checkTx(); }, timeouts.pop() || 4000);
            };
            checkTx();
        }));
    }

@ricmoo
Copy link
Member Author

ricmoo commented Dec 17, 2023

@wenjoy The reason that value is passed to Signature.from is that it will use any signing properties on the transaction to derive the Signature. It could be r, s and v or might use yParity instead of V if one is missing and will also validate that everything matches.

Ethers is very much a “don’t trust, verify" mindset, which is why there is a problem right now; the node is returning corrupt (missing the v) transactions. This is why you see libraries that just return the raw result without validating it work.

I do have an idea for a fix if this isn’t fixed upstream soon, which is to “just try” both yParity of 0 and 1, and whichever matches the from address, use it to populate the v. It feels a bit hacky, but it’s important things work. :)

The uncatchable part is entirely my fault though, and I’m still working on it. My current fix is still showing some weirdness in my tests I’m trying to track down.

@eolszewski
Copy link

eolszewski commented Dec 17, 2023

Hey @ricmoo - is there anything in particular that you'd recommend to mitigate this issue in the meantime? It seems like this is an error coming from metamask, so, I imagine this won't be addressed for a little bit.

@glitch-txs
Copy link

has anyone opened an issue in MM repo?

@ricmoo ricmoo added fixed/complete This Bug is fixed or Enhancement is complete and published. and removed on-deck This Enhancement or Bug is currently being worked on. next-patch Issues scheduled for the next arch release. labels Dec 20, 2023
@kfazil
Copy link

kfazil commented Dec 20, 2023

@ricmoo I'm using 6.9.1 version directly from github. I've tested 10+ tx on goerli network everthing was good but then I got a same missing v error on a tx.

PS: I think this is in catch part. Catch works but metamask issue still persist.

missing-v-6 9 1

@danielojedapy
Copy link

danielojedapy commented Dec 20, 2023

Yes, when i use the release 6.9.1, the error is happen again.

Actually, i'm using the current version of main from ether.
With that, i didn't see the error again. @ricmoo

@daenamkim
Copy link

I think the latest version (11.7.2) of MetaMask has fixed this issue.
MetaMask/metamask-extension@v11.7.1...v11.7.2

@syamsoul
Copy link

I think the latest version (11.7.2) of MetaMask has fixed this issue. MetaMask/metamask-extension@v11.7.1...v11.7.2

confirmed...after update MetaMask, it's working fine now...

@ricmoo
Copy link
Member Author

ricmoo commented Jan 13, 2024

Closing this now. If anyone continues to experience any issues (after updating to the latest version of Ethers), please re-open or create a new issue.

Thanks! :)

@ricmoo ricmoo closed this as completed Jan 13, 2024
Woodpile37 pushed a commit to Woodpile37/ethers.js that referenced this issue Jan 14, 2024
Woodpile37 pushed a commit to Woodpile37/ethers.js that referenced this issue Jan 14, 2024
Woodpile37 pushed a commit to Woodpile37/ethers.js that referenced this issue Jan 14, 2024
rrw-zilliqa added a commit to Zilliqa/ethers.js that referenced this issue Apr 29, 2024
* docs: fixed typo in jsdocs for Wallet.createRandom (ethers-io#4461)

* admin: added diff scripts for build page

* admin: updated dist files

* Added safe and finalized provider events (ethers-io#3921).

* tests: bumped Node versions for testing (ethers-io#4451)

* admin: style fix (ethers-io#4356)

* More robust FallbackProvider broadcast (ethers-io#4186, ethers-io#4297, ethers-io#4442).

* Account for provider config weight when kicking off a request in FallbackProvider (ethers-io#4298).

* Fixed ParamType formatting causing bad tuple full and minimal ABI output (ethers-io#4329, ethers-io#4479).

* Added Base network to AlchemyProvider (ethers-io#4384).

* Add auto-detected static network support to providers and allow customizing socket provider options (ethers-io#4199, ethers-io#4418, ethers-io#4441).

* Use provider-specified suggested priority fee when available, otherwise fallback onto existing logic of 1 gwei (ethers-io#4463).

* admin: updated dist files

* admin: update changelog after build-clean

* docs: Fixed some grammar in getting-started (ethers-io#4486, ethers-io#4487, ethers-io#4488)

* Fix uncatchable issue when sending transactions over JSON-RPC and provide some retry-recovery for missing v (ethers-io#4513).

* admin: update dist files

* Fix Base58 padding for string representation of binary data (ethers-io#4527).

* admin: updated dist files

* Limit decoded result imflation ratio from ABI-encoded data (ethers-io#4537).

* admin: updated dist files

* Better debugging output on fetch errors.

* docs: added StaticJsonRpcProvider to migration docs

* Fixed typo in Error string (ethers-io#4539).

* Fix EIP-712 type aliases for uint and int (ethers-io#4541).

* Added additional sepolia testnets.

* Updated third-party provider network URLs (ethers-io#4542).

* admin: updated dist files

* Fixed normalization and abstracted EIP-712 Array parsing (ethers-io#4541).

* admin: updated dist files

* tests: added testing for correct thrid-party URLs

* Updated thrid-part provider URLs for QuickNode.

* tests: rename test suite to follow naming convention

* admin: updated dist files

* Normalize EIP-712 types before computing the payload (ethers-io#4541).

* tests: add tests for EIP-712 payload aliases

* admin: updated dist files

---------

Co-authored-by: Richard Moore <me@ricmoo.com>
rrw-zilliqa added a commit to Zilliqa/ethers.js that referenced this issue Apr 29, 2024
* Fix uncatchable issue when sending transactions over JSON-RPC and provide some retry-recovery for missing v (ethers-io#4513).

* admin: update dist files

* Fix Base58 padding for string representation of binary data (ethers-io#4527).

* admin: updated dist files

* Limit decoded result imflation ratio from ABI-encoded data (ethers-io#4537).

* admin: updated dist files

* Better debugging output on fetch errors.

* docs: added StaticJsonRpcProvider to migration docs

* Fixed typo in Error string (ethers-io#4539).

* Fix EIP-712 type aliases for uint and int (ethers-io#4541).

* Added additional sepolia testnets.

* Updated third-party provider network URLs (ethers-io#4542).

* admin: updated dist files

* Fixed normalization and abstracted EIP-712 Array parsing (ethers-io#4541).

* admin: updated dist files

* tests: added testing for correct thrid-party URLs

* Updated thrid-part provider URLs for QuickNode.

* tests: rename test suite to follow naming convention

* admin: updated dist files

* Normalize EIP-712 types before computing the payload (ethers-io#4541).

* tests: add tests for EIP-712 payload aliases

* admin: updated dist files

* (feat) ZIL-5458: Add emacs backups to .gitignore
(feat) ZIL-5458: Don't validate canonical signatures

---------

Co-authored-by: Richard Moore <me@ricmoo.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Verified to be an issue. fixed/complete This Bug is fixed or Enhancement is complete and published. v6 Issues regarding v6
Projects
None yet
Development

No branches or pull requests