Skip to content

Commit

Permalink
Add custom serialization for Address (#742)
Browse files Browse the repository at this point in the history
* Add custom serialization for Address

* Update crates/primitives/src/bits/serde.rs

Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com>

* Use to_checksum_buffer

---------

Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com>
  • Loading branch information
jenpaff and DaniPopes authored Sep 20, 2024
1 parent 6d2deb2 commit 4b823f7
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 1 deletion.
49 changes: 49 additions & 0 deletions crates/dyn-abi/src/eip712/typed_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,55 @@ mod tests {
);
}

#[test]
fn test_full_domain_contract_format() {
let json = json!({
"types": {
"EIP712Domain": [
{
"name": "name",
"type": "string"
},
{
"name": "version",
"type": "string"
},
{
"name": "chainId",
"type": "uint256"
},
{
"name": "verifyingContract",
"type": "address"
},
{
"name": "salt",
"type": "bytes32"
}
]
},
"primaryType": "EIP712Domain",
"domain": {
"name": "example.metamask.io",
"version": "1",
"chainId": 1,
"verifyingContract": "0xfb6916095ca1df60bb79ce92ce3ea74c37c5d359"
},
"message": {}
});

let typed_data: TypedData = serde_json::from_value(json).unwrap();

let serialized_contract = typed_data.domain.verifying_contract.unwrap();
assert_eq!(serialized_contract.to_string(), "0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359");

let hash = typed_data.eip712_signing_hash().unwrap();
assert_eq!(
hex::encode(&hash[..]),
"4863a6e9735dee205f3010f78d613c425a26ae2db6e4cf207f88b5d26735d378",
);
}

#[test]
fn test_minimal_message() {
let json = json!({
Expand Down
3 changes: 3 additions & 0 deletions crates/primitives/src/bits/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,9 @@ macro_rules! impl_allocative {
#[macro_export]
#[cfg(feature = "serde")]
macro_rules! impl_serde {
(Address) => {
// Use custom implementation for Address
};
($t:ty) => {
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
impl $crate::private::serde::Serialize for $t {
Expand Down
35 changes: 34 additions & 1 deletion crates/primitives/src/bits/serde.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,33 @@
use super::FixedBytes;
use super::{Address, FixedBytes};
use core::fmt;
use serde::{
de::{self, Visitor},
Deserialize, Deserializer, Serialize, Serializer,
};

impl Serialize for Address {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if serializer.is_human_readable() {
let checksum_address = self.to_checksum_buffer(None);
serializer.serialize_str(checksum_address.as_str())
} else {
serializer.serialize_bytes(self.as_slice())
}
}
}

impl<'de> Deserialize<'de> for Address {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Deserialize::deserialize(deserializer).map(Self)
}
}

impl<const N: usize> Serialize for FixedBytes<N> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
if serializer.is_human_readable() {
Expand Down Expand Up @@ -67,6 +90,8 @@ impl<'de, const N: usize> Deserialize<'de> for FixedBytes<N> {

#[cfg(test)]
mod tests {
use core::str::FromStr;

use super::*;
use alloc::string::ToString;
use serde::Deserialize;
Expand All @@ -88,6 +113,14 @@ mod tests {
assert_eq!(serde_json::from_value::<FixedBytes<12>>(val).unwrap(), bytes);
}

#[test]
fn serde_address() {
let address = Address::from_str("0xfb6916095ca1df60bb79ce92ce3ea74c37c5d359").unwrap();
let ser = serde_json::to_string(&address).unwrap();
// serialize in checksum format
assert_eq!(ser, "\"0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359\"");
}

#[test]
fn serde_num_array() {
let json = serde_json::json! {{"fixed": [0,1,2,3,4]}};
Expand Down

0 comments on commit 4b823f7

Please sign in to comment.