chore: clean up ambient (#136)

* fix: remove unnecessary tx field in ProtocolComponent

* chore: move ambient protobuf files to ambient module

* chore: remove dependency on common message types

This allows us to isolate the ambient specific messages within the ambient module

* feat: update ambient substream with new message structs

* chore: update substream configs

And remove use of deprecated BlockContractChanges.

* feat: implement From for AmbientProtocolComponent to ProtocolComponent
This commit is contained in:
Louise Poole
2025-01-27 10:36:13 +02:00
committed by GitHub
parent 28dd2fc858
commit ad0a391f72
18 changed files with 171 additions and 125 deletions

View File

@@ -3,7 +3,6 @@ modules:
- path: proto - path: proto
excludes: excludes:
- proto/sf - proto/sf
- path: substreams/ethereum-ambient/proto
lint: lint:
use: use:
- BASIC - BASIC

View File

@@ -90,8 +90,6 @@ message ProtocolComponent {
ChangeType change = 5; ChangeType change = 5;
/// Represents the functionality of the component. /// Represents the functionality of the component.
ProtocolType protocol_type = 6; ProtocolType protocol_type = 6;
// Transaction where this component was created
Transaction tx = 7;
} }
// A struct for following the changes of Total Value Locked (TVL) of a protocol component. // A struct for following the changes of Total Value Locked (TVL) of a protocol component.

20
substreams/Cargo.lock generated
View File

@@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 4
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
@@ -1141,7 +1141,7 @@ dependencies = [
"substreams", "substreams",
"substreams-ethereum", "substreams-ethereum",
"tiny-keccak", "tiny-keccak",
"tycho-substreams 0.2.0 (git+https://github.com/propeller-heads/tycho-protocol-sdk.git?rev=b8aeaa3)", "tycho-substreams 0.2.0 (git+https://github.com/propeller-heads/tycho-protocol-sdk.git?rev=f90c33b)",
] ]
[[package]] [[package]]
@@ -1369,6 +1369,22 @@ dependencies = [
"substreams-ethereum", "substreams-ethereum",
] ]
[[package]]
name = "tycho-substreams"
version = "0.2.0"
source = "git+https://github.com/propeller-heads/tycho-protocol-sdk.git?rev=f90c33b#f90c33bcc229a1bca1fe86ee6fc4024cbdc25aeb"
dependencies = [
"ethabi 18.0.0",
"hex",
"itertools 0.12.1",
"num-bigint",
"prost 0.11.9",
"serde",
"serde_json",
"substreams",
"substreams-ethereum",
]
[[package]] [[package]]
name = "typenum" name = "typenum"
version = "1.17.0" version = "1.17.0"

View File

