feat: Add a generic function to extract balance deltas from Transfer events.
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tycho-substreams"
|
name = "tycho-substreams"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
@@ -8,4 +8,6 @@ substreams-ethereum.workspace = true
|
|||||||
substreams.workspace = true
|
substreams.workspace = true
|
||||||
prost.workspace = true
|
prost.workspace = true
|
||||||
hex.workspace = true
|
hex.workspace = true
|
||||||
itertools = "0.12.0"
|
itertools = "0.12.0"
|
||||||
|
ethabi.workspace = true
|
||||||
|
num-bigint = "0.4.4"
|
||||||
|
|||||||
1066
substreams/crates/tycho-substreams/src/abi/erc20.rs
Normal file
1066
substreams/crates/tycho-substreams/src/abi/erc20.rs
Normal file
File diff suppressed because it is too large
Load Diff
2
substreams/crates/tycho-substreams/src/abi/mod.rs
Normal file
2
substreams/crates/tycho-substreams/src/abi/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#![allow(clippy::all)]
|
||||||
|
pub mod erc20;
|
||||||
@@ -21,7 +21,11 @@
|
|||||||
//! Through this sequence, the module ensures the transformation from relative to absolute
|
//! Through this sequence, the module ensures the transformation from relative to absolute
|
||||||
//! balances is conducted with high fidelity, upholding the integrity of transactional data.
|
//! balances is conducted with high fidelity, upholding the integrity of transactional data.
|
||||||
|
|
||||||
use crate::pb::tycho::evm::v1::{BalanceChange, BlockBalanceDeltas, Transaction};
|
use crate::{
|
||||||
|
abi,
|
||||||
|
pb::tycho::evm::v1::{BalanceChange, BlockBalanceDeltas, Transaction},
|
||||||
|
prelude::BalanceDelta,
|
||||||
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use std::{collections::HashMap, str::FromStr};
|
use std::{collections::HashMap, str::FromStr};
|
||||||
use substreams::{
|
use substreams::{
|
||||||
@@ -29,6 +33,7 @@ use substreams::{
|
|||||||
pb::substreams::StoreDeltas,
|
pb::substreams::StoreDeltas,
|
||||||
prelude::{BigInt, StoreAdd},
|
prelude::{BigInt, StoreAdd},
|
||||||
};
|
};
|
||||||
|
use substreams_ethereum::{pb::eth::v2::TransactionTrace, Event};
|
||||||
|
|
||||||
/// Stores relative balance changes in an additive manner.
|
/// Stores relative balance changes in an additive manner.
|
||||||
///
|
///
|
||||||
@@ -158,6 +163,79 @@ pub fn aggregate_balances_changes(
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extracts balance deltas from a transaction trace based on a given address predicate.
|
||||||
|
///
|
||||||
|
/// This function processes the logs within a transaction trace to identify ERC-20 token transfer
|
||||||
|
/// events. It applies the given predicate to determine which addresses are of interest and extracts
|
||||||
|
/// the balance changes (deltas) for those addresses. The balance deltas are then returned as a
|
||||||
|
/// vector.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `tx` - A reference to a `TransactionTrace` which contains the transaction logs and other
|
||||||
|
/// details.
|
||||||
|
/// * `address_predicate` - A predicate function that takes two byte slices representing a token and
|
||||||
|
/// a component and returns a boolean. This function is used to filter which addresses' balance
|
||||||
|
/// changes should be extracted.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// A vector of `BalanceDelta` structs, each representing a change in balance for a specific address
|
||||||
|
/// within the transaction.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let predicate = |log_address: &[u8], transfer_address: &[u8]| -> bool {
|
||||||
|
/// // Your predicate logic here, e.g., checking if the address matches a specific pattern.
|
||||||
|
/// true
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// let balance_deltas = extract_balance_deltas_from_tx(&tx, predicate);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Notes
|
||||||
|
///
|
||||||
|
/// - It is assumed that the transactor is the component. If the protocol follows a different
|
||||||
|
/// design, this function may not be applicable.
|
||||||
|
/// - The `address_predicate` is applied to both the log address and the `from`/`to` addresses in
|
||||||
|
/// the transfer event.
|
||||||
|
pub fn extract_balance_deltas_from_tx<F: Fn(&[u8], &[u8]) -> bool>(
|
||||||
|
tx: &TransactionTrace,
|
||||||
|
address_predicate: F,
|
||||||
|
) -> Vec<BalanceDelta> {
|
||||||
|
let mut balance_deltas = vec![];
|
||||||
|
|
||||||
|
tx.logs_with_calls()
|
||||||
|
.for_each(|(log, _)| {
|
||||||
|
if let Some(transfer) = abi::erc20::events::Transfer::match_and_decode(log) {
|
||||||
|
let mut create_balance_delta = |transactor: &[u8], delta: BigInt| {
|
||||||
|
balance_deltas.push(BalanceDelta {
|
||||||
|
ord: log.ordinal,
|
||||||
|
tx: Some(Transaction {
|
||||||
|
to: tx.to.clone(),
|
||||||
|
from: tx.from.clone(),
|
||||||
|
hash: tx.hash.clone(),
|
||||||
|
index: tx.index.into(),
|
||||||
|
}),
|
||||||
|
token: log.address.clone(),
|
||||||
|
delta: delta.to_signed_bytes_be(),
|
||||||
|
component_id: hex::encode(transactor).into(),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if address_predicate(&log.address, &transfer.from) {
|
||||||
|
create_balance_delta(&transfer.from, transfer.value.neg());
|
||||||
|
}
|
||||||
|
if address_predicate(&log.address, &transfer.to) {
|
||||||
|
create_balance_delta(&transfer.to, transfer.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
balance_deltas
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
mod abi;
|
||||||
pub mod balances;
|
pub mod balances;
|
||||||
pub mod contract;
|
pub mod contract;
|
||||||
mod mock_store;
|
mod mock_store;
|
||||||
|
|||||||
Reference in New Issue
Block a user