chore: simplify eip712 example (#492)

* chore(contract): gate eip712

* examples: simplify permit hash

* chore: fmt
This commit is contained in:
Georgios Konstantopoulos 2021-10-08 17:31:42 +01:00 committed by GitHub
parent d7ab229a4c
commit 0c94b58cd5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 35 additions and 90 deletions

View File

@ -81,7 +81,7 @@ ethers-signers = { version = "^0.5.0", default-features = false, path = "./ether
ethers-middleware = { version = "^0.5.0", default-features = false, path = "./ethers-middleware" } ethers-middleware = { version = "^0.5.0", default-features = false, path = "./ethers-middleware" }
[dev-dependencies] [dev-dependencies]
ethers-contract = { version = "^0.5.0", default-features = false, path = "./ethers-contract", features = ["abigen"] } ethers-contract = { version = "^0.5.0", default-features = false, path = "./ethers-contract", features = ["abigen", "eip712"] }
ethers-providers = { version = "^0.5.0", default-features = false, path = "./ethers-providers", features = ["ws", "ipc"] } ethers-providers = { version = "^0.5.0", default-features = false, path = "./ethers-providers", features = ["ws", "ipc"] }
anyhow = "1.0.39" anyhow = "1.0.39"

View File

@ -11,9 +11,10 @@ keywords = ["ethereum", "web3", "celo", "ethers"]
[dependencies] [dependencies]
ethers-providers = { version = "^0.5.0", path = "../ethers-providers", default-features = false } ethers-providers = { version = "^0.5.0", path = "../ethers-providers", default-features = false }
ethers-core = { version = "^0.5.0", path = "../ethers-core", default-features = false, features = ["eip712"]} ethers-core = { version = "^0.5.0", path = "../ethers-core", default-features = false }
ethers-contract-abigen = { version = "^0.5.0", path = "ethers-contract-abigen", optional = true } ethers-contract-abigen = { version = "^0.5.0", path = "ethers-contract-abigen", optional = true }
ethers-contract-derive = { version = "^0.5.0", path = "ethers-contract-derive", optional = true } ethers-contract-derive = { version = "^0.5.0", path = "ethers-contract-derive", optional = true }
ethers-derive-eip712 = { version = "0.1.0", path = "../ethers-core/ethers-derive-eip712", optional = true }
serde = { version = "1.0.124", default-features = false } serde = { version = "1.0.124", default-features = false }
serde_json = { version = "1.0.64", default-features = false } serde_json = { version = "1.0.64", default-features = false }
@ -29,12 +30,14 @@ ethers-providers = { version = "^0.5.0", path = "../ethers-providers", default-f
ethers-signers = { version = "^0.5.0", path = "../ethers-signers" } ethers-signers = { version = "^0.5.0", path = "../ethers-signers" }
ethers-contract-abigen = { version = "^0.5.0", path = "ethers-contract-abigen" } ethers-contract-abigen = { version = "^0.5.0", path = "ethers-contract-abigen" }
ethers-contract-derive = { version = "^0.5.0", path = "ethers-contract-derive" } ethers-contract-derive = { version = "^0.5.0", path = "ethers-contract-derive" }
ethers-core = { version = "^0.5.0", path = "../ethers-core", default-features = false, features = ["eip712"]}
ethers-derive-eip712 = { version = "0.1.0", path = "../ethers-core/ethers-derive-eip712"} ethers-derive-eip712 = { version = "0.1.0", path = "../ethers-core/ethers-derive-eip712"}
[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
tokio = { version = "1.5", default-features = false, features = ["macros"] } tokio = { version = "1.5", default-features = false, features = ["macros"] }
[features] [features]
eip712 = ["ethers-derive-eip712", "ethers-core/eip712"]
abigen = ["ethers-contract-abigen", "ethers-contract-derive"] abigen = ["ethers-contract-abigen", "ethers-contract-derive"]
celo = ["legacy", "ethers-core/celo", "ethers-core/celo", "ethers-providers/celo"] celo = ["legacy", "ethers-core/celo", "ethers-core/celo", "ethers-providers/celo"]
legacy = [] legacy = []

View File

@ -1,94 +1,36 @@
use ethers::{ use ethers::{
abi, contract::Eip712,
abi::Token, contract::EthAbiType,
prelude::U256, core::types::transaction::eip712::Eip712,
types::Address, types::{Address, U256},
utils,
utils::{keccak256, parse_ether},
}; };
const UNISWAP_V2_USDC_ETH_PAIR: &'static str = "0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc";
// Generate the EIP712 permit hash to sign for a Uniswap V2 pair. // Generate the EIP712 permit hash to sign for a Uniswap V2 pair.
// https://eips.ethereum.org/EIPS/eip-712 // https://eips.ethereum.org/EIPS/eip-712
// https://eips.ethereum.org/EIPS/eip-2612 // https://eips.ethereum.org/EIPS/eip-2612
fn main() { #[derive(Eip712, EthAbiType, Clone)]
// Test data #[eip712(
let owner: Address = "0x617072Cb2a1897192A9d301AC53fC541d35c4d9D" name = "Uniswap V2",
.parse() version = "1",
.unwrap(); chain_id = 1,
let spender: Address = "0x2819c144D5946404C0516B6f817a960dB37D4929" verifying_contract = "0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc"
.parse() )]
.unwrap(); struct Permit {
let value = parse_ether(10).unwrap(); owner: Address,
let nonce = U256::from(1); spender: Address,
let deadline = U256::from(3133728498 as u32); value: U256,
let verifying_contract: Address = UNISWAP_V2_USDC_ETH_PAIR.parse().unwrap(); nonce: U256,
let name = "Uniswap V2"; deadline: U256,
let version = "1"; }
let chainid = 1;
fn main() {
// Typehash for the permit() function let permit = Permit {
let permit_typehash = utils::keccak256( owner: Address::random(),
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)", spender: Address::random(),
); value: 100.into(),
// Typehash for the struct used to generate the domain separator nonce: 0.into(),
let domain_typehash = keccak256( deadline: U256::MAX,
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)", };
); let permit_hash = permit.encode_eip712().unwrap();
println!("Permit hash: 0x{}", hex::encode(permit_hash));
// Corresponds to solidity's abi.encode()
let domain_separator_input = abi::encode(&vec![
Token::Uint(U256::from(domain_typehash)),
Token::Uint(U256::from(keccak256(&name))),
Token::Uint(U256::from(keccak256(&version))),
Token::Uint(U256::from(chainid)),
Token::Address(verifying_contract),
]);
// Corresponds to the following solidity:
// DOMAIN_SEPARATOR = keccak256(
// abi.encode(
// keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'),
// keccak256(bytes(name)),
// keccak256(bytes('1')),
// chainId,
// address(this)
// )
// );
let domain_separator = keccak256(&domain_separator_input);
// Corresponds to solidity's abi.encode()
let struct_input = abi::encode(&vec![
Token::Uint(U256::from(permit_typehash)),
Token::Address(owner),
Token::Address(spender),
Token::Uint(value),
Token::Uint(nonce),
Token::Uint(deadline),
]);
let struct_hash = keccak256(&struct_input);
// Corresponds to solidity's abi.encodePacked()
let digest_input = [
&[0x19, 0x01],
domain_separator.as_ref(),
struct_hash.as_ref(),
]
.concat();
// Matches the following solidity:
// bytes32 digest = keccak256(
// abi.encodePacked(
// '\x19\x01',
// DOMAIN_SEPARATOR,
// keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
// )
// );
let permit_hash = keccak256(&digest_input);
assert_eq!(
hex::encode(permit_hash),
"7b90248477de48c0b971e0af8951a55974733455191480e1e117c86cc2a6cd03"
);
} }