feat: add Pancakeswap v3 Substreams module (#178)
* feat: Add Pancakeswap V3 Substreams module At this point it's just hard copy of Uniswap V3. It will be adapted in the following commits to make reviewing easier. * refactor: adapt uniswapv3 module logic for pancakeswap v3 The main change is how they handle protocol fees. Protocol fees are set by default depending on the fee of the pool. * refactor: use new protobuf structs The "EntityChanges" got deprecated in favor of the hybrid messages. This commit makes PancakeswapV3 module use the new structs. * fix: set correct factory address --------- Co-authored-by: zizou <111426680+flopell@users.noreply.github.com> Co-authored-by: Louise Poole <louise@datarevenue.com>
This commit is contained in:
195
substreams/ethereum-pancakeswap-v3/src/modules/3_map_events.rs
Normal file
195
substreams/ethereum-pancakeswap-v3/src/modules/3_map_events.rs
Normal file
@@ -0,0 +1,195 @@
|
||||
use anyhow::Ok;
|
||||
use substreams::{
|
||||
store::{StoreGet, StoreGetProto},
|
||||
Hex,
|
||||
};
|
||||
use substreams_ethereum::{
|
||||
pb::eth::v2::{self as eth, Log, TransactionTrace},
|
||||
Event,
|
||||
};
|
||||
use substreams_helper::hex::Hexable;
|
||||
|
||||
use crate::{
|
||||
abi::pool::events::{
|
||||
Burn, Collect, CollectProtocol, Flash, Initialize, Mint, SetFeeProtocol, Swap,
|
||||
},
|
||||
pb::pancakeswap::v3::{
|
||||
events::{
|
||||
pool_event::{self, Type},
|
||||
PoolEvent,
|
||||
},
|
||||
Events, Pool,
|
||||
},
|
||||
};
|
||||
|
||||
#[substreams::handlers::map]
|
||||
pub fn map_events(
|
||||
block: eth::Block,
|
||||
pools_store: StoreGetProto<Pool>,
|
||||
) -> Result<Events, anyhow::Error> {
|
||||
let mut pool_events = block
|
||||
.transaction_traces
|
||||
.into_iter()
|
||||
.filter(|tx| tx.status == 1)
|
||||
.flat_map(|tx| {
|
||||
let receipt = tx
|
||||
.receipt
|
||||
.as_ref()
|
||||
.expect("all transaction traces have a receipt");
|
||||
|
||||
receipt
|
||||
.logs
|
||||
.iter()
|
||||
.filter_map(|log| {
|
||||
let key = format!("{}:{}", "Pool", log.address.to_hex());
|
||||
// Skip if the log is not from a known pool.
|
||||
if let Some(pool) = pools_store.get_last(key) {
|
||||
log_to_event(log, pool, &tx)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
pool_events.sort_unstable_by_key(|e| e.log_ordinal);
|
||||
|
||||
Ok(Events { pool_events })
|
||||
}
|
||||
|
||||
fn log_to_event(event: &Log, pool: Pool, tx: &TransactionTrace) -> Option<PoolEvent> {
|
||||
if let Some(init) = Initialize::match_and_decode(event) {
|
||||
Some(PoolEvent {
|
||||
log_ordinal: event.ordinal,
|
||||
pool_address: Hex(pool.address).to_string(),
|
||||
token0: Hex(pool.token0).to_string(),
|
||||
token1: Hex(pool.token1).to_string(),
|
||||
fee: pool.fee,
|
||||
transaction: Some(tx.into()),
|
||||
r#type: Some(Type::Initialize(pool_event::Initialize {
|
||||
sqrt_price: init.sqrt_price_x96.to_string(),
|
||||
tick: init.tick.into(),
|
||||
})),
|
||||
})
|
||||
} else if let Some(swap) = Swap::match_and_decode(event) {
|
||||
Some(PoolEvent {
|
||||
log_ordinal: event.ordinal,
|
||||
pool_address: Hex(pool.address).to_string(),
|
||||
token0: Hex(pool.token0).to_string(),
|
||||
token1: Hex(pool.token1).to_string(),
|
||||
fee: pool.fee,
|
||||
transaction: Some(tx.into()),
|
||||
r#type: Some(Type::Swap(pool_event::Swap {
|
||||
sender: Hex(swap.sender).to_string(),
|
||||
recipient: Hex(swap.recipient).to_string(),
|
||||
amount_0: swap.amount0.to_string(),
|
||||
amount_1: swap.amount1.to_string(),
|
||||
sqrt_price: swap.sqrt_price_x96.to_string(),
|
||||
liquidity: swap.liquidity.to_string(),
|
||||
tick: swap.tick.into(),
|
||||
})),
|
||||
})
|
||||
} else if let Some(flash) = Flash::match_and_decode(event) {
|
||||
Some(PoolEvent {
|
||||
log_ordinal: event.ordinal,
|
||||
pool_address: Hex(pool.address).to_string(),
|
||||
token0: Hex(pool.token0).to_string(),
|
||||
token1: Hex(pool.token1).to_string(),
|
||||
fee: pool.fee,
|
||||
transaction: Some(tx.into()),
|
||||
r#type: Some(Type::Flash(pool_event::Flash {
|
||||
sender: Hex(flash.sender).to_string(),
|
||||
recipient: Hex(flash.recipient).to_string(),
|
||||
amount_0: flash.amount0.to_string(),
|
||||
amount_1: flash.amount1.to_string(),
|
||||
paid_0: flash.paid0.to_string(),
|
||||
paid_1: flash.paid1.to_string(),
|
||||
})),
|
||||
})
|
||||
} else if let Some(mint) = Mint::match_and_decode(event) {
|
||||
Some(PoolEvent {
|
||||
log_ordinal: event.ordinal,
|
||||
pool_address: Hex(pool.address).to_string(),
|
||||
token0: Hex(pool.token0).to_string(),
|
||||
token1: Hex(pool.token1).to_string(),
|
||||
fee: pool.fee,
|
||||
transaction: Some(tx.into()),
|
||||
r#type: Some(Type::Mint(pool_event::Mint {
|
||||
sender: Hex(mint.sender).to_string(),
|
||||
owner: Hex(mint.owner).to_string(),
|
||||
tick_lower: mint.tick_lower.into(),
|
||||
tick_upper: mint.tick_upper.into(),
|
||||
amount: mint.amount.to_string(),
|
||||
amount_0: mint.amount0.to_string(),
|
||||
amount_1: mint.amount1.to_string(),
|
||||
})),
|
||||
})
|
||||
} else if let Some(burn) = Burn::match_and_decode(event) {
|
||||
Some(PoolEvent {
|
||||
log_ordinal: event.ordinal,
|
||||
pool_address: Hex(pool.address).to_string(),
|
||||
token0: Hex(pool.token0).to_string(),
|
||||
token1: Hex(pool.token1).to_string(),
|
||||
fee: pool.fee,
|
||||
transaction: Some(tx.into()),
|
||||
r#type: Some(Type::Burn(pool_event::Burn {
|
||||
owner: Hex(burn.owner).to_string(),
|
||||
tick_lower: burn.tick_lower.into(),
|
||||
tick_upper: burn.tick_upper.into(),
|
||||
amount: burn.amount.to_string(),
|
||||
amount_0: burn.amount0.to_string(),
|
||||
amount_1: burn.amount1.to_string(),
|
||||
})),
|
||||
})
|
||||
} else if let Some(collect) = Collect::match_and_decode(event) {
|
||||
Some(PoolEvent {
|
||||
log_ordinal: event.ordinal,
|
||||
pool_address: Hex(pool.address).to_string(),
|
||||
token0: Hex(pool.token0).to_string(),
|
||||
token1: Hex(pool.token1).to_string(),
|
||||
fee: pool.fee,
|
||||
transaction: Some(tx.into()),
|
||||
r#type: Some(Type::Collect(pool_event::Collect {
|
||||
owner: Hex(collect.owner).to_string(),
|
||||
recipient: Hex(collect.recipient).to_string(),
|
||||
tick_lower: collect.tick_lower.into(),
|
||||
tick_upper: collect.tick_upper.into(),
|
||||
amount_0: collect.amount0.to_string(),
|
||||
amount_1: collect.amount1.to_string(),
|
||||
})),
|
||||
})
|
||||
} else if let Some(set_fp) = SetFeeProtocol::match_and_decode(event) {
|
||||
Some(PoolEvent {
|
||||
log_ordinal: event.ordinal,
|
||||
pool_address: Hex(pool.address).to_string(),
|
||||
token0: Hex(pool.token0).to_string(),
|
||||
token1: Hex(pool.token1).to_string(),
|
||||
fee: pool.fee,
|
||||
transaction: Some(tx.into()),
|
||||
r#type: Some(Type::SetFeeProtocol(pool_event::SetFeeProtocol {
|
||||
fee_protocol_0_old: set_fp.fee_protocol0_old.to_u64(),
|
||||
fee_protocol_1_old: set_fp.fee_protocol1_old.to_u64(),
|
||||
fee_protocol_0_new: set_fp.fee_protocol0_new.to_u64(),
|
||||
fee_protocol_1_new: set_fp.fee_protocol1_new.to_u64(),
|
||||
})),
|
||||
})
|
||||
} else if let Some(cp) = CollectProtocol::match_and_decode(event) {
|
||||
Some(PoolEvent {
|
||||
log_ordinal: event.ordinal,
|
||||
pool_address: Hex(pool.address).to_string(),
|
||||
token0: Hex(pool.token0).to_string(),
|
||||
token1: Hex(pool.token1).to_string(),
|
||||
fee: pool.fee,
|
||||
transaction: Some(tx.into()),
|
||||
r#type: Some(Type::CollectProtocol(pool_event::CollectProtocol {
|
||||
sender: Hex(cp.sender).to_string(),
|
||||
recipient: Hex(cp.recipient).to_string(),
|
||||
amount_0: cp.amount0.to_string(),
|
||||
amount_1: cp.amount1.to_string(),
|
||||
})),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user