feat(substreams): add substreams for Uniswap v2 and v3

This commit is contained in:
zizou
2024-10-11 12:57:34 +02:00
parent 58455a1188
commit 73d48236ba
70 changed files with 16697 additions and 1 deletions

View File

@@ -0,0 +1,45 @@
use substreams_ethereum::pb::eth::v2::StorageChange;
use substreams_helper::storage_change::StorageChangesFilter;
use crate::{
abi::pool::events::Burn,
pb::{tycho::evm::v1::Attribute, uniswap::v3::Pool},
storage::{constants::TRACKED_SLOTS, pool_storage::UniswapPoolStorage},
};
use super::{BalanceDelta, EventTrait};
impl EventTrait for Burn {
fn get_changed_attributes(
&self,
storage_changes: &[StorageChange],
pool_address: &[u8; 20],
) -> Vec<Attribute> {
let storage_vec = storage_changes.to_vec();
let filtered_storage_changes = storage_vec
.filter_by_address(pool_address)
.into_iter()
.cloned()
.collect();
let pool_storage = UniswapPoolStorage::new(&filtered_storage_changes);
let mut changed_attributes =
pool_storage.get_changed_attributes(TRACKED_SLOTS.to_vec().iter().collect());
let changed_ticks =
pool_storage.get_ticks_changes(vec![&self.tick_upper, &self.tick_lower]);
changed_attributes.extend(changed_ticks);
changed_attributes
}
fn get_balance_delta(&self, _pool: &Pool, _ordinal: u64) -> Vec<BalanceDelta> {
// Burn event balances deltas are accounted for by the Collect event.
// In the case of a burn, the Collect event amounts will include both the burned amount and
// the fees earned.
vec![]
}
}

View File

@@ -0,0 +1,58 @@
use substreams_ethereum::pb::eth::v2::StorageChange;
use crate::{
abi::pool::events::Collect,
pb::{tycho::evm::v1::Attribute, uniswap::v3::Pool},
storage::{constants::TRACKED_SLOTS, pool_storage::UniswapPoolStorage},
};
use substreams_helper::storage_change::StorageChangesFilter;
use super::{BalanceDelta, EventTrait};
impl EventTrait for Collect {
fn get_changed_attributes(
&self,
storage_changes: &[StorageChange],
pool_address: &[u8; 20],
) -> Vec<Attribute> {
let storage_vec = storage_changes.to_vec();
let filtered_storage_changes = storage_vec
.filter_by_address(pool_address)
.into_iter()
.cloned()
.collect();
let pool_storage = UniswapPoolStorage::new(&filtered_storage_changes);
let mut changed_attributes =
pool_storage.get_changed_attributes(TRACKED_SLOTS.to_vec().iter().collect());
let changed_ticks =
pool_storage.get_ticks_changes(vec![&self.tick_upper, &self.tick_lower]);
changed_attributes.extend(changed_ticks);
changed_attributes
}
fn get_balance_delta(&self, pool: &Pool, ordinal: u64) -> Vec<BalanceDelta> {
let changed_balance = vec![
BalanceDelta {
token_address: pool.token0.clone(),
amount: self.amount0.clone().to_bytes_le().1,
sign: false,
pool_address: pool.address.clone(),
ordinal,
},
BalanceDelta {
token_address: pool.token1.clone(),
amount: self.amount1.clone().to_bytes_le().1,
sign: false,
pool_address: pool.address.clone(),
ordinal,
},
];
changed_balance
}
}

View File

