1use crate::{
5 MoveTypeTagTrait, MoveTypeTagTraitGeneric, SUI_ACCUMULATOR_ROOT_OBJECT_ID,
6 SUI_FRAMEWORK_ADDRESS, SUI_FRAMEWORK_PACKAGE_ID,
7 base_types::{ObjectID, SequenceNumber, SuiAddress},
8 collection_types::Bag,
9 dynamic_field::{DynamicFieldKey, DynamicFieldObject},
10 error::SuiResult,
11 object::Object,
12 storage::{ChildObjectResolver, ObjectStore},
13};
14use move_core_types::{
15 ident_str,
16 identifier::IdentStr,
17 language_storage::{StructTag, TypeTag},
18};
19use serde::{Deserialize, Serialize};
20
21pub const ACCUMULATOR_METADATA_MODULE: &IdentStr = ident_str!("accumulator_metadata");
22pub const ACCUMULATOR_OBJECT_COUNT_KEY_STRUCT_NAME: &IdentStr =
23 ident_str!("AccumulatorObjectCountKey");
24pub const ACCUMULATOR_OWNER_KEY_TYPE: &IdentStr = ident_str!("OwnerKey");
25pub const ACCUMULATOR_OWNER_TYPE: &IdentStr = ident_str!("Owner");
26pub const ACCUMULATOR_METADATA_KEY_TYPE: &IdentStr = ident_str!("MetadataKey");
27pub const ACCUMULATOR_METADATA_TYPE: &IdentStr = ident_str!("Metadata");
28
29#[derive(Serialize, Deserialize)]
30pub struct AccumulatorOwner {
31 pub balances: Bag,
32 pub owner: SuiAddress,
33}
34
35impl MoveTypeTagTrait for AccumulatorOwner {
36 fn get_type_tag() -> TypeTag {
37 TypeTag::Struct(Box::new(StructTag {
38 address: SUI_FRAMEWORK_ADDRESS,
39 module: ACCUMULATOR_METADATA_MODULE.to_owned(),
40 name: ACCUMULATOR_OWNER_TYPE.to_owned(),
41 type_params: vec![],
42 }))
43 }
44}
45
46#[derive(Serialize, Deserialize, Debug, Default)]
47pub struct MetadataKey(u8);
48
49impl MoveTypeTagTraitGeneric for MetadataKey {
50 fn get_type_tag(type_params: &[TypeTag]) -> TypeTag {
51 TypeTag::Struct(Box::new(StructTag {
52 address: SUI_FRAMEWORK_PACKAGE_ID.into(),
53 module: ACCUMULATOR_METADATA_MODULE.to_owned(),
54 name: ACCUMULATOR_METADATA_KEY_TYPE.to_owned(),
55 type_params: type_params.to_vec(),
56 }))
57 }
58}
59
60#[derive(Serialize, Deserialize)]
61pub struct AccumulatorMetadata {
62 fields: Bag,
64}
65
66impl MoveTypeTagTraitGeneric for AccumulatorMetadata {
67 fn get_type_tag(type_params: &[TypeTag]) -> TypeTag {
68 TypeTag::Struct(Box::new(StructTag {
69 address: SUI_FRAMEWORK_ADDRESS,
70 module: ACCUMULATOR_METADATA_MODULE.to_owned(),
71 name: ACCUMULATOR_METADATA_TYPE.to_owned(),
72 type_params: type_params.to_vec(),
73 }))
74 }
75}
76
77#[derive(Serialize, Deserialize, Debug)]
78pub struct OwnerKey {
79 owner: SuiAddress,
80}
81
82impl MoveTypeTagTrait for OwnerKey {
83 fn get_type_tag() -> TypeTag {
84 TypeTag::Struct(Box::new(StructTag {
85 address: SUI_FRAMEWORK_ADDRESS,
86 module: ACCUMULATOR_METADATA_MODULE.to_owned(),
87 name: ACCUMULATOR_OWNER_KEY_TYPE.to_owned(),
88 type_params: vec![],
89 }))
90 }
91}
92
93impl AccumulatorOwner {
94 pub fn type_() -> StructTag {
95 StructTag {
96 address: SUI_FRAMEWORK_ADDRESS,
97 module: ACCUMULATOR_METADATA_MODULE.to_owned(),
98 name: ACCUMULATOR_OWNER_TYPE.to_owned(),
99 type_params: vec![],
100 }
101 }
102
103 pub fn get_object_id(owner: SuiAddress) -> SuiResult<ObjectID> {
104 let key = OwnerKey { owner };
105 DynamicFieldKey(
106 SUI_ACCUMULATOR_ROOT_OBJECT_ID,
107 key,
108 OwnerKey::get_type_tag(),
109 )
110 .object_id()
111 }
112
113 pub fn exists(
114 child_object_resolver: &dyn ChildObjectResolver,
115 version_bound: Option<SequenceNumber>,
116 owner: SuiAddress,
117 ) -> SuiResult<bool> {
118 let key = OwnerKey { owner };
119
120 DynamicFieldKey(
121 SUI_ACCUMULATOR_ROOT_OBJECT_ID,
122 key,
123 OwnerKey::get_type_tag(),
124 )
125 .into_id_with_bound(version_bound.unwrap_or(SequenceNumber::MAX))?
126 .exists(child_object_resolver)
127 }
128
129 pub fn load_object(
130 child_object_resolver: &dyn ChildObjectResolver,
131 root_version: Option<SequenceNumber>,
132 owner: SuiAddress,
133 ) -> SuiResult<Option<Object>> {
134 let key = OwnerKey { owner };
135 Ok(DynamicFieldKey(
136 SUI_ACCUMULATOR_ROOT_OBJECT_ID,
137 key,
138 OwnerKey::get_type_tag(),
139 )
140 .into_id_with_bound(root_version.unwrap_or(SequenceNumber::MAX))?
141 .load_object(child_object_resolver)?
142 .map(|o| o.into_object()))
143 }
144
145 pub fn from_object(object: Object) -> SuiResult<Self> {
146 DynamicFieldObject::<OwnerKey>::new(object).load_value::<Self>()
147 }
148
149 pub fn load(
150 child_object_resolver: &dyn ChildObjectResolver,
151 root_version: Option<SequenceNumber>,
152 owner: SuiAddress,
153 ) -> SuiResult<Option<Self>> {
154 let key = OwnerKey { owner };
155 DynamicFieldKey(
156 SUI_ACCUMULATOR_ROOT_OBJECT_ID,
157 key,
158 OwnerKey::get_type_tag(),
159 )
160 .into_id_with_bound(root_version.unwrap_or(SequenceNumber::MAX))?
161 .load_object(child_object_resolver)?
162 .map(|o| o.load_value::<Self>())
163 .transpose()
164 }
165
166 pub fn metadata_exists(
167 &self,
168 child_object_resolver: &dyn ChildObjectResolver,
169 version_bound: Option<SequenceNumber>,
170 type_: &TypeTag,
171 ) -> SuiResult<bool> {
172 let key = MetadataKey::default();
173 DynamicFieldKey(
174 *self.balances.id.object_id(),
175 key,
176 MetadataKey::get_type_tag(std::slice::from_ref(type_)),
177 )
178 .into_id_with_bound(version_bound.unwrap_or(SequenceNumber::MAX))?
179 .exists(child_object_resolver)
180 }
181
182 pub fn load_metadata(
183 &self,
184 child_object_resolver: &dyn ChildObjectResolver,
185 version_bound: Option<SequenceNumber>,
186 type_: &TypeTag,
187 ) -> SuiResult<Option<AccumulatorMetadata>> {
188 let key = MetadataKey::default();
189 DynamicFieldKey(
190 *self.balances.id.object_id(),
191 key,
192 MetadataKey::get_type_tag(std::slice::from_ref(type_)),
193 )
194 .into_id_with_bound(version_bound.unwrap_or(SequenceNumber::MAX))?
195 .load_object(child_object_resolver)?
196 .map(|o| o.load_value::<AccumulatorMetadata>())
197 .transpose()
198 }
199}
200
201#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default)]
208pub struct AccumulatorObjectCountKey(u8);
209
210impl MoveTypeTagTrait for AccumulatorObjectCountKey {
211 fn get_type_tag() -> TypeTag {
212 TypeTag::Struct(Box::new(StructTag {
213 address: SUI_FRAMEWORK_ADDRESS,
214 module: ACCUMULATOR_METADATA_MODULE.to_owned(),
215 name: ACCUMULATOR_OBJECT_COUNT_KEY_STRUCT_NAME.to_owned(),
216 type_params: vec![],
217 }))
218 }
219}
220
221pub fn get_accumulator_object_count(object_store: &dyn ObjectStore) -> SuiResult<Option<u64>> {
223 DynamicFieldKey(
224 SUI_ACCUMULATOR_ROOT_OBJECT_ID,
225 AccumulatorObjectCountKey(0),
226 AccumulatorObjectCountKey::get_type_tag(),
227 )
228 .into_unbounded_id()?
229 .load_object(object_store)
230 .map(|o| o.load_value::<u64>())
231 .transpose()
232}