Repository: MystenLabs/sui
File: crates/sui-indexer-alt/src/handlers/tx_balance_changes.rs (Rust)

Code before:
        } = tx_interval(conn, from..to_exclusive).await?;
        let filter = tx_balance_changes::table.filter(
            tx_balance_changes::tx_sequence_number.between(from_tx as i64, to_tx as i64 - 1),
        );

        Ok(diesel::delete(filter).execute(conn).await?)
    }
}

/// Calculate balance changes based on the object's input and output objects.
fn balance_changes(
    transaction: &ExecutedTransaction,
    checkpoint: &Checkpoint,
) -> Result<Vec<BalanceChange>> {
    // Shortcut if the transaction failed -- we know that only gas was charged.
    if transaction.effects.status().is_err() {
        let net_gas_usage = transaction.effects.gas_cost_summary().net_gas_usage();
        // This can happen if the transaction failed due to insufficient address balance.
        if net_gas_usage == 0 {
            return Ok(vec![]);
        }
        return Ok(vec![BalanceChange::V1 {
            owner: transaction.effects.gas_object().1,
            coin_type: GAS::type_tag().to_canonical_string(/* with_prefix */ true),
            amount: -(net_gas_usage as i128),
        }]);
    }

    // First gather address balance changes from accumulator events.
    let mut balance_changes = address_balance_changes_from_accumulator_events(&transaction.effects)
        .fold(
            BTreeMap::<(Owner, TypeTag), i128>::new(),
            |mut acc, (addr, coin_type, amt)| {
                // We always transfer address balance funds to an address.
                *acc.entry((Owner::AddressOwner(addr), coin_type))
                    .or_default() += amt;
                acc
            },
        );

    // Then gather coin balance changes from input and output objects.
    for object in transaction.input_objects(&checkpoint.object_set) {
        if let Some((type_, balance)) = Coin::extract_balance_if_coin(object)? {
            *balance_changes
                .entry((object.owner().clone(), type_))
                .or_insert(0i128) -= balance as i128;
        }
    }

    for object in transaction.output_objects(&checkpoint.object_set) {
        if let Some((type_, balance)) = Coin::extract_balance_if_coin(object)? {

Review comment (suggestion):
optional -- this is a cute way of doing the same

```rust
return Ok(Vec::from_iter((net_gas_usage > 0).then(|| BalanceChange::V1 {
    owner: transaction.effects.gas_object().1,
    coin_type: GAS::type_tag().to_canonical_string(true),
    amount: -(net_gas_usage as i128),
})));
```

Code after:
        } = tx_interval(conn, from..to_exclusive).await?;
        let filter = tx_balance_changes::table.filter(
            tx_balance_changes::tx_sequence_number.between(from_tx as i64, to_tx as i64 - 1),
        );

        Ok(diesel::delete(filter).execute(conn).await?)
    }
}

/// Calculate balance changes based on the object's input and output objects.
fn balance_changes(
    transaction: &ExecutedTransaction,
    checkpoint: &Checkpoint,
) -> Result<Vec<BalanceChange>> {
    // Shortcut if the transaction failed -- we know that only gas was charged.
    if transaction.effects.status().is_err() {
        let net_gas_usage = transaction.effects.gas_cost_summary().net_gas_usage();
        return Ok(Vec::from_iter((net_gas_usage > 0).then(|| {
            BalanceChange::V1 {
                owner: transaction.effects.gas_object().1,
                coin_type: GAS::type_tag().to_canonical_string(true),
                amount: -(net_gas_usage as i128),
            }
        })));
    }

    let mut changes = BTreeMap::new();

    // First gather address balance changes from accumulator events.
    for (addr, type_, balance) in
        address_balance_changes_from_accumulator_events(&transaction.effects)
    {
        *changes
            .entry((Owner::AddressOwner(addr), type_))
            .or_insert(0i128) += balance;
    }

    // Then gather coin balance changes from input and output objects.
    for object in transaction.input_objects(&checkpoint.object_set) {
        if let Some((type_, balance)) = Coin::extract_balance_if_coin(object)? {
            *changes
                .entry((object.owner().clone(), type_))
                .or_insert(0i128) -= balance as i128;
        }
    }

    for object in transaction.output_objects(&checkpoint.object_set) {
        if let Some((type_, balance)) = Coin::extract_balance_if_coin(object)? {
            *changes
                .entry((object.owner().clone(), type_))
                .or_insert(0i128) += balance as i128;