hotshot_contract_adapter/
sol_types.rs

1//! Solidity types for interacting with contracts
2//! Re-export types that are used, sometimes renamed to avoid collision.
3//!
4//! TODO: (alex) Due to <https://github.com/foundry-rs/foundry/issues/10153>,
5//! try to re-export the same type from the "youngest" child contract since that is the contract whose functions are being called,
6//! thus from whom the rust bindings are expected.
7//! E.g. Both PlonkVerifier and LightClient, and LightClientV2 depends on BN254. The inheritance relationship is:
8//!   BN254 <- PlonkVerifier <- LIghtClient <- LightClientV2
9//! Most of the time, we interact with PlonkVerifier's function via LightClientV2, thus import BN254.G1Point from `bindings::plonkverifierv2`.
10//! When we need to directly interact with PlonkVerifier's method, implement stupid plain `From<lc2::BN254::G1Point> for pv::BN254::G1Point`.
11//! If you are lazy, you can even use unsafe memory transmute since they are literally the same representation, duplicated in different modules,
12//! thus treated by the rust type systems as distinct types.
13//!
14//! Another usage is in the differential testing in Solidity tests. In those cases, the actual types don't matter, since they will all `abi_encode()`
15//! into the exact same bytes before being communicated over to contract via FFI. Thus using any one of them is fine.
16
17use alloy::sol;
18
19/// # What to re-export, what to hide?
20/// - export contract struct itself, but try to avoid export instance type (instead, use ::new() to get a handle)
21/// - avoid exporting `xxCall` and `xxReturn` types, they usually can be converted/transmuted from existing struct
22/// - Event types should be exported
23/// - structs should be exported and renamed with `xxSol` suffix to avoid confusion with other rust types
24///   - see module doc for more explanation on types duplication issue in alloy
25pub use crate::bindings::{
26    access_control_upgradeable::AccessControlUpgradeable,
27    erc1967_proxy::ERC1967Proxy,
28    esp_token::EspToken,
29    esp_token_v2::EspTokenV2,
30    fee_contract::FeeContract::{self, Deposit},
31    light_client::{
32        IPlonkVerifier::{PlonkProof as PlonkProofSol, VerifyingKey as VerifyingKeySol},
33        LightClient::{
34            self, LightClientErrors, LightClientInstance, LightClientState as LightClientStateSol,
35            StakeTableState as StakeTableStateSol,
36        },
37        BN254::G1Point as G1PointSol,
38    },
39    light_client_mock::{self, LightClientMock},
40    light_client_v2::{self, LightClientV2},
41    light_client_v2_mock::{self, LightClientV2Mock},
42    light_client_v3::{self, LightClientV3},
43    light_client_v3_mock::{self, LightClientV3Mock},
44    ops_timelock::OpsTimelock,
45    ownable_upgradeable::OwnableUpgradeable,
46    plonk_verifier::PlonkVerifier,
47    plonk_verifier_v2::PlonkVerifierV2,
48    plonk_verifier_v3::PlonkVerifierV3,
49    reward_claim::RewardClaim,
50    safe_exit_timelock::SafeExitTimelock,
51    stake_table::StakeTable,
52    stake_table_v2::{
53        self, EdOnBN254::EdOnBN254Point as EdOnBN254PointSol, StakeTableV2,
54        BN254::G2Point as G2PointSol,
55    },
56};
57
58// For types that we need to interact with some functions but their bindings are not generated
59// we manually declare them there. It's possible that they get included in the future commits,
60// at which point, the rust type system will complain and we simply remove the manual declaration
61// and re-export the type from bindings instead.
62sol! {
63    /// types in src/legacy/Transcript.sol
64    struct TranscriptDataSol {
65        bytes32 state;
66        bytes transcript;
67    }
68
69    /// types in src/libraries/PlonkVerifierV2.sol
70    struct ChallengesSol {
71        uint256 alpha;
72        uint256 alpha2;
73        uint256 alpha3;
74        uint256 beta;
75        uint256 gamma;
76        uint256 zeta;
77        uint256 v;
78        uint256 u;
79    }
80}
81
82// Due to <https://github.com/foundry-rs/foundry/issues/10153> the rust bindings contain duplicate types for our solidity types.
83// In order to avoid writing a lot of boilerplate code we use transmute to convert between these duplicated types.
84// Since all the types we transmute between are generated by foundry from the same underlying solidity type
85// we expect that the order of fields and types of fields are always the same.
86impl From<LightClient::genesisStateReturn> for LightClientStateSol {
87    fn from(v: LightClient::genesisStateReturn) -> Self {
88        unsafe { std::mem::transmute(v) }
89    }
90}
91
92impl From<light_client_mock::LightClient::LightClientState> for LightClientStateSol {
93    fn from(v: light_client_mock::LightClient::LightClientState) -> Self {
94        unsafe { std::mem::transmute(v) }
95    }
96}
97impl From<light_client_mock::LightClientMock::finalizedStateReturn> for LightClientStateSol {
98    fn from(v: light_client_mock::LightClientMock::finalizedStateReturn) -> Self {
99        unsafe { std::mem::transmute(v) }
100    }
101}
102
103impl From<LightClientStateSol> for light_client_mock::LightClient::LightClientState {
104    fn from(v: LightClientStateSol) -> Self {
105        unsafe { std::mem::transmute(v) }
106    }
107}
108
109impl From<PlonkProofSol> for light_client_mock::IPlonkVerifier::PlonkProof {
110    fn from(v: PlonkProofSol) -> Self {
111        unsafe { std::mem::transmute(v) }
112    }
113}
114
115impl From<light_client_mock::LightClientMock::genesisStateReturn> for LightClientStateSol {
116    fn from(v: light_client_mock::LightClientMock::genesisStateReturn) -> Self {
117        unsafe { std::mem::transmute(v) }
118    }
119}
120
121impl From<LightClientV2::finalizedStateReturn> for LightClientStateSol {
122    fn from(v: LightClientV2::finalizedStateReturn) -> Self {
123        unsafe { std::mem::transmute(v) }
124    }
125}
126
127impl From<LightClientV2::votingStakeTableStateReturn> for StakeTableStateSol {
128    fn from(v: LightClientV2::votingStakeTableStateReturn) -> Self {
129        unsafe { std::mem::transmute(v) }
130    }
131}
132
133impl From<light_client_v2_mock::LightClient::LightClientState> for LightClientStateSol {
134    fn from(v: light_client_v2_mock::LightClient::LightClientState) -> Self {
135        unsafe { std::mem::transmute(v) }
136    }
137}
138impl From<LightClientStateSol> for light_client_v2_mock::LightClient::LightClientState {
139    fn from(v: LightClientStateSol) -> Self {
140        unsafe { std::mem::transmute(v) }
141    }
142}
143impl From<LightClientStateSol> for light_client_v2::LightClient::LightClientState {
144    fn from(v: LightClientStateSol) -> Self {
145        unsafe { std::mem::transmute(v) }
146    }
147}
148
149impl From<StakeTableStateSol> for light_client_v2::LightClient::StakeTableState {
150    fn from(v: StakeTableStateSol) -> Self {
151        unsafe { std::mem::transmute(v) }
152    }
153}
154impl From<StakeTableStateSol> for light_client_v2_mock::LightClient::StakeTableState {
155    fn from(v: StakeTableStateSol) -> Self {
156        unsafe { std::mem::transmute(v) }
157    }
158}
159
160impl From<LightClientV2Mock::genesisStateReturn> for LightClientStateSol {
161    fn from(v: LightClientV2Mock::genesisStateReturn) -> Self {
162        unsafe { std::mem::transmute(v) }
163    }
164}
165
166impl From<LightClientV2Mock::finalizedStateReturn> for LightClientStateSol {
167    fn from(v: LightClientV2Mock::finalizedStateReturn) -> Self {
168        unsafe { std::mem::transmute(v) }
169    }
170}
171
172impl From<PlonkProofSol> for light_client_v2::IPlonkVerifier::PlonkProof {
173    fn from(v: PlonkProofSol) -> Self {
174        unsafe { std::mem::transmute(v) }
175    }
176}
177
178impl From<LightClientV2Mock::votingStakeTableStateReturn> for StakeTableStateSol {
179    fn from(v: LightClientV2Mock::votingStakeTableStateReturn) -> Self {
180        unsafe { std::mem::transmute(v) }
181    }
182}
183
184impl From<G1PointSol> for stake_table_v2::BN254::G1Point {
185    fn from(v: G1PointSol) -> Self {
186        unsafe { std::mem::transmute(v) }
187    }
188}
189
190impl From<stake_table_v2::BN254::G1Point> for G1PointSol {
191    fn from(v: stake_table_v2::BN254::G1Point) -> Self {
192        unsafe { std::mem::transmute(v) }
193    }
194}
195
196// Transmute conversion functions for LightClientV3
197impl From<LightClientV3::finalizedStateReturn> for LightClientStateSol {
198    fn from(v: LightClientV3::finalizedStateReturn) -> Self {
199        unsafe { std::mem::transmute(v) }
200    }
201}
202
203impl From<LightClientV3::votingStakeTableStateReturn> for StakeTableStateSol {
204    fn from(v: LightClientV3::votingStakeTableStateReturn) -> Self {
205        unsafe { std::mem::transmute(v) }
206    }
207}
208
209impl From<LightClientStateSol> for light_client_v3::LightClient::LightClientState {
210    fn from(v: LightClientStateSol) -> Self {
211        unsafe { std::mem::transmute(v) }
212    }
213}
214
215impl From<StakeTableStateSol> for light_client_v3::LightClient::StakeTableState {
216    fn from(v: StakeTableStateSol) -> Self {
217        unsafe { std::mem::transmute(v) }
218    }
219}
220
221impl From<PlonkProofSol> for light_client_v3::IPlonkVerifier::PlonkProof {
222    fn from(v: PlonkProofSol) -> Self {
223        unsafe { std::mem::transmute(v) }
224    }
225}
226
227// Transmute conversion functions for LightClientV3Mock
228impl From<light_client_v3_mock::LightClient::LightClientState> for LightClientStateSol {
229    fn from(v: light_client_v3_mock::LightClient::LightClientState) -> Self {
230        unsafe { std::mem::transmute(v) }
231    }
232}
233
234impl From<LightClientStateSol> for light_client_v3_mock::LightClient::LightClientState {
235    fn from(v: LightClientStateSol) -> Self {
236        unsafe { std::mem::transmute(v) }
237    }
238}
239
240impl From<StakeTableStateSol> for light_client_v3_mock::LightClient::StakeTableState {
241    fn from(v: StakeTableStateSol) -> Self {
242        unsafe { std::mem::transmute(v) }
243    }
244}
245
246impl From<LightClientV3Mock::genesisStateReturn> for LightClientStateSol {
247    fn from(v: LightClientV3Mock::genesisStateReturn) -> Self {
248        unsafe { std::mem::transmute(v) }
249    }
250}
251
252impl From<LightClientV3Mock::finalizedStateReturn> for LightClientStateSol {
253    fn from(v: LightClientV3Mock::finalizedStateReturn) -> Self {
254        unsafe { std::mem::transmute(v) }
255    }
256}
257
258impl From<LightClientV3Mock::votingStakeTableStateReturn> for StakeTableStateSol {
259    fn from(v: LightClientV3Mock::votingStakeTableStateReturn) -> Self {
260        unsafe { std::mem::transmute(v) }
261    }
262}
263
264use self::StakeTableV2::{
265    ConsensusKeysUpdated, ConsensusKeysUpdatedV2, ValidatorRegistered, ValidatorRegisteredV2,
266};
267
268impl PartialEq for ValidatorRegistered {
269    fn eq(&self, other: &Self) -> bool {
270        self.account == other.account
271            && self.blsVk == other.blsVk
272            && self.schnorrVk == other.schnorrVk
273            && self.commission == other.commission
274    }
275}
276
277impl PartialEq for ValidatorRegisteredV2 {
278    fn eq(&self, other: &Self) -> bool {
279        self.account == other.account
280            && self.blsVK == other.blsVK
281            && self.schnorrVK == other.schnorrVK
282            && self.commission == other.commission
283            && self.blsSig == other.blsSig
284            && self.schnorrSig == other.schnorrSig
285    }
286}
287
288impl PartialEq for ConsensusKeysUpdated {
289    fn eq(&self, other: &Self) -> bool {
290        self.account == other.account
291            && self.blsVK == other.blsVK
292            && self.schnorrVK == other.schnorrVK
293    }
294}
295
296impl PartialEq for ConsensusKeysUpdatedV2 {
297    fn eq(&self, other: &Self) -> bool {
298        self.account == other.account
299            && self.blsVK == other.blsVK
300            && self.schnorrVK == other.schnorrVK
301            && self.blsSig == other.blsSig
302            && self.schnorrSig == other.schnorrSig
303    }
304}
305
306impl Clone for StakeTableV2::StakeTableV2Events {
307    fn clone(&self) -> Self {
308        match self {
309            Self::ValidatorRegistered(v) => Self::ValidatorRegistered(*v),
310            Self::ValidatorRegisteredV2(v) => Self::ValidatorRegisteredV2(v.clone()),
311            Self::ValidatorExit(v) => Self::ValidatorExit(*v),
312            Self::ValidatorExitV2(v) => Self::ValidatorExitV2(v.clone()),
313            Self::Delegated(v) => Self::Delegated(*v),
314            Self::Undelegated(v) => Self::Undelegated(*v),
315            Self::UndelegatedV2(v) => Self::UndelegatedV2(v.clone()),
316            Self::ConsensusKeysUpdated(v) => Self::ConsensusKeysUpdated(*v),
317            Self::ConsensusKeysUpdatedV2(v) => Self::ConsensusKeysUpdatedV2(v.clone()),
318            Self::CommissionUpdated(v) => Self::CommissionUpdated(v.clone()),
319            Self::ExitEscrowPeriodUpdated(v) => Self::ExitEscrowPeriodUpdated(v.clone()),
320            Self::MaxCommissionIncreaseUpdated(v) => Self::MaxCommissionIncreaseUpdated(v.clone()),
321            Self::MinCommissionUpdateIntervalUpdated(v) => {
322                Self::MinCommissionUpdateIntervalUpdated(v.clone())
323            },
324            Self::OwnershipTransferred(v) => Self::OwnershipTransferred(v.clone()),
325            Self::Paused(v) => Self::Paused(v.clone()),
326            Self::Unpaused(v) => Self::Unpaused(v.clone()),
327            Self::Initialized(v) => Self::Initialized(v.clone()),
328            Self::RoleAdminChanged(v) => Self::RoleAdminChanged(v.clone()),
329            Self::RoleGranted(v) => Self::RoleGranted(v.clone()),
330            Self::RoleRevoked(v) => Self::RoleRevoked(v.clone()),
331            Self::WithdrawalClaimed(v) => Self::WithdrawalClaimed(v.clone()),
332            Self::Upgraded(v) => Self::Upgraded(v.clone()),
333            Self::ValidatorExitClaimed(v) => Self::ValidatorExitClaimed(v.clone()),
334            Self::Withdrawal(v) => Self::Withdrawal(v.clone()),
335            Self::MetadataUriUpdated(v) => Self::MetadataUriUpdated(v.clone()),
336        }
337    }
338}
339
340impl std::fmt::Debug for StakeTableV2::StakeTableV2Events {
341    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
342        match self {
343            Self::ValidatorRegistered(_) => write!(f, "ValidatorRegistered(_)"),
344            Self::ValidatorRegisteredV2(_) => write!(f, "ValidatorRegisteredV2(_)"),
345            Self::ValidatorExit(v) => write!(f, "ValidatorExit({v:?})"),
346            Self::ValidatorExitV2(v) => write!(f, "ValidatorExitV2({v:?})"),
347            Self::Delegated(v) => write!(f, "Delegated({v:?})"),
348            Self::Undelegated(v) => write!(f, "Undelegated({v:?})"),
349            Self::UndelegatedV2(v) => write!(f, "UndelegatedV2({v:?})"),
350            Self::ConsensusKeysUpdated(_) => write!(f, "ConsensusKeysUpdated(_)"),
351            Self::ConsensusKeysUpdatedV2(_) => write!(f, "ConsensusKeysUpdatedV2(_)"),
352            Self::CommissionUpdated(v) => write!(f, "CommissionUpdated({v:?})"),
353            Self::ExitEscrowPeriodUpdated(v) => write!(f, "ExitEscrowPeriodUpdated({v:?})"),
354            Self::MaxCommissionIncreaseUpdated(v) => {
355                write!(f, "MaxCommissionIncreaseUpdated({v:?})")
356            },
357            Self::MinCommissionUpdateIntervalUpdated(v) => {
358                write!(f, "MinCommissionUpdateIntervalUpdated({v:?})")
359            },
360            Self::OwnershipTransferred(v) => write!(f, "OwnershipTransferred({v:?})"),
361            Self::Paused(v) => write!(f, "Paused({v:?})"),
362            Self::Unpaused(v) => write!(f, "Unpaused({v:?})"),
363            Self::Initialized(v) => write!(f, "Initialized({v:?})"),
364            Self::RoleAdminChanged(v) => write!(f, "RoleAdminChanged({v:?})"),
365            Self::RoleGranted(v) => write!(f, "RoleGranted({v:?})"),
366            Self::RoleRevoked(v) => write!(f, "RoleRevoked({v:?})"),
367            Self::WithdrawalClaimed(v) => write!(f, "WithdrawalClaimed({v:?})"),
368            Self::Upgraded(v) => write!(f, "Upgraded({v:?})"),
369            Self::ValidatorExitClaimed(v) => write!(f, "ValidatorExitClaimed({v:?})"),
370            Self::Withdrawal(v) => write!(f, "Withdrawal({v:?})"),
371            Self::MetadataUriUpdated(v) => write!(f, "MetadataUriUpdated({v:?})"),
372        }
373    }
374}
375#[cfg(test)]
376mod tests {
377    use alloy::{primitives::U256, sol_types::private::Address};
378
379    use crate::sol_types::StakeTableV2::CommissionUpdated;
380
381    #[test]
382    fn test_commission_updated_serde_roundtrip() {
383        let original = CommissionUpdated {
384            validator: Address::random(),
385            timestamp: U256::from(999),
386            oldCommission: 123,
387            newCommission: 456,
388        };
389
390        let serialized = bincode::serialize(&original).expect("Failed to serialize");
391        let deserialized: CommissionUpdated =
392            bincode::deserialize(&serialized).expect("Failed to deserialize");
393
394        assert_eq!(original.validator, deserialized.validator);
395        assert_eq!(original.timestamp, deserialized.timestamp);
396        assert_eq!(original.oldCommission, deserialized.oldCommission);
397        assert_eq!(original.newCommission, deserialized.newCommission);
398    }
399}