Search code examples
swiftethereumcryptocurrencywallet-connect

How to implement eth_signTypedData in swift?


I am developing a crypto wallet, I have implemented personal_sign and eth_sign in swift, how to implement eth_signTypedData, the official walletConnect documentation seems to have no relevant information. Any idears? Thanks!


Solution

  • Very late answer, but I'll try to post some finding and code here, in the hopes of it helps someone looking for it in the future.

    First some preliminary information:

    • eth_signTypedData has at least 4 different versions, as described in https://docs.metamask.io/guide/signing-data.html#signtypeddata-v4 . Depending on what type of complex objects you want to support signing, or how complete you want your implementation to be, some parts of my answer could be missing or outdated. My goal with this implementation was to pass the eth_signTypedData test at https://example.walletconnect.org/
    • The task is separated into two parts: First, parsing the received JSON parameter in some EIP712TypedData object, that cares about proper parsing, encoding and is able to expose the correct data to be signed at the end. Second, actually signing this data, which can depend heavily on what swift library you are using to sign things using your wallet credentials. I will focus on the first part.

    You will need all the files from https://github.com/muratogat/wallet-connect-swift/tree/master/WalletConnect/Models/EIP-712 This is my forked version of WalletConnect (v1) , where I copied necessary files for EIP-712 support from https://github.com/trustwallet/trust-core/tree/833ec3f263bb9b257b6ec04359cb98d1bae7cf17/Sources/Ethereum/Solidity

    The important file here is EIP712TypedData, other files are models that it depends on. With some changes though:

    • Trust Wallet SDK uses Crypto.hash() for keccak256. I did not include their crypto library, but replaced all calls to keccak256 with data.sha3(.keccak256) which is the web3swift way of keccak256 and I already had in my project.
    • Renamed "EthereumAddress" to "EthereumAddressEncoding" to avoid type conflicts in my project
    • FIXED A BUG in Trust Wallet "bytes" encoding, where TW encodes bytes by converting their string representation to bytes, which erroneously included 0x, giving wrong hashes.

    If you manage to get this working in your project and fix any other warnings / errors you may have encountered, you should be able to call :

    let decodedEIP712TypedData = new JSONDecoder().decode(EIP712TypedData.self, from: params[1].data(using: .utf8)!)
    

    Here params is the payload string array you get from the WalletConnect JSONRPCRequest, where the first string is the address and the second string is the structured data JSON object.

    Afterwards,

    decodedEIP712TypedData.signHash
    

    should give you the byte[] to be actually signed.

    Then, depending on your web3 swift library, you can actually have this byte[] signed and respond to the WC request. Note that you should not use personal_sign that adds the Ethereum Signed Message prefix. If your web3 swift library doesn't have convenience methods for directly signing data, you may keccak256 this data manually and use lower level SECP256K1.signForRecovery manually to sign it with your private key.

    Good luck.