-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy patheip712example.sol
184 lines (159 loc) · 5.42 KB
/
eip712example.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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
// SPDX-License-Identifier: MIT
//https://testnet.bscscan.com/address/0x1ba491c5078a109685877f5a368dde0303a83fe5#code
pragma solidity 0.8.17;
pragma experimental ABIEncoderV2;
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;
uint256 amount;
uint256 expiration;
}
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,uint256 amount,uint256 expiration)Person(string name,address wallet)"
);
bytes32 public DOMAIN_SEPARATOR;
constructor () {
DOMAIN_SEPARATOR = hash(EIP712Domain({
name: "Ether Mail",
version: '1',
chainId: 1,
// verifyingContract: this
verifyingContract: 0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC
}));
}
function hash(EIP712Domain memory eip712Domain) public pure returns (bytes32) {
return keccak256(abi.encode(
EIP712DOMAIN_TYPEHASH,
keccak256(bytes(eip712Domain.name)),
keccak256(bytes(eip712Domain.version)),
eip712Domain.chainId,
eip712Domain.verifyingContract
));
}
function hash(Person memory person) public pure returns (bytes32) {
return keccak256(abi.encode(
PERSON_TYPEHASH,
keccak256(bytes(person.name)),
person.wallet
));
}
function hash(Mail memory mail) public pure returns (bytes32) {
return keccak256(abi.encode(
MAIL_TYPEHASH,
hash(mail.from),
hash(mail.to),
keccak256(bytes(mail.contents)),
mail.amount,
mail.expiration
));
}
function verify(Mail memory mail, uint8 v, bytes32 r, bytes32 s) public 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 verify(Mail memory mail, bytes memory signature) public view returns (bool) {
// Note: we need to use `encodePacked` here instead of `encode`.
bytes32 digest = keccak256(abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR,
hash(mail)
));
(uint8 v, bytes32 r, bytes32 s) = parseSignature(signature);
return ecrecover(digest, v, r, s) == mail.from.wallet;
}
function parseSignature(bytes memory signature)
public
pure
returns (
uint8 v,
bytes32 r,
bytes32 s
)
{
// The signature format is a compact form of:
// {bytes32 r}{bytes32 s}{uint8 v}
// Compact means, uint8 is not padded to 32 bytes.
assembly {
// solium-disable-line security/no-inline-assembly
r := mload(add(signature, 32))
s := mload(add(signature, 64))
// Here we are loading the last 32 bytes, including 31 bytes
// of 's'. There is no 'mload8' to do this.
//
// 'byte' is not working due to the Solidity parser, so lets
// use the second best option, 'and'
v := and(mload(add(signature, 65)), 0xff)
}
if (v < 27) {
v += 27;
}
require(v == 27 || v == 28, "invalid v of signature(r, s, v)");
}
function test() public view returns (bool) {
// Example signed message
Mail memory mail = Mail({
from: Person({
name: "Cow",
wallet: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
}),
to: Person({
name: "Bob",
wallet: 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB
}),
contents: "Hello, Bob!",
amount: 10000000000,
expiration: 1667659989
});
uint8 v = 27;
bytes32 r = 0xfe1408ef873223d473a9130ecafad79c297b79286e38d90bb107f049831bbb61;
bytes32 s = 0x11058bb70448776840216e6ceb27fe9f56a7fb9682fc63c0ab708b7bba296baa;
assert(DOMAIN_SEPARATOR == 0xf2cee375fa42b42143804025fc449deafd50cc031ca257e0b194a650a912090f);
assert(hash(mail) == 0x83fb919a6723739a9187fa6b145d321d7a747703fb65ff02e5adca18a3537c2a);
assert(verify(mail, v, r, s));
return true;
}
function getDigest() public view returns (bytes32){
Mail memory mail = Mail({
from: Person({
name: "Cow",
wallet: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
}),
to: Person({
name: "Bob",
wallet: 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB
}),
contents: "Hello, Bob!",
amount: 10000000000,
expiration: 1667659989
});
bytes32 digest = keccak256(abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR,
hash(mail)
));
return digest;
}
}