hotshot_contract_adapter/
reward.rs1use alloy::{
2 primitives::{Bytes, B256, U256},
3 sol_types::SolValue,
4};
5use derive_more::{From, Into};
6use serde::{Deserialize, Serialize};
7
8pub const REWARD_MERKLE_TREE_V2_HEIGHT: usize = 160;
10pub const OTHER_AUTH_ROOT_INPUTS_LEN: usize = 7;
11
12type RewardAuthDataRaw = (
13 [B256; REWARD_MERKLE_TREE_V2_HEIGHT],
14 [B256; OTHER_AUTH_ROOT_INPUTS_LEN],
15);
16
17#[derive(Clone, Debug, Eq, PartialEq, From)]
18pub struct RewardProofSiblings([B256; REWARD_MERKLE_TREE_V2_HEIGHT]);
19
20#[derive(Clone, Debug, Eq, PartialEq, From, Default)]
21pub struct RewardAuthRootInputs([B256; OTHER_AUTH_ROOT_INPUTS_LEN]);
22
23#[derive(Clone, Debug, Eq, PartialEq)]
24pub struct RewardAuthData {
25 siblings: RewardProofSiblings,
26 auth_root_inputs: RewardAuthRootInputs,
27}
28
29impl RewardAuthData {
30 pub fn new(siblings: RewardProofSiblings) -> Self {
35 RewardAuthData {
36 siblings,
37 auth_root_inputs: Default::default(),
38 }
39 }
40}
41
42impl From<RewardAuthDataRaw> for RewardAuthData {
43 fn from((siblings, auth_root_inputs): RewardAuthDataRaw) -> Self {
44 RewardAuthData {
45 siblings: siblings.into(),
46 auth_root_inputs: auth_root_inputs.into(),
47 }
48 }
49}
50
51impl TryFrom<RewardAuthDataEncoded> for RewardAuthData {
52 type Error = alloy::sol_types::Error;
53
54 fn try_from(value: RewardAuthDataEncoded) -> Result<Self, Self::Error> {
55 let decoded: RewardAuthDataRaw = SolValue::abi_decode(&value.0)?;
56 Ok(decoded.into())
57 }
58}
59
60#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, From, Into)]
61pub struct RewardAuthDataEncoded(Bytes);
62
63impl From<RewardAuthData> for RewardAuthDataEncoded {
64 fn from(value: RewardAuthData) -> Self {
65 Self(
66 (value.siblings.0, value.auth_root_inputs.0)
67 .abi_encode()
68 .into(),
69 )
70 }
71}
72
73#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
74pub struct RewardClaimInput {
75 pub lifetime_rewards: U256,
76 pub auth_data: RewardAuthDataEncoded,
77}
78
79#[cfg(test)]
80mod tests {
81 use std::array::from_fn;
82
83 use serde_json;
84
85 use super::*;
86
87 impl RewardAuthData {
88 fn random() -> Self {
89 (from_fn(|_| B256::random()), from_fn(|_| B256::random())).into()
90 }
91 }
92
93 impl RewardClaimInput {
94 fn random() -> Self {
95 Self {
96 lifetime_rewards: B256::random().into(),
97 auth_data: RewardAuthData::random().into(),
98 }
99 }
100 }
101
102 #[test]
103 fn test_reward_claim_input_roundtrip_json() {
104 let original = RewardClaimInput::random();
105 let json = serde_json::to_string(&original).unwrap();
106 let decoded: RewardClaimInput = serde_json::from_str(&json).unwrap();
107 assert_eq!(decoded, original);
108 }
109
110 #[test]
111 fn test_decode_abi_auth_data() {
112 let original = RewardClaimInput::random();
113 let auth_data = RewardAuthData::try_from(original.auth_data.clone()).unwrap();
114 let json = serde_json::to_string(&original).unwrap();
115 let value: serde_json::Value = serde_json::from_str(&json).unwrap();
116 let auth_str = value.get("auth_data").unwrap().as_str().unwrap();
117 assert!(auth_str.starts_with("0x"));
118
119 let (siblings, auth_root_inputs): RewardAuthDataRaw =
122 SolValue::abi_decode(&alloy::hex::decode(&auth_str[2..]).unwrap()).unwrap();
123 assert_eq!(siblings, auth_data.siblings.0);
124 assert_eq!(auth_root_inputs, auth_data.auth_root_inputs.0);
125 }
126}