Use manual updates on singleton template.
This commit is contained in:
@@ -7,6 +7,11 @@
|
|||||||
//! If your protocol supports native ETH, you may need to adjust the balance tracking
|
//! If your protocol supports native ETH, you may need to adjust the balance tracking
|
||||||
//! logic in `map_relative_component_balance` to account for native token handling.
|
//! logic in `map_relative_component_balance` to account for native token handling.
|
||||||
//!
|
//!
|
||||||
|
//! ## Assumptions
|
||||||
|
//! - Assumes each pool has a single newly deployed contract linked to it
|
||||||
|
//! - Assumes pool identifier equals the deployed contract address
|
||||||
|
//! - Assumes any price or liquidity updated correlates with a pools contract storage update.
|
||||||
|
//!
|
||||||
//! ## Alternative Module
|
//! ## Alternative Module
|
||||||
//! If your protocol uses a vault-like contract to manage balances, or if pools are
|
//! If your protocol uses a vault-like contract to manage balances, or if pools are
|
||||||
//! registered within a singleton contract, refer to the `ethereum-template-singleton`
|
//! registered within a singleton contract, refer to the `ethereum-template-singleton`
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
const INTERNAL_ERR: &'static str = "`ethabi_derive` internal error";
|
const INTERNAL_ERR: &'static str = "`ethabi_derive` internal error";
|
||||||
/// Contract's functions.
|
/// Contract's functions.
|
||||||
#[allow(dead_code, unused_imports, unused_variables)]
|
#[allow(dead_code, unused_imports, unused_variables)]
|
||||||
|
|||||||
@@ -4,6 +4,10 @@
|
|||||||
//! pattern. Usually these protocols employ a fixed set of contracts instead of
|
//! pattern. Usually these protocols employ a fixed set of contracts instead of
|
||||||
//! deploying new contracts per component.
|
//! deploying new contracts per component.
|
||||||
//!
|
//!
|
||||||
|
//! ## Assumptions
|
||||||
|
//! - Assumes a single vault contract is enough to simulate all swaps
|
||||||
|
//! - Assumes any price or liquidity change on a pool is linked to a tvl change
|
||||||
|
//!
|
||||||
//! ## Alternative Module
|
//! ## Alternative Module
|
||||||
//! If your protocol uses individual contracts deployed with a factory to manage
|
//! If your protocol uses individual contracts deployed with a factory to manage
|
||||||
//! components and balances, refer to the `ethereum-template-factory` substream for an
|
//! components and balances, refer to the `ethereum-template-factory` substream for an
|
||||||
@@ -17,10 +21,9 @@
|
|||||||
use crate::{pool_factories, pool_factories::DeploymentConfig};
|
use crate::{pool_factories, pool_factories::DeploymentConfig};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use prost::Message;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use substreams::{pb::substreams::StoreDeltas, prelude::*};
|
use substreams::{pb::substreams::StoreDeltas, prelude::*};
|
||||||
use substreams_ethereum::{block_view::CallView, pb::eth, Event};
|
use substreams_ethereum::pb::eth;
|
||||||
use tycho_substreams::{
|
use tycho_substreams::{
|
||||||
balances::aggregate_balances_changes, contract::extract_contract_changes_builder, prelude::*,
|
balances::aggregate_balances_changes, contract::extract_contract_changes_builder, prelude::*,
|
||||||
};
|
};
|
||||||
@@ -80,58 +83,60 @@ fn store_protocol_tokens(
|
|||||||
|
|
||||||
/// Extracts balance changes per component
|
/// Extracts balance changes per component
|
||||||
///
|
///
|
||||||
/// This template function inspects ERC20 transfer events to/from the singleton contract
|
/// This function parses protocol specific events that incur tvl changes into
|
||||||
/// to extract balance changes. If a transfer to the component is detected, it's
|
/// BalanceDelta structs.
|
||||||
/// balanced is increased and if a balance from the component is detected its balance
|
|
||||||
/// is decreased.
|
|
||||||
///
|
///
|
||||||
/// ## Note:
|
/// ## Note:
|
||||||
/// - If your protocol emits events that let you calculate balance deltas more efficiently you may
|
/// - You only need to account for balances that immediately available as liquidity, e.g. user
|
||||||
/// want to use those instead of raw transfers.
|
/// deposits or accumulated swap fees should not be accounted for.
|
||||||
/// - Changes are necessary if your protocol uses native ETH or your component burns or mints tokens
|
/// - Take special care if your protocol uses native ETH or your component burns or mints tokens.
|
||||||
/// without emitting transfer events.
|
/// - You may want to ignore LP tokens if the tvl is covered via regular erc20 tokens.
|
||||||
/// - You may want to ignore LP tokens if your protocol emits transfer events for these here.
|
|
||||||
#[substreams::handlers::map]
|
#[substreams::handlers::map]
|
||||||
fn map_relative_component_balance(
|
fn map_relative_component_balance(
|
||||||
params: String,
|
params: String,
|
||||||
block: eth::v2::Block,
|
block: eth::v2::Block,
|
||||||
store: StoreGetInt64,
|
_store: StoreGetInt64,
|
||||||
) -> Result<BlockBalanceDeltas> {
|
) -> Result<BlockBalanceDeltas> {
|
||||||
let config: DeploymentConfig = serde_qs::from_str(params.as_str())?;
|
let _config: DeploymentConfig = serde_qs::from_str(params.as_str())?;
|
||||||
let res = block
|
let res = block
|
||||||
.transactions()
|
.transactions()
|
||||||
.flat_map(|tx| {
|
.flat_map(|tx| {
|
||||||
tx.logs_with_calls()
|
tx.logs_with_calls()
|
||||||
.filter_map(|(log, call)| {
|
.map(|(_log, _call)| -> Vec<BalanceDelta> {
|
||||||
let token_addr_hex = hex::encode(&log.address);
|
/*
|
||||||
if !store.has_last(&token_addr_hex) {
|
TODO: Parse events/calls to extract balance deltas
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
crate::abi::erc20::events::Transfer::match_and_decode(log).map(|transfer| {
|
Please parse your protocols events here that incur tvl changes to
|
||||||
let to_addr = transfer.to.as_slice();
|
components and emit a BalanceChange event for each affected
|
||||||
let from_addr = transfer.from.as_slice();
|
component and token combination.
|
||||||
if let Some(component_id) = extract_component_id_from_call(call) {
|
|
||||||
if to_addr == config.vault_address {
|
## Example
|
||||||
return Some(BalanceDelta {
|
|
||||||
|
```rust
|
||||||
|
if let Some(ev) = core_events::Swapped::match_and_decode(log) {
|
||||||
|
let pool_id = hash_pool_key(&ev.pool_key);
|
||||||
|
vec![
|
||||||
|
BalanceDelta {
|
||||||
ord: log.ordinal,
|
ord: log.ordinal,
|
||||||
tx: Some(tx.into()),
|
tx: Some(tx.into()),
|
||||||
token: log.address.to_vec(),
|
token: ev.pool_key.0.clone(),
|
||||||
delta: transfer.value.to_signed_bytes_be(),
|
delta: ev.delta0.to_signed_bytes_be(),
|
||||||
component_id: component_id.encode_to_vec(),
|
component_id: pool_id.clone().into(),
|
||||||
});
|
},
|
||||||
} else if from_addr == config.vault_address {
|
BalanceDelta {
|
||||||
return Some(BalanceDelta {
|
|
||||||
ord: log.ordinal,
|
ord: log.ordinal,
|
||||||
tx: Some(tx.into()),
|
tx: Some(tx.into()),
|
||||||
token: log.address.to_vec(),
|
token: ev.pool_key.1.clone(),
|
||||||
delta: (transfer.value.neg()).to_signed_bytes_be(),
|
delta: &ev.delta1.to_signed_bytes_be(),
|
||||||
component_id: component_id.encode_to_vec(),
|
component_id: pool_id.into(),
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
]
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
}
|
}
|
||||||
None
|
```
|
||||||
})
|
*/
|
||||||
|
vec![]
|
||||||
})
|
})
|
||||||
.flatten()
|
.flatten()
|
||||||
})
|
})
|
||||||
@@ -140,12 +145,6 @@ fn map_relative_component_balance(
|
|||||||
Ok(BlockBalanceDeltas { balance_deltas: res })
|
Ok(BlockBalanceDeltas { balance_deltas: res })
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: given a relevant balance changing call associate it with the respective
|
|
||||||
// component
|
|
||||||
fn extract_component_id_from_call(_call: CallView) -> Option<String> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Aggregates relative balances values into absolute values
|
/// Aggregates relative balances values into absolute values
|
||||||
///
|
///
|
||||||
/// Aggregate the relative balances in an additive store since tycho-indexer expects
|
/// Aggregate the relative balances in an additive store since tycho-indexer expects
|
||||||
@@ -221,6 +220,11 @@ fn map_protocol_changes(
|
|||||||
token_bc_map.values().for_each(|bc| {
|
token_bc_map.values().for_each(|bc| {
|
||||||
// track component balance
|
// track component balance
|
||||||
builder.add_balance_change(bc);
|
builder.add_balance_change(bc);
|
||||||
|
// Mark this component as updates since we are using manual update tracking
|
||||||
|
// TODO: ensure this covers all cases a component should be marked as
|
||||||
|
let component_id =
|
||||||
|
String::from_utf8(bc.component_id.clone()).expect("bad component id");
|
||||||
|
builder.mark_component_as_updated(&component_id);
|
||||||
// track vault contract balance
|
// track vault contract balance
|
||||||
contract_changes
|
contract_changes
|
||||||
.upsert_token_balance(bc.token.as_slice(), bc.balance.as_slice())
|
.upsert_token_balance(bc.token.as_slice(), bc.balance.as_slice())
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use substreams_ethereum::pb::eth::v2::{Call, Log, TransactionTrace};
|
use substreams_ethereum::pb::eth::v2::{Call, Log, TransactionTrace};
|
||||||
use tycho_substreams::models::{
|
use tycho_substreams::models::{
|
||||||
ChangeType, FinancialType, ImplementationType, ProtocolComponent, ProtocolType,
|
Attribute, ChangeType, FinancialType, ImplementationType, ProtocolComponent, ProtocolType,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
@@ -31,10 +31,18 @@ pub fn maybe_create_component(
|
|||||||
// TODO: add the components tokens
|
// TODO: add the components tokens
|
||||||
],
|
],
|
||||||
contracts: vec![
|
contracts: vec![
|
||||||
// TODO: any contracts required during swapping
|
config.vault_address.clone(),
|
||||||
|
// TODO: any additional contracts required during swapping
|
||||||
],
|
],
|
||||||
static_att: vec![
|
static_att: vec![
|
||||||
// TODO: any additional metadata required, e.g. for swap encoding
|
// Singleton components are marked as manual updates since we can't
|
||||||
|
// infer component updates from vault storage updates. The template
|
||||||
|
// later sets update markers on components that had a balance change.
|
||||||
|
Attribute {
|
||||||
|
name: "manual_updates".to_string(),
|
||||||
|
value: vec![1u8],
|
||||||
|
change: ChangeType::Creation.into(),
|
||||||
|
}, // TODO: any additional metadata required, e.g. for swap encoding
|
||||||
],
|
],
|
||||||
change: ChangeType::Creation.into(),
|
change: ChangeType::Creation.into(),
|
||||||
protocol_type: Some(ProtocolType {
|
protocol_type: Some(ProtocolType {
|
||||||
|
|||||||
Reference in New Issue
Block a user