Files
tycho-protocol-sdk/substreams/ethereum-curve/src/pool_changes.rs
Zizou 4d4d05203a fix(curve-substreams): miscellaneous fixes for balances extractions in Curve (#118)
* fix(curve-substreams): filter out reverted calls in `emit_eth_deltas`

* feat(substreams-sdk): extract balances from `Deposit` events in `extract_balance_deltas_from_tx`

* ci: ignore fmt for abi files

* feat(sdk): also account for `Withdrawal` event from WETH

* chore: reorder mod.rs, remove unused import

* chore: cargo fmt

---------

Co-authored-by: zizou <111426680+flopell@users.noreply.github.com>
Co-authored-by: Thales <thales@datarevenue.com>
2024-12-06 18:21:07 -03:00

80 lines
3.5 KiB
Rust

use substreams::{
scalar::BigInt,
store::{StoreGet, StoreGetString},
};
use substreams_ethereum::pb::eth::v2::TransactionTrace;
use tycho_substreams::prelude::*;
use crate::consts::ETH_ADDRESS;
fn get_pool_tokens(pool_address: &Vec<u8>, tokens_store: &StoreGetString) -> Option<Vec<String>> {
let pool_key = format!("pool:{}", hex::encode(pool_address));
Some(
tokens_store
.get_last(pool_key)?
.split(":")
.map(|token| token.to_owned())
.collect::<Vec<_>>(),
)
}
/// Tracks ETH balance changes in and out of tracked pools if it matches the specific tokens.
/// Note: Pools might report as WETH or ETH. Some pools might even accept either WETH or ETH and
/// convert them on the fly (checkout pools with `WETHOptimized` in the name). It's a bit tricky
/// to figure this stuff out on the fly, but our rule of thumb is as follows:
/// - If a pool reports ETH in the `pool_tokens`, we use the fake ETH erc20 address.
/// - If a pool reports WETH, we report with the WETH erc20 address.
/// - If neither, it's likely an erroneous ETH transactions that many older pools don't reject.
pub fn emit_eth_deltas(tx: &TransactionTrace, tokens_store: &StoreGetString) -> Vec<BalanceDelta> {
tx.calls()
.filter(|call| !call.call.state_reverted)
.flat_map(|call| {
call.call
.balance_changes
.iter()
.filter_map(|balance_change| {
if let Some(pool_tokens) =
get_pool_tokens(&balance_change.address, tokens_store)
{
if !pool_tokens.contains(&hex::encode(ETH_ADDRESS)) {
// The pool that was matched to the call doesn't contain ETH so
// found eth balance changes are not relevant.
return None;
};
// We need to convert to the usable `BigInt` type to be able to calculate
// subtraction. This is seemingly the easiest way to do this.
let delta = BigInt::from_unsigned_bytes_be(
&balance_change
.new_value
.clone()
.unwrap_or_default()
.bytes,
) - BigInt::from_unsigned_bytes_be(
&balance_change
.old_value
.clone()
.unwrap_or_default()
.bytes,
);
Some(BalanceDelta {
ord: call.call.end_ordinal,
tx: Some(Transaction {
to: tx.to.clone(),
from: tx.from.clone(),
hash: tx.hash.clone(),
index: tx.index.into(),
}),
token: ETH_ADDRESS.to_vec(),
delta: delta.to_signed_bytes_be(),
component_id: hex::encode(balance_change.address.clone()).into(),
})
} else {
None
}
})
.collect::<Vec<_>>()
})
.collect::<Vec<_>>()
}