Following the technique to verify ethereum signature with ECDSA.

Sign it like you mean it: creating and verifying Ethereum signatures

Signing and Verifying Messages in Ethereum

A Closer Look At Ethereum Signatures

I would like to know if someone here, could see any security issue with this approach on Solidity:

mapping(uint256 => bool) usedIDS;

function claimTokens(uint256 amount, uint256 id, bytes memory sig) public {
    usedIDS[id] = true;

    bytes32 message = keccak256(abi.encodePacked(amount, id));
    require(recoverSigner(message, sig) == expectedAddressWhichCreateSig);

    _mint(msg.sender, amount);


function claimTokens(uint256 amount, uint256 nonce, bytes memory sig) public {
    usedNonces[nonce] = true;

    bytes32 message = keccak256(abi.encodePacked(msg.sender, amount, nonce, this));
    require(recoverSigner(message, sig) == expectedAddressWhichCreateSig);

    _mint(msg.sender, amount);

I found this! It could be a potential problem with ECDSA, however, it could be considered a problem in the entire blockchain and also other technologies which use ECDSA, m I right?

ECDSA: Revealing the private key, if nonce known (NIST256p)

Thank you very much for your time!

  • Is that from a real contract already deployed? Could you send the address?
    – Undead8
    Jan 18 at 21:09
  • @Undead8 No! I didn't deployed yet! Do you have any suggestions? Jan 18 at 21:46
  • 1
    Don't deploy it. I'll post an answer.
    – Undead8
    Jan 19 at 15:02

2 Answers 2


In general there is no issue in using ecrecover the most important part is how you create the hash that you sign (e.g. include the contract address and chain id into the hash to prevent replay attacks)

Most wallets don't let you sign data that could potentially be a raw transaction. Therefore you have a couple standards for signing.

The most notable ones are EIP-712 and EIP-191.

To generate signatures according to these standards you can use existing rpc methods (e.g. eth_signTypedData and eth_sign) and verify these then on your contract.

  • Thank you for your answer @Richard Would you have any examples which explain better how to implement these standards? I got it that I need to structure the message better and follow these standards using Struct for each piece of information: claim { amount, wallet } But I didn't get well the part that verifies the contract, since we have a new structure. That means that my original implementation must be changed, m I right? What do you think to use this one: github.com/OpenZeppelin/openzeppelin-contracts/blob/master/… Jan 26 at 15:07

There is a clear front-running issue with the claimTokens function.

Let's say that user A sends a claimTokens transaction with a signed message as the sig parameter.

User B (evil) sees the transaction in the mempool. To claim the tokens that belong to A, all B has to do is copy the parameters of A's transaction, including sig, and send its own claimTokens transaction with a higher gas price than A.

B transaction will be mined first and the tokens will be minted to msg.sender - B in that case. A transaction will revert because of require(!usedIDS[id])

I would disagree with the other answer and say that in real-case scenarios, ECDSA are full of potential security issues and is one of the most difficult things to get right in a contract. I saw the front-running issue at first sight, but I would not be surprised that other security issues are lurking in this implementation or any other that you may come up with. Use ECDSA at your own (and your users) risk.

  • Thank you for your answer @Undead8 Would you have any examples that you noticed these problems with ECDSA? Just for I understand and maybe reduce those ones! I also found this implementation: github.com/OpenZeppelin/openzeppelin-contracts/blob/master/… What do you think? BTW using your comments and Richard I fixed and updated the method. Jan 26 at 14:56
  • 1
    I once saw a protocol that was sending oracle price update with ECDSA signatures. The way that it was implemented, the signature could be reused with other assets, so anyone for instance could take the price of DOGE and send it to the BTC oracle and it would be recorded. Or, there was no timestamp check so you could send an old BTC price to the oracle by reusing a previous signature and the oracle would accept it. Take great care of thinking of how the signature could be reused by someone else or at a different time and see if it would work or not based on your implementation.
    – Undead8
    Jan 26 at 18:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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