-
Notifications
You must be signed in to change notification settings - Fork 686
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
signMessage doesn't work for bytestring data #71
Comments
Thanks @localethereumMichael for the super detailed description. This makes the issue more clear. Can you confirm the following is correct: public async signByteMessage (params: any[]) {
if (!this._connected) {
throw new Error('Session currently disconnected')
}
params[1] = convertUtf8ToHex(params[1])
const request = this._formatRequest({
method: 'personal_sign',
params
})
try {
const result = await this._sendCallRequest(request)
return result
} catch (error) {
throw error
}
} |
Sorry, I've confused myself. When referring to WalletConnect's current sign(keccak256("\x19Ethereum Signed Message:\n" + len(message) + message)))
Because I got the naming wrong, the method Also, the new method doesn't need to support UTF-8 strings because the dApp developer should use const sigA = await walletConnect.signMessage([address, "hello"]);
const sigB = await walletConnect.signByteMessage([address, "0x68656c6c6f"]);
console.log(sigA === sigB); // true
// These are the same because hex("hello") = "0x68656c6c6f"
// Doesn't need to work:
// await walletConnect.signByteMessage([address, "hello"]); I think the |
I think this might just be a wallet bug. I didn't realize WC is passing over standard Ethereum JSON-RPC requests. Wallets should be treating eth_sign's
I've tested the above in a couple of WalletConnect wallets. To JSON-RPC spec, they should sign 0xdeadbeaf as a bytestring, however they are each signing "0xdeadbeaf" as a UTF-8 string. Wallets should be doing:
What they are actually doing:
|
Ok so I've looked into what you have posted and I think that from the WalletConnect SDK, it was as simple as exposing a new method for personal_sign that will hex encode the message on the JSON-RPC request. It's up to the wallets to currently sign and return a spec-complaint signature. cc @localethereumMichael So with the last update public async signPersonalMessage (params: any[]) {
if (!this._connected) {
throw new Error('Session currently disconnected')
}
if (!isHexStrict(params[1])) {
params[1] = convertUtf8ToHex(params[1])
}
const request = this._formatRequest({
method: 'personal_sign',
params
})
try {
const result = await this._sendCallRequest(request)
return result
} catch (error) {
throw error
}
} |
Fixed on #77 |
Problem
There is no way to sign arbitrary bytestring data. It's only possible to sign data that can be encoded as UTF-8. This is a problem for dApps with smart contracts that require wallets to sign arbitrary nonsense such as hashes (and which don't support EIP-712/signTypedData). LocalEthereum is one of those dApps.
The problem lies in the fact the data needs to be encoded as JSON before it's encrypted. Converting to JSON requires that the input message be encoded as UTF-8.
Whenever we convert an arbitrary bytestring to UTF-8 and then back, we lose data; e.g.:
And so, the wallet receives a corrupted message to sign if we do something like:
What web3.js does
WalletConnect's
signMessage([address, data])
is similar toweb3.eth.personal.sign(data, address)
, however only the latter works for bytestrings currently.To sign a bytestring with web3, you can use
web3.eth.personal.sign('0xabcd', address)
.The specs of
web3.eth.personal.sign
say that if thedata
parameter is a plain string, it will be encoded to hex usingweb3.utils.utf8ToHex
. In other words,data
is expected to be a hex-encoded bytestring however the function allows UTF-8 strings for convenience.In transport, the message is always hex-encoded (i.e. if a dApp asks to sign "hello", the web3 library will ask the wallet to sign "0x68656c6c6f").
Proposal 1
WalletConnect could do the same thing as web3. At the top of
signMessage
, before the_formatRequest
call, it could convertparams[1]
to a hex-encoded string if it isn't already. On the wallet end, it'll decode the message from hex when it gets theeth_sign
call request.walletconnect-monorepo/packages/core/src/index.ts
Lines 536 to 544 in 9496ace
For example:
(
isHexStrict
andutf8ToHex
are simple functions inweb3.utils
.)Caveats
Proposal 2
Implement the change on the wallet side only. When the wallet sees a call request
eth_sign
with a message beginning with "0x", it'll treat it as a bytestring.This will (a) let the wallet know when it's signing a UTF-8 string; and (b) only cause a breaking change for WC dApps that sign "0xabcd" strings intended to be displayed as UTF-8.
Proposal 3
Create a new method called something like
signByteMessage
and a new corresponding call request. This will resolve both of the caveats.The text was updated successfully, but these errors were encountered: