ethers-rs: eip712 compatibility problem between ethers-js and ethers-rs
Version
├── ethers v0.5.4 (https://github.com/gakonst/ethers-rs.git#ec00325a)
│ ├── ethers-contract v0.5.3 (https://github.com/gakonst/ethers-rs.git#ec00325a)
│ │ ├── ethers-contract-abigen v0.5.3 (https://github.com/gakonst/ethers-rs.git#ec00325a)
│ │ │ ├── ethers-core v0.5.5 (https://github.com/gakonst/ethers-rs.git#ec00325a)
│ │ ├── ethers-contract-derive v0.5.3 (proc-macro) (https://github.com/gakonst/ethers-rs.git#ec00325a)
│ │ │ ├── ethers-contract-abigen v0.5.3 (https://github.com/gakonst/ethers-rs.git#ec00325a)
│ │ │ │ ├── ethers-core v0.5.5 (https://github.com/gakonst/ethers-rs.git#ec00325a)
│ │ │ ├── ethers-core v0.5.5 (https://github.com/gakonst/ethers-rs.git#ec00325a) (*)
│ │ ├── ethers-core v0.5.5 (https://github.com/gakonst/ethers-rs.git#ec00325a) (*)
│ │ ├── ethers-derive-eip712 v0.1.0 (proc-macro) (https://github.com/gakonst/ethers-rs.git#ec00325a)
│ │ │ ├── ethers-core v0.5.5 (https://github.com/gakonst/ethers-rs.git#ec00325a) (*)
│ │ ├── ethers-providers v0.5.4 (https://github.com/gakonst/ethers-rs.git#ec00325a)
│ │ │ ├── ethers-core v0.5.5 (https://github.com/gakonst/ethers-rs.git#ec00325a) (*)
│ ├── ethers-core v0.5.5 (https://github.com/gakonst/ethers-rs.git#ec00325a) (*)
│ ├── ethers-middleware v0.5.3 (https://github.com/gakonst/ethers-rs.git#ec00325a)
│ │ ├── ethers-contract v0.5.3 (https://github.com/gakonst/ethers-rs.git#ec00325a) (*)
│ │ ├── ethers-core v0.5.5 (https://github.com/gakonst/ethers-rs.git#ec00325a) (*)
│ │ ├── ethers-providers v0.5.4 (https://github.com/gakonst/ethers-rs.git#ec00325a) (*)
│ │ ├── ethers-signers v0.5.3 (https://github.com/gakonst/ethers-rs.git#ec00325a)
│ │ │ ├── ethers-core v0.5.5 (https://github.com/gakonst/ethers-rs.git#ec00325a) (*)
│ ├── ethers-providers v0.5.4 (https://github.com/gakonst/ethers-rs.git#ec00325a) (*)
│ ├── ethers-signers v0.5.3 (https://github.com/gakonst/ethers-rs.git#ec00325a) (*)
│ └── ethers-solc v0.1.0 (https://github.com/gakonst/ethers-rs.git#ec00325a)
│ ├── ethers-core v0.5.5 (https://github.com/gakonst/ethers-rs.git#ec00325a) (*)
Platform windows 11
Description use the etheris sign a typed data and then copy the data & signature to rust side, it verified failed
the js code
const {Wallet, ethers} = require("ethers");
const crypto = require('crypto');
async function sign_eip712() {
const mnemonic = "announce room limb pattern dry unit scale effort smooth jazz weasel alcohol"
const walletMnemonic = Wallet.fromMnemonic(mnemonic)
const domain = {
name: 'Relationship dApp',
version: '1',
chainId: 1,
verifyingContract: '0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc',
//salt: 'aBrqX434MenBV2yBhAf5oD7VrqbSLW3p'
};
const types = {
Receipt : [
{ name: 'address', type: 'string' },
{ name: 'nonce', type: 'string' },
{ name: 'timestamp', type: 'uint256' }
]
};
const value = {
address: walletMnemonic.address,
nonce: crypto.randomBytes(16).toString('base64'),
timestamp: Math.floor(Date.now() / 1000)
};
const rawSignature = await walletMnemonic._signTypedData(domain, types, value);
const signature = ethers.utils.splitSignature(rawSignature);
console.log(JSON.stringify({
address: value.address,
nonce: value.nonce,
timestamp: value.timestamp,
r: signature.r,
s: signature.s,
v: signature.v
}));
}
sign_eip712().then(_ => {})
rust code:
use chrono::{Duration, TimeZone, Utc};
use ethers::types::U256;
use ethers::{
contract::{Eip712, EthAbiType},
core::types::transaction::eip712::Eip712,
types::{Address, Signature},
utils::hex,
};
use serde::{Deserialize, Deserializer};
fn deserialize_u256_from_i64<'de, D>(deserializer: D) -> Result<U256, D::Error>
where
D: Deserializer<'de>,
{
i64::deserialize(deserializer).map(U256::from)
}
#[derive(Clone, Debug, Deserialize, Eip712, EthAbiType)]
#[eip712(
name = "Relationship dApp",
version = "1",
chain_id = 1,
verifying_contract = "0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc"
)]
pub struct Receipt {
pub address: Address,
pub nonce: String,
#[serde(deserialize_with = "deserialize_u256_from_i64")]
pub timestamp: U256,
}
impl Receipt {
pub fn is_expired(&self, expired: Duration) -> bool {
let datetime = Utc.timestamp(self.timestamp.try_into().unwrap(), 0);
(Utc::now() - datetime) > expired
}
pub fn verify(&self, signature: &Signature) -> anyhow::Result<()> {
self.encode_eip712()
.map_err(anyhow::Error::from)
.and_then(|receipt_hash| {
signature
.verify(receipt_hash, self.address)
.map_err(anyhow::Error::from)
})
.map_err(Into::into)
}
}
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Comments: 15 (15 by maintainers)
@Ryanmtate @sebastinez do you folks mind taking a look, given you implemented this feature?
So to make sure we understand, it should be “{ name: ‘address’, type: ‘address’ }”?
Thanks, don’t have time to review deeply right now. Away for the holiday. On the surface everything looks fine. Might suggest testing signature against a third library (e.g. https://www.npmjs.com/package/eip-712) to confirm the problem is on this implementation.
Also might be worth creating a solidity contract to test against.
Will try to find time to dig in deeper over the weekend.
yes, sure, it matches…
Hey @gakonst we’ll look into it 👍