chore(rpc): use TypedData type in eth_signTypedData signature (#8845)

This commit is contained in:
DaniPopes
2024-06-14 18:46:37 +02:00
committed by GitHub
parent e6017c3cd9
commit 40d588470f
8 changed files with 39 additions and 40 deletions

1
Cargo.lock generated
View File

@ -7883,6 +7883,7 @@ dependencies = [
name = "reth-rpc-api"
version = "1.0.0-rc.1"
dependencies = [
"alloy-dyn-abi",
"jsonrpsee",
"reth-engine-primitives",
"reth-network-peers",

View File

@ -19,9 +19,12 @@ reth-engine-primitives.workspace = true
reth-network-peers.workspace = true
# misc
alloy-dyn-abi = { workspace = true, features = ["eip712"] }
jsonrpsee = { workspace = true, features = ["server", "macros"] }
serde_json.workspace = true
serde = { workspace = true, features = ["derive"] }
[dev-dependencies]
serde_json.workspace = true
[features]
client = ["jsonrpsee/client", "jsonrpsee/async-client"]

View File

@ -1,3 +1,4 @@
use alloy_dyn_abi::TypedData;
use jsonrpsee::{core::RpcResult, proc_macros::rpc};
use reth_primitives::{Address, BlockId, BlockNumberOrTag, Bytes, B256, B64, U256, U64};
use reth_rpc_types::{
@ -296,7 +297,7 @@ pub trait EthApi {
/// Signs data via [EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md).
#[method(name = "signTypedData")]
async fn sign_typed_data(&self, address: Address, data: serde_json::Value) -> RpcResult<Bytes>;
async fn sign_typed_data(&self, address: Address, data: TypedData) -> RpcResult<Bytes>;
/// Returns the account and storage values of the specified account including the Merkle-proof.
/// This call can be used to verify that the data you are pulling from is not tampered with.

View File

@ -159,6 +159,17 @@ where
let transaction_request = TransactionRequest::default();
let bytes = Bytes::default();
let tx = Bytes::from(hex!("02f871018303579880850555633d1b82520894eee27662c2b8eba3cd936a23f039f3189633e4c887ad591c62bdaeb180c080a07ea72c68abfb8fca1bd964f0f99132ed9280261bdca3e549546c0205e800f7d0a05b4ef3039e9c9b9babc179a1878fb825b5aaf5aed2fa8744854150157b08d6f3"));
let typed_data = serde_json::from_str(
r#"{
"types": {
"EIP712Domain": []
},
"primaryType": "EIP712Domain",
"domain": {},
"message": {}
}"#,
)
.unwrap();
// Implemented
EthApiClient::protocol_version(client).await.unwrap();
@ -180,9 +191,7 @@ where
EthApiClient::uncle_by_block_hash_and_index(client, hash, index).await.unwrap();
EthApiClient::uncle_by_block_number_and_index(client, block_number, index).await.unwrap();
EthApiClient::sign(client, address, bytes.clone()).await.unwrap_err();
EthApiClient::sign_typed_data(client, address, jsonrpsee::core::JsonValue::Null)
.await
.unwrap_err();
EthApiClient::sign_typed_data(client, address, typed_data).await.unwrap_err();
EthApiClient::transaction_by_hash(client, tx_hash).await.unwrap();
EthApiClient::transaction_by_block_hash_and_index(client, hash, index).await.unwrap();
EthApiClient::transaction_by_block_number_and_index(client, block_number, index).await.unwrap();

View File

@ -24,10 +24,8 @@ futures.workspace = true
jsonrpsee = { workspace = true, features = ["client", "async-client"] }
serde_json.workspace = true
# assertions
similar-asserts.workspace = true
[dev-dependencies]
tokio = { workspace = true, features = ["rt-multi-thread", "macros", "rt"] }

View File

@ -1,6 +1,16 @@
//! Implementation of the [`jsonrpsee`] generated [`reth_rpc_api::EthApiServer`] trait
//! Handles RPC requests for the `eth_` namespace.
use super::EthApiSpec;
use crate::{
eth::{
api::{EthApi, EthTransactions},
error::EthApiError,
revm_utils::EvmOverrides,
},
result::{internal_rpc_err, ToRpcResult},
};
use alloy_dyn_abi::TypedData;
use jsonrpsee::core::RpcResult as Result;
use reth_evm::ConfigureEvm;
use reth_network_api::NetworkInfo;
@ -16,20 +26,8 @@ use reth_rpc_types::{
FeeHistory, Header, Index, RichBlock, StateContext, SyncStatus, TransactionRequest, Work,
};
use reth_transaction_pool::TransactionPool;
use serde_json::Value;
use tracing::trace;
use crate::{
eth::{
api::{EthApi, EthTransactions},
error::EthApiError,
revm_utils::EvmOverrides,
},
result::{internal_rpc_err, ToRpcResult},
};
use super::EthApiSpec;
#[async_trait::async_trait]
impl<Provider, Pool, Network, EvmConfig> EthApiServer for EthApi<Provider, Pool, Network, EvmConfig>
where
@ -391,7 +389,7 @@ where
/// Handler for: `eth_sign`
async fn sign(&self, address: Address, message: Bytes) -> Result<Bytes> {
trace!(target: "rpc::eth", ?address, ?message, "Serving eth_sign");
Ok(Self::sign(self, address, message).await?)
Ok(Self::sign(self, address, &message).await?)
}
/// Handler for: `eth_signTransaction`
@ -400,9 +398,9 @@ where
}
/// Handler for: `eth_signTypedData`
async fn sign_typed_data(&self, address: Address, data: Value) -> Result<Bytes> {
async fn sign_typed_data(&self, address: Address, data: TypedData) -> Result<Bytes> {
trace!(target: "rpc::eth", ?address, ?data, "Serving eth_signTypedData");
Ok(Self::sign_typed_data(self, data, address)?)
Ok(Self::sign_typed_data(self, &data, address)?)
}
/// Handler for: `eth_getProof`

View File

@ -9,22 +9,14 @@ use crate::{
};
use alloy_dyn_abi::TypedData;
use reth_primitives::{Address, Bytes};
use serde_json::Value;
impl<Provider, Pool, Network, EvmConfig> EthApi<Provider, Pool, Network, EvmConfig> {
pub(crate) async fn sign(&self, account: Address, message: Bytes) -> EthResult<Bytes> {
Ok(self.find_signer(&account)?.sign(account, &message).await?.to_hex_bytes())
pub(crate) async fn sign(&self, account: Address, message: &[u8]) -> EthResult<Bytes> {
Ok(self.find_signer(&account)?.sign(account, message).await?.to_hex_bytes())
}
pub(crate) fn sign_typed_data(&self, data: Value, account: Address) -> EthResult<Bytes> {
Ok(self
.find_signer(&account)?
.sign_typed_data(
account,
&serde_json::from_value::<TypedData>(data)
.map_err(|_| SignError::InvalidTypedData)?,
)?
.to_hex_bytes())
pub(crate) fn sign_typed_data(&self, data: &TypedData, account: Address) -> EthResult<Bytes> {
Ok(self.find_signer(&account)?.sign_typed_data(account, data)?.to_hex_bytes())
}
pub(crate) fn find_signer(

View File

@ -115,7 +115,6 @@ impl EthSigner for DevSigner {
fn sign_typed_data(&self, address: Address, payload: &TypedData) -> Result<Signature> {
let encoded = payload.eip712_signing_hash().map_err(|_| SignError::InvalidTypedData)?;
// let b256 = encoded;
self.sign_hash(encoded, address)
}
}
@ -136,8 +135,7 @@ mod tests {
#[tokio::test]
async fn test_sign_type_data() {
let eip_712_example = serde_json::json!(
r#"{
let eip_712_example = r#"{
"types": {
"EIP712Domain": [
{
@ -200,9 +198,8 @@ mod tests {
},
"contents": "Hello, Bob!"
}
}"#
);
let data: TypedData = serde_json::from_value(eip_712_example).unwrap();
}"#;
let data: TypedData = serde_json::from_str(eip_712_example).unwrap();
let signer = build_signer();
let sig = signer.sign_typed_data(Address::default(), &data).unwrap();
let expected = Signature {