sui_types/
balance_change.rsuse crate::base_types::SuiAddress;
use crate::coin::Coin;
use crate::effects::TransactionEffects;
use crate::effects::TransactionEffectsAPI;
use crate::full_checkpoint_content::ObjectSet;
use crate::object::Object;
use crate::object::Owner;
use crate::storage::ObjectKey;
use move_core_types::language_storage::TypeTag;
#[derive(Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq, PartialOrd, Ord)]
pub struct BalanceChange {
pub address: SuiAddress,
pub coin_type: TypeTag,
pub amount: i128,
}
impl std::fmt::Debug for BalanceChange {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("BalanceChange")
.field("address", &self.address)
.field("coin_type", &self.coin_type.to_canonical_string(true))
.field("amount", &self.amount)
.finish()
}
}
fn coins(objects: &[Object]) -> impl Iterator<Item = (&SuiAddress, TypeTag, u64)> + '_ {
objects.iter().filter_map(|object| {
let address = match object.owner() {
Owner::AddressOwner(sui_address)
| Owner::ObjectOwner(sui_address)
| Owner::ConsensusAddressOwner {
owner: sui_address, ..
} => sui_address,
Owner::Shared { .. } | Owner::Immutable => return None,
};
let (coin_type, balance) = Coin::extract_balance_if_coin(object).ok().flatten()?;
Some((address, coin_type, balance))
})
}
pub fn derive_balance_changes(
_effects: &TransactionEffects,
input_objects: &[Object],
output_objects: &[Object],
) -> Vec<BalanceChange> {
let balances = coins(input_objects).fold(
std::collections::BTreeMap::<_, i128>::new(),
|mut acc, (address, coin_type, balance)| {
*acc.entry((address, coin_type)).or_default() -= balance as i128;
acc
},
);
let balances =
coins(output_objects).fold(balances, |mut acc, (address, coin_type, balance)| {
*acc.entry((address, coin_type)).or_default() += balance as i128;
acc
});
balances
.into_iter()
.filter_map(|((address, coin_type), amount)| {
if amount == 0 {
return None;
}
Some(BalanceChange {
address: *address,
coin_type,
amount,
})
})
.collect()
}
pub fn derive_balance_changes_2(
effects: &TransactionEffects,
objects: &ObjectSet,
) -> Vec<BalanceChange> {
let input_objects = effects
.modified_at_versions()
.into_iter()
.filter_map(|(object_id, version)| objects.get(&ObjectKey(object_id, version)).cloned())
.collect::<Vec<_>>();
let output_objects = effects
.all_changed_objects()
.into_iter()
.filter_map(|(object_ref, _owner, _kind)| objects.get(&object_ref.into()).cloned())
.collect::<Vec<_>>();
let balances = coins(&input_objects).fold(
std::collections::BTreeMap::<_, i128>::new(),
|mut acc, (address, coin_type, balance)| {
*acc.entry((address, coin_type)).or_default() -= balance as i128;
acc
},
);
let balances =
coins(&output_objects).fold(balances, |mut acc, (address, coin_type, balance)| {
*acc.entry((address, coin_type)).or_default() += balance as i128;
acc
});
balances
.into_iter()
.filter_map(|((address, coin_type), amount)| {
if amount == 0 {
return None;
}
Some(BalanceChange {
address: *address,
coin_type,
amount,
})
})
.collect()
}