EIPs/assets/eip-712/Example.sol
Leonid Logvinov d686a655de [WIP] Add eth_signTypedData as a standard for machine-verifiable and human-readable typed data signing with Ethereum keys (#712)
* Add eip-signTypedData

* Change namespace from personal to eth

* Change a way schema hash is combined together with data as proposed by @MicahZoltu

* Add a note about it being implemented in MetaMask as an experimental feature

* Add signerAddress as a parameter

* Add test vectors

* Fix an example

* Missing commas, periods

* Address the feedback

* Add a missing signerAddress parameter in the example

* Change the order of parameters to have an address as a second arg

* Wrote motivation

* WIP

* First draft of specification

* Fixes

* Update to new EIP format

* Assign EIP number

* Clarify encoding of short static byte arrays

* Removed Solidity changes

* Fixup

* Fix typos

* WIP EIP191

* WIP TODO

* WIP Replay attacks

* Fixes the sorted by name example encoding

* Remove Solidity hash

* Added note on replay protection

* Redesign domain separator

* Include images and simple motivation

* Fix up EIP metadata formatting

* Add domain separator

* Remove replay attacks from todo list

* Add Jacob Evans to authors

* Clarify encodeData

* Rename Message example to Mail

* Update mock signing screen

* Rework EIP712Domain

* Update Solidity example

* Update Javascript example

* Relocate files

* Rename DomainSeparator to EIP712Domain (fix)

* Move examples to separate files

* Remove httpOrigin domain parameter

* Update JSON-Schema

* Add registery of version bytes

* Add eip712 to eip191 registery

* Add requires header

* Set correct language on all snipets

* GitHub highlighting for Solidity files

* Update Web3 API specification

* Use abi.encode where possible

* Update JSON-RPC specification

* Asset path repo is ethereums

* Correctly spelling of registry
2018-06-09 20:19:15 +01:00

107 lines
3.1 KiB
Solidity

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;
}
}