@@ -2,7 +2,7 @@ use std::collections::{HashMap, HashSet};
use substreams_ethereum::pb::eth::v2::{self as sf, StorageChange}; use substreams_ethereum::pb::eth::v2::{self as sf, StorageChange};
// re-export the protobuf types here. // re-export the protobuf types here.
pub use crate::pb::tycho::{ambient::v1::*, evm::v1::*}; pub use crate::pb::tycho::evm::v1::*;
impl TransactionContractChanges { impl TransactionContractChanges {
/// Creates a new empty `TransactionContractChanges` instance. /// Creates a new empty `TransactionContractChanges` instance.
@@ -213,7 +213,7 @@ impl ProtocolComponent {
/// ## Parameters /// ## Parameters
/// - `id`: Identifier for the component. /// - `id`: Identifier for the component.
/// - `tx`: Reference to the associated transaction. /// - `tx`: Reference to the associated transaction.
pub fn new(id: &str, tx: &Transaction) -> Self { pub fn new(id: &str) -> Self {
Self { Self {
id: id.to_string(), id: id.to_string(),
tokens: Vec::new(), tokens: Vec::new(),
@@ -221,7 +221,6 @@ impl ProtocolComponent {
static_att: Vec::new(), static_att: Vec::new(),
change: ChangeType::Creation.into(), change: ChangeType::Creation.into(),
protocol_type: None, protocol_type: None,
tx: Some(tx.clone()),
} }
} }
@@ -233,7 +232,7 @@ impl ProtocolComponent {
/// ## Parameters /// ## Parameters
/// - `id`: Contract address to be encoded and set as the component's ID. /// - `id`: Contract address to be encoded and set as the component's ID.
/// - `tx`: Reference to the associated transaction. /// - `tx`: Reference to the associated transaction.
pub fn at_contract(id: &[u8], tx: &Transaction) -> Self { pub fn at_contract(id: &[u8]) -> Self {
Self { Self {
id: format!("0x{}", hex::encode(id)), id: format!("0x{}", hex::encode(id)),
tokens: Vec::new(), tokens: Vec::new(),
@@ -241,7 +240,6 @@ impl ProtocolComponent {
static_att: Vec::new(), static_att: Vec::new(),
change: ChangeType::Creation.into(), change: ChangeType::Creation.into(),
protocol_type: None, protocol_type: None,
tx: Some(tx.clone()),
} }
} }

View File

@@ -1,12 +1,5 @@
// @generated // @generated
pub mod tycho { pub mod tycho {
pub mod ambient {
// @@protoc_insertion_point(attribute:tycho.ambient.v1)
pub mod v1 {
include!("tycho.ambient.v1.rs");
// @@protoc_insertion_point(tycho.ambient.v1)
}
}
pub mod evm { pub mod evm {
// @@protoc_insertion_point(attribute:tycho.evm.v1) // @@protoc_insertion_point(attribute:tycho.evm.v1)
pub mod v1 { pub mod v1 {

View File

@@ -95,9 +95,6 @@ pub struct ProtocolComponent {
/// / Represents the functionality of the component. /// / Represents the functionality of the component.
#[prost(message, optional, tag="6")] #[prost(message, optional, tag="6")]
pub protocol_type: ::core::option::Option<ProtocolType>, pub protocol_type: ::core::option::Option<ProtocolType>,
/// Transaction where this component was created
#[prost(message, optional, tag = "7")]
pub tx: ::core::option::Option<Transaction>,
} }
/// A struct for following the changes of Total Value Locked (TVL) of a protocol component. /// A struct for following the changes of Total Value Locked (TVL) of a protocol component.
/// Note that if a ProtocolComponent contains multiple contracts, the TVL is tracked for the component as a whole. /// Note that if a ProtocolComponent contains multiple contracts, the TVL is tracked for the component as a whole.

View File

@@ -8,7 +8,7 @@ name = "substreams_ethereum_ambient"
crate-type = ["cdylib"] crate-type = ["cdylib"]
[dependencies] [dependencies]
tycho-substreams = { git = "https://github.com/propeller-heads/tycho-protocol-sdk.git", rev = "b8aeaa3" } tycho-substreams = { git = "https://github.com/propeller-heads/tycho-protocol-sdk.git", rev = "f90c33b" }
substreams = "0.5.22" substreams = "0.5.22"
substreams-ethereum = "0.9.9" substreams-ethereum = "0.9.9"
prost = "0.11" prost = "0.11"

View File

@@ -9,7 +9,7 @@ Modules Description
* **Type**: Map * **Type**: Map
* **Purpose**: This module detects new pools within the Ethereum blockchain and balance changes. * **Purpose**: This module detects new pools within the Ethereum blockchain and balance changes.
* **Inputs**: Ethereum block data (`sf.ethereum.type.v2.Block`). * **Inputs**: Ethereum block data (`sf.ethereum.type.v2.Block`).
* **Output**: Emits data of type `proto:tycho.evm.state.v1.BlockPoolChanges`. * **Output**: Emits data of type `proto:tycho.ambient.v1.BlockPoolChanges`.
### `store_pools_balances` ### `store_pools_balances`
@@ -26,10 +26,10 @@ Modules Description
### `map_changes` ### `map_changes`
* **Type**: Map * **Type**: Map
* **Purpose**: This module integrates all the processed information to generate comprehensive `BlockContractChanges`. It considers new pools, balance changes and contract changes. * **Purpose**: This module integrates all the processed information to generate comprehensive `BlockChanges`. It considers new pools, balance changes and contract changes.
* **Inputs**: * **Inputs**:
* Ethereum block data (`sf.ethereum.type.v2.Block`). * Ethereum block data (`sf.ethereum.type.v2.Block`).
* Data from `map_pool_changes`. * Data from `map_pool_changes`.
* Data from `store_pools_balances`. * Data from `store_pools_balances`.
* Data from `store_pools`. * Data from `store_pools`.
* **Output**: Emits `proto:tycho.evm.state.v1.BlockContractChanges`. * **Output**: Emits `proto:tycho.evm.state.v1.BlockChanges`.

View File

@@ -2,8 +2,6 @@ syntax = "proto3";
package tycho.ambient.v1; package tycho.ambient.v1;
import "tycho/evm/v1/common.proto";
// A change to a pool's balance. Ambient specific. // A change to a pool's balance. Ambient specific.
message AmbientBalanceDelta { message AmbientBalanceDelta {
// The address of the ERC20 token whose balance changed. // The address of the ERC20 token whose balance changed.
@@ -14,14 +12,25 @@ message AmbientBalanceDelta {
bytes token_delta = 3; bytes token_delta = 3;
// Used to determine the order of the balance changes. Necessary for the balance store. // Used to determine the order of the balance changes. Necessary for the balance store.
uint64 ordinal = 4; uint64 ordinal = 4;
// Transaction where the balance changed. // Transaction index of the balance change
tycho.evm.v1.Transaction tx = 5; uint64 tx_index = 5;
}
message AmbientProtocolComponent {
// A unique identifier for the component within the protocol.
string id = 1;
// Addresses of the ERC20 tokens used by the component.
repeated bytes tokens = 2;
// Ambient pool index [static attribute for ambient pools]
bytes pool_index = 3;
// Transaction index for the component creation
uint64 tx_index = 4;
} }
// Ambient pool changes within a single block // Ambient pool changes within a single block
message BlockPoolChanges { message BlockPoolChanges {
// New protocol components added in this block // New protocol components added in this block
repeated tycho.evm.v1.ProtocolComponent protocol_components = 1; repeated AmbientProtocolComponent new_components = 1;
// Balance changes to pools in this block // Balance changes on this block
repeated AmbientBalanceDelta balance_deltas = 2; repeated AmbientBalanceDelta balance_deltas = 2;
} }

View File

@@ -1,14 +1,17 @@
use anyhow::{anyhow, bail}; use anyhow::{anyhow, bail};
use tycho_substreams::models::{
Attribute, ChangeType, FinancialType, ImplementationType, ProtocolComponent, ProtocolType,
Transaction,
};
use crate::utils::{decode_flows_from_output, encode_pool_hash};
use ethabi::{decode, ParamType}; use ethabi::{decode, ParamType};
use hex_literal::hex; use hex_literal::hex;
use substreams_ethereum::pb::eth::v2::Call; use substreams_ethereum::pb::eth::v2::Call;
use tycho_substreams::models::{
Attribute, ChangeType, FinancialType, ImplementationType, ProtocolComponent, ProtocolType,
};
use crate::{
pb::tycho::ambient::v1::AmbientProtocolComponent,
utils::{decode_flows_from_output, encode_pool_hash},
};
pub const AMBIENT_CONTRACT: [u8; 20] = hex!("aaaaaaaaa24eeeb8d57d431224f73832bc34f688"); pub const AMBIENT_CONTRACT: [u8; 20] = hex!("aaaaaaaaa24eeeb8d57d431224f73832bc34f688");
pub const USER_CMD_FN_SIG: [u8; 4] = hex!("a15112f9"); pub const USER_CMD_FN_SIG: [u8; 4] = hex!("a15112f9");
@@ -91,10 +94,11 @@ pub fn decode_direct_swap_call(
bail!("Failed to decode swap call inputs.".to_string()); bail!("Failed to decode swap call inputs.".to_string());
} }
} }
pub fn decode_pool_init( pub fn decode_pool_init(
call: &Call, call: &Call,
tx: Transaction, tx_index: u64,
) -> Result<Option<ProtocolComponent>, anyhow::Error> { ) -> Result<Option<AmbientProtocolComponent>, anyhow::Error> {
// Decode external call to UserCmd // Decode external call to UserCmd
if let Ok(external_params) = decode(USER_CMD_EXTERNAL_ABI, &call.input[4..]) { if let Ok(external_params) = decode(USER_CMD_EXTERNAL_ABI, &call.input[4..]) {
let cmd_bytes = external_params[1] let cmd_bytes = external_params[1]
@@ -134,28 +138,14 @@ pub fn decode_pool_init(
let pool_index = pool_index_buf.to_vec(); let pool_index = pool_index_buf.to_vec();
let pool_hash = encode_pool_hash(base.clone(), quote.clone(), pool_index.clone()); let pool_hash = encode_pool_hash(base.clone(), quote.clone(), pool_index.clone());
let static_attribute = Attribute {
name: String::from("pool_index"),
value: pool_index,
change: ChangeType::Creation.into(),
};
let mut tokens: Vec<Vec<u8>> = vec![base.clone(), quote.clone()]; let mut tokens: Vec<Vec<u8>> = vec![base.clone(), quote.clone()];
tokens.sort(); tokens.sort();
let new_component = ProtocolComponent { let new_component = AmbientProtocolComponent {
id: hex::encode(pool_hash), id: hex::encode(pool_hash),
tokens, tokens,
contracts: vec![AMBIENT_CONTRACT.to_vec()], pool_index,
static_att: vec![static_attribute], tx_index,
change: ChangeType::Creation.into(),
protocol_type: Some(ProtocolType {
name: "ambient_pool".to_string(),
attribute_schema: vec![],
financial_type: FinancialType::Swap.into(),
implementation_type: ImplementationType::Vm.into(),
}),
tx: Some(tx.clone()),
}; };
Ok(Some(new_component)) Ok(Some(new_component))
} else { } else {
@@ -168,3 +158,25 @@ pub fn decode_pool_init(
bail!("Failed to decode ABI external call.".to_string()); bail!("Failed to decode ABI external call.".to_string());
} }
} }
impl From<AmbientProtocolComponent> for ProtocolComponent {
fn from(component: AmbientProtocolComponent) -> Self {
ProtocolComponent {
id: component.id,
tokens: component.tokens,
contracts: vec![AMBIENT_CONTRACT.to_vec()],
static_att: vec![Attribute {
name: "pool_index".to_string(),
value: component.pool_index,
change: ChangeType::Creation.into(),
}],
change: ChangeType::Creation.into(),
protocol_type: Some(ProtocolType {
name: "ambient_pool".to_string(),
attribute_schema: vec![],
financial_type: FinancialType::Swap.into(),
implementation_type: ImplementationType::Vm.into(),
}),
}
}
}

View File

@@ -1,4 +1,5 @@
mod contracts; mod contracts;
mod pb;
pub use modules::*; pub use modules::*;
mod modules; mod modules;

View File

@@ -20,24 +20,17 @@ use crate::{
decode_warm_path_user_cmd_call, AMBIENT_WARMPATH_CONTRACT, USER_CMD_WARMPATH_FN_SIG, decode_warm_path_user_cmd_call, AMBIENT_WARMPATH_CONTRACT, USER_CMD_WARMPATH_FN_SIG,
}, },
}, },
pb::tycho::ambient::v1::{AmbientBalanceDelta, BlockPoolChanges},
utils::from_u256_to_vec, utils::from_u256_to_vec,
}; };
use tycho_substreams::{
models::{AmbientBalanceDelta, BlockPoolChanges},
prelude::Transaction,
};
#[substreams::handlers::map] #[substreams::handlers::map]
fn map_pool_changes(block: eth::v2::Block) -> Result<BlockPoolChanges, substreams::errors::Error> { fn map_pool_changes(block: eth::v2::Block) -> Result<BlockPoolChanges, substreams::errors::Error> {
let mut protocol_components = Vec::new();
let mut balance_deltas = Vec::new(); let mut balance_deltas = Vec::new();
let mut protocol_components = Vec::new();
for block_tx in block.transactions() { for block_tx in block.transactions() {
let tx = Transaction { let tx_index = block_tx.index as u64;
hash: block_tx.hash.clone(),
from: block_tx.from.clone(),
to: block_tx.to.clone(),
index: block_tx.index as u64,
};
// extract storage changes // extract storage changes
let mut storage_changes = block_tx let mut storage_changes = block_tx
.calls .calls
@@ -66,7 +59,7 @@ fn map_pool_changes(block: eth::v2::Block) -> Result<BlockPoolChanges, substream
if call.address == AMBIENT_CONTRACT && selector == USER_CMD_FN_SIG { if call.address == AMBIENT_CONTRACT && selector == USER_CMD_FN_SIG {
// Extract pool creations // Extract pool creations
if let Some(protocol_component) = decode_pool_init(call, tx.clone())? { if let Some(protocol_component) = decode_pool_init(call, tx_index)? {
protocol_components.push(protocol_component); protocol_components.push(protocol_component);
} }
} }
@@ -109,19 +102,18 @@ fn map_pool_changes(block: eth::v2::Block) -> Result<BlockPoolChanges, substream
token_type: "base".to_string(), token_type: "base".to_string(),
token_delta: from_u256_to_vec(base_flow), token_delta: from_u256_to_vec(base_flow),
ordinal: call.index as u64, ordinal: call.index as u64,
tx: Some(tx.clone()), tx_index,
}; };
let quote_balance_delta = AmbientBalanceDelta { let quote_balance_delta = AmbientBalanceDelta {
pool_hash: Vec::from(pool_hash), pool_hash: Vec::from(pool_hash),
token_type: "quote".to_string(), token_type: "quote".to_string(),
token_delta: from_u256_to_vec(quote_flow), token_delta: from_u256_to_vec(quote_flow),
ordinal: call.index as u64, ordinal: call.index as u64,
tx: Some(tx.clone()), tx_index,
}; };
balance_deltas.extend([base_balance_delta.clone(), quote_balance_delta.clone()]); balance_deltas.extend([base_balance_delta.clone(), quote_balance_delta.clone()]);
} }
} }
balance_deltas.sort_by_key(|delta| (delta.ordinal, delta.token_type.clone())); balance_deltas.sort_by_key(|delta| (delta.ordinal, delta.token_type.clone()));
let pool_changes = BlockPoolChanges { protocol_components, balance_deltas }; Ok(BlockPoolChanges { balance_deltas, new_components: protocol_components })
Ok(pool_changes)
} }

View File

@@ -2,12 +2,12 @@ use substreams::{
scalar::BigInt, scalar::BigInt,
store::{StoreAdd, StoreAddBigInt, StoreNew}, store::{StoreAdd, StoreAddBigInt, StoreNew},
}; };
use tycho_substreams::models::BlockPoolChanges;
use crate::pb::tycho::ambient::v1::BlockPoolChanges;
#[substreams::handlers::store] #[substreams::handlers::store]
pub fn store_pool_balances(changes: BlockPoolChanges, balance_store: StoreAddBigInt) { pub fn store_pool_balances(changes: BlockPoolChanges, balance_store: StoreAddBigInt) {
let deltas = changes.balance_deltas.clone(); for balance_delta in changes.balance_deltas {
for balance_delta in deltas {
let pool_hash_hex = hex::encode(&balance_delta.pool_hash); let pool_hash_hex = hex::encode(&balance_delta.pool_hash);
balance_store.add( balance_store.add(
balance_delta.ordinal, balance_delta.ordinal,

View File

@@ -1,9 +1,12 @@
use substreams::store::{StoreNew, StoreSet, StoreSetProto}; use substreams::store::{StoreNew, StoreSet, StoreSetProto};
use tycho_substreams::models::{BlockPoolChanges, ProtocolComponent}; use tycho_substreams::models::ProtocolComponent;
use crate::pb::tycho::ambient::v1::BlockPoolChanges;
#[substreams::handlers::store] #[substreams::handlers::store]
pub fn store_pools(changes: BlockPoolChanges, component_store: StoreSetProto<ProtocolComponent>) { pub fn store_pools(changes: BlockPoolChanges, component_store: StoreSetProto<ProtocolComponent>) {
for component in changes.protocol_components { for component in changes.new_components {
component_store.set(0, component.id.clone(), &component); let protocol_component: ProtocolComponent = component.into();
component_store.set(0, protocol_component.id.clone(), &protocol_component);
} }
} }

View File

@@ -3,14 +3,16 @@ use std::{
collections::{hash_map::Entry, HashMap}, collections::{hash_map::Entry, HashMap},
str::FromStr, str::FromStr,
}; };
use substreams::pb::substreams::StoreDeltas; use substreams::{
pb::substreams::StoreDeltas,
store::{StoreGet, StoreGetProto},
};
use substreams_ethereum::pb::eth::{self}; use substreams_ethereum::pb::eth::{self};
use crate::contracts::main::AMBIENT_CONTRACT;
use substreams::store::{StoreGet, StoreGetProto};
use tycho_substreams::prelude::*; use tycho_substreams::prelude::*;
use crate::{contracts::main::AMBIENT_CONTRACT, pb::tycho::ambient::v1::BlockPoolChanges};
struct SlotValue { struct SlotValue {
new_value: Vec<u8>, new_value: Vec<u8>,
start_value: Vec<u8>, start_value: Vec<u8>,
@@ -74,10 +76,10 @@ fn map_changes(
block_pool_changes: BlockPoolChanges, block_pool_changes: BlockPoolChanges,
balance_store: StoreDeltas, balance_store: StoreDeltas,
pool_store: StoreGetProto<ProtocolComponent>, pool_store: StoreGetProto<ProtocolComponent>,
) -> Result<BlockContractChanges, substreams::errors::Error> { ) -> Result<BlockChanges, substreams::errors::Error> {
let mut block_changes = BlockContractChanges::default(); let mut block_changes = BlockChanges::default();
let mut tx_change = TransactionContractChanges::default(); let mut transaction_changes = TransactionChanges::default();
let mut changed_contracts: HashMap<Vec<u8>, InterimContractChange> = HashMap::new(); let mut changed_contracts: HashMap<Vec<u8>, InterimContractChange> = HashMap::new();
@@ -93,6 +95,13 @@ fn map_changes(
.collect(); .collect();
for block_tx in block.transactions() { for block_tx in block.transactions() {
let tx = Transaction {
hash: block_tx.hash.clone(),
from: block_tx.from.clone(),
to: block_tx.to.clone(),
index: block_tx.index as u64,
};
// extract storage changes // extract storage changes
let mut storage_changes = block_tx let mut storage_changes = block_tx
.calls .calls
@@ -244,44 +253,37 @@ fn map_changes(
// if there were any changes, add transaction and push the changes // if there were any changes, add transaction and push the changes
if !storage_changes.is_empty() || !balance_changes.is_empty() || !code_changes.is_empty() { if !storage_changes.is_empty() || !balance_changes.is_empty() || !code_changes.is_empty() {
tx_change.tx = Some(Transaction { transaction_changes.tx = Some(tx.clone());
hash: block_tx.hash.clone(),
from: block_tx.from.clone(),
to: block_tx.to.clone(),
index: block_tx.index as u64,
});
// reuse changed_contracts hash map by draining it, next iteration // reuse changed_contracts hash map by draining it, next iteration
// will start empty. This avoids a costly reallocation // will start empty. This avoids a costly reallocation
for (_, change) in changed_contracts.drain() { for (_, change) in changed_contracts.drain() {
tx_change transaction_changes
.contract_changes .contract_changes
.push(change.into()) .push(change.into())
} }
block_changes block_changes
.changes .changes
.push(tx_change.clone()); .push(transaction_changes.clone());
// clear out the interim contract changes after we pushed those. // clear out the interim contract changes after we pushed those.
tx_change.tx = None; transaction_changes.tx = None;
tx_change.contract_changes.clear(); transaction_changes
.contract_changes
.clear();
} }
} }
// extract new protocol components
let mut grouped_components = HashMap::new(); let mut grouped_components = HashMap::new();
for component in &block_pool_changes.protocol_components { for component in &block_pool_changes.new_components {
let tx_hash = component
.tx
.clone()
.expect("Transaction is missing")
.hash;
grouped_components grouped_components
.entry(tx_hash) .entry(component.tx_index)
.or_insert_with(Vec::new) .or_insert_with(Vec::new)
.push(component.clone()); .push(component.clone());
} }
for (tx_index, components) in grouped_components {
for (tx_hash, components) in grouped_components {
if let Some(tx_change) = block_changes if let Some(tx_change) = block_changes
.changes .changes
.iter_mut() .iter_mut()
@@ -290,14 +292,20 @@ fn map_changes(
tx_change tx_change
.tx .tx
.as_ref() .as_ref()
.is_some_and(|tx| tx.hash == tx_hash) .is_some_and(|tx| tx.index == tx_index)
}) })
{ {
let new_components = components
.into_iter()
.map(Into::into)
.collect::<Vec<ProtocolComponent>>();
tx_change tx_change
.component_changes .component_changes
.extend(components); .extend(new_components);
} }
} }
// extract component balance changes
let mut balance_changes = HashMap::new(); let mut balance_changes = HashMap::new();
balance_store balance_store
.deltas .deltas
@@ -323,17 +331,12 @@ fn map_changes(
token: pool.tokens[token_index].clone(), token: pool.tokens[token_index].clone(),
balance: big_endian_bytes_balance.to_vec(), balance: big_endian_bytes_balance.to_vec(),
}; };
let tx_hash = balance_delta
.tx
.expect("Transaction is missing")
.hash;
balance_changes balance_changes
.entry(tx_hash) .entry(balance_delta.tx_index)
.or_insert_with(Vec::new) .or_insert_with(Vec::new)
.push(balance_change); .push(balance_change);
}); });
for (tx_index, grouped_balance_changes) in balance_changes {
for (tx_hash, grouped_balance_changes) in balance_changes {
if let Some(tx_change) = block_changes if let Some(tx_change) = block_changes
.changes .changes
.iter_mut() .iter_mut()
@@ -342,7 +345,7 @@ fn map_changes(
tx_change tx_change
.tx .tx
.as_ref() .as_ref()
.is_some_and(|tx| tx.hash == tx_hash) .is_some_and(|tx| tx.index == tx_index)
}) })
{ {
tx_change tx_change

View File

@@ -0,0 +1,10 @@
// @generated
pub mod tycho {
pub mod ambient {
// @@protoc_insertion_point(attribute:tycho.ambient.v1)
pub mod v1 {
include!("tycho.ambient.v1.rs");
// @@protoc_insertion_point(tycho.ambient.v1)
}
}
}

View File

@@ -15,9 +15,25 @@ pub struct AmbientBalanceDelta {
/// Used to determine the order of the balance changes. Necessary for the balance store. /// Used to determine the order of the balance changes. Necessary for the balance store.
#[prost(uint64, tag="4")] #[prost(uint64, tag="4")]
pub ordinal: u64, pub ordinal: u64,
/// Transaction where the balance changed. /// Transaction index of the balance change
#[prost(message, optional, tag="5")] #[prost(uint64, tag="5")]
pub tx: ::core::option::Option<super::super::evm::v1::Transaction>, pub tx_index: u64,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct AmbientProtocolComponent {
/// A unique identifier for the component within the protocol.
#[prost(string, tag="1")]
pub id: ::prost::alloc::string::String,
/// Addresses of the ERC20 tokens used by the component.
#[prost(bytes="vec", repeated, tag="2")]
pub tokens: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec<u8>>,
/// Ambient pool index [static attribute for ambient pools]
#[prost(bytes="vec", tag="3")]
pub pool_index: ::prost::alloc::vec::Vec<u8>,
/// Transaction index for the component creation
#[prost(uint64, tag="4")]
pub tx_index: u64,
} }
/// Ambient pool changes within a single block /// Ambient pool changes within a single block
#[allow(clippy::derive_partial_eq_without_eq)] #[allow(clippy::derive_partial_eq_without_eq)]
@@ -25,8 +41,8 @@ pub struct AmbientBalanceDelta {
pub struct BlockPoolChanges { pub struct BlockPoolChanges {
/// New protocol components added in this block /// New protocol components added in this block
#[prost(message, repeated, tag="1")] #[prost(message, repeated, tag="1")]
pub protocol_components: ::prost::alloc::vec::Vec<super::super::evm::v1::ProtocolComponent>, pub new_components: ::prost::alloc::vec::Vec<AmbientProtocolComponent>,
/// Balance changes to pools in this block /// Balance changes on this block
#[prost(message, repeated, tag="2")] #[prost(message, repeated, tag="2")]
pub balance_deltas: ::prost::alloc::vec::Vec<AmbientBalanceDelta>, pub balance_deltas: ::prost::alloc::vec::Vec<AmbientBalanceDelta>,
} }

View File

@@ -1,21 +1,20 @@
specVersion: v0.1.0 specVersion: v0.1.0
package: package:
name: "substreams_ethereum_ambient" name: "substreams_ethereum_ambient"
version: v0.5.1 version: v0.6.0
protobuf: protobuf:
files: files:
- tycho/evm/v1/common.proto - tycho/evm/v1/common.proto
- tycho/evm/v1/vm.proto
- ambient.proto - ambient.proto
importPaths: importPaths:
- ./proto/v1 - ./proto
- ../../proto/ - ../../proto
binaries: binaries:
default: default:
type: wasm/rust-v1 type: wasm/rust-v1
file: ../../target/wasm32-unknown-unknown/substreams/substreams_ethereum_ambient.wasm file: ../target/wasm32-unknown-unknown/release/substreams_ethereum_ambient.wasm
modules: modules:
- name: map_pool_changes - name: map_pool_changes
@@ -24,7 +23,7 @@ modules:
inputs: inputs:
- source: sf.ethereum.type.v2.Block - source: sf.ethereum.type.v2.Block
output: output:
type: proto:tycho.evm.v1.BlockPoolChanges type: proto:tycho.ambient.v1.BlockPoolChanges
- name: store_pools - name: store_pools
kind: store kind: store
initialBlock: 17361664 initialBlock: 17361664
@@ -49,4 +48,4 @@ modules:
mode: deltas mode: deltas
- store: store_pools - store: store_pools
output: output:
type: proto:tycho.evm.v1.BlockContractChanges type: proto:tycho.evm.v1.BlockChanges