-
Notifications
You must be signed in to change notification settings - Fork 280
/
eip712hashing.sol
87 lines (72 loc) · 2.93 KB
/
eip712hashing.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
pragma solidity ^0.4.24;
contract Example {
struct EIP712Domain {
string name;
string version;
uint256 chainId;
address verifyingContract;
}
struct Person {
string name;
address wallet;
}
struct Mail {
Person from;
Person to;
string contents;
}
bytes32 constant EIP712DOMAIN_TYPEHASH =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
bytes32 constant PERSON_TYPEHASH = keccak256("Person(string name,address wallet)");
bytes32 constant MAIL_TYPEHASH =
keccak256("Mail(Person from,Person to,string contents)Person(string name,address wallet)");
bytes32 DOMAIN_SEPARATOR;
constructor() public {
DOMAIN_SEPARATOR = hash(
EIP712Domain({
name: "Ether Mail",
version: "1",
chainId: 1,
// verifyingContract: this
verifyingContract: 0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC
})
);
}
function hash(EIP712Domain eip712Domain) internal pure returns (bytes32) {
return keccak256(
abi.encode(
EIP712DOMAIN_TYPEHASH,
keccak256(bytes(eip712Domain.name)),
keccak256(bytes(eip712Domain.version)),
eip712Domain.chainId,
eip712Domain.verifyingContract
)
);
}
function hash(Person person) internal pure returns (bytes32) {
return keccak256(abi.encode(PERSON_TYPEHASH, keccak256(bytes(person.name)), person.wallet));
}
function hash(Mail mail) internal pure returns (bytes32) {
return keccak256(abi.encode(MAIL_TYPEHASH, hash(mail.from), hash(mail.to), keccak256(bytes(mail.contents))));
}
function verify(Mail mail, uint8 v, bytes32 r, bytes32 s) internal view returns (bool) {
// Note: we need to use `encodePacked` here instead of `encode`.
bytes32 digest = keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR, hash(mail)));
return ecrecover(digest, v, r, s) == mail.from.wallet;
}
function test() public view returns (bool) {
// Example signed message
Mail memory mail = Mail({
from: Person({name: "Cow", wallet: 0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826}),
to: Person({name: "Bob", wallet: 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB}),
contents: "Hello, Bob!"
});
uint8 v = 28;
bytes32 r = 0x4355c47d63924e8a72e509b65029052eb6c299d53a04e167c5775fd466751c9d;
bytes32 s = 0x07299936d304c153f6443dfa05f40ff007d72911b6f72307f996231605b91562;
assert(DOMAIN_SEPARATOR == 0xf2cee375fa42b42143804025fc449deafd50cc031ca257e0b194a650a912090f);
assert(hash(mail) == 0xc52c0ee5d84264471806290a3f2c4cecfc5490626bf912d01f240d7a274b371e);
assert(verify(mail, v, r, s));
return true;
}
}