SignatureCheckerUpgradeable Revoking Signatures


Looking in the OZ “SignatureCheckerUpgradeable” I see the comment:

Note: unlike ECDSA signatures, contract signature’s are revocable, and the outcome of this function can thus change
through time. It could return true at block N and false at block N+1 (or the opposite).

As of right now I’m using this signature checker alongside the draft-EIP712Upgradeable.sol to implement lazy-minting. I’m calling this code with javascript in order to get a signature, and then basically unpacking it with the signature checker:

signerObj = new ethers.providers.Web3Provider(window.ethereum).getSigner();
    const signature = await signerObj._signTypedData(

        // Domain
            name: 'NPortV1',
            version: '1.0.0',
            chainId: cD,
            verifyingContract: contractAddress,
        // Types
            NFT: [
                { name: 'tokenId', type: 'uint256' },
                { name: 'price', type: 'uint256' }
        // Value
        { tokenId, price },

What I’m concerned about is: What if a user “authorizes” the salfe of NFT with ID: 4 and price 100, for example, and then a user comes along and passes in the signature which authorizes this exact transaction, but then reverts the request? Now this user has the signature required to purchase this NFT at this price going forward. If the seller then decides they want to change the price to 200 instead, the old signature the buyer has will still be able to acquire this NFT at the old price.

In short, is there a way to revoke this signature somehow?

1 Like

I didn’t understand this part of the problem.

For this problem, you shouldn’t be looking at the caveat that we documented in SignatureChecker.

Instead, your signatures should probably contain more information about their validity. For example, you can add a deadline after which the signature becomes invalid, this is in fact quite common practice. Your contract should validate that the deadline hasn’t passed or otherwise the signature is considered no longer valid and the contract reverts.

Thank you for the reply,

Sorry, the way we’re doing it is having the seller retrieve the signature (which is then stored in our DB) and at the time of purchase we send the signature to the buyer through javascript (which is necessary, unless I’m mistaken, I’m not terribly experienced with networking) so if their client has this specific signature, and then the buyer rejects (this is the word I was looking for) the transaction, then they could in theory hold onto the signature we sent them to authorize the transaction later at an undesired time.

I’m not sure I fully understand how validating the deadline would work. 1). Couldn’t the user just forge the date passed into the ethers js function? and 2). The byte string passed into verify the signature should match exactly the byte string signed off by the seller when they authorized the transaction, right? I’m maybe just a bit brain-fried, but how would I check to see if the buyer attempted to purchase the NFT in the given time slot? Do you know if there are any examples of this anywhere?

Hey was hoping to bump this, I’m still very confused on how I would send up a date to verify against the original signature. Afaik it’s not possible to unpack the contents of the original signature once in the contract? The other option would just be revoking the signature but this doesn’t appear possible unless I’m paying gas to store the used signature in a mapping in the contract itself. Any help would be amazing

Sorry haven’t been able to give you a detailed answer the past few days and I’m still short on time but I’ll share the general idea.

The signature should include a deadline timestamp. Your contract needs to receive all parameters to validate the signature: token id, price, and deadline. It will then hash that together and recover the signer, verify that the signer is the token id owner, and so on. As part of verifying that a signature is “valid”, you will also have to verify that block.timestamp < deadline. Otherwise, you reject the signature, just as if it had been signed by someone that didn’t own this token.

1 Like

Okay the block.timestamp thing is cool, thanks. I guess my question is how to retrieve the “deadline” from the original signature? The verification method I see is just

isValidSignatureNow(signer, digest, signature);

Which just gives me “yes this person signed this”, or “no this isn’t a valid signature” but gives me nothing about the actual original contents of the signature.

I’m looking for something like

retrieveParameter(signature, parameterNo) returns uint256

where parameterNo is the parameter position handed up by the signer in the first place. Otherwise how can I get deadline ?

Take a look at the documentation for EIP712 and in particular the code example for _hashTypedDataV4.

bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
    keccak256("Mail(address to,string contents)"),
address signer = ECDSA.recover(digest, signature);

You need to pass all the parameters together with the signature. There is no other way to correctly verify that it was actually signed by the signer.