@@ -0,0 +1,50 @@
use substreams_ethereum::pb::eth::v2::StorageChange;
use substreams_helper::storage_change::StorageChangesFilter;
use crate::{
abi::pool::events::CollectProtocol,
pb::{tycho::evm::v1::Attribute, uniswap::v3::Pool},
storage::{constants::TRACKED_SLOTS, pool_storage::UniswapPoolStorage},
};
use super::{BalanceDelta, EventTrait};
impl EventTrait for CollectProtocol {
fn get_changed_attributes(
&self,
storage_changes: &[StorageChange],
pool_address: &[u8; 20],
) -> Vec<Attribute> {
let storage_vec = storage_changes.to_vec();
let filtered_storage_changes = storage_vec
.filter_by_address(pool_address)
.into_iter()
.cloned()
.collect();
let pool_storage = UniswapPoolStorage::new(&filtered_storage_changes);
pool_storage.get_changed_attributes(TRACKED_SLOTS.to_vec().iter().collect())
}
fn get_balance_delta(&self, pool: &Pool, ordinal: u64) -> Vec<BalanceDelta> {
let changed_balance = vec![
BalanceDelta {
token_address: pool.token0.clone(),
amount: self.amount0.clone().to_bytes_le().1,
sign: false,
pool_address: pool.address.clone(),
ordinal,
},
BalanceDelta {
token_address: pool.token1.clone(),
amount: self.amount1.clone().to_bytes_le().1,
sign: false,
pool_address: pool.address.clone(),
ordinal,
},
];
changed_balance
}
}

View File

@@ -0,0 +1,50 @@
use substreams_ethereum::pb::eth::v2::StorageChange;
use crate::{
abi::pool::events::Flash,
pb::{tycho::evm::v1::Attribute, uniswap::v3::Pool},
storage::{constants::TRACKED_SLOTS, pool_storage::UniswapPoolStorage},
};
use substreams_helper::storage_change::StorageChangesFilter;
use super::{BalanceDelta, EventTrait};
impl EventTrait for Flash {
fn get_changed_attributes(
&self,
storage_changes: &[StorageChange],
pool_address: &[u8; 20],
) -> Vec<Attribute> {
let storage_vec = storage_changes.to_vec();
let filtered_storage_changes = storage_vec
.filter_by_address(pool_address)
.into_iter()
.cloned()
.collect();
let pool_storage = UniswapPoolStorage::new(&filtered_storage_changes);
pool_storage.get_changed_attributes(TRACKED_SLOTS.to_vec().iter().collect())
}
fn get_balance_delta(&self, pool: &Pool, ordinal: u64) -> Vec<BalanceDelta> {
let changed_balance = vec![
BalanceDelta {
token_address: pool.token0.clone(),
amount: self.paid0.clone().to_bytes_le().1,
sign: true,
pool_address: pool.address.clone(),
ordinal,
},
BalanceDelta {
token_address: pool.token1.clone(),
amount: self.paid1.clone().to_bytes_le().1,
sign: true,
pool_address: pool.address.clone(),
ordinal,
},
];
changed_balance
}
}

View File

@@ -0,0 +1,34 @@
use substreams_ethereum::pb::eth::v2::StorageChange;
use crate::{
abi::pool::events::Initialize,
pb::{tycho::evm::v1::Attribute, uniswap::v3::Pool},
storage::{constants::TRACKED_SLOTS, pool_storage::UniswapPoolStorage},
};
use substreams_helper::storage_change::StorageChangesFilter;
use super::{BalanceDelta, EventTrait};
impl EventTrait for Initialize {
fn get_changed_attributes(
&self,
storage_changes: &[StorageChange],
pool_address: &[u8; 20],
) -> Vec<Attribute> {
let storage_vec = storage_changes.to_vec();
let filtered_storage_changes = storage_vec
.filter_by_address(pool_address)
.into_iter()
.cloned()
.collect();
let pool_storage = UniswapPoolStorage::new(&filtered_storage_changes);
pool_storage.get_changed_attributes(TRACKED_SLOTS.to_vec().iter().collect())
}
fn get_balance_delta(&self, _pool: &Pool, _ordinal: u64) -> Vec<BalanceDelta> {
vec![]
}
}

View File

