Files
tycho-protocol-sdk/substreams/ethereum-curve/src/pool_changes.rs
Florian Pellissier 10a36c0a9b fix: Replace buggy balance extraction with SDK extract_balance_deltas_from_tx
The bug occurred when a Transfer event involved both the sender and recipient being pools. In such cases, the previous implementation only created a BalanceDelta for the "to" address and missed accounting for the "from" address.
2024-07-12 14:59:54 +02:00

83 lines
3.6 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, WETH_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()
.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)
{
let token = if pool_tokens.contains(&hex::encode(ETH_ADDRESS)) {
ETH_ADDRESS.to_vec()
} else if pool_tokens.contains(&hex::encode(WETH_ADDRESS)) {
WETH_ADDRESS.to_vec()
} else {
// The pool that was matched to the call doesn't contain either ETH
// or WETH so found eth balance changes are erroneous.
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,
delta: delta.to_signed_bytes_be(),
component_id: hex::encode(balance_change.address.clone()).into(),
})
} else {
None
}
})
.collect::<Vec<_>>()
})
.collect::<Vec<_>>()
}