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