@@ -0,0 +1,58 @@
use substreams_ethereum::pb::eth::v2::StorageChange;
use crate::{
abi::pool::events::Mint,
pb::{tycho::evm::v1::Attribute, uniswap::v3::Pool},
storage::{constants::TRACKED_SLOTS, pool_storage::UniswapPoolStorage},
};
use substreams_helper::storage_change::StorageChangesFilter;
use super::{BalanceDelta, EventTrait};
impl EventTrait for Mint {
fn get_changed_attributes(
&self,
storage_changes: &[StorageChange],
pool_address: &[u8; 20],
) -> Vec<Attribute> {
let storage_vec = storage_changes.to_vec();
let filtered_storage_changes = storage_vec
.filter_by_address(pool_address)
.into_iter()
.cloned()
.collect();
let pool_storage = UniswapPoolStorage::new(&filtered_storage_changes);
let mut changed_attributes =
pool_storage.get_changed_attributes(TRACKED_SLOTS.to_vec().iter().collect());
let changed_ticks =
pool_storage.get_ticks_changes(vec![&self.tick_upper, &self.tick_lower]);
changed_attributes.extend(changed_ticks);
changed_attributes
}
fn get_balance_delta(&self, pool: &Pool, ordinal: u64) -> Vec<BalanceDelta> {
let changed_balance = vec![
BalanceDelta {
token_address: pool.token0.clone(),
amount: self.amount0.clone().to_bytes_le().1,
sign: true,
pool_address: pool.address.clone(),
ordinal,
},
BalanceDelta {
token_address: pool.token1.clone(),
amount: self.amount1.clone().to_bytes_le().1,
sign: true,
pool_address: pool.address.clone(),
ordinal,
},
];
changed_balance
}
}

View File

@@ -0,0 +1,150 @@
use substreams_ethereum::{
pb::eth::v2::{Log, StorageChange},
Event,
};
use crate::{
abi::pool::events::{
Burn, Collect, CollectProtocol, Flash, Initialize, Mint, SetFeeProtocol, Swap,
},
pb::{
tycho::evm::v1::Attribute,
uniswap::v3::{BalanceDelta, Pool},
},
};
pub mod burn;
pub mod collect;
pub mod collect_fee_protocol;
pub mod flash;
pub mod initialize;
pub mod mint;
pub mod set_fee_protocol;
pub mod swap;
/// A trait for extracting changed attributes and balance from an event.
pub trait EventTrait {
/// Get all relevant changed attributes from the `[StorageChange]`.
/// If an attribute is changed multiple times, only the last state will be returned.
///
/// # Arguments
///
/// * `storage_changes` - A slice of `StorageChange` that indicates the changes in storage.
/// * `pool` - Reference to the `Pool`.
///
/// # Returns
///
/// A vector of `Attribute` that represents the changed attributes.
fn get_changed_attributes(
&self,
storage_changes: &[StorageChange],
pool_address: &[u8; 20],
) -> Vec<Attribute>;
/// Get all balance deltas from the event.
///
/// # Arguments
///
/// * `pool` - Reference to the `Pool`.
/// * `ordinal` - The ordinal number of the event. This is used by the balance store to sort the
/// balance deltas in the correct order.
///
/// # Returns
///
/// A vector of `BalanceDelta` that represents the balance deltas.
fn get_balance_delta(&self, pool: &Pool, ordinal: u64) -> Vec<BalanceDelta>;
}
/// Represent every events of a UniswapV3 pool.
pub enum EventType {
Initialize(Initialize),
Swap(Swap),
Flash(Flash),
Mint(Mint),
Burn(Burn),
Collect(Collect),
SetFeeProtocol(SetFeeProtocol),
CollectProtocol(CollectProtocol),
}
impl EventType {
fn as_event_trait(&self) -> &dyn EventTrait {
match self {
EventType::Initialize(e) => e,
EventType::Swap(e) => e,
EventType::Flash(e) => e,
EventType::Mint(e) => e,
EventType::Burn(e) => e,
EventType::Collect(e) => e,
EventType::SetFeeProtocol(e) => e,
EventType::CollectProtocol(e) => e,
}
}
}
/// Decodes a given log into an `EventType`.
///
/// # Arguments
///
/// * `event` - A reference to the `Log`.
///
/// # Returns
///
/// An `Option<EventType>` that represents the decoded event type.
pub fn decode_event(event: &Log) -> Option<EventType> {
[
Initialize::match_and_decode(event).map(EventType::Initialize),
Swap::match_and_decode(event).map(EventType::Swap),
Flash::match_and_decode(event).map(EventType::Flash),
Mint::match_and_decode(event).map(EventType::Mint),
Burn::match_and_decode(event).map(EventType::Burn),
Collect::match_and_decode(event).map(EventType::Collect),
SetFeeProtocol::match_and_decode(event).map(EventType::SetFeeProtocol),
CollectProtocol::match_and_decode(event).map(EventType::CollectProtocol),
]
.into_iter()
.find_map(std::convert::identity)
}
/// Gets the changed attributes from the log.
///
/// # Arguments
///
/// * `event` - A reference to the `Log`.
/// * `storage_changes` - A slice of `StorageChange` that indicates the changes in storage.
/// * `pool` - Reference to the `Pool` structure.
///
/// # Returns
///
/// A vector of `Attribute` that represents the changed attributes.
pub fn get_log_changed_attributes(
event: &Log,
storage_changes: &[StorageChange],
pool_address: &[u8; 20],
) -> Vec<Attribute> {
decode_event(event)
.map(|e| {
e.as_event_trait()
.get_changed_attributes(storage_changes, pool_address)
})
.unwrap_or_default()
}
/// Gets the changed balances from the log.
///
/// # Arguments
///
/// * `event` - A reference to the `Log`.
/// * `pool` - Reference to the `Pool` structure.
///
/// # Returns
///
/// A vector of `BalanceDelta` that represents
pub fn get_log_changed_balances(event: &Log, pool: &Pool) -> Vec<BalanceDelta> {
decode_event(event)
.map(|e| {
e.as_event_trait()
.get_balance_delta(pool, event.ordinal)
})
.unwrap_or_default()
}

