refactor(substreams): improve logic to ignore updates (#96)
* refactor(substreams): ignore transaction if contracts update are ignored. There are some cases where we ignore contracts updates (for example if the old and new values are the same). In that case if the transaction only contains ignored updates we don't emit it. * refactor(substreams): ignore deletions for freshly created attributes. There are cases where an attribute can be created and deleted during the same transaction. To avoid sending a confusing deletion for something that was never created before, we just ignore the deletion in that particular case. * feat(substreams): Add uniswap V3 logs only module (#98) * feat(substreams): add uniswapV3 logs only Substreams module * refactor(substreams): encode everything as big endian * refactor(substreams): mark changes as creation when a tick liq is updated from 0 This will allow the SDK to detect cases where a tick is created and deleted in the same transaction and ignore it. * ci(substreams): ignore built files for uniswapv3 logs only module and clean code * refactor(substreams): update uniswapv3 substreams with new SDK interface * feat(subtreams): emit default token balances value for uniswapv3 --------- Co-authored-by: zizou <111426680+flopell@users.noreply.github.com> --------- Co-authored-by: zizou <111426680+flopell@users.noreply.github.com>
This commit is contained in:
92
substreams/Cargo.lock
generated
92
substreams/Cargo.lock
generated
@@ -347,6 +347,26 @@ dependencies = [
|
||||
"tycho-substreams",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ethereum-uniswap-v3-logs-only"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"ethabi 18.0.0",
|
||||
"getrandom",
|
||||
"hex",
|
||||
"hex-literal 0.4.1",
|
||||
"itertools 0.13.0",
|
||||
"num-bigint",
|
||||
"prost 0.11.9",
|
||||
"substreams",
|
||||
"substreams-entity-change",
|
||||
"substreams-ethereum",
|
||||
"substreams-helper",
|
||||
"tiny-keccak",
|
||||
"tycho-substreams",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.0.1"
|
||||
@@ -660,6 +680,51 @@ version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||
|
||||
[[package]]
|
||||
name = "pest"
|
||||
version = "2.7.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"thiserror",
|
||||
"ucd-trie",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_derive"
|
||||
version = "2.7.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_generator",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_generator"
|
||||
version = "2.7.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_meta",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.52",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_meta"
|
||||
version = "2.7.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"pest",
|
||||
"sha2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "petgraph"
|
||||
version = "0.6.4"
|
||||
@@ -968,6 +1033,17 @@ dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha3"
|
||||
version = "0.10.8"
|
||||
@@ -986,9 +1062,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "substreams"
|
||||
version = "0.5.13"
|
||||
version = "0.5.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3520661f782c338f0e3c6cfc001ac790ed5e68d8f28515139e2aa674f8bb54da"
|
||||
checksum = "92e47e531af83a3cbb78c627ee8232a0ac86604f11c89e34bd4b721ec41e03e5"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bigdecimal",
|
||||
@@ -998,6 +1074,8 @@ dependencies = [
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"pad",
|
||||
"pest",
|
||||
"pest_derive",
|
||||
"prost 0.11.9",
|
||||
"prost-build",
|
||||
"prost-types 0.11.9",
|
||||
@@ -1141,9 +1219,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "substreams-macro"
|
||||
version = "0.5.13"
|
||||
version = "0.5.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c15595ceab80fece579e462d4823048fe85d67922584c681f5e94305727ad9ee"
|
||||
checksum = "a4ac77f08d723dace35739d65df8ed122f6d04e2a3e47929831d4021e3339240"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1258,6 +1336,12 @@ version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||
|
||||
[[package]]
|
||||
name = "ucd-trie"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971"
|
||||
|
||||
[[package]]
|
||||
name = "uint"
|
||||
version = "0.9.5"
|
||||
|
||||
@@ -9,13 +9,14 @@ members = [
|
||||
"ethereum-uniswap-v3",
|
||||
"ethereum-sfrax",
|
||||
"ethereum-sfraxeth",
|
||||
"ethereum-uniswap-v3-logs-only",
|
||||
]
|
||||
resolver = "2"
|
||||
|
||||
|
||||
[workspace.dependencies]
|
||||
substreams-ethereum = "0.9.9"
|
||||
substreams = "0.5"
|
||||
substreams = "0.5.22"
|
||||
prost = "0.11"
|
||||
prost-types = "0.12.3"
|
||||
hex-literal = "0.4.1"
|
||||
|
||||
@@ -59,7 +59,7 @@ pub fn extract_contract_changes<F: Fn(&[u8]) -> bool>(
|
||||
changed_contracts
|
||||
.clone()
|
||||
.into_values()
|
||||
.map(|change| change.into()),
|
||||
.filter_map(|change| change.into()),
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use substreams_ethereum::pb::eth::v2::{self as sf, StorageChange};
|
||||
|
||||
// re-export the protobuf types here.
|
||||
@@ -114,6 +114,13 @@ impl TransactionChangesBuilder {
|
||||
.into_iter()
|
||||
.map(|a| (a.name.clone(), a))
|
||||
.collect(),
|
||||
created_attributes: change
|
||||
.attributes
|
||||
.clone()
|
||||
.iter()
|
||||
.filter(|&attr| (attr.change == i32::from(ChangeType::Creation)))
|
||||
.map(|attr| attr.name.clone())
|
||||
.collect(),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -141,24 +148,17 @@ impl TransactionChangesBuilder {
|
||||
}
|
||||
|
||||
pub fn build(self) -> Option<TransactionChanges> {
|
||||
if self.contract_changes.is_empty() &&
|
||||
self.component_changes.is_empty() &&
|
||||
self.balance_changes.is_empty() &&
|
||||
self.entity_changes.is_empty()
|
||||
{
|
||||
None
|
||||
} else {
|
||||
Some(TransactionChanges {
|
||||
let tx_changes = TransactionChanges {
|
||||
tx: self.tx,
|
||||
contract_changes: self
|
||||
.contract_changes
|
||||
.into_values()
|
||||
.map(|interim| interim.into())
|
||||
.filter_map(|interim| interim.into())
|
||||
.collect::<Vec<_>>(),
|
||||
entity_changes: self
|
||||
.entity_changes
|
||||
.into_values()
|
||||
.map(|interim| interim.into())
|
||||
.filter_map(|interim| interim.into())
|
||||
.collect::<Vec<_>>(),
|
||||
component_changes: self
|
||||
.component_changes
|
||||
@@ -168,7 +168,11 @@ impl TransactionChangesBuilder {
|
||||
.balance_changes
|
||||
.into_values()
|
||||
.collect::<Vec<_>>(),
|
||||
})
|
||||
};
|
||||
if tx_changes.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(tx_changes)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -389,6 +393,8 @@ impl ProtocolComponent {
|
||||
pub struct InterimEntityChanges {
|
||||
component_id: String,
|
||||
attributes: HashMap<String, Attribute>,
|
||||
/// A set of created attributes during this transaction
|
||||
created_attributes: HashSet<String>,
|
||||
}
|
||||
|
||||
impl InterimEntityChanges {
|
||||
@@ -397,26 +403,45 @@ impl InterimEntityChanges {
|
||||
}
|
||||
|
||||
pub fn set_attribute(&mut self, attr: &Attribute) {
|
||||
// Add any attribute creation to the map
|
||||
if attr.change == i32::from(ChangeType::Creation) {
|
||||
self.created_attributes
|
||||
.insert(attr.name.clone());
|
||||
}
|
||||
|
||||
if attr.change == i32::from(ChangeType::Deletion) &&
|
||||
self.created_attributes
|
||||
.contains(&attr.name)
|
||||
{
|
||||
// If a freshly created attribute is deleted, remove the creation.
|
||||
self.attributes.remove(&attr.name);
|
||||
} else {
|
||||
self.attributes
|
||||
.entry(attr.name.clone())
|
||||
.and_modify(|existing| *existing = attr.clone())
|
||||
.or_insert(attr.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<InterimEntityChanges> for EntityChanges {
|
||||
impl From<InterimEntityChanges> for Option<EntityChanges> {
|
||||
fn from(value: InterimEntityChanges) -> Self {
|
||||
EntityChanges {
|
||||
let changes = EntityChanges {
|
||||
component_id: value.component_id.clone(),
|
||||
attributes: value
|
||||
.attributes
|
||||
.into_values()
|
||||
.collect::<Vec<_>>(),
|
||||
};
|
||||
if changes.attributes.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(changes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
struct SlotValue {
|
||||
new_value: Vec<u8>,
|
||||
start_value: Vec<u8>,
|
||||
@@ -435,7 +460,7 @@ impl From<&StorageChange> for SlotValue {
|
||||
}
|
||||
|
||||
// Uses a map for slots, protobuf does not allow bytes in hashmap keys
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct InterimContractChange {
|
||||
address: Vec<u8>,
|
||||
balance: Vec<u8>,
|
||||
@@ -492,9 +517,9 @@ impl InterimContractChange {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<InterimContractChange> for ContractChange {
|
||||
impl From<InterimContractChange> for Option<ContractChange> {
|
||||
fn from(value: InterimContractChange) -> Self {
|
||||
ContractChange {
|
||||
let contract_change = ContractChange {
|
||||
address: value.address,
|
||||
balance: value.balance,
|
||||
code: value.code,
|
||||
@@ -505,6 +530,87 @@ impl From<InterimContractChange> for ContractChange {
|
||||
.map(|(slot, value)| ContractSlot { slot, value: value.new_value })
|
||||
.collect(),
|
||||
change: value.change.into(),
|
||||
};
|
||||
if contract_change.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(contract_change)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ContractChange {
|
||||
fn is_empty(&self) -> bool {
|
||||
self.balance.is_empty() &&
|
||||
self.slots.is_empty() &&
|
||||
self.code.is_empty() &&
|
||||
self.change == i32::from(ChangeType::Update)
|
||||
}
|
||||
}
|
||||
|
||||
impl TransactionChanges {
|
||||
fn is_empty(&self) -> bool {
|
||||
self.contract_changes.is_empty() &&
|
||||
self.component_changes.is_empty() &&
|
||||
self.balance_changes.is_empty() &&
|
||||
self.entity_changes.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use substreams_ethereum::pb::eth::v2::StorageChange;
|
||||
|
||||
use crate::models::{Attribute, ChangeType, EntityChanges};
|
||||
|
||||
use super::{InterimContractChange, TransactionChangesBuilder};
|
||||
|
||||
#[test]
|
||||
fn test_transaction_changes_builder_ignored_contract_changes() {
|
||||
let mut builder = TransactionChangesBuilder::new(&super::Transaction::default());
|
||||
let mut contract_changes = InterimContractChange::new(&[1], false);
|
||||
contract_changes.upsert_slot(&StorageChange {
|
||||
address: [1].to_vec(),
|
||||
key: [0].to_vec(),
|
||||
old_value: [1].to_vec(),
|
||||
new_value: [1].to_vec(), //Same old and new value, must be ignored
|
||||
ordinal: 1,
|
||||
});
|
||||
builder.add_contract_changes(&contract_changes);
|
||||
|
||||
let tx_changes = builder.build();
|
||||
assert!(tx_changes.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transaction_changes_builder_ignored_deletion() {
|
||||
let mut builder = TransactionChangesBuilder::new(&super::Transaction::default());
|
||||
|
||||
// Create an attribute
|
||||
let changes = EntityChanges {
|
||||
component_id: "component".to_string(),
|
||||
attributes: vec![Attribute {
|
||||
name: "attribute".to_string(),
|
||||
value: vec![1],
|
||||
change: ChangeType::Creation.into(),
|
||||
}],
|
||||
};
|
||||
|
||||
builder.add_entity_change(&changes);
|
||||
|
||||
// Delete the attribute
|
||||
let changes = EntityChanges {
|
||||
component_id: "component".to_string(),
|
||||
attributes: vec![Attribute {
|
||||
name: "attribute".to_string(),
|
||||
value: vec![0],
|
||||
change: ChangeType::Deletion.into(),
|
||||
}],
|
||||
};
|
||||
|
||||
builder.add_entity_change(&changes);
|
||||
|
||||
let tx_changes = builder.build();
|
||||
assert!(tx_changes.is_none());
|
||||
}
|
||||
}
|
||||
|
||||
30
substreams/ethereum-uniswap-v3-logs-only/Cargo.toml
Normal file
30
substreams/ethereum-uniswap-v3-logs-only/Cargo.toml
Normal file
@@ -0,0 +1,30 @@
|
||||
[package]
|
||||
name = "ethereum-uniswap-v3-logs-only"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
name = "ethereum_uniswap_v3_logs_only"
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
substreams.workspace = true
|
||||
substreams-ethereum.workspace = true
|
||||
prost.workspace = true
|
||||
ethabi.workspace = true
|
||||
anyhow = { workspace = true, features = [] }
|
||||
hex-literal.workspace = true
|
||||
substreams-helper.workspace = true
|
||||
tycho-substreams.workspace = true
|
||||
num-bigint = "0.4.4"
|
||||
hex.workspace = true
|
||||
tiny-keccak = "2.0"
|
||||
substreams-entity-change = "1.3"
|
||||
itertools = "0.13.0"
|
||||
|
||||
[target.wasm32-unknown-unknown.dependencies]
|
||||
getrandom = { version = "0.2", features = ["custom"] }
|
||||
|
||||
[build-dependencies]
|
||||
anyhow.workspace = true
|
||||
substreams-ethereum.workspace = true
|
||||
2
substreams/ethereum-uniswap-v3-logs-only/Makefile
Normal file
2
substreams/ethereum-uniswap-v3-logs-only/Makefile
Normal file
@@ -0,0 +1,2 @@
|
||||
build:
|
||||
cargo build --target wasm32-unknown-unknown --profile substreams
|
||||
198
substreams/ethereum-uniswap-v3-logs-only/abi/Factory.json
Normal file
198
substreams/ethereum-uniswap-v3-logs-only/abi/Factory.json
Normal file
@@ -0,0 +1,198 @@
|
||||
[
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "uint24",
|
||||
"name": "fee",
|
||||
"type": "uint24"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "int24",
|
||||
"name": "tickSpacing",
|
||||
"type": "int24"
|
||||
}
|
||||
],
|
||||
"name": "FeeAmountEnabled",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "oldOwner",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "newOwner",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "OwnerChanged",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "token0",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "token1",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "uint24",
|
||||
"name": "fee",
|
||||
"type": "uint24"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "int24",
|
||||
"name": "tickSpacing",
|
||||
"type": "int24"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "address",
|
||||
"name": "pool",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "PoolCreated",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "tokenA",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "tokenB",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint24",
|
||||
"name": "fee",
|
||||
"type": "uint24"
|
||||
}
|
||||
],
|
||||
"name": "createPool",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "pool",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint24",
|
||||
"name": "fee",
|
||||
"type": "uint24"
|
||||
},
|
||||
{
|
||||
"internalType": "int24",
|
||||
"name": "tickSpacing",
|
||||
"type": "int24"
|
||||
}
|
||||
],
|
||||
"name": "enableFeeAmount",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint24",
|
||||
"name": "fee",
|
||||
"type": "uint24"
|
||||
}
|
||||
],
|
||||
"name": "feeAmountTickSpacing",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "int24",
|
||||
"name": "",
|
||||
"type": "int24"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "tokenA",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "tokenB",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint24",
|
||||
"name": "fee",
|
||||
"type": "uint24"
|
||||
}
|
||||
],
|
||||
"name": "getPool",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "pool",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "owner",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_owner",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "setOwner",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
}
|
||||
]
|
||||
988
substreams/ethereum-uniswap-v3-logs-only/abi/Pool.json
Normal file
988
substreams/ethereum-uniswap-v3-logs-only/abi/Pool.json
Normal file
@@ -0,0 +1,988 @@
|
||||
[
|
||||
{
|
||||
"inputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "constructor"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "owner",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "int24",
|
||||
"name": "tickLower",
|
||||
"type": "int24"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "int24",
|
||||
"name": "tickUpper",
|
||||
"type": "int24"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint128",
|
||||
"name": "amount",
|
||||
"type": "uint128"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "amount0",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "amount1",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "Burn",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "owner",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "address",
|
||||
"name": "recipient",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "int24",
|
||||
"name": "tickLower",
|
||||
"type": "int24"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "int24",
|
||||
"name": "tickUpper",
|
||||
"type": "int24"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint128",
|
||||
"name": "amount0",
|
||||
"type": "uint128"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint128",
|
||||
"name": "amount1",
|
||||
"type": "uint128"
|
||||
}
|
||||
],
|
||||
"name": "Collect",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "sender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "recipient",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint128",
|
||||
"name": "amount0",
|
||||
"type": "uint128"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint128",
|
||||
"name": "amount1",
|
||||
"type": "uint128"
|
||||
}
|
||||
],
|
||||
"name": "CollectProtocol",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "sender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "recipient",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "amount0",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "amount1",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "paid0",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "paid1",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "Flash",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint16",
|
||||
"name": "observationCardinalityNextOld",
|
||||
"type": "uint16"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint16",
|
||||
"name": "observationCardinalityNextNew",
|
||||
"type": "uint16"
|
||||
}
|
||||
],
|
||||
"name": "IncreaseObservationCardinalityNext",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint160",
|
||||
"name": "sqrtPriceX96",
|
||||
"type": "uint160"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "int24",
|
||||
"name": "tick",
|
||||
"type": "int24"
|
||||
}
|
||||
],
|
||||
"name": "Initialize",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "address",
|
||||
"name": "sender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "owner",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "int24",
|
||||
"name": "tickLower",
|
||||
"type": "int24"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "int24",
|
||||
"name": "tickUpper",
|
||||
"type": "int24"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint128",
|
||||
"name": "amount",
|
||||
"type": "uint128"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "amount0",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "amount1",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "Mint",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint8",
|
||||
"name": "feeProtocol0Old",
|
||||
"type": "uint8"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint8",
|
||||
"name": "feeProtocol1Old",
|
||||
"type": "uint8"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint8",
|
||||
"name": "feeProtocol0New",
|
||||
"type": "uint8"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint8",
|
||||
"name": "feeProtocol1New",
|
||||
"type": "uint8"
|
||||
}
|
||||
],
|
||||
"name": "SetFeeProtocol",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "sender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "recipient",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "int256",
|
||||
"name": "amount0",
|
||||
"type": "int256"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "int256",
|
||||
"name": "amount1",
|
||||
"type": "int256"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint160",
|
||||
"name": "sqrtPriceX96",
|
||||
"type": "uint160"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint128",
|
||||
"name": "liquidity",
|
||||
"type": "uint128"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "int24",
|
||||
"name": "tick",
|
||||
"type": "int24"
|
||||
}
|
||||
],
|
||||
"name": "Swap",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "int24",
|
||||
"name": "tickLower",
|
||||
"type": "int24"
|
||||
},
|
||||
{
|
||||
"internalType": "int24",
|
||||
"name": "tickUpper",
|
||||
"type": "int24"
|
||||
},
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "amount",
|
||||
"type": "uint128"
|
||||
}
|
||||
],
|
||||
"name": "burn",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amount0",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amount1",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "recipient",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "int24",
|
||||
"name": "tickLower",
|
||||
"type": "int24"
|
||||
},
|
||||
{
|
||||
"internalType": "int24",
|
||||
"name": "tickUpper",
|
||||
"type": "int24"
|
||||
},
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "amount0Requested",
|
||||
"type": "uint128"
|
||||
},
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "amount1Requested",
|
||||
"type": "uint128"
|
||||
}
|
||||
],
|
||||
"name": "collect",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "amount0",
|
||||
"type": "uint128"
|
||||
},
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "amount1",
|
||||
"type": "uint128"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "recipient",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "amount0Requested",
|
||||
"type": "uint128"
|
||||
},
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "amount1Requested",
|
||||
"type": "uint128"
|
||||
}
|
||||
],
|
||||
"name": "collectProtocol",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "amount0",
|
||||
"type": "uint128"
|
||||
},
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "amount1",
|
||||
"type": "uint128"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "factory",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "fee",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint24",
|
||||
"name": "",
|
||||
"type": "uint24"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "feeGrowthGlobal0X128",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "feeGrowthGlobal1X128",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "recipient",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amount0",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amount1",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "bytes",
|
||||
"name": "data",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"name": "flash",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint16",
|
||||
"name": "observationCardinalityNext",
|
||||
"type": "uint16"
|
||||
}
|
||||
],
|
||||
"name": "increaseObservationCardinalityNext",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint160",
|
||||
"name": "sqrtPriceX96",
|
||||
"type": "uint160"
|
||||
}
|
||||
],
|
||||
"name": "initialize",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "liquidity",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "",
|
||||
"type": "uint128"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "maxLiquidityPerTick",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "",
|
||||
"type": "uint128"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "recipient",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "int24",
|
||||
"name": "tickLower",
|
||||
"type": "int24"
|
||||
},
|
||||
{
|
||||
"internalType": "int24",
|
||||
"name": "tickUpper",
|
||||
"type": "int24"
|
||||
},
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "amount",
|
||||
"type": "uint128"
|
||||
},
|
||||
{
|
||||
"internalType": "bytes",
|
||||
"name": "data",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"name": "mint",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amount0",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amount1",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "index",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "observations",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint32",
|
||||
"name": "blockTimestamp",
|
||||
"type": "uint32"
|
||||
},
|
||||
{
|
||||
"internalType": "int56",
|
||||
"name": "tickCumulative",
|
||||
"type": "int56"
|
||||
},
|
||||
{
|
||||
"internalType": "uint160",
|
||||
"name": "secondsPerLiquidityCumulativeX128",
|
||||
"type": "uint160"
|
||||
},
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "initialized",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint32[]",
|
||||
"name": "secondsAgos",
|
||||
"type": "uint32[]"
|
||||
}
|
||||
],
|
||||
"name": "observe",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "int56[]",
|
||||
"name": "tickCumulatives",
|
||||
"type": "int56[]"
|
||||
},
|
||||
{
|
||||
"internalType": "uint160[]",
|
||||
"name": "secondsPerLiquidityCumulativeX128s",
|
||||
"type": "uint160[]"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "bytes32",
|
||||
"name": "key",
|
||||
"type": "bytes32"
|
||||
}
|
||||
],
|
||||
"name": "positions",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "_liquidity",
|
||||
"type": "uint128"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "feeGrowthInside0LastX128",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "feeGrowthInside1LastX128",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "tokensOwed0",
|
||||
"type": "uint128"
|
||||
},
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "tokensOwed1",
|
||||
"type": "uint128"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "protocolFees",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "token0",
|
||||
"type": "uint128"
|
||||
},
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "token1",
|
||||
"type": "uint128"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint8",
|
||||
"name": "feeProtocol0",
|
||||
"type": "uint8"
|
||||
},
|
||||
{
|
||||
"internalType": "uint8",
|
||||
"name": "feeProtocol1",
|
||||
"type": "uint8"
|
||||
}
|
||||
],
|
||||
"name": "setFeeProtocol",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "slot0",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint160",
|
||||
"name": "sqrtPriceX96",
|
||||
"type": "uint160"
|
||||
},
|
||||
{
|
||||
"internalType": "int24",
|
||||
"name": "tick",
|
||||
"type": "int24"
|
||||
},
|
||||
{
|
||||
"internalType": "uint16",
|
||||
"name": "observationIndex",
|
||||
"type": "uint16"
|
||||
},
|
||||
{
|
||||
"internalType": "uint16",
|
||||
"name": "observationCardinality",
|
||||
"type": "uint16"
|
||||
},
|
||||
{
|
||||
"internalType": "uint16",
|
||||
"name": "observationCardinalityNext",
|
||||
"type": "uint16"
|
||||
},
|
||||
{
|
||||
"internalType": "uint8",
|
||||
"name": "feeProtocol",
|
||||
"type": "uint8"
|
||||
},
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "unlocked",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "int24",
|
||||
"name": "tickLower",
|
||||
"type": "int24"
|
||||
},
|
||||
{
|
||||
"internalType": "int24",
|
||||
"name": "tickUpper",
|
||||
"type": "int24"
|
||||
}
|
||||
],
|
||||
"name": "snapshotCumulativesInside",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "int56",
|
||||
"name": "tickCumulativeInside",
|
||||
"type": "int56"
|
||||
},
|
||||
{
|
||||
"internalType": "uint160",
|
||||
"name": "secondsPerLiquidityInsideX128",
|
||||
"type": "uint160"
|
||||
},
|
||||
{
|
||||
"internalType": "uint32",
|
||||
"name": "secondsInside",
|
||||
"type": "uint32"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "recipient",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "zeroForOne",
|
||||
"type": "bool"
|
||||
},
|
||||
{
|
||||
"internalType": "int256",
|
||||
"name": "amountSpecified",
|
||||
"type": "int256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint160",
|
||||
"name": "sqrtPriceLimitX96",
|
||||
"type": "uint160"
|
||||
},
|
||||
{
|
||||
"internalType": "bytes",
|
||||
"name": "data",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"name": "swap",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "int256",
|
||||
"name": "amount0",
|
||||
"type": "int256"
|
||||
},
|
||||
{
|
||||
"internalType": "int256",
|
||||
"name": "amount1",
|
||||
"type": "int256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "int16",
|
||||
"name": "wordPosition",
|
||||
"type": "int16"
|
||||
}
|
||||
],
|
||||
"name": "tickBitmap",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "tickSpacing",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "int24",
|
||||
"name": "",
|
||||
"type": "int24"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "int24",
|
||||
"name": "tick",
|
||||
"type": "int24"
|
||||
}
|
||||
],
|
||||
"name": "ticks",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "liquidityGross",
|
||||
"type": "uint128"
|
||||
},
|
||||
{
|
||||
"internalType": "int128",
|
||||
"name": "liquidityNet",
|
||||
"type": "int128"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "feeGrowthOutside0X128",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "feeGrowthOutside1X128",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "int56",
|
||||
"name": "tickCumulativeOutside",
|
||||
"type": "int56"
|
||||
},
|
||||
{
|
||||
"internalType": "uint160",
|
||||
"name": "secondsPerLiquidityOutsideX128",
|
||||
"type": "uint160"
|
||||
},
|
||||
{
|
||||
"internalType": "uint32",
|
||||
"name": "secondsOutside",
|
||||
"type": "uint32"
|
||||
},
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "initialized",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "token0",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "token1",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
}
|
||||
]
|
||||
12
substreams/ethereum-uniswap-v3-logs-only/buf.gen.yaml
Normal file
12
substreams/ethereum-uniswap-v3-logs-only/buf.gen.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
version: v1
|
||||
plugins:
|
||||
- plugin: buf.build/community/neoeinstein-prost:v0.2.2
|
||||
out: src/pb
|
||||
opt:
|
||||
- file_descriptor_set=false
|
||||
|
||||
- plugin: buf.build/community/neoeinstein-prost-crate:v0.3.1
|
||||
out: src/pb
|
||||
opt:
|
||||
- no_features
|
||||
12
substreams/ethereum-uniswap-v3-logs-only/build.rs
Normal file
12
substreams/ethereum-uniswap-v3-logs-only/build.rs
Normal file
@@ -0,0 +1,12 @@
|
||||
use anyhow::{Ok, Result};
|
||||
use substreams_ethereum::Abigen;
|
||||
|
||||
fn main() -> Result<(), anyhow::Error> {
|
||||
Abigen::new("Factory", "abi/Factory.json")?
|
||||
.generate()?
|
||||
.write_to_file("src/abi/factory.rs")?;
|
||||
Abigen::new("Pool", "abi/Pool.json")?
|
||||
.generate()?
|
||||
.write_to_file("src/abi/pool.rs")?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
specVersion: v0.1.0
|
||||
package:
|
||||
name: "ethereum_uniswap_v3_logs_only"
|
||||
version: v0.1.0
|
||||
|
||||
protobuf:
|
||||
files:
|
||||
- tycho/evm/v1/entity.proto
|
||||
- tycho/evm/v1/common.proto
|
||||
- tycho/evm/v1/utils.proto
|
||||
- uniswap.proto
|
||||
importPaths:
|
||||
- ./proto/v1
|
||||
- ../../proto/
|
||||
|
||||
binaries:
|
||||
default:
|
||||
type: wasm/rust-v1
|
||||
file: ../target/wasm32-unknown-unknown/release/ethereum_uniswap_v3_logs_only.wasm
|
||||
|
||||
modules:
|
||||
- name: map_pools_created
|
||||
kind: map
|
||||
initialBlock: 12369621
|
||||
inputs:
|
||||
- params: string
|
||||
- source: sf.ethereum.type.v2.Block
|
||||
output:
|
||||
type: proto:tycho.evm.v1.BlockEntityChanges
|
||||
|
||||
- name: store_pools
|
||||
kind: store
|
||||
initialBlock: 12369621
|
||||
updatePolicy: set_if_not_exists
|
||||
valueType: proto:uniswap.v3.Pool
|
||||
inputs:
|
||||
- map: map_pools_created
|
||||
|
||||
- name: map_events
|
||||
kind: map
|
||||
initialBlock: 12369621
|
||||
inputs:
|
||||
- source: sf.ethereum.type.v2.Block
|
||||
- store: store_pools
|
||||
output:
|
||||
type: proto:uniswap.v3.Events
|
||||
|
||||
- name: map_balance_changes
|
||||
kind: map
|
||||
initialBlock: 12369621
|
||||
inputs:
|
||||
- map: map_events
|
||||
output:
|
||||
type: proto:tycho.evm.v1.BlockBalanceDeltas
|
||||
|
||||
- name: store_pools_balances
|
||||
kind: store
|
||||
initialBlock: 12369621
|
||||
updatePolicy: add
|
||||
valueType: bigint
|
||||
inputs:
|
||||
- map: map_balance_changes
|
||||
|
||||
- name: map_ticks_changes
|
||||
kind: map
|
||||
initialBlock: 12369621
|
||||
inputs:
|
||||
- map: map_events
|
||||
output:
|
||||
type: proto:uniswap.v3.TickDeltas
|
||||
|
||||
- name: store_ticks_liquidity
|
||||
kind: store
|
||||
initialBlock: 12369621
|
||||
updatePolicy: add
|
||||
valueType: bigint
|
||||
inputs:
|
||||
- map: map_ticks_changes
|
||||
|
||||
- name: store_pool_current_tick
|
||||
kind: store
|
||||
initialBlock: 12369621
|
||||
updatePolicy: set
|
||||
valueType: int64
|
||||
inputs:
|
||||
- map: map_events
|
||||
|
||||
- name: map_liquidity_changes
|
||||
kind: map
|
||||
initialBlock: 12369621
|
||||
inputs:
|
||||
- map: map_events
|
||||
- store: store_pool_current_tick
|
||||
output:
|
||||
type: proto:uniswap.v3.LiquidityChanges
|
||||
|
||||
- name: store_liquidity
|
||||
kind: store
|
||||
initialBlock: 12369621
|
||||
updatePolicy: set_sum
|
||||
valueType: bigint
|
||||
inputs:
|
||||
- map: map_liquidity_changes
|
||||
|
||||
- name: map_protocol_changes
|
||||
kind: map
|
||||
initialBlock: 12369621
|
||||
inputs:
|
||||
- source: sf.ethereum.type.v2.Block
|
||||
- map: map_pools_created
|
||||
- map: map_events
|
||||
- map: map_balance_changes
|
||||
- store: store_pools_balances
|
||||
mode: deltas
|
||||
- map: map_ticks_changes
|
||||
- store: store_ticks_liquidity
|
||||
mode: deltas
|
||||
- map: map_liquidity_changes
|
||||
- store: store_liquidity
|
||||
mode: deltas
|
||||
output:
|
||||
type: proto:tycho.evm.v1.BlockChanges
|
||||
|
||||
params:
|
||||
map_pools_created: "1F98431c8aD98523631AE4a59f267346ea31F984"
|
||||
177
substreams/ethereum-uniswap-v3-logs-only/proto/v1/uniswap.proto
Normal file
177
substreams/ethereum-uniswap-v3-logs-only/proto/v1/uniswap.proto
Normal file
@@ -0,0 +1,177 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package uniswap.v3;
|
||||
|
||||
message Pool {
|
||||
bytes address = 1;
|
||||
bytes token0 = 2;
|
||||
bytes token1 = 3;
|
||||
bytes created_tx_hash = 4;
|
||||
}
|
||||
|
||||
// A struct describing a transaction.
|
||||
message Transaction {
|
||||
// The transaction hash.
|
||||
bytes hash = 1;
|
||||
// The sender of the transaction.
|
||||
bytes from = 2;
|
||||
// The receiver of the transaction.
|
||||
bytes to = 3;
|
||||
// The transactions index within the block.
|
||||
uint64 index = 4;
|
||||
}
|
||||
|
||||
// A change to a pool's tick.
|
||||
message TickDelta {
|
||||
// The address of the pool.
|
||||
bytes pool_address = 1;
|
||||
// The index of the tick.
|
||||
int32 tick_index = 2;
|
||||
// The liquidity net delta of this tick. Bigint encoded as signed little endian bytes.
|
||||
bytes liquidity_net_delta = 3;
|
||||
// Used to determine the order of the balance changes. Necessary for the balance store.
|
||||
uint64 ordinal = 4;
|
||||
Transaction transaction = 5;
|
||||
}
|
||||
|
||||
// A group of TickDelta
|
||||
message TickDeltas {
|
||||
repeated TickDelta deltas = 1;
|
||||
}
|
||||
|
||||
// A change to a pool's liquidity.
|
||||
message LiquidityChange {
|
||||
// The address of the pool.
|
||||
bytes pool_address = 1;
|
||||
// The liquidity changed amount. Bigint encoded as signed little endian bytes.
|
||||
bytes value = 2;
|
||||
// The type of update, can be absolute or delta.
|
||||
LiquidityChangeType change_type = 3;
|
||||
// Used to determine the order of the balance changes. Necessary for the balance store.
|
||||
uint64 ordinal = 4;
|
||||
Transaction transaction = 5;
|
||||
}
|
||||
|
||||
// A group of LiquidityChange
|
||||
message LiquidityChanges {
|
||||
repeated LiquidityChange changes = 1;
|
||||
}
|
||||
|
||||
|
||||
enum LiquidityChangeType {
|
||||
DELTA = 0;
|
||||
ABSOLUTE = 1;
|
||||
}
|
||||
|
||||
message Events {
|
||||
repeated PoolEvent pool_events = 3;
|
||||
|
||||
message PoolEvent {
|
||||
oneof type {
|
||||
Initialize initialize = 1;
|
||||
Mint mint = 2;
|
||||
Collect collect = 3;
|
||||
Burn burn = 4;
|
||||
Swap swap = 5;
|
||||
Flash flash = 6;
|
||||
SetFeeProtocol set_fee_protocol = 7;
|
||||
CollectProtocol collect_protocol = 8;
|
||||
}
|
||||
uint64 log_ordinal = 100;
|
||||
string pool_address = 102;
|
||||
string token0 = 103;
|
||||
string token1 = 104;
|
||||
Transaction transaction = 105;
|
||||
|
||||
message Initialize {
|
||||
// Unsigned
|
||||
string sqrt_price = 1;
|
||||
int32 tick = 2;
|
||||
}
|
||||
|
||||
message Mint {
|
||||
string sender = 1;
|
||||
string owner = 2;
|
||||
// Signed
|
||||
int32 tick_lower = 3;
|
||||
// Signed
|
||||
int32 tick_upper = 4;
|
||||
// Unsigned
|
||||
string amount = 5;
|
||||
// Unsigned
|
||||
string amount_0 = 6;
|
||||
// Unsigned
|
||||
string amount_1 = 7;
|
||||
}
|
||||
|
||||
message Collect {
|
||||
string owner = 1;
|
||||
string recipient = 2;
|
||||
int32 tick_lower = 3;
|
||||
int32 tick_upper = 4;
|
||||
// Unsigned
|
||||
string amount_0 = 5;
|
||||
// Unsigned
|
||||
string amount_1 = 6;
|
||||
}
|
||||
|
||||
message Burn {
|
||||
string owner = 1;
|
||||
int32 tick_lower = 2;
|
||||
int32 tick_upper = 3;
|
||||
// Unsigned
|
||||
string amount = 4;
|
||||
// Unsigned
|
||||
string amount_0 = 5;
|
||||
// Unsigned
|
||||
string amount_1 = 6;
|
||||
}
|
||||
|
||||
message Swap {
|
||||
string sender = 1;
|
||||
string recipient = 2;
|
||||
// Signed
|
||||
string amount_0 = 3;
|
||||
// Signed
|
||||
string amount_1 = 4;
|
||||
// Unsigned
|
||||
string sqrt_price = 6;
|
||||
// Unsigned
|
||||
string liquidity = 7;
|
||||
int32 tick = 8;
|
||||
}
|
||||
|
||||
message Flash {
|
||||
string sender = 1;
|
||||
string recipient = 2;
|
||||
// Unsigned
|
||||
string amount_0 = 3;
|
||||
// Unsigned
|
||||
string amount_1 = 4;
|
||||
// Unsigned
|
||||
string paid_0 = 5;
|
||||
// Unsigned
|
||||
string paid_1 = 6;
|
||||
}
|
||||
|
||||
message SetFeeProtocol {
|
||||
// Unsigned
|
||||
uint64 fee_protocol_0_old = 1;
|
||||
// Unsigned
|
||||
uint64 fee_protocol_1_old = 2;
|
||||
// Unsigned
|
||||
uint64 fee_protocol_0_new = 3;
|
||||
// Unsigned
|
||||
uint64 fee_protocol_1_new = 4;
|
||||
}
|
||||
|
||||
message CollectProtocol {
|
||||
string sender = 1;
|
||||
string recipient = 2;
|
||||
// Unsigned
|
||||
string amount_0 = 3;
|
||||
// Unsigned
|
||||
string amount_1 = 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
1040
substreams/ethereum-uniswap-v3-logs-only/src/abi/factory.rs
Normal file
1040
substreams/ethereum-uniswap-v3-logs-only/src/abi/factory.rs
Normal file
File diff suppressed because it is too large
Load Diff
4
substreams/ethereum-uniswap-v3-logs-only/src/abi/mod.rs
Normal file
4
substreams/ethereum-uniswap-v3-logs-only/src/abi/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
#![allow(clippy::all, clippy::pedantic, clippy::nursery)]
|
||||
|
||||
pub mod factory;
|
||||
pub mod pool;
|
||||
5153
substreams/ethereum-uniswap-v3-logs-only/src/abi/pool.rs
Normal file
5153
substreams/ethereum-uniswap-v3-logs-only/src/abi/pool.rs
Normal file
File diff suppressed because it is too large
Load Diff
7
substreams/ethereum-uniswap-v3-logs-only/src/lib.rs
Normal file
7
substreams/ethereum-uniswap-v3-logs-only/src/lib.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
#![allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
|
||||
mod abi;
|
||||
mod modules;
|
||||
mod pb;
|
||||
|
||||
pub use modules::*;
|
||||
@@ -0,0 +1,114 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use ethabi::ethereum_types::Address;
|
||||
use substreams::scalar::BigInt;
|
||||
use substreams_ethereum::pb::eth::v2::{self as eth};
|
||||
|
||||
use substreams_helper::{event_handler::EventHandler, hex::Hexable};
|
||||
|
||||
use crate::abi::factory::events::PoolCreated;
|
||||
|
||||
use tycho_substreams::prelude::*;
|
||||
|
||||
#[substreams::handlers::map]
|
||||
pub fn map_pools_created(
|
||||
params: String,
|
||||
block: eth::Block,
|
||||
) -> Result<BlockEntityChanges, substreams::errors::Error> {
|
||||
let mut new_pools: Vec<TransactionEntityChanges> = vec![];
|
||||
let factory_address = params.as_str();
|
||||
|
||||
get_new_pools(&block, &mut new_pools, factory_address);
|
||||
|
||||
Ok(BlockEntityChanges { block: None, changes: new_pools })
|
||||
}
|
||||
|
||||
// Extract new pools from PoolCreated events
|
||||
fn get_new_pools(
|
||||
block: ð::Block,
|
||||
new_pools: &mut Vec<TransactionEntityChanges>,
|
||||
factory_address: &str,
|
||||
) {
|
||||
// Extract new pools from PoolCreated events
|
||||
let mut on_pool_created = |event: PoolCreated, _tx: ð::TransactionTrace, _log: ð::Log| {
|
||||
let tycho_tx: Transaction = _tx.into();
|
||||
|
||||
new_pools.push(TransactionEntityChanges {
|
||||
tx: Some(tycho_tx.clone()),
|
||||
entity_changes: vec![EntityChanges {
|
||||
component_id: event.pool.clone().to_hex(),
|
||||
attributes: vec![
|
||||
Attribute {
|
||||
name: "liquidity".to_string(),
|
||||
value: BigInt::from(0).to_signed_bytes_be(),
|
||||
change: ChangeType::Creation.into(),
|
||||
},
|
||||
Attribute {
|
||||
name: "tick".to_string(),
|
||||
value: BigInt::from(0).to_signed_bytes_be(),
|
||||
change: ChangeType::Creation.into(),
|
||||
},
|
||||
Attribute {
|
||||
name: "sqrt_price_x96".to_string(),
|
||||
value: BigInt::from(0).to_signed_bytes_be(),
|
||||
change: ChangeType::Creation.into(),
|
||||
},
|
||||
],
|
||||
}],
|
||||
component_changes: vec![ProtocolComponent {
|
||||
id: event.pool.to_hex(),
|
||||
tokens: vec![event.token0.clone(), event.token1.clone()],
|
||||
contracts: vec![],
|
||||
static_att: vec![
|
||||
Attribute {
|
||||
name: "fee".to_string(),
|
||||
value: event.fee.to_signed_bytes_be(),
|
||||
change: ChangeType::Creation.into(),
|
||||
},
|
||||
Attribute {
|
||||
name: "tick_spacing".to_string(),
|
||||
value: event.tick_spacing.to_signed_bytes_be(),
|
||||
change: ChangeType::Creation.into(),
|
||||
},
|
||||
Attribute {
|
||||
name: "pool_address".to_string(),
|
||||
value: event.pool.clone(),
|
||||
change: ChangeType::Creation.into(),
|
||||
},
|
||||
],
|
||||
change: i32::from(ChangeType::Creation),
|
||||
protocol_type: Option::from(ProtocolType {
|
||||
name: "uniswap_v3_pool".to_string(),
|
||||
financial_type: FinancialType::Swap.into(),
|
||||
attribute_schema: vec![],
|
||||
implementation_type: ImplementationType::Custom.into(),
|
||||
}),
|
||||
tx: Some(tycho_tx),
|
||||
}],
|
||||
balance_changes: vec![
|
||||
BalanceChange {
|
||||
token: event.token0,
|
||||
balance: BigInt::from(0).to_signed_bytes_be(),
|
||||
component_id: event
|
||||
.pool
|
||||
.clone()
|
||||
.to_hex()
|
||||
.as_bytes()
|
||||
.to_vec(),
|
||||
},
|
||||
BalanceChange {
|
||||
token: event.token1,
|
||||
balance: BigInt::from(0).to_signed_bytes_be(),
|
||||
component_id: event.pool.to_hex().as_bytes().to_vec(),
|
||||
},
|
||||
],
|
||||
})
|
||||
};
|
||||
|
||||
let mut eh = EventHandler::new(block);
|
||||
|
||||
eh.filter_by_address(vec![Address::from_str(factory_address).unwrap()]);
|
||||
|
||||
eh.on::<PoolCreated, _>(&mut on_pool_created);
|
||||
eh.handle_events();
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
use std::str;
|
||||
|
||||
use substreams::store::{StoreNew, StoreSetIfNotExists, StoreSetIfNotExistsProto};
|
||||
use tycho_substreams::models::BlockEntityChanges;
|
||||
|
||||
use crate::pb::uniswap::v3::Pool;
|
||||
|
||||
#[substreams::handlers::store]
|
||||
pub fn store_pools(pools_created: BlockEntityChanges, store: StoreSetIfNotExistsProto<Pool>) {
|
||||
// Store pools. Required so the next maps can match any event to a known pool by their address
|
||||
|
||||
for change in pools_created.changes {
|
||||
for component_change in &change.component_changes {
|
||||
let pool_address: &str = &component_change.id;
|
||||
let pool: Pool = Pool {
|
||||
address: hex::decode(pool_address.trim_start_matches("0x")).unwrap(),
|
||||
token0: component_change.tokens[0].clone(),
|
||||
token1: component_change.tokens[1].clone(),
|
||||
created_tx_hash: change.tx.as_ref().unwrap().hash.clone(),
|
||||
};
|
||||
store.set_if_not_exists(0, format!("{}:{}", "Pool", pool_address), &pool);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
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::uniswap::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| {
|
||||
tx.clone()
|
||||
.receipt
|
||||
.into_iter()
|
||||
.flat_map(|receipt| receipt.logs)
|
||||
.filter_map(|log| {
|
||||
let key = format!("{}:{}", "Pool", log.address.to_hex());
|
||||
// Skip if the log is not from a known uniswapV3 pool.
|
||||
if let Some(pool) = pools_store.get_last(key) {
|
||||
log_to_event(&log, pool, tx.clone())
|
||||
} 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(),
|
||||
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(),
|
||||
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(),
|
||||
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(),
|
||||
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(),
|
||||
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(),
|
||||
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(),
|
||||
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(),
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use anyhow::Ok;
|
||||
use tycho_substreams::models::{BalanceDelta, BlockBalanceDeltas};
|
||||
|
||||
use crate::pb::uniswap::v3::{
|
||||
events::{pool_event, PoolEvent},
|
||||
Events,
|
||||
};
|
||||
use substreams::{
|
||||
scalar::BigInt,
|
||||
store::{StoreAddBigInt, StoreNew},
|
||||
};
|
||||
|
||||
#[substreams::handlers::map]
|
||||
pub fn map_balance_changes(events: Events) -> Result<BlockBalanceDeltas, anyhow::Error> {
|
||||
let balance_deltas = events
|
||||
.pool_events
|
||||
.into_iter()
|
||||
.flat_map(event_to_balance_deltas)
|
||||
.collect();
|
||||
|
||||
Ok(BlockBalanceDeltas { balance_deltas })
|
||||
}
|
||||
|
||||
#[substreams::handlers::store]
|
||||
pub fn store_pools_balances(balances_deltas: BlockBalanceDeltas, store: StoreAddBigInt) {
|
||||
tycho_substreams::balances::store_balance_changes(balances_deltas, store);
|
||||
}
|
||||
|
||||
fn event_to_balance_deltas(event: PoolEvent) -> Vec<BalanceDelta> {
|
||||
let address = format!("0x{}", event.pool_address)
|
||||
.as_bytes()
|
||||
.to_vec();
|
||||
match event.r#type.unwrap() {
|
||||
pool_event::Type::Mint(e) => vec![
|
||||
BalanceDelta {
|
||||
token: hex::decode(event.token0.clone()).unwrap(),
|
||||
delta: BigInt::from_str(&e.amount_0)
|
||||
.unwrap()
|
||||
.to_signed_bytes_be(),
|
||||
component_id: address.clone(),
|
||||
ord: event.log_ordinal,
|
||||
tx: event
|
||||
.transaction
|
||||
.clone()
|
||||
.map(Into::into),
|
||||
},
|
||||
BalanceDelta {
|
||||
token: hex::decode(event.token1.clone()).unwrap(),
|
||||
delta: BigInt::from_str(&e.amount_1)
|
||||
.unwrap()
|
||||
.to_signed_bytes_be(),
|
||||
component_id: address,
|
||||
ord: event.log_ordinal,
|
||||
tx: event.transaction.map(Into::into),
|
||||
},
|
||||
],
|
||||
pool_event::Type::Collect(e) => vec![
|
||||
BalanceDelta {
|
||||
token: hex::decode(event.token0.clone()).unwrap(),
|
||||
delta: BigInt::from_str(&e.amount_0)
|
||||
.unwrap()
|
||||
.neg()
|
||||
.to_signed_bytes_be(),
|
||||
component_id: address.clone(),
|
||||
ord: event.log_ordinal,
|
||||
tx: event
|
||||
.transaction
|
||||
.clone()
|
||||
.map(Into::into),
|
||||
},
|
||||
BalanceDelta {
|
||||
token: hex::decode(event.token1.clone()).unwrap(),
|
||||
delta: BigInt::from_str(&e.amount_1)
|
||||
.unwrap()
|
||||
.neg()
|
||||
.to_signed_bytes_be(),
|
||||
component_id: address,
|
||||
ord: event.log_ordinal,
|
||||
tx: event.transaction.map(Into::into),
|
||||
},
|
||||
],
|
||||
//Burn balance changes are accounted for in the Collect event.
|
||||
pool_event::Type::Burn(_) => vec![],
|
||||
pool_event::Type::Swap(e) => {
|
||||
vec![
|
||||
BalanceDelta {
|
||||
token: hex::decode(event.token0.clone()).unwrap(),
|
||||
delta: BigInt::from_str(&e.amount_0)
|
||||
.unwrap()
|
||||
.to_signed_bytes_be(),
|
||||
component_id: address.clone(),
|
||||
ord: event.log_ordinal,
|
||||
tx: event
|
||||
.transaction
|
||||
.clone()
|
||||
.map(Into::into),
|
||||
},
|
||||
BalanceDelta {
|
||||
token: hex::decode(event.token1.clone()).unwrap(),
|
||||
delta: BigInt::from_str(&e.amount_1)
|
||||
.unwrap()
|
||||
.to_signed_bytes_be(),
|
||||
component_id: address.clone(),
|
||||
ord: event.log_ordinal,
|
||||
tx: event.transaction.map(Into::into),
|
||||
},
|
||||
]
|
||||
}
|
||||
pool_event::Type::Flash(e) => vec![
|
||||
BalanceDelta {
|
||||
token: hex::decode(event.token0).unwrap(),
|
||||
delta: BigInt::from_str(&e.paid_0)
|
||||
.unwrap()
|
||||
.clone()
|
||||
.to_signed_bytes_be(),
|
||||
component_id: address.clone(),
|
||||
ord: event.log_ordinal,
|
||||
tx: event
|
||||
.transaction
|
||||
.clone()
|
||||
.map(Into::into),
|
||||
},
|
||||
BalanceDelta {
|
||||
token: hex::decode(event.token1).unwrap(),
|
||||
delta: BigInt::from_str(&e.paid_1)
|
||||
.unwrap()
|
||||
.clone()
|
||||
.to_signed_bytes_be(),
|
||||
component_id: address,
|
||||
ord: event.log_ordinal,
|
||||
tx: event.transaction.map(Into::into),
|
||||
},
|
||||
],
|
||||
pool_event::Type::CollectProtocol(e) => {
|
||||
vec![
|
||||
BalanceDelta {
|
||||
token: hex::decode(event.token0).unwrap(),
|
||||
delta: BigInt::from_str(&e.amount_0)
|
||||
.unwrap()
|
||||
.neg()
|
||||
.clone()
|
||||
.to_signed_bytes_be(),
|
||||
component_id: event
|
||||
.pool_address
|
||||
.clone()
|
||||
.as_bytes()
|
||||
.to_vec(),
|
||||
ord: event.log_ordinal,
|
||||
tx: event
|
||||
.transaction
|
||||
.clone()
|
||||
.map(Into::into),
|
||||
},
|
||||
BalanceDelta {
|
||||
token: hex::decode(event.token1).unwrap(),
|
||||
delta: BigInt::from_str(&e.amount_1)
|
||||
.unwrap()
|
||||
.clone()
|
||||
.neg()
|
||||
.to_signed_bytes_be(),
|
||||
component_id: event
|
||||
.pool_address
|
||||
.clone()
|
||||
.as_bytes()
|
||||
.to_vec(),
|
||||
ord: event.log_ordinal,
|
||||
tx: event.transaction.map(Into::into),
|
||||
},
|
||||
]
|
||||
}
|
||||
_ => vec![],
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use substreams::store::{
|
||||
StoreGet, StoreGetInt64, StoreSet, StoreSetInt64, StoreSetSum, StoreSetSumBigInt,
|
||||
};
|
||||
|
||||
use crate::pb::uniswap::v3::{
|
||||
events::{pool_event, PoolEvent},
|
||||
Events, LiquidityChange, LiquidityChangeType, LiquidityChanges,
|
||||
};
|
||||
|
||||
use substreams::{scalar::BigInt, store::StoreNew};
|
||||
|
||||
use anyhow::Ok;
|
||||
|
||||
#[substreams::handlers::store]
|
||||
pub fn store_pool_current_tick(events: Events, store: StoreSetInt64) {
|
||||
events
|
||||
.pool_events
|
||||
.into_iter()
|
||||
.filter_map(event_to_current_tick)
|
||||
.for_each(|(pool, ordinal, new_tick_index)| {
|
||||
store.set(ordinal, format!("pool:{0}", pool), &new_tick_index.into())
|
||||
});
|
||||
}
|
||||
|
||||
#[substreams::handlers::map]
|
||||
pub fn map_liquidity_changes(
|
||||
events: Events,
|
||||
pools_current_tick_store: StoreGetInt64,
|
||||
) -> Result<LiquidityChanges, anyhow::Error> {
|
||||
let mut changes = events
|
||||
.pool_events
|
||||
.into_iter()
|
||||
.filter(PoolEvent::can_introduce_liquidity_changes)
|
||||
.map(|e| {
|
||||
(
|
||||
pools_current_tick_store
|
||||
.get_at(e.log_ordinal, format!("pool:{0}", &e.pool_address))
|
||||
.unwrap_or(0),
|
||||
e,
|
||||
)
|
||||
})
|
||||
.filter_map(|(current_tick, event)| event_to_liquidity_deltas(current_tick, event))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
changes.sort_unstable_by_key(|l| l.ordinal);
|
||||
Ok(LiquidityChanges { changes })
|
||||
}
|
||||
|
||||
#[substreams::handlers::store]
|
||||
pub fn store_liquidity(ticks_deltas: LiquidityChanges, store: StoreSetSumBigInt) {
|
||||
ticks_deltas
|
||||
.changes
|
||||
.iter()
|
||||
.for_each(|changes| match changes.change_type() {
|
||||
LiquidityChangeType::Delta => {
|
||||
store.sum(
|
||||
changes.ordinal,
|
||||
format!("pool:{0}", hex::encode(&changes.pool_address)),
|
||||
BigInt::from_signed_bytes_be(&changes.value),
|
||||
);
|
||||
}
|
||||
LiquidityChangeType::Absolute => {
|
||||
store.set(
|
||||
changes.ordinal,
|
||||
format!("pool:{0}", hex::encode(&changes.pool_address)),
|
||||
BigInt::from_signed_bytes_be(&changes.value),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn event_to_liquidity_deltas(current_tick: i64, event: PoolEvent) -> Option<LiquidityChange> {
|
||||
match event.r#type.as_ref().unwrap() {
|
||||
pool_event::Type::Mint(mint) => {
|
||||
if current_tick >= mint.tick_lower.into() && current_tick < mint.tick_upper.into() {
|
||||
Some(LiquidityChange {
|
||||
pool_address: hex::decode(event.pool_address).unwrap(),
|
||||
value: BigInt::from_str(&mint.amount)
|
||||
.unwrap()
|
||||
.to_signed_bytes_be(),
|
||||
change_type: LiquidityChangeType::Delta.into(),
|
||||
ordinal: event.log_ordinal,
|
||||
transaction: Some(event.transaction.unwrap()),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
pool_event::Type::Burn(burn) => {
|
||||
if current_tick >= burn.tick_lower.into() && current_tick < burn.tick_upper.into() {
|
||||
Some(LiquidityChange {
|
||||
pool_address: hex::decode(event.pool_address).unwrap(),
|
||||
value: BigInt::from_str(&burn.amount)
|
||||
.unwrap()
|
||||
.neg()
|
||||
.to_signed_bytes_be(),
|
||||
change_type: LiquidityChangeType::Delta.into(),
|
||||
ordinal: event.log_ordinal,
|
||||
transaction: Some(event.transaction.unwrap()),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
pool_event::Type::Swap(swap) => Some(LiquidityChange {
|
||||
pool_address: hex::decode(event.pool_address).unwrap(),
|
||||
value: BigInt::from_str(&swap.liquidity)
|
||||
.unwrap()
|
||||
.to_signed_bytes_be(),
|
||||
change_type: LiquidityChangeType::Absolute.into(),
|
||||
ordinal: event.log_ordinal,
|
||||
transaction: Some(event.transaction.unwrap()),
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
impl PoolEvent {
|
||||
fn can_introduce_liquidity_changes(&self) -> bool {
|
||||
matches!(
|
||||
self.r#type.as_ref().unwrap(),
|
||||
pool_event::Type::Mint(_) | pool_event::Type::Burn(_) | pool_event::Type::Swap(_)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn event_to_current_tick(event: PoolEvent) -> Option<(String, u64, i32)> {
|
||||
match event.r#type.as_ref().unwrap() {
|
||||
pool_event::Type::Initialize(initialize) => {
|
||||
Some((event.pool_address, event.log_ordinal, initialize.tick))
|
||||
}
|
||||
pool_event::Type::Swap(swap) => Some((event.pool_address, event.log_ordinal, swap.tick)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use substreams::store::StoreAddBigInt;
|
||||
|
||||
use crate::pb::uniswap::v3::{
|
||||
events::{pool_event, PoolEvent},
|
||||
Events, TickDelta, TickDeltas,
|
||||
};
|
||||
|
||||
use substreams::{
|
||||
scalar::BigInt,
|
||||
store::{StoreAdd, StoreNew},
|
||||
};
|
||||
|
||||
use anyhow::Ok;
|
||||
|
||||
#[substreams::handlers::map]
|
||||
pub fn map_ticks_changes(events: Events) -> Result<TickDeltas, anyhow::Error> {
|
||||
let ticks_deltas = events
|
||||
.pool_events
|
||||
.into_iter()
|
||||
.flat_map(event_to_ticks_deltas)
|
||||
.collect();
|
||||
|
||||
Ok(TickDeltas { deltas: ticks_deltas })
|
||||
}
|
||||
|
||||
#[substreams::handlers::store]
|
||||
pub fn store_ticks_liquidity(ticks_deltas: TickDeltas, store: StoreAddBigInt) {
|
||||
let mut deltas = ticks_deltas.deltas.clone();
|
||||
|
||||
deltas.sort_unstable_by_key(|delta| delta.ordinal);
|
||||
|
||||
deltas.iter().for_each(|delta| {
|
||||
store.add(
|
||||
delta.ordinal,
|
||||
format!("pool:{0}:tick:{1}", hex::encode(&delta.pool_address), delta.tick_index,),
|
||||
BigInt::from_signed_bytes_be(&delta.liquidity_net_delta),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
fn event_to_ticks_deltas(event: PoolEvent) -> Vec<TickDelta> {
|
||||
match event.r#type.as_ref().unwrap() {
|
||||
pool_event::Type::Mint(mint) => {
|
||||
vec![
|
||||
TickDelta {
|
||||
pool_address: hex::decode(&event.pool_address).unwrap(),
|
||||
tick_index: mint.tick_lower,
|
||||
liquidity_net_delta: BigInt::from_str(&mint.amount)
|
||||
.unwrap()
|
||||
.to_signed_bytes_be(),
|
||||
ordinal: event.log_ordinal,
|
||||
transaction: event.transaction.clone(),
|
||||
},
|
||||
TickDelta {
|
||||
pool_address: hex::decode(&event.pool_address).unwrap(),
|
||||
tick_index: mint.tick_upper,
|
||||
liquidity_net_delta: BigInt::from_str(&mint.amount)
|
||||
.unwrap()
|
||||
.neg()
|
||||
.to_signed_bytes_be(),
|
||||
ordinal: event.log_ordinal,
|
||||
transaction: event.transaction,
|
||||
},
|
||||
]
|
||||
}
|
||||
pool_event::Type::Burn(burn) => vec![
|
||||
TickDelta {
|
||||
pool_address: hex::decode(&event.pool_address).unwrap(),
|
||||
tick_index: burn.tick_lower,
|
||||
liquidity_net_delta: BigInt::from_str(&burn.amount)
|
||||
.unwrap()
|
||||
.neg()
|
||||
.to_signed_bytes_be(),
|
||||
ordinal: event.log_ordinal,
|
||||
transaction: event.transaction.clone(),
|
||||
},
|
||||
TickDelta {
|
||||
pool_address: hex::decode(&event.pool_address).unwrap(),
|
||||
tick_index: burn.tick_upper,
|
||||
liquidity_net_delta: BigInt::from_str(&burn.amount)
|
||||
.unwrap()
|
||||
.to_signed_bytes_be(),
|
||||
ordinal: event.log_ordinal,
|
||||
transaction: event.transaction,
|
||||
},
|
||||
],
|
||||
_ => vec![],
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
use crate::pb::uniswap::v3::{
|
||||
events::{pool_event, PoolEvent},
|
||||
Events, LiquidityChanges, TickDeltas,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use std::{collections::HashMap, str::FromStr, vec};
|
||||
use substreams::{pb::substreams::StoreDeltas, scalar::BigInt};
|
||||
use substreams_ethereum::pb::eth::v2::{self as eth};
|
||||
use substreams_helper::hex::Hexable;
|
||||
use tycho_substreams::{balances::aggregate_balances_changes, prelude::*};
|
||||
|
||||
type PoolAddress = Vec<u8>;
|
||||
|
||||
#[substreams::handlers::map]
|
||||
pub fn map_protocol_changes(
|
||||
block: eth::Block,
|
||||
created_pools: BlockEntityChanges,
|
||||
events: Events,
|
||||
balances_map_deltas: BlockBalanceDeltas,
|
||||
balances_store_deltas: StoreDeltas,
|
||||
ticks_map_deltas: TickDeltas,
|
||||
ticks_store_deltas: StoreDeltas,
|
||||
pool_liquidity_changes: LiquidityChanges,
|
||||
pool_liquidity_store_deltas: StoreDeltas,
|
||||
) -> Result<BlockChanges, substreams::errors::Error> {
|
||||
// We merge contract changes by transaction (identified by transaction index) making it easy to
|
||||
// sort them at the very end.
|
||||
let mut transaction_changes: HashMap<_, TransactionChangesBuilder> = HashMap::new();
|
||||
|
||||
// Add created pools to the tx_changes_map
|
||||
for change in created_pools.changes.into_iter() {
|
||||
let tx = change.tx.as_ref().unwrap();
|
||||
let builder = transaction_changes
|
||||
.entry(tx.index)
|
||||
.or_insert_with(|| TransactionChangesBuilder::new(tx));
|
||||
change
|
||||
.component_changes
|
||||
.iter()
|
||||
.for_each(|c| {
|
||||
builder.add_protocol_component(c);
|
||||
});
|
||||
change
|
||||
.entity_changes
|
||||
.iter()
|
||||
.for_each(|ec| {
|
||||
builder.add_entity_change(ec);
|
||||
});
|
||||
change
|
||||
.balance_changes
|
||||
.iter()
|
||||
.for_each(|bc| {
|
||||
builder.add_balance_change(bc);
|
||||
});
|
||||
}
|
||||
|
||||
// Balance changes are gathered by the `StoreDelta` based on `PoolBalanceChanged` creating
|
||||
// `BlockBalanceDeltas`. We essentially just process the changes that occurred to the `store`
|
||||
// this block. Then, these balance changes are merged onto the existing map of tx contract
|
||||
// changes, inserting a new one if it doesn't exist.
|
||||
aggregate_balances_changes(balances_store_deltas, balances_map_deltas)
|
||||
.into_iter()
|
||||
.for_each(|(_, (tx, balances))| {
|
||||
let builder = transaction_changes
|
||||
.entry(tx.index)
|
||||
.or_insert_with(|| TransactionChangesBuilder::new(&tx));
|
||||
balances
|
||||
.values()
|
||||
.for_each(|token_bc_map| {
|
||||
token_bc_map
|
||||
.values()
|
||||
.for_each(|bc| builder.add_balance_change(bc))
|
||||
});
|
||||
});
|
||||
|
||||
// Insert ticks net-liquidity changes
|
||||
ticks_store_deltas
|
||||
.deltas
|
||||
.into_iter()
|
||||
.zip(ticks_map_deltas.deltas)
|
||||
.for_each(|(store_delta, tick_delta)| {
|
||||
let new_value_bigint =
|
||||
BigInt::from_str(&String::from_utf8(store_delta.new_value).unwrap()).unwrap();
|
||||
|
||||
// If old value is empty or the int value is 0, it's considered as a creation.
|
||||
let is_creation = store_delta.old_value.is_empty() ||
|
||||
BigInt::from_str(&String::from_utf8(store_delta.old_value).unwrap())
|
||||
.unwrap()
|
||||
.is_zero();
|
||||
let attribute_name = format!("ticks/{}/net-liquidity", tick_delta.tick_index);
|
||||
let attribute = Attribute {
|
||||
name: attribute_name,
|
||||
value: new_value_bigint.to_signed_bytes_be(),
|
||||
change: if is_creation {
|
||||
ChangeType::Creation.into()
|
||||
} else if new_value_bigint.is_zero() {
|
||||
ChangeType::Deletion.into()
|
||||
} else {
|
||||
ChangeType::Update.into()
|
||||
},
|
||||
};
|
||||
let tx = tick_delta.transaction.unwrap();
|
||||
let builder = transaction_changes
|
||||
.entry(tx.index)
|
||||
.or_insert_with(|| TransactionChangesBuilder::new(&tx.into()));
|
||||
|
||||
builder.add_entity_change(&EntityChanges {
|
||||
component_id: tick_delta.pool_address.to_hex(),
|
||||
attributes: vec![attribute],
|
||||
});
|
||||
});
|
||||
|
||||
// Insert liquidity changes
|
||||
pool_liquidity_store_deltas
|
||||
.deltas
|
||||
.into_iter()
|
||||
.zip(pool_liquidity_changes.changes)
|
||||
.for_each(|(store_delta, change)| {
|
||||
let new_value_bigint = BigInt::from_str(
|
||||
String::from_utf8(store_delta.new_value)
|
||||
.unwrap()
|
||||
.split(':')
|
||||
.nth(1)
|
||||
.unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
let tx = change.transaction.unwrap();
|
||||
let builder = transaction_changes
|
||||
.entry(tx.index)
|
||||
.or_insert_with(|| TransactionChangesBuilder::new(&tx.into()));
|
||||
|
||||
builder.add_entity_change(&EntityChanges {
|
||||
component_id: change.pool_address.to_hex(),
|
||||
attributes: vec![Attribute {
|
||||
name: "liquidity".to_string(),
|
||||
value: new_value_bigint.to_signed_bytes_be(),
|
||||
change: ChangeType::Update.into(),
|
||||
}],
|
||||
});
|
||||
});
|
||||
|
||||
// Insert others changes
|
||||
events
|
||||
.pool_events
|
||||
.into_iter()
|
||||
.flat_map(event_to_attributes_updates)
|
||||
.for_each(|(tx, pool_address, attr)| {
|
||||
let builder = transaction_changes
|
||||
.entry(tx.index)
|
||||
.or_insert_with(|| TransactionChangesBuilder::new(&tx));
|
||||
builder.add_entity_change(&EntityChanges {
|
||||
component_id: pool_address.to_hex(),
|
||||
attributes: vec![attr],
|
||||
});
|
||||
});
|
||||
|
||||
Ok(BlockChanges {
|
||||
block: Some((&block).into()),
|
||||
changes: transaction_changes
|
||||
.drain()
|
||||
.sorted_unstable_by_key(|(index, _)| *index)
|
||||
.filter_map(|(_, builder)| builder.build())
|
||||
.collect::<Vec<_>>(),
|
||||
})
|
||||
}
|
||||
|
||||
fn event_to_attributes_updates(event: PoolEvent) -> Vec<(Transaction, PoolAddress, Attribute)> {
|
||||
match event.r#type.as_ref().unwrap() {
|
||||
pool_event::Type::Initialize(initalize) => {
|
||||
vec![
|
||||
(
|
||||
event
|
||||
.transaction
|
||||
.clone()
|
||||
.unwrap()
|
||||
.into(),
|
||||
hex::decode(event.pool_address.clone()).unwrap(),
|
||||
Attribute {
|
||||
name: "sqrt_price_x96".to_string(),
|
||||
value: BigInt::from_str(&initalize.sqrt_price)
|
||||
.unwrap()
|
||||
.to_signed_bytes_be(),
|
||||
change: ChangeType::Update.into(),
|
||||
},
|
||||
),
|
||||
(
|
||||
event.transaction.unwrap().into(),
|
||||
hex::decode(event.pool_address).unwrap(),
|
||||
Attribute {
|
||||
name: "tick".to_string(),
|
||||
value: BigInt::from(initalize.tick).to_signed_bytes_be(),
|
||||
change: ChangeType::Update.into(),
|
||||
},
|
||||
),
|
||||
]
|
||||
}
|
||||
pool_event::Type::Swap(swap) => vec![
|
||||
(
|
||||
event
|
||||
.transaction
|
||||
.clone()
|
||||
.unwrap()
|
||||
.into(),
|
||||
hex::decode(event.pool_address.clone()).unwrap(),
|
||||
Attribute {
|
||||
name: "sqrt_price_x96".to_string(),
|
||||
value: BigInt::from_str(&swap.sqrt_price)
|
||||
.unwrap()
|
||||
.to_signed_bytes_be(),
|
||||
change: ChangeType::Update.into(),
|
||||
},
|
||||
),
|
||||
(
|
||||
event.transaction.unwrap().into(),
|
||||
hex::decode(event.pool_address).unwrap(),
|
||||
Attribute {
|
||||
name: "tick".to_string(),
|
||||
value: BigInt::from(swap.tick).to_signed_bytes_be(),
|
||||
change: ChangeType::Update.into(),
|
||||
},
|
||||
),
|
||||
],
|
||||
pool_event::Type::SetFeeProtocol(sfp) => vec![
|
||||
(
|
||||
event
|
||||
.transaction
|
||||
.clone()
|
||||
.unwrap()
|
||||
.into(),
|
||||
hex::decode(event.pool_address.clone()).unwrap(),
|
||||
Attribute {
|
||||
name: "protocol_fees/token0".to_string(),
|
||||
value: BigInt::from(sfp.fee_protocol_0_new).to_signed_bytes_be(),
|
||||
change: ChangeType::Update.into(),
|
||||
},
|
||||
),
|
||||
(
|
||||
event.transaction.unwrap().into(),
|
||||
hex::decode(event.pool_address).unwrap(),
|
||||
Attribute {
|
||||
name: "protocol_fees/token1".to_string(),
|
||||
value: BigInt::from(sfp.fee_protocol_1_new).to_signed_bytes_be(),
|
||||
change: ChangeType::Update.into(),
|
||||
},
|
||||
),
|
||||
],
|
||||
_ => vec![],
|
||||
}
|
||||
}
|
||||
39
substreams/ethereum-uniswap-v3-logs-only/src/modules/mod.rs
Normal file
39
substreams/ethereum-uniswap-v3-logs-only/src/modules/mod.rs
Normal file
@@ -0,0 +1,39 @@
|
||||
pub use map_pool_created::map_pools_created;
|
||||
pub use map_protocol_changes::map_protocol_changes;
|
||||
pub use store_pools::store_pools;
|
||||
use substreams_ethereum::pb::eth::v2::TransactionTrace;
|
||||
|
||||
use crate::pb::uniswap::v3::Transaction;
|
||||
|
||||
#[path = "1_map_pool_created.rs"]
|
||||
mod map_pool_created;
|
||||
|
||||
#[path = "2_store_pools.rs"]
|
||||
mod store_pools;
|
||||
|
||||
#[path = "3_map_events.rs"]
|
||||
mod map_events;
|
||||
|
||||
#[path = "4_map_and_store_balance_changes.rs"]
|
||||
mod map_store_balance_changes;
|
||||
|
||||
#[path = "4_map_and_store_ticks.rs"]
|
||||
mod map_store_ticks;
|
||||
|
||||
#[path = "4_map_and_store_liquidity.rs"]
|
||||
mod map_store_liquidity;
|
||||
|
||||
#[path = "5_map_protocol_changes.rs"]
|
||||
mod map_protocol_changes;
|
||||
|
||||
impl From<TransactionTrace> for Transaction {
|
||||
fn from(value: TransactionTrace) -> Self {
|
||||
Self { hash: value.hash, from: value.from, to: value.to, index: value.index.into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Transaction> for tycho_substreams::prelude::Transaction {
|
||||
fn from(value: Transaction) -> Self {
|
||||
Self { hash: value.hash, from: value.from, to: value.to, index: value.index }
|
||||
}
|
||||
}
|
||||
8
substreams/ethereum-uniswap-v3-logs-only/src/pb/mod.rs
Normal file
8
substreams/ethereum-uniswap-v3-logs-only/src/pb/mod.rs
Normal file
@@ -0,0 +1,8 @@
|
||||
// @generated
|
||||
pub mod uniswap {
|
||||
// @@protoc_insertion_point(attribute:uniswap.v3)
|
||||
pub mod v3 {
|
||||
include!("uniswap.v3.rs");
|
||||
// @@protoc_insertion_point(uniswap.v3)
|
||||
}
|
||||
}
|
||||
298
substreams/ethereum-uniswap-v3-logs-only/src/pb/uniswap.v3.rs
Normal file
298
substreams/ethereum-uniswap-v3-logs-only/src/pb/uniswap.v3.rs
Normal file
@@ -0,0 +1,298 @@
|
||||
// @generated
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Pool {
|
||||
#[prost(bytes="vec", tag="1")]
|
||||
pub address: ::prost::alloc::vec::Vec<u8>,
|
||||
#[prost(bytes="vec", tag="2")]
|
||||
pub token0: ::prost::alloc::vec::Vec<u8>,
|
||||
#[prost(bytes="vec", tag="3")]
|
||||
pub token1: ::prost::alloc::vec::Vec<u8>,
|
||||
#[prost(bytes="vec", tag="4")]
|
||||
pub created_tx_hash: ::prost::alloc::vec::Vec<u8>,
|
||||
}
|
||||
/// A struct describing a transaction.
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Transaction {
|
||||
/// The transaction hash.
|
||||
#[prost(bytes="vec", tag="1")]
|
||||
pub hash: ::prost::alloc::vec::Vec<u8>,
|
||||
/// The sender of the transaction.
|
||||
#[prost(bytes="vec", tag="2")]
|
||||
pub from: ::prost::alloc::vec::Vec<u8>,
|
||||
/// The receiver of the transaction.
|
||||
#[prost(bytes="vec", tag="3")]
|
||||
pub to: ::prost::alloc::vec::Vec<u8>,
|
||||
/// The transactions index within the block.
|
||||
#[prost(uint64, tag="4")]
|
||||
pub index: u64,
|
||||
}
|
||||
/// A change to a pool's tick.
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct TickDelta {
|
||||
/// The address of the pool.
|
||||
#[prost(bytes="vec", tag="1")]
|
||||
pub pool_address: ::prost::alloc::vec::Vec<u8>,
|
||||
/// The index of the tick.
|
||||
#[prost(int32, tag="2")]
|
||||
pub tick_index: i32,
|
||||
/// The liquidity net delta of this tick. Bigint encoded as signed little endian bytes.
|
||||
#[prost(bytes="vec", tag="3")]
|
||||
pub liquidity_net_delta: ::prost::alloc::vec::Vec<u8>,
|
||||
/// Used to determine the order of the balance changes. Necessary for the balance store.
|
||||
#[prost(uint64, tag="4")]
|
||||
pub ordinal: u64,
|
||||
#[prost(message, optional, tag="5")]
|
||||
pub transaction: ::core::option::Option<Transaction>,
|
||||
}
|
||||
/// A group of TickDelta
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct TickDeltas {
|
||||
#[prost(message, repeated, tag="1")]
|
||||
pub deltas: ::prost::alloc::vec::Vec<TickDelta>,
|
||||
}
|
||||
/// A change to a pool's liquidity.
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct LiquidityChange {
|
||||
/// The address of the pool.
|
||||
#[prost(bytes="vec", tag="1")]
|
||||
pub pool_address: ::prost::alloc::vec::Vec<u8>,
|
||||
/// The liquidity changed amount. Bigint encoded as signed little endian bytes.
|
||||
#[prost(bytes="vec", tag="2")]
|
||||
pub value: ::prost::alloc::vec::Vec<u8>,
|
||||
/// The type of update, can be absolute or delta.
|
||||
#[prost(enumeration="LiquidityChangeType", tag="3")]
|
||||
pub change_type: i32,
|
||||
/// Used to determine the order of the balance changes. Necessary for the balance store.
|
||||
#[prost(uint64, tag="4")]
|
||||
pub ordinal: u64,
|
||||
#[prost(message, optional, tag="5")]
|
||||
pub transaction: ::core::option::Option<Transaction>,
|
||||
}
|
||||
/// A group of LiquidityChange
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct LiquidityChanges {
|
||||
#[prost(message, repeated, tag="1")]
|
||||
pub changes: ::prost::alloc::vec::Vec<LiquidityChange>,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Events {
|
||||
#[prost(message, repeated, tag="3")]
|
||||
pub pool_events: ::prost::alloc::vec::Vec<events::PoolEvent>,
|
||||
}
|
||||
/// Nested message and enum types in `Events`.
|
||||
pub mod events {
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct PoolEvent {
|
||||
#[prost(uint64, tag="100")]
|
||||
pub log_ordinal: u64,
|
||||
#[prost(string, tag="102")]
|
||||
pub pool_address: ::prost::alloc::string::String,
|
||||
#[prost(string, tag="103")]
|
||||
pub token0: ::prost::alloc::string::String,
|
||||
#[prost(string, tag="104")]
|
||||
pub token1: ::prost::alloc::string::String,
|
||||
#[prost(message, optional, tag="105")]
|
||||
pub transaction: ::core::option::Option<super::Transaction>,
|
||||
#[prost(oneof="pool_event::Type", tags="1, 2, 3, 4, 5, 6, 7, 8")]
|
||||
pub r#type: ::core::option::Option<pool_event::Type>,
|
||||
}
|
||||
/// Nested message and enum types in `PoolEvent`.
|
||||
pub mod pool_event {
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Initialize {
|
||||
/// Unsigned
|
||||
#[prost(string, tag="1")]
|
||||
pub sqrt_price: ::prost::alloc::string::String,
|
||||
#[prost(int32, tag="2")]
|
||||
pub tick: i32,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Mint {
|
||||
#[prost(string, tag="1")]
|
||||
pub sender: ::prost::alloc::string::String,
|
||||
#[prost(string, tag="2")]
|
||||
pub owner: ::prost::alloc::string::String,
|
||||
/// Signed
|
||||
#[prost(int32, tag="3")]
|
||||
pub tick_lower: i32,
|
||||
/// Signed
|
||||
#[prost(int32, tag="4")]
|
||||
pub tick_upper: i32,
|
||||
/// Unsigned
|
||||
#[prost(string, tag="5")]
|
||||
pub amount: ::prost::alloc::string::String,
|
||||
/// Unsigned
|
||||
#[prost(string, tag="6")]
|
||||
pub amount_0: ::prost::alloc::string::String,
|
||||
/// Unsigned
|
||||
#[prost(string, tag="7")]
|
||||
pub amount_1: ::prost::alloc::string::String,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Collect {
|
||||
#[prost(string, tag="1")]
|
||||
pub owner: ::prost::alloc::string::String,
|
||||
#[prost(string, tag="2")]
|
||||
pub recipient: ::prost::alloc::string::String,
|
||||
#[prost(int32, tag="3")]
|
||||
pub tick_lower: i32,
|
||||
#[prost(int32, tag="4")]
|
||||
pub tick_upper: i32,
|
||||
/// Unsigned
|
||||
#[prost(string, tag="5")]
|
||||
pub amount_0: ::prost::alloc::string::String,
|
||||
/// Unsigned
|
||||
#[prost(string, tag="6")]
|
||||
pub amount_1: ::prost::alloc::string::String,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Burn {
|
||||
#[prost(string, tag="1")]
|
||||
pub owner: ::prost::alloc::string::String,
|
||||
#[prost(int32, tag="2")]
|
||||
pub tick_lower: i32,
|
||||
#[prost(int32, tag="3")]
|
||||
pub tick_upper: i32,
|
||||
/// Unsigned
|
||||
#[prost(string, tag="4")]
|
||||
pub amount: ::prost::alloc::string::String,
|
||||
/// Unsigned
|
||||
#[prost(string, tag="5")]
|
||||
pub amount_0: ::prost::alloc::string::String,
|
||||
/// Unsigned
|
||||
#[prost(string, tag="6")]
|
||||
pub amount_1: ::prost::alloc::string::String,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Swap {
|
||||
#[prost(string, tag="1")]
|
||||
pub sender: ::prost::alloc::string::String,
|
||||
#[prost(string, tag="2")]
|
||||
pub recipient: ::prost::alloc::string::String,
|
||||
/// Signed
|
||||
#[prost(string, tag="3")]
|
||||
pub amount_0: ::prost::alloc::string::String,
|
||||
/// Signed
|
||||
#[prost(string, tag="4")]
|
||||
pub amount_1: ::prost::alloc::string::String,
|
||||
/// Unsigned
|
||||
#[prost(string, tag="6")]
|
||||
pub sqrt_price: ::prost::alloc::string::String,
|
||||
/// Unsigned
|
||||
#[prost(string, tag="7")]
|
||||
pub liquidity: ::prost::alloc::string::String,
|
||||
#[prost(int32, tag="8")]
|
||||
pub tick: i32,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Flash {
|
||||
#[prost(string, tag="1")]
|
||||
pub sender: ::prost::alloc::string::String,
|
||||
#[prost(string, tag="2")]
|
||||
pub recipient: ::prost::alloc::string::String,
|
||||
/// Unsigned
|
||||
#[prost(string, tag="3")]
|
||||
pub amount_0: ::prost::alloc::string::String,
|
||||
/// Unsigned
|
||||
#[prost(string, tag="4")]
|
||||
pub amount_1: ::prost::alloc::string::String,
|
||||
/// Unsigned
|
||||
#[prost(string, tag="5")]
|
||||
pub paid_0: ::prost::alloc::string::String,
|
||||
/// Unsigned
|
||||
#[prost(string, tag="6")]
|
||||
pub paid_1: ::prost::alloc::string::String,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SetFeeProtocol {
|
||||
/// Unsigned
|
||||
#[prost(uint64, tag="1")]
|
||||
pub fee_protocol_0_old: u64,
|
||||
/// Unsigned
|
||||
#[prost(uint64, tag="2")]
|
||||
pub fee_protocol_1_old: u64,
|
||||
/// Unsigned
|
||||
#[prost(uint64, tag="3")]
|
||||
pub fee_protocol_0_new: u64,
|
||||
/// Unsigned
|
||||
#[prost(uint64, tag="4")]
|
||||
pub fee_protocol_1_new: u64,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct CollectProtocol {
|
||||
#[prost(string, tag="1")]
|
||||
pub sender: ::prost::alloc::string::String,
|
||||
#[prost(string, tag="2")]
|
||||
pub recipient: ::prost::alloc::string::String,
|
||||
/// Unsigned
|
||||
#[prost(string, tag="3")]
|
||||
pub amount_0: ::prost::alloc::string::String,
|
||||
/// Unsigned
|
||||
#[prost(string, tag="4")]
|
||||
pub amount_1: ::prost::alloc::string::String,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
||||
pub enum Type {
|
||||
#[prost(message, tag="1")]
|
||||
Initialize(Initialize),
|
||||
#[prost(message, tag="2")]
|
||||
Mint(Mint),
|
||||
#[prost(message, tag="3")]
|
||||
Collect(Collect),
|
||||
#[prost(message, tag="4")]
|
||||
Burn(Burn),
|
||||
#[prost(message, tag="5")]
|
||||
Swap(Swap),
|
||||
#[prost(message, tag="6")]
|
||||
Flash(Flash),
|
||||
#[prost(message, tag="7")]
|
||||
SetFeeProtocol(SetFeeProtocol),
|
||||
#[prost(message, tag="8")]
|
||||
CollectProtocol(CollectProtocol),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
|
||||
#[repr(i32)]
|
||||
pub enum LiquidityChangeType {
|
||||
Delta = 0,
|
||||
Absolute = 1,
|
||||
}
|
||||
impl LiquidityChangeType {
|
||||
/// String value of the enum field names used in the ProtoBuf definition.
|
||||
///
|
||||
/// The values are not transformed in any way and thus are considered stable
|
||||
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
|
||||
pub fn as_str_name(&self) -> &'static str {
|
||||
match self {
|
||||
LiquidityChangeType::Delta => "DELTA",
|
||||
LiquidityChangeType::Absolute => "ABSOLUTE",
|
||||
}
|
||||
}
|
||||
/// Creates an enum from field names used in the ProtoBuf definition.
|
||||
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
|
||||
match value {
|
||||
"DELTA" => Some(Self::Delta),
|
||||
"ABSOLUTE" => Some(Self::Absolute),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
// @@protoc_insertion_point(module)
|
||||
@@ -15,4 +15,5 @@ ignore = [
|
||||
"ethereum-curve/src/abi",
|
||||
"ethereum-uniswap-v2/src/abi",
|
||||
"ethereum-uniswap-v3/src/abi",
|
||||
"ethereum-uniswap-v3-logs-only/src/abi",
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user