Skip to content
This repository was archived by the owner on Nov 6, 2020. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 35 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions util/EIP-712/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,9 @@ ethereum-types = "0.6.0"
failure = "0.1"
itertools = "0.7"
lazy_static = "1.1"
toolshed = "0.4"
regex = "1.0"
validator = "0.8"
validator_derive = "0.8"
lunarity-lexer = "0.1"
lunarity-lexer = "0.2"
rustc-hex = "2.0"
indexmap = "1.0.2"
218 changes: 207 additions & 11 deletions util/EIP-712/src/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use std::str::FromStr;
use itertools::Itertools;
use indexmap::IndexSet;
use serde_json::to_value;
use crate::parser::{Parser, Type};
use crate::parser::{parse_type, Type};
use crate::error::{Result, ErrorKind, serde_error};
use crate::eip712::{EIP712, MessageTypes};
use rustc_hex::FromHex;
Expand Down Expand Up @@ -56,11 +56,17 @@ fn build_dependencies<'a>(message_type: &'a str, message_types: &'a MessageTypes
deps.insert(item);

for field in fields {
// check if this field is an array type
let field_type = if let Some(index) = field.type_.find('[') {
&field.type_[..index]
} else {
&field.type_
};
// seen this type before? or not a custom type skip
if deps.contains(&*field.type_) || !message_types.contains_key(&*field.type_) {
continue;
if deps.contains(field_type) || !message_types.contains_key(field_type) {
Comment thread
seunlanlege marked this conversation as resolved.
Outdated
continue
}
types.insert(&*field.type_);
types.insert(field_type);
}
}
};
Expand Down Expand Up @@ -99,7 +105,6 @@ fn type_hash(message_type: &str, typed_data: &MessageTypes) -> Result<H256> {
}

fn encode_data(
parser: &Parser,
message_type: &Type,
message_types: &MessageTypes,
value: &Value,
Expand All @@ -122,7 +127,7 @@ fn encode_data(
}

for item in values {
let mut encoded = encode_data(parser, &*inner, &message_types, item, field_name)?;
let mut encoded = encode_data(&*inner, &message_types, item, field_name)?;
items.append(&mut encoded);
}

Expand All @@ -135,8 +140,8 @@ fn encode_data(

for field in message_types.get(ident).expect("Already checked in match guard; qed") {
let value = &value[&field.name];
let type_ = parser.parse_type(&*field.type_)?;
let mut encoded = encode_data(parser, &type_, &message_types, &value, Some(&*field.name))?;
let type_ = parse_type(&*field.type_)?;
let mut encoded = encode_data(&type_, &message_types, &value, Some(&*field.name))?;
tokens.append(&mut encoded);
}

Expand Down Expand Up @@ -213,10 +218,9 @@ pub fn hash_structured_data(typed_data: EIP712) -> Result<H256> {
// EIP-191 compliant
let prefix = (b"\x19\x01").to_vec();
let domain = to_value(&typed_data.domain).unwrap();
let parser = Parser::new();
let (domain_hash, data_hash) = (
encode_data(&parser, &Type::Custom("EIP712Domain".into()), &typed_data.types, &domain, None)?,
encode_data(&parser, &Type::Custom(typed_data.primary_type), &typed_data.types, &typed_data.message, None)?
encode_data(&Type::Custom("EIP712Domain".into()), &typed_data.types, &domain, None)?,
encode_data(&Type::Custom(typed_data.primary_type), &typed_data.types, &typed_data.message, None)?
);
let concat = [&prefix[..], &domain_hash[..], &data_hash[..]].concat();
Ok(keccak(concat))
Expand Down Expand Up @@ -412,4 +416,196 @@ mod tests {
ErrorKind::UnequalArrayItems(2, "Person[2]".into(), 1)
)
}

#[test]
fn test_typed_data_v4() {
let string = r#"{
"types": {
"EIP712Domain": [
{
"name": "name",
"type": "string"
},
{
"name": "version",
"type": "string"
},
{
"name": "chainId",
"type": "uint256"
},
{
"name": "verifyingContract",
"type": "address"
}
],
"Person": [
{
"name": "name",
"type": "string"
},
{
"name": "wallets",
"type": "address[]"
}
],
"Mail": [
{
"name": "from",
"type": "Person"
},
{
"name": "to",
"type": "Person[]"
},
{
"name": "contents",
"type": "string"
}
],
"Group": [
{
"name": "name",
"type": "string"
},
{
"name": "members",
"type": "Person[]"
}
]
},
"domain": {
"name": "Ether Mail",
"version": "1",
"chainId": "0x1",
"verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
},
"primaryType": "Mail",
"message": {
"from": {
"name": "Cow",
"wallets": [
"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
"0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF"
]
},
"to": [
{
"name": "Bob",
"wallets": [
"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB",
"0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57",
"0xB0B0b0b0b0b0B000000000000000000000000000"
]
}
],
"contents": "Hello, Bob!"
}
}"#;

let typed_data = from_str::<EIP712>(string).expect("alas error!");
let hash = hash_structured_data(typed_data.clone()).expect("alas error!");
assert_eq!(
&format!("{:x}", hash)[..],

"a85c2e2b118698e88db68a8105b794a8cc7cec074e89ef991cb4f5f533819cc2",
);
}

#[test]
fn test_typed_data_v4_custom_array() {
let string = r#"{
"types": {
"EIP712Domain": [
{
"name": "name",
"type": "string"
},
{
"name": "version",
"type": "string"
},
{
"name": "chainId",
"type": "uint256"
},
{
"name": "verifyingContract",
"type": "address"
}
],
"Person": [
{
"name": "name",
"type": "string"
},
{
"name": "wallets",
"type": "address[]"
}
],
"Mail": [
{
"name": "from",
"type": "Person"
},
{
"name": "to",
"type": "Group"
},
{
"name": "contents",
"type": "string"
}
],
"Group": [
{
"name": "name",
"type": "string"
},
{
"name": "members",
"type": "Person[]"
}
]
},
"domain": {
"name": "Ether Mail",
"version": "1",
"chainId": "0x1",
"verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
},
"primaryType": "Mail",
"message": {
"from": {
"name": "Cow",
"wallets": [
"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
"0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF"
]
},
"to": {
"name": "Farmers",
"members": [
{
"name": "Bob",
"wallets": [
"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB",
"0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57",
"0xB0B0b0b0b0b0B000000000000000000000000000"
]
}
]
},
"contents": "Hello, Bob!"
}
}"#;
let typed_data = from_str::<EIP712>(string).expect("alas error!");
let hash = hash_structured_data(typed_data.clone()).expect("alas error!");

assert_eq!(
&format!("{:x}", hash)[..],
"cd8b34cd09c541cfc0a2fcd147e47809b98b335649c2aa700db0b0c4501a02a0",
);
}
}
Loading