View File

@@ -0,0 +1,34 @@
use substreams_ethereum::pb::eth::v2::StorageChange;
use crate::{
abi::pool::events::SetFeeProtocol,
pb::{tycho::evm::v1::Attribute, uniswap::v3::Pool},
storage::{constants::TRACKED_SLOTS, pool_storage::UniswapPoolStorage},
};
use substreams_helper::storage_change::StorageChangesFilter;
use super::{BalanceDelta, EventTrait};
impl EventTrait for SetFeeProtocol {
fn get_changed_attributes(
&self,
storage_changes: &[StorageChange],
pool_address: &[u8; 20],
) -> Vec<Attribute> {
let storage_vec = storage_changes.to_vec();
let filtered_storage_changes = storage_vec
.filter_by_address(pool_address)
.into_iter()
.cloned()
.collect();
let pool_storage = UniswapPoolStorage::new(&filtered_storage_changes);
pool_storage.get_changed_attributes(TRACKED_SLOTS.to_vec().iter().collect())
}
fn get_balance_delta(&self, _pool: &Pool, _ordinal: u64) -> Vec<BalanceDelta> {
vec![]
}
}

View File

@@ -0,0 +1,50 @@
use num_bigint::Sign;
use substreams::scalar::BigInt;
use substreams_ethereum::pb::eth::v2::StorageChange;
use substreams_helper::storage_change::StorageChangesFilter;
use crate::{
abi::pool::events::Swap,
pb::{tycho::evm::v1::Attribute, uniswap::v3::Pool},
storage::{constants::TRACKED_SLOTS, pool_storage::UniswapPoolStorage},
};
use super::{BalanceDelta, EventTrait};
impl EventTrait for Swap {
fn get_changed_attributes(
&self,
storage_changes: &[StorageChange],
pool_address: &[u8; 20],
) -> Vec<Attribute> {
let storage_vec = storage_changes.to_vec();
let filtered_storage_changes = storage_vec
.filter_by_address(pool_address)
.into_iter()
.cloned()
.collect();
let pool_storage = UniswapPoolStorage::new(&filtered_storage_changes);
pool_storage.get_changed_attributes(TRACKED_SLOTS.to_vec().iter().collect())
}
fn get_balance_delta(&self, pool: &Pool, ordinal: u64) -> Vec<BalanceDelta> {
let create_balance_delta = |token_address: Vec<u8>, amount: BigInt| -> BalanceDelta {
let (amount_sign, amount_bytes) = amount.clone().to_bytes_le();
BalanceDelta {
token_address,
amount: amount_bytes,
sign: amount_sign == Sign::Plus,
pool_address: pool.address.clone(),
ordinal,
}
};
vec![
create_balance_delta(pool.token0.clone(), self.amount0.clone()),
create_balance_delta(pool.token1.clone(), self.amount1.clone()),
]
}
}