feat(substreams): add substreams for Uniswap v2 and v3
This commit is contained in:
45
substreams/ethereum-uniswap-v3/src/events/burn.rs
Normal file
45
substreams/ethereum-uniswap-v3/src/events/burn.rs
Normal 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![]
|
||||
}
|
||||
}
|
||||
58
substreams/ethereum-uniswap-v3/src/events/collect.rs
Normal file
58
substreams/ethereum-uniswap-v3/src/events/collect.rs
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
50
substreams/ethereum-uniswap-v3/src/events/flash.rs
Normal file
50
substreams/ethereum-uniswap-v3/src/events/flash.rs
Normal 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
|
||||
}
|
||||
}
|
||||
34
substreams/ethereum-uniswap-v3/src/events/initialize.rs
Normal file
34
substreams/ethereum-uniswap-v3/src/events/initialize.rs
Normal 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![]
|
||||
}
|
||||
}
|
||||
58
substreams/ethereum-uniswap-v3/src/events/mint.rs
Normal file
58
substreams/ethereum-uniswap-v3/src/events/mint.rs
Normal 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
|
||||
}
|
||||
}
|
||||
150
substreams/ethereum-uniswap-v3/src/events/mod.rs
Normal file
150
substreams/ethereum-uniswap-v3/src/events/mod.rs
Normal 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()
|
||||
}
|
||||
@@ -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![]
|
||||
}
|
||||
}
|
||||
50
substreams/ethereum-uniswap-v3/src/events/swap.rs
Normal file
50
substreams/ethereum-uniswap-v3/src/events/swap.rs
Normal 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()),
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user