sui_types/
accumulator_event.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use move_core_types::ident_str;
5use move_core_types::identifier::IdentStr;
6use mysten_common::{fatal, in_test_configuration};
7
8use crate::TypeTag;
9use crate::accumulator_root::AccumulatorObjId;
10use crate::balance::Balance;
11use crate::base_types::SuiAddress;
12use crate::effects::{
13    AccumulatorAddress, AccumulatorOperation, AccumulatorValue, AccumulatorWriteV1,
14};
15use crate::error::{SuiError, SuiErrorKind};
16use crate::gas_coin::GasCoin;
17
18pub const ACCUMULATOR_MODULE_NAME: &IdentStr = ident_str!("accumulator");
19
20#[derive(Debug, Clone)]
21pub struct AccumulatorEvent {
22    pub accumulator_obj: AccumulatorObjId,
23    pub write: AccumulatorWriteV1,
24}
25
26impl AccumulatorEvent {
27    pub fn new(accumulator_obj: AccumulatorObjId, write: AccumulatorWriteV1) -> Self {
28        if in_test_configuration()
29            && let Ok(expected_obj) = crate::accumulator_root::AccumulatorValue::get_field_id(
30                write.address.address,
31                &write.address.ty,
32            )
33        {
34            debug_assert_eq!(
35                *accumulator_obj.inner(),
36                *expected_obj.inner(),
37                "Accumulator object ID {:?} does not match expected ID {:?} for address {:?} and type {:?}",
38                accumulator_obj.inner(),
39                expected_obj.inner(),
40                write.address.address,
41                write.address.ty
42            );
43        }
44        Self {
45            accumulator_obj,
46            write,
47        }
48    }
49
50    pub fn from_balance_change(
51        address: SuiAddress,
52        balance_type: TypeTag,
53        net_change: i64,
54    ) -> Result<Self, SuiError> {
55        if !Balance::is_balance_type(&balance_type) {
56            return Err(SuiErrorKind::TypeError {
57                error: "only Balance<T> is supported".to_string(),
58            }
59            .into());
60        }
61        let accumulator_obj =
62            crate::accumulator_root::AccumulatorValue::get_field_id(address, &balance_type)?;
63
64        let accumulator_address = AccumulatorAddress::new(address, balance_type);
65
66        let (operation, amount) = if net_change > 0 {
67            (AccumulatorOperation::Split, net_change as u64)
68        } else {
69            (AccumulatorOperation::Merge, (-net_change) as u64)
70        };
71
72        let accumulator_write = AccumulatorWriteV1 {
73            address: accumulator_address,
74            operation,
75            value: AccumulatorValue::Integer(amount),
76        };
77
78        Ok(Self::new(accumulator_obj, accumulator_write))
79    }
80
81    pub fn total_sui_in_event(&self) -> (u64 /* input */, u64 /* output */) {
82        let Self {
83            write:
84                AccumulatorWriteV1 {
85                    address: AccumulatorAddress { ty, .. },
86                    operation,
87                    value,
88                },
89            ..
90        } = self;
91
92        let sui = match ty {
93            TypeTag::Struct(struct_tag) => {
94                if !GasCoin::is_gas_balance(struct_tag) {
95                    0
96                } else {
97                    match value {
98                        AccumulatorValue::Integer(v) => *v,
99                        AccumulatorValue::IntegerTuple(_, _) => fatal!("invalid accumulator value"),
100                        AccumulatorValue::EventDigest(_, _) => fatal!("invalid accumulator value"),
101                    }
102                }
103            }
104            _ => 0,
105        };
106
107        match operation {
108            AccumulatorOperation::Merge => (0, sui),
109            AccumulatorOperation::Split => (sui, 0),
110        }
111    }
112}