From 28dd2fc858eacb6af8a1f6da90f37a1479bd466e Mon Sep 17 00:00:00 2001 From: Louise Poole Date: Thu, 23 Jan 2025 11:00:12 +0200 Subject: [PATCH] feat: add AccountBalanceChange proto message (#137) --- proto/tycho/evm/v1/common.proto | 11 +- .../crates/tycho-substreams/src/models.rs | 7 + .../tycho-substreams/src/pb/tycho.evm.v1.rs | 163 +++++++++--------- 3 files changed, 102 insertions(+), 79 deletions(-) diff --git a/proto/tycho/evm/v1/common.proto b/proto/tycho/evm/v1/common.proto index cfead81..9f6386a 100644 --- a/proto/tycho/evm/v1/common.proto +++ b/proto/tycho/evm/v1/common.proto @@ -55,7 +55,6 @@ enum FinancialType{ PSM = 3; } - enum ImplementationType { VM = 0; CUSTOM = 1; @@ -128,6 +127,14 @@ message ContractSlot { bytes value = 3; } +// A struct for following the token balance changes for a contract. +message AccountBalanceChange { + // The address of the ERC20 token whose balance changed. + bytes token = 1; + // The new balance of the token. Note: it must be a big endian encoded int. + bytes balance = 2; +} + // Changes made to a single contract's state. message ContractChange { // The contract's address @@ -140,6 +147,8 @@ message ContractChange { repeated ContractSlot slots = 4; // Whether this is an update, a creation or a deletion. ChangeType change = 5; + // The new ERC20 balances of the contract. + repeated AccountBalanceChange token_balances = 6; } // Aggregate entities diff --git a/substreams/crates/tycho-substreams/src/models.rs b/substreams/crates/tycho-substreams/src/models.rs index 969710e..fb2a1d8 100644 --- a/substreams/crates/tycho-substreams/src/models.rs +++ b/substreams/crates/tycho-substreams/src/models.rs @@ -467,6 +467,7 @@ pub struct InterimContractChange { code: Vec, slots: HashMap, SlotValue>, change: ChangeType, + token_balances: HashMap, Vec>, } impl InterimContractChange { @@ -477,6 +478,7 @@ impl InterimContractChange { code: vec![], slots: Default::default(), change: if creation { ChangeType::Creation } else { ChangeType::Update }, + token_balances: Default::default(), } } @@ -530,6 +532,11 @@ impl From for Option { .map(|(slot, value)| ContractSlot { slot, value: value.new_value }) .collect(), change: value.change.into(), + token_balances: value + .token_balances + .into_iter() + .map(|(k, v)| AccountBalanceChange { token: k, balance: v }) + .collect(), }; if contract_change.is_empty() { None diff --git a/substreams/crates/tycho-substreams/src/pb/tycho.evm.v1.rs b/substreams/crates/tycho-substreams/src/pb/tycho.evm.v1.rs index effce40..f1a8fa8 100644 --- a/substreams/crates/tycho-substreams/src/pb/tycho.evm.v1.rs +++ b/substreams/crates/tycho-substreams/src/pb/tycho.evm.v1.rs @@ -6,16 +6,16 @@ #[derive(Clone, PartialEq, ::prost::Message)] pub struct Block { /// The blocks hash. - #[prost(bytes = "vec", tag = "1")] + #[prost(bytes="vec", tag="1")] pub hash: ::prost::alloc::vec::Vec, /// The parent blocks hash. - #[prost(bytes = "vec", tag = "2")] + #[prost(bytes="vec", tag="2")] pub parent_hash: ::prost::alloc::vec::Vec, /// The block number. - #[prost(uint64, tag = "3")] + #[prost(uint64, tag="3")] pub number: u64, /// The block timestamp. - #[prost(uint64, tag = "4")] + #[prost(uint64, tag="4")] pub ts: u64, } /// A struct describing a transaction. @@ -24,102 +24,96 @@ pub struct Block { #[derive(Clone, PartialEq, ::prost::Message)] pub struct Transaction { /// The transaction hash. - #[prost(bytes = "vec", tag = "1")] + #[prost(bytes="vec", tag="1")] pub hash: ::prost::alloc::vec::Vec, /// The sender of the transaction. - #[prost(bytes = "vec", tag = "2")] + #[prost(bytes="vec", tag="2")] pub from: ::prost::alloc::vec::Vec, /// The receiver of the transaction. - #[prost(bytes = "vec", tag = "3")] + #[prost(bytes="vec", tag="3")] pub to: ::prost::alloc::vec::Vec, /// The transactions index within the block. /// TODO: should this be uint32? to match the type from the native substream type? - #[prost(uint64, tag = "4")] + #[prost(uint64, tag="4")] pub index: u64, } /// A custom struct representing an arbitrary attribute of a protocol component. -/// This is mainly used by the native integration to track the necessary information about the -/// protocol. +/// This is mainly used by the native integration to track the necessary information about the protocol. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Attribute { /// The name of the attribute. - #[prost(string, tag = "1")] + #[prost(string, tag="1")] pub name: ::prost::alloc::string::String, /// The value of the attribute. - #[prost(bytes = "vec", tag = "2")] + #[prost(bytes="vec", tag="2")] pub value: ::prost::alloc::vec::Vec, /// The type of change the attribute underwent. - #[prost(enumeration = "ChangeType", tag = "3")] + #[prost(enumeration="ChangeType", tag="3")] pub change: i32, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ProtocolType { - #[prost(string, tag = "1")] + #[prost(string, tag="1")] pub name: ::prost::alloc::string::String, - #[prost(enumeration = "FinancialType", tag = "2")] + #[prost(enumeration="FinancialType", tag="2")] pub financial_type: i32, - #[prost(message, repeated, tag = "3")] + #[prost(message, repeated, tag="3")] pub attribute_schema: ::prost::alloc::vec::Vec, - #[prost(enumeration = "ImplementationType", tag = "4")] + #[prost(enumeration="ImplementationType", tag="4")] pub implementation_type: i32, } /// A struct describing a part of the protocol. -/// -/// Note: For example this can be a UniswapV2 pair, that tracks the two ERC20 tokens used by the -/// pair, the component would represent a single contract. In case of VM integration, such component -/// would not need any attributes, because all the relevant info would be tracked via storage slots -/// and balance changes. It can also be a wrapping contract, like WETH, that has a constant price, -/// but it allows swapping tokens. This is why the name ProtocolComponent is used instead of "Pool" -/// or "Pair". +/// Note: For example this can be a UniswapV2 pair, that tracks the two ERC20 tokens used by the pair, +/// the component would represent a single contract. In case of VM integration, such component would +/// not need any attributes, because all the relevant info would be tracked via storage slots and balance changes. +/// It can also be a wrapping contract, like WETH, that has a constant price, but it allows swapping tokens. +/// This is why the name ProtocolComponent is used instead of "Pool" or "Pair". #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ProtocolComponent { /// A unique identifier for the component within the protocol. /// Can be e.g. a stringified address or a string describing the trading pair. - #[prost(string, tag = "1")] + #[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")] + #[prost(bytes="vec", repeated, tag="2")] pub tokens: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, /// Addresses of the contracts used by the component. /// Usually it is a single contract, but some protocols use multiple contracts. - #[prost(bytes = "vec", repeated, tag = "3")] + #[prost(bytes="vec", repeated, tag="3")] pub contracts: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, /// Static attributes of the component. /// These attributes MUST be immutable. If it can ever change, it should be given as an EntityChanges for this component id. /// The inner ChangeType of the attribute has to match the ChangeType of the ProtocolComponent. - #[prost(message, repeated, tag = "4")] + #[prost(message, repeated, tag="4")] pub static_att: ::prost::alloc::vec::Vec, /// Type of change the component underwent. - #[prost(enumeration = "ChangeType", tag = "5")] + #[prost(enumeration="ChangeType", tag="5")] pub change: i32, /// / Represents the functionality of the component. - #[prost(message, optional, tag = "6")] + #[prost(message, optional, tag="6")] pub protocol_type: ::core::option::Option, /// Transaction where this component was created #[prost(message, optional, tag = "7")] pub tx: ::core::option::Option, } /// 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. E.g. for UniswapV2 pair WETH/USDC, this tracks the USDC and WETH balance -/// of the pair contract. +/// Note that if a ProtocolComponent contains multiple contracts, the TVL is tracked for the component as a whole. +/// E.g. for UniswapV2 pair WETH/USDC, this tracks the USDC and WETH balance of the pair contract. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct BalanceChange { /// The address of the ERC20 token whose balance changed. - #[prost(bytes = "vec", tag = "1")] + #[prost(bytes="vec", tag="1")] pub token: ::prost::alloc::vec::Vec, /// The new balance of the token. Note: it must be a big endian encoded int. - #[prost(bytes = "vec", tag = "2")] + #[prost(bytes="vec", tag="2")] pub balance: ::prost::alloc::vec::Vec, /// The id of the component whose TVL is tracked. Note: This MUST be utf8 encoded. - /// If the protocol component includes multiple contracts, the balance change must be - /// aggregated to reflect how much tokens can be traded. - #[prost(bytes = "vec", tag = "3")] + /// If the protocol component includes multiple contracts, the balance change must be aggregated to reflect how much tokens can be traded. + #[prost(bytes="vec", tag="3")] pub component_id: ::prost::alloc::vec::Vec, } // Native entities @@ -129,10 +123,10 @@ pub struct BalanceChange { #[derive(Clone, PartialEq, ::prost::Message)] pub struct EntityChanges { /// A unique identifier of the entity within the protocol. - #[prost(string, tag = "1")] + #[prost(string, tag="1")] pub component_id: ::prost::alloc::string::String, /// The set of attributes that are associated with the entity. - #[prost(message, repeated, tag = "2")] + #[prost(message, repeated, tag="2")] pub attributes: ::prost::alloc::vec::Vec, } // VM entities @@ -142,31 +136,45 @@ pub struct EntityChanges { #[derive(Clone, PartialEq, ::prost::Message)] pub struct ContractSlot { /// A contract's storage slot. - #[prost(bytes = "vec", tag = "2")] + #[prost(bytes="vec", tag="2")] pub slot: ::prost::alloc::vec::Vec, /// The new value for this storage slot. - #[prost(bytes = "vec", tag = "3")] + #[prost(bytes="vec", tag="3")] pub value: ::prost::alloc::vec::Vec, } +/// A struct for following the token balance changes for a contract. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AccountBalanceChange { + /// The address of the ERC20 token whose balance changed. + #[prost(bytes="vec", tag="1")] + pub token: ::prost::alloc::vec::Vec, + /// The new balance of the token. Note: it must be a big endian encoded int. + #[prost(bytes="vec", tag="2")] + pub balance: ::prost::alloc::vec::Vec, +} /// Changes made to a single contract's state. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ContractChange { /// The contract's address - #[prost(bytes = "vec", tag = "1")] + #[prost(bytes="vec", tag="1")] pub address: ::prost::alloc::vec::Vec, /// The new balance of the contract, empty bytes indicates no change. - #[prost(bytes = "vec", tag = "2")] + #[prost(bytes="vec", tag="2")] pub balance: ::prost::alloc::vec::Vec, /// The new code of the contract, empty bytes indicates no change. - #[prost(bytes = "vec", tag = "3")] + #[prost(bytes="vec", tag="3")] pub code: ::prost::alloc::vec::Vec, /// The changes to this contract's slots, empty sequence indicates no change. - #[prost(message, repeated, tag = "4")] + #[prost(message, repeated, tag="4")] pub slots: ::prost::alloc::vec::Vec, /// Whether this is an update, a creation or a deletion. - #[prost(enumeration = "ChangeType", tag = "5")] + #[prost(enumeration="ChangeType", tag="5")] pub change: i32, + /// The new ERC20 balances of the contract. + #[prost(message, repeated, tag="6")] + pub token_balances: ::prost::alloc::vec::Vec, } // Aggregate entities @@ -175,22 +183,21 @@ pub struct ContractChange { #[derive(Clone, PartialEq, ::prost::Message)] pub struct TransactionChanges { /// The transaction instance that results in the changes. - #[prost(message, optional, tag = "1")] + #[prost(message, optional, tag="1")] pub tx: ::core::option::Option, /// Contains the changes induced by the above transaction, aggregated on a per-contract basis. - /// Contains the contract changes induced by the above transaction, usually for tracking VM - /// components. - #[prost(message, repeated, tag = "2")] + /// Contains the contract changes induced by the above transaction, usually for tracking VM components. + #[prost(message, repeated, tag="2")] pub contract_changes: ::prost::alloc::vec::Vec, /// Contains the entity changes induced by the above transaction. /// Usually for tracking native components or used for VM extensions (plugins). - #[prost(message, repeated, tag = "3")] + #[prost(message, repeated, tag="3")] pub entity_changes: ::prost::alloc::vec::Vec, /// An array of newly added components. - #[prost(message, repeated, tag = "4")] + #[prost(message, repeated, tag="4")] pub component_changes: ::prost::alloc::vec::Vec, /// An array of balance changes to components. - #[prost(message, repeated, tag = "5")] + #[prost(message, repeated, tag="5")] pub balance_changes: ::prost::alloc::vec::Vec, } /// A set of transaction changes within a single block. @@ -199,10 +206,10 @@ pub struct TransactionChanges { #[derive(Clone, PartialEq, ::prost::Message)] pub struct BlockChanges { /// The block for which these changes are collectively computed. - #[prost(message, optional, tag = "1")] + #[prost(message, optional, tag="1")] pub block: ::core::option::Option, /// The set of transaction changes observed in the specified block. - #[prost(message, repeated, tag = "2")] + #[prost(message, repeated, tag="2")] pub changes: ::prost::alloc::vec::Vec, } /// Enum to specify the type of a change. @@ -302,15 +309,15 @@ impl ImplementationType { #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct TransactionEntityChanges { - #[prost(message, optional, tag = "1")] + #[prost(message, optional, tag="1")] pub tx: ::core::option::Option, - #[prost(message, repeated, tag = "2")] + #[prost(message, repeated, tag="2")] pub entity_changes: ::prost::alloc::vec::Vec, /// An array of newly added components. - #[prost(message, repeated, tag = "3")] + #[prost(message, repeated, tag="3")] pub component_changes: ::prost::alloc::vec::Vec, /// An array of balance changes to components. - #[prost(message, repeated, tag = "4")] + #[prost(message, repeated, tag="4")] pub balance_changes: ::prost::alloc::vec::Vec, } /// A set of transaction changes within a single block. @@ -318,10 +325,10 @@ pub struct TransactionEntityChanges { #[derive(Clone, PartialEq, ::prost::Message)] pub struct BlockEntityChanges { /// The block for which these changes are collectively computed. - #[prost(message, optional, tag = "1")] + #[prost(message, optional, tag="1")] pub block: ::core::option::Option, /// The set of transaction changes observed in the specified block. - #[prost(message, repeated, tag = "2")] + #[prost(message, repeated, tag="2")] pub changes: ::prost::alloc::vec::Vec, } /// A message containing relative balance changes. @@ -333,44 +340,44 @@ pub struct BlockEntityChanges { pub struct BalanceDelta { /// The ordinal of the balance change. Must be unique & deterministic over all balances /// changes within a block. - #[prost(uint64, tag = "1")] + #[prost(uint64, tag="1")] pub ord: u64, /// The tx hash of the transaction that caused the balance change. - #[prost(message, optional, tag = "2")] + #[prost(message, optional, tag="2")] pub tx: ::core::option::Option, /// The address of the ERC20 token whose balance changed. - #[prost(bytes = "vec", tag = "3")] + #[prost(bytes="vec", tag="3")] pub token: ::prost::alloc::vec::Vec, /// The delta balance of the token. - #[prost(bytes = "vec", tag = "4")] + #[prost(bytes="vec", tag="4")] pub delta: ::prost::alloc::vec::Vec, /// The id of the component whose TVL is tracked. /// If the protocol component includes multiple contracts, the balance change must be /// aggregated to reflect how much tokens can be traded. - #[prost(bytes = "vec", tag = "5")] + #[prost(bytes="vec", tag="5")] pub component_id: ::prost::alloc::vec::Vec, } /// A set of balances deltas, usually a group of changes within a single block. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct BlockBalanceDeltas { - #[prost(message, repeated, tag = "1")] + #[prost(message, repeated, tag="1")] pub balance_deltas: ::prost::alloc::vec::Vec, } /// A message containing protocol components that were created by a single tx. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct TransactionProtocolComponents { - #[prost(message, optional, tag = "1")] + #[prost(message, optional, tag="1")] pub tx: ::core::option::Option, - #[prost(message, repeated, tag = "2")] + #[prost(message, repeated, tag="2")] pub components: ::prost::alloc::vec::Vec, } /// All protocol components that were created within a block with their corresponding tx. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct BlockTransactionProtocolComponents { - #[prost(message, repeated, tag = "1")] + #[prost(message, repeated, tag="1")] pub tx_components: ::prost::alloc::vec::Vec, } // WARNING: DEPRECATED. Please use common.proto's TransactionChanges and BlockChanges instead. @@ -381,16 +388,16 @@ pub struct BlockTransactionProtocolComponents { #[derive(Clone, PartialEq, ::prost::Message)] pub struct TransactionContractChanges { /// The transaction instance that results in the changes. - #[prost(message, optional, tag = "1")] + #[prost(message, optional, tag="1")] pub tx: ::core::option::Option, /// Contains the changes induced by the above transaction, aggregated on a per-contract basis. - #[prost(message, repeated, tag = "2")] + #[prost(message, repeated, tag="2")] pub contract_changes: ::prost::alloc::vec::Vec, /// An array of newly added components. - #[prost(message, repeated, tag = "3")] + #[prost(message, repeated, tag="3")] pub component_changes: ::prost::alloc::vec::Vec, /// An array of balance changes to components. - #[prost(message, repeated, tag = "4")] + #[prost(message, repeated, tag="4")] pub balance_changes: ::prost::alloc::vec::Vec, } /// A set of transaction changes within a single block. @@ -398,10 +405,10 @@ pub struct TransactionContractChanges { #[derive(Clone, PartialEq, ::prost::Message)] pub struct BlockContractChanges { /// The block for which these changes are collectively computed. - #[prost(message, optional, tag = "1")] + #[prost(message, optional, tag="1")] pub block: ::core::option::Option, /// The set of transaction changes observed in the specified block. - #[prost(message, repeated, tag = "2")] + #[prost(message, repeated, tag="2")] pub changes: ::prost::alloc::vec::Vec, } // @@protoc_insertion_point(module)