Metamask-extension: EIP 712: Unable to use eth_signTypedData_v3 with Dex smart contracts

Created on 3 Oct 2018  路  6Comments  路  Source: MetaMask/metamask-extension

Describe the bug
Not necessarily a bug, but I'm unable to sign a hash and get the same output signature that I need in order to interact with popular Dex Exchange contracts.

For example, for Airswap's Exchange contract, (see Validate function), I have to hash a user's order parameters and signing the output of that hash with personal_sign.

I also tried using eth_signTypedData, but was returning a different signature hash.

const types = [
  'address', // makerAddress
  'uint256', // makerAmount
  'address', // makerToken
  'address', // takerAddress
  'uint256', // takerAmount
  'address', // takertoken
  'uint256', // expiration
  'uint256', // nonce
]
const orderHash = ethers.utils.solidityKeccak256(
      types,
      [
        makerAddress, /0x12....
        makerAmount, // 1
        makerTokenAddress, // 0x1f...
        takerAddress, // 0x1c...
        takerAmount, // 1
        takerTokenAddress, // 0x1a...
        expiration, //unix timestamp + delay
        nonce
      ]
    )
    const testOrderHash = "0x323a0630961846b7e0e9d1a453cc87caa5ca909cc890ac735a63b8d5ccbe7e21" //ouput of a previous personal_sign hash- use in testing and you can ignore the above order hash
const domainData = {
      verifyingContract: "0xbcd24b757c08843010b94cda1f8d03b90b167301",
    }
    const order = [
      { name: "orderHash", type: "bytes32" },
    ]
    const msg = {
      orderHash: testOrderHash
    }
    const data = {
      types: {
        Order: order,
        EIP712Domain: [
          { name: "verifyingContract", type: "bytes32"  },
        ],
      },
      domain: domainData,
      primaryType: "Order",
      message: msg,
    }
 const typedMessageJSON = JSON.stringify(typedMessage)
  var params = [userAccount, typedMessageJSON]
  var method = 'eth_signTypedData_v3'
  console.log()
  web3.currentProvider.sendAsync({
    method,
    params,
    from: userAccount,
  }, function(err, result) {
    if (err) return console.error(err)
    cb(result)
  })

Airswap validation function

function validate(address makerAddress, uint makerAmount, address makerToken,
                      address takerAddress, uint takerAmount, address takerToken,
                      uint256 expiration, uint256 nonce, uint8 v, bytes32 r, bytes32 s) private returns (bytes32) {

        // Hash arguments to identify the order.
        bytes32 hashV = keccak256(makerAddress, makerAmount, makerToken,
            takerAddress, takerAmount, takerToken,
            expiration, nonce);

        bytes memory prefix = "\x19Ethereum Signed Message:\n32";
        bytes32 prefixedHash = sha3(prefix, hashV);

        require(ecrecover(prefixedHash, v, r, s) == makerAddress);

        return hashV;
    }

I got an output signature and did not receive any errors upon signing. Does eth_signTypedData_v3 also sign the verifyingContract address that I supplied and not just the message? I read on your Medium post that a minimum of one domainData parameters was needed, and verifyingContract address was the only one I'm able to use.

image

To Reproduce

Steps to reproduce the behavior:
See above code^

Expected behavior

We currently have no other signing option except to use personal_sign which is unable to recognize hex and instead returns WingDing-esque characters to the user (see screenshot). This issue is discussed here - #3931

We need to be able sign and order hash (hex) and return the same signature output as personal_sign but in a presentable fashion.
image

Browser details (please complete the following information):

  • OS: Mac 10.13.6
  • Browser: Chrome
  • MetaMask Version: 4.12.0
  • New UI

Most helpful comment

We don't currently have plans to improve personal_sign rendering, but if community members feel strongly, we would probably be open to adding a hex tab to that view.

Before opening a PR for such a feature, please propose the behavior, be it a decoding schema (maybe MIME-type like), or just an interface tab in an EIP, or an ethereum-magicians post, since it would require standardization across clients. I think we would probably be open to adding a hex decoding tab, but would also want to give a brief design pass.

In the meanwhile, we will be focusing on EIP712 compatible signing methods, because they are both more human readable, and cheaper to verify on-chain, and I encourage smart contract developers to strive to make their contracts compatible with the new method instead.

Closing this issue, since it reflects the current intended behavior, and the new idea is already being discussed in #3931.

All 6 comments

Hi @pakaplace, thanks for reaching out and taking the time to file an issue. What signature are you verifying this against? How are you verifying the signature produced by eth_signTypedData_v3 is incorrect in this case?

I was able to verify that your code does produce a signature, but I don't see anything in Airswap's contract that would support verifying an eth_signTypedData_v3 signature; instead, it looks like the contract expects a signature from eth_sign.

It's possible that you're signing data using eth_signTypedData_v3 and passing the resulting signature to a contract expecting a different type of signature, most likely one from eth_sign.

Thanks @bitpshr , I added Airswap's contract validate function to my above issue.

For testing purposes, I've been signing this hash with personal_sign: 0xc428c5471cfdd5ff7876056ebb0446d9e383fc7f44b2ce5996b1e2ccebaf633a

I was hoping to get the same signature output with personal_sign and signTypedData_v3.
With the returned signature output of personal_sign, I'm able to recover my address with the Airswap validate function.

Signing the above hash 0x428c54... creates a different output. I inferred that this might be due to

  1. domain parameters being signed in addition to message
  2. \x19Ethereum Signed Message:\n not being appended to the message upon sign

^The above are just guesses...

Thanks for the additional information @pakaplace.

I was hoping to get the same signature output with personal_sign and signTypedData_v3

Signatures produced by personal_sign are not (and were never meant to be) compatible with those produced by eth_signTypedData_v3. These RPC methods encode data differently, resulting in different hash output for the same data input.

Thanks @bitpshr .

Is there any plan to improve the display of hex in personal_sign?

Currently we have the option to display a scary warning message or the "wingdings"- like option in the above snapshot. It was last discussed here #3931, and it looks like @bwheeler96 attempted a PR fix.

Hex signing is used in both Airswap and 0x.

Bounty maybe? ;)

We don't currently have plans to improve personal_sign rendering, but if community members feel strongly, we would probably be open to adding a hex tab to that view.

Before opening a PR for such a feature, please propose the behavior, be it a decoding schema (maybe MIME-type like), or just an interface tab in an EIP, or an ethereum-magicians post, since it would require standardization across clients. I think we would probably be open to adding a hex decoding tab, but would also want to give a brief design pass.

In the meanwhile, we will be focusing on EIP712 compatible signing methods, because they are both more human readable, and cheaper to verify on-chain, and I encourage smart contract developers to strive to make their contracts compatible with the new method instead.

Closing this issue, since it reflects the current intended behavior, and the new idea is already being discussed in #3931.

Was this page helpful?
0 / 5 - 0 ratings