michielpost / MetaMask.Blazor

Use MetaMask with Blazor WebAssembly
MIT License
44 stars 21 forks source link

Add support for SignTypedDataV4 #5

Closed AlexandreBazeaud closed 2 years ago

AlexandreBazeaud commented 2 years ago

Add support to sign using eth_signTypedData_v4 method from metamask example of utilisation

await window.ethereum.request({method: 'eth_signTypedData_v4', params:["0x",'{"types":{"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"}],"Message":[{"name":"contents","type":"string"}]},"primaryType":"Message","domain":{"name":"AAA","version":"1","chainId":250},"message":{"contents":"Salut"}}'],from:"0x"})
AlexandreBazeaud commented 2 years ago

Proposition on the way to handle TypedData Class:

public class TypedDataPayload<T>
{
    public Dictionary<string,TypeMemberValue[]> Types { get; set; }
    public string PrimaryType { get; set; }
    public Domain Domain { get; set; }
    public T Message { get; set; }

    public string ToJson()
    {
        var serializerSettings = new JsonSerializerSettings
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver()
            {
                NamingStrategy = new CamelCaseNamingStrategy()
                {
                    ProcessDictionaryKeys = false
                }
            },

            DefaultValueHandling = DefaultValueHandling.Ignore
        };
        return JsonConvert.SerializeObject(this, serializerSettings);
    }
}

public class Domain
{
    public string Name { get; set; }
    public string Version { get; set; }
    public BigInteger? ChainId { get; set; }
}

public class TypeMemberValue
{
    public string Name { get; set; }
    public string Type { get; set; }
}

Usage:

public record struct Message(string contents);
new TypedDataPayload<Message>
        {
            Domain = new Domain
            {
                Name = "AAA",
                Version = "1",
                ChainId = 250
            },
            Types = new Dictionary<string, TypeMemberValue[]>
            {
                ["EIP712Domain"] = new[]
                {
                    new TypeMemberValue { Name = "name", Type = "string" },
                    new TypeMemberValue { Name = "version", Type = "string" },
                    new TypeMemberValue { Name = "chainId", Type = "uint256" }
                },
                ["Message"] = new[]
                {
                    new TypeMemberValue { Name = "contents", Type = "string" }
                }
            },
            PrimaryType = "Message",
            Message = new Message
            {
                contents = "Salut"
            }
        };

and ToJson() => {"types":{"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"}],"Message":[{"name":"contents","type":"string"}]},"primaryType":"Message","domain":{"name":"AAA","version":"1","chainId":250},"message":{"contents":"Salut"}} Which is a totally valid string to input for eth_signTypedData_v4

michielpost commented 2 years ago

Thanks for the issue and PR. I also updated the sample application and used the code from this issue.