chore: simplify eip712 example (#492)
* chore(contract): gate eip712 * examples: simplify permit hash * chore: fmt
This commit is contained in:
parent
d7ab229a4c
commit
0c94b58cd5
|
@ -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"
|
||||||
|
@ -90,4 +90,4 @@ serde = { version = "1.0.124", features = ["derive"] }
|
||||||
serde_json = "1.0.64"
|
serde_json = "1.0.64"
|
||||||
tokio = { version = "1.5", features = ["macros", "rt-multi-thread"] }
|
tokio = { version = "1.5", features = ["macros", "rt-multi-thread"] }
|
||||||
hex = "0.4.3"
|
hex = "0.4.3"
|
||||||
bytes = "1.1.0"
|
bytes = "1.1.0"
|
||||||
|
|
|
@ -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 = []
|
||||||
|
|
|
@ -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"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue