Skip to content

Commit 2ba0e29

Browse files
authored
generic state lens client state type (#3574)
2 parents 0543024 + ddcb0f1 commit 2ba0e29

File tree

24 files changed

+817
-465
lines changed

24 files changed

+817
-465
lines changed

Cargo.lock

+12
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@ tendermint-rpc = { git = "https://github.com/unionlabs/tendermint-rs", branch =
280280

281281
alloy = { version = "0.6", default-features = false }
282282
alloy-primitives = { version = "0.8.16", default-features = false }
283+
alloy-sol-types = { version = "0.8.12", default-features = true }
283284

284285
# https://github.com/aptos-labs/aptos-core/pull/12636
285286
aptos-crypto = { git = "https://github.com/unionlabs/aptos-core" }

cosmwasm/ibc-union/light-clients/state-lens-ics23-mpt/src/client.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -133,17 +133,17 @@ impl IbcClient for StateLensIcs23MptLightClient {
133133

134134
let l2_timestamp = extract_uint64(
135135
&header.l2_consensus_state,
136-
client_state.timestamp_offset as usize,
136+
client_state.extra.timestamp_offset as usize,
137137
);
138138

139139
let l2_state_root = extract_bytes32(
140140
&header.l2_consensus_state,
141-
client_state.state_root_offset as usize,
141+
client_state.extra.state_root_offset as usize,
142142
);
143143

144144
let l2_storage_root = extract_bytes32(
145145
&header.l2_consensus_state,
146-
client_state.storage_root_offset as usize,
146+
client_state.extra.storage_root_offset as usize,
147147
);
148148

149149
if client_state.l2_latest_height < header.l2_height.height() {

lib/create3/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ version = "0.1.0"
77

88
[dependencies]
99
alloy-primitives = { workspace = true }
10-
alloy-sol-types = "0.8.12"
10+
alloy-sol-types = { workspace = true }
1111
sha3.workspace = true
1212

1313
[lints]

lib/macros/src/lib.rs

+76-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ use syn::{
1111
punctuated::Punctuated,
1212
spanned::Spanned,
1313
Attribute, Data, DeriveInput, Expr, ExprPath, Field, Fields, GenericParam, Generics, Ident,
14-
Item, ItemEnum, ItemStruct, LitStr, MacroDelimiter, Meta, MetaList, Path, Token, Type, Variant,
15-
WhereClause, WherePredicate,
14+
Index, Item, ItemEnum, ItemStruct, LitStr, MacroDelimiter, Meta, MetaList, Path, Token, Type,
15+
Variant, WhereClause, WherePredicate,
1616
};
1717

1818
#[proc_macro_attribute]
@@ -1107,3 +1107,77 @@ fn parse_ibc_path(path: LitStr) -> Vec<Segment> {
11071107
})
11081108
.collect()
11091109
}
1110+
1111+
#[proc_macro_derive(AsTuple)]
1112+
pub fn as_tuple(ts: TokenStream) -> TokenStream {
1113+
derive_as_tuple(parse_macro_input!(ts as DeriveInput))
1114+
// .inspect(|x| println!("{x}"))
1115+
.map_err(|e| e.into_compile_error())
1116+
.unwrap_or_else(convert::identity)
1117+
.into()
1118+
}
1119+
1120+
fn derive_as_tuple(
1121+
DeriveInput {
1122+
ident,
1123+
generics,
1124+
data,
1125+
..
1126+
}: DeriveInput,
1127+
) -> Result<proc_macro2::TokenStream, syn::Error> {
1128+
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
1129+
1130+
let Data::Struct(data_struct) = data else {
1131+
return Err(syn::Error::new(
1132+
Span::call_site(),
1133+
"only structs are supported",
1134+
));
1135+
};
1136+
1137+
let (into_tuple_fields, as_tuple_fields, from_tuple_fields) = (
1138+
data_struct.fields.members(),
1139+
data_struct.fields.members(),
1140+
data_struct.fields.members(),
1141+
);
1142+
1143+
let field_types = data_struct.fields.iter().map(|f| &f.ty);
1144+
1145+
let from_tuple_tuple_idxs = data_struct
1146+
.fields
1147+
.members()
1148+
.enumerate()
1149+
.map(|(idx, _)| Index::from(idx));
1150+
1151+
Ok(quote! {
1152+
const _: () = {
1153+
#[automatically_derived]
1154+
impl #impl_generics ::unionlabs::tuple::AsTuple for #ident #ty_generics #where_clause {
1155+
type Tuple = (#(#field_types,)*);
1156+
1157+
fn as_tuple(&self) -> <Self::Tuple as ::unionlabs::tuple::Tuple>::Ref<'_> {
1158+
(
1159+
#(
1160+
&self.#as_tuple_fields,
1161+
)*
1162+
)
1163+
}
1164+
1165+
fn into_tuple(self) -> Self::Tuple {
1166+
(
1167+
#(
1168+
self.#into_tuple_fields,
1169+
)*
1170+
)
1171+
}
1172+
1173+
fn from_tuple(tuple: Self::Tuple) -> Self {
1174+
Self {
1175+
#(
1176+
#from_tuple_fields: tuple.#from_tuple_tuple_idxs,
1177+
)*
1178+
}
1179+
}
1180+
}
1181+
};
1182+
})
1183+
}

lib/state-lens-ics23-ics23-light-client-types/Cargo.toml

+9-7
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,18 @@ name = "state-lens-ics23-ics23-light-client-types"
44
version = "0.1.0"
55

66
[dependencies]
7-
alloy = { workspace = true, features = ["sol-types"], optional = true }
8-
protos = { workspace = true, optional = true, features = ["proto_full", "serde"] }
9-
serde = { workspace = true, optional = true, features = ["derive"] }
10-
thiserror = { workspace = true }
11-
unionlabs = { workspace = true, features = ["ethabi", "proto"] }
7+
alloy = { workspace = true, optional = true, features = ["sol-types"] }
8+
protos = { workspace = true, optional = true, features = ["proto_full", "serde"] }
9+
serde = { workspace = true, optional = true, features = ["derive"] }
10+
state-lens-light-client-types = { workspace = true }
11+
thiserror = { workspace = true }
12+
unionlabs = { workspace = true }
1213

1314
[dev-dependencies]
1415
hex-literal = { workspace = true }
1516

1617
[features]
1718
default = []
18-
ethabi = ["unionlabs/ethabi", "dep:alloy", "dep:protos"]
19-
serde = ["dep:serde"]
19+
20+
ethabi = ["unionlabs/ethabi", "dep:alloy", "dep:protos", "state-lens-light-client-types/ethabi"]
21+
serde = ["dep:serde", "state-lens-light-client-types/serde"]
Original file line numberDiff line numberDiff line change
@@ -1,89 +1,10 @@
1-
use unionlabs::primitives::H256;
1+
use unionlabs::{primitives::H256, tuple::AsTuple};
22

3-
#[derive(Debug, Clone, PartialEq)]
3+
pub type ClientState = state_lens_light_client_types::ClientState<Extra>;
4+
5+
#[derive(Debug, Clone, PartialEq, AsTuple)]
46
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
5-
pub struct ClientState {
6-
/// l2 chain id
7-
pub l2_chain_id: String,
8-
/// l1 client id used to check the l2 inclusion proof against
9-
pub l1_client_id: u32,
10-
/// l2 client id
11-
pub l2_client_id: u32,
12-
/// l2 latest height
13-
pub l2_latest_height: u64,
7+
pub struct Extra {
148
/// ibc contract that is running on l2
159
pub contract_address: H256,
1610
}
17-
18-
#[cfg(feature = "ethabi")]
19-
pub mod ethabi {
20-
use core::str;
21-
use std::string::FromUtf8Error;
22-
23-
use alloy::sol_types::SolValue;
24-
use unionlabs::{
25-
encoding::{Decode, Encode, EthAbi},
26-
TryFromEthAbiBytesErrorAlloy,
27-
};
28-
29-
use crate::ClientState;
30-
31-
alloy::sol! {
32-
struct SolClientState {
33-
string l2ChainId;
34-
uint32 l1ClientId;
35-
uint32 l2ClientId;
36-
uint64 l2LatestHeight;
37-
bytes32 contractAddress;
38-
}
39-
}
40-
41-
impl Encode<EthAbi> for ClientState {
42-
fn encode(self) -> Vec<u8> {
43-
SolClientState {
44-
l2ChainId: self.l2_chain_id,
45-
l1ClientId: self.l1_client_id,
46-
l2ClientId: self.l2_client_id,
47-
l2LatestHeight: self.l2_latest_height,
48-
contractAddress: self.contract_address.into(),
49-
}
50-
.abi_encode_params()
51-
}
52-
}
53-
54-
impl Decode<EthAbi> for ClientState {
55-
type Error = TryFromEthAbiBytesErrorAlloy<Error>;
56-
57-
fn decode(bytes: &[u8]) -> Result<Self, Self::Error> {
58-
let client_state = SolClientState::abi_decode_params(bytes, true)?;
59-
60-
Ok(Self {
61-
l2_chain_id: String::from_utf8(client_state.l2ChainId.into_bytes())
62-
.map_err(|err| TryFromEthAbiBytesErrorAlloy::Convert(Error::ChainId(err)))?,
63-
l1_client_id: client_state.l1ClientId,
64-
l2_client_id: client_state.l2ClientId,
65-
l2_latest_height: client_state.l2LatestHeight,
66-
contract_address: client_state.contractAddress.into(),
67-
})
68-
}
69-
}
70-
71-
#[derive(Debug, Clone, PartialEq, thiserror::Error)]
72-
pub enum Error {
73-
#[error("invalid chain_id")]
74-
ChainId(#[from] FromUtf8Error),
75-
}
76-
77-
#[cfg(test)]
78-
mod test {
79-
#[test]
80-
fn test_decode() {
81-
// TODO(aeryz): impl
82-
}
83-
84-
#[test]
85-
fn test_encode() {
86-
// TODO(aeryz): impl
87-
}
88-
}
89-
}

0 commit comments

Comments
 (0)