refactor(curve): stateless contracts as state attribute instead of static.

This commit is contained in:
Florian Pellissier
2024-08-15 10:42:06 +02:00
parent 420cf13466
commit c218252548
7 changed files with 775 additions and 679 deletions

View File

@@ -36,63 +36,69 @@ impl PartialEq for TransactionWrapper {
}
#[substreams::handlers::map]
pub fn map_components(
params: String,
block: eth::v2::Block,
) -> Result<BlockTransactionProtocolComponents> {
// Gather contract changes by indexing `PoolCreated` events and analysing the `Create` call
// We store these as a hashmap by tx hash since we need to agg by tx hash later
Ok(BlockTransactionProtocolComponents {
tx_components: block
.transactions()
.filter_map(|tx| {
let mut components = tx
.logs_with_calls()
.filter(|(_, call)| !call.call.state_reverted)
.filter_map(|(log, call)| {
pool_factories::address_map(
call.call
.address
.as_slice()
.try_into()
.ok()?, // this shouldn't fail
log,
call.call,
tx,
)
})
.collect::<Vec<_>>();
// Map all created components and their related entity changes.
pub fn map_components(params: String, block: eth::v2::Block) -> Result<BlockChanges> {
let changes = block
.transactions()
.filter_map(|tx| {
let mut entity_changes = vec![];
let mut components = vec![];
if let Some(component) = emit_specific_pools(&params, tx).expect(
"An unexpected error occured when parsing params for emitting specific pools",
for (log, call) in tx
.logs_with_calls()
.filter(|(_, call)| !call.call.state_reverted)
{
if let Some((component, mut state)) = pool_factories::address_map(
call.call
.address
.as_slice()
.try_into()
.ok()?, // this shouldn't fail
log,
call.call,
tx,
) {
components.push(component)
entity_changes.append(&mut state);
components.push(component);
}
}
if !components.is_empty() {
Some(TransactionProtocolComponents {
tx: Some(Transaction {
hash: tx.hash.clone(),
from: tx.from.clone(),
to: tx.to.clone(),
index: Into::<u64>::into(tx.index),
}),
components,
})
} else {
None
}
})
.collect::<Vec<_>>(),
})
if let Some((component, mut state)) = emit_specific_pools(&params, tx).expect(
"An unexpected error occured when parsing params for emitting specific pools",
) {
entity_changes.append(&mut state);
components.push(component);
}
if components.is_empty() {
None
} else {
Some(TransactionChanges {
tx: Some(Transaction {
hash: tx.hash.clone(),
from: tx.from.clone(),
to: tx.to.clone(),
index: tx.index.into(),
}),
contract_changes: vec![],
entity_changes,
component_changes: components,
balance_changes: vec![],
})
}
})
.collect::<Vec<_>>();
Ok(BlockChanges { block: None, changes })
}
/// Simply stores the `ProtocolComponent`s with the pool id as the key and tokens as the value
/// Get result `map_components` and stores the created `ProtocolComponent`s with the pool id as the
/// key and tokens as the value
#[substreams::handlers::store]
pub fn store_component_tokens(map: BlockTransactionProtocolComponents, store: StoreSetString) {
map.tx_components
pub fn store_component_tokens(map: BlockChanges, store: StoreSetString) {
map.changes
.iter()
.flat_map(|tx_components| &tx_components.components)
.flat_map(|tx_changes| &tx_changes.component_changes)
.for_each(|component| {
store.set(
0,
@@ -110,10 +116,10 @@ pub fn store_component_tokens(map: BlockTransactionProtocolComponents, store: St
/// pool.
/// This is later used to index them with `extract_contract_changes`
#[substreams::handlers::store]
pub fn store_non_component_accounts(map: BlockTransactionProtocolComponents, store: StoreSetInt64) {
map.tx_components
pub fn store_non_component_accounts(map: BlockChanges, store: StoreSetInt64) {
map.changes
.iter()
.flat_map(|tx_components| &tx_components.components)
.flat_map(|tx_changes| &tx_changes.component_changes)
.for_each(|component| {
// Crypto pool factory creates LP token separated from the pool, we need to index it so
// we add it to the store if the new protocol component comes from this factory
@@ -194,7 +200,7 @@ pub fn store_balances(deltas: BlockBalanceDeltas, store: StoreAddBigInt) {
#[substreams::handlers::map]
pub fn map_protocol_changes(
block: eth::v2::Block,
grouped_components: BlockTransactionProtocolComponents,
grouped_components: BlockChanges,
deltas: BlockBalanceDeltas,
components_store: StoreGetString,
non_component_accounts_store: StoreGetInt64,
@@ -204,14 +210,14 @@ pub fn map_protocol_changes(
// sort them at the very end.
let mut transaction_changes: HashMap<_, TransactionChanges> = HashMap::new();
// `ProtocolComponents` are gathered from `map_pools_created` which just need a bit of work to
// convert into `TransactionChanges`
// `ProtocolComponents` are gathered with some entity changes from `map_pools_created` which
// just need a bit of work to convert into `TransactionChanges`
grouped_components
.tx_components
.changes
.into_iter()
.for_each(|tx_component| {
let tx = tx_component.tx.as_ref().unwrap();
transaction_changes
.for_each(|tx_changes| {
let tx = tx_changes.tx.as_ref().unwrap();
let transaction_entry = transaction_changes
.entry(tx.index)
.or_insert_with(|| TransactionChanges {
tx: Some(tx.clone()),
@@ -219,18 +225,23 @@ pub fn map_protocol_changes(
component_changes: vec![],
balance_changes: vec![],
entity_changes: vec![],
})
});
let formated_components: Vec<_> = tx_changes //TODO: format directly at creation
.component_changes
.extend_from_slice(
&(tx_component
.components
.into_iter()
.map(|mut component| {
component.id = format!("0x{}", component.id);
component
})
.collect::<Vec<_>>()),
);
.into_iter()
.map(|mut component| {
component.id = format!("0x{}", component.id);
component
})
.collect();
transaction_entry
.component_changes
.extend(formated_components);
transaction_entry
.entity_changes
.extend(tx_changes.entity_changes);
});
// Balance changes are gathered by the `StoreDelta` based on `TokenExchange`, etc. creating

File diff suppressed because it is too large Load Diff

View File

@@ -12,6 +12,8 @@ struct PoolQueryParams {
contracts: Option<Vec<String>>,
tx_hash: String,
tokens: Vec<String>,
static_attribute_keys: Option<Vec<String>>,
static_attribute_vals: Option<Vec<String>>,
attribute_keys: Option<Vec<String>>,
attribute_vals: Option<Vec<String>>,
}
@@ -32,7 +34,7 @@ struct PoolQueryParams {
pub fn emit_specific_pools(
params: &str,
tx: &TransactionTrace,
) -> Result<Option<ProtocolComponent>> {
) -> Result<Option<(ProtocolComponent, Vec<EntityChanges>)>> {
let pools = parse_params(params)?;
create_component(tx, pools)
}
@@ -40,61 +42,81 @@ pub fn emit_specific_pools(
fn create_component(
tx: &TransactionTrace,
pools: HashMap<String, PoolQueryParams>,
) -> Result<Option<ProtocolComponent>> {
) -> Result<Option<(ProtocolComponent, Vec<EntityChanges>)>> {
let encoded_hash = hex::encode(tx.hash.clone());
if let Some(pool) = pools.get(&encoded_hash) {
Ok(Some(ProtocolComponent {
id: pool.address.clone(),
tx: Some(Transaction {
to: tx.to.clone(),
from: tx.from.clone(),
hash: tx.hash.clone(),
index: tx.index.into(),
}),
tokens: pool
.tokens
.clone()
.into_iter()
.map(|token| Result::Ok(hex::decode(token)?))
.collect::<Result<Vec<_>>>()
.with_context(|| "Token addresses were not formatted properly")?,
static_att: zip(
pool.attribute_keys
Ok(Some((
ProtocolComponent {
id: pool.address.clone(),
tx: Some(Transaction {
to: tx.to.clone(),
from: tx.from.clone(),
hash: tx.hash.clone(),
index: tx.index.into(),
}),
tokens: pool
.tokens
.clone()
.unwrap_or(vec![]),
pool.attribute_vals
.clone()
.unwrap_or(vec![]),
)
.clone()
.map(|(key, value)| Attribute {
name: key,
value: value.into(),
change: ChangeType::Creation.into(),
})
.collect::<Vec<_>>(),
contracts: pool
.contracts
.into_iter()
.map(|token| Result::Ok(hex::decode(token)?))
.collect::<Result<Vec<_>>>()
.with_context(|| "Token addresses were not formatted properly")?,
static_att: zip(
pool.static_attribute_keys
.clone()
.unwrap_or(vec![]),
pool.static_attribute_vals
.clone()
.unwrap_or(vec![]),
)
.clone()
.unwrap_or_default()
.into_iter()
.map(|contract| {
hex::decode(contract)
.with_context(|| "Pool contracts was not formatted properly")
.map(|(key, value)| Attribute {
name: key,
value: value.into(),
change: ChangeType::Creation.into(),
})
.chain(std::iter::once(
hex::decode(&pool.address)
.with_context(|| "Pool address was not formatted properly"),
))
.collect::<Result<Vec<Vec<u8>>>>()?,
change: ChangeType::Creation.into(),
protocol_type: Some(ProtocolType {
name: "curve_pool".into(),
financial_type: FinancialType::Swap.into(),
attribute_schema: Vec::new(),
implementation_type: ImplementationType::Vm.into(),
}),
}))
.collect::<Vec<_>>(),
contracts: pool
.contracts
.clone()
.unwrap_or_default()
.into_iter()
.map(|contract| {
hex::decode(contract)
.with_context(|| "Pool contracts was not formatted properly")
})
.chain(std::iter::once(
hex::decode(&pool.address)
.with_context(|| "Pool address was not formatted properly"),
))
.collect::<Result<Vec<Vec<u8>>>>()?,
change: ChangeType::Creation.into(),
protocol_type: Some(ProtocolType {
name: "curve_pool".into(),
financial_type: FinancialType::Swap.into(),
attribute_schema: Vec::new(),
implementation_type: ImplementationType::Vm.into(),
}),
},
vec![EntityChanges {
component_id: format!("0x{}", pool.address.clone()),
attributes: zip(
pool.attribute_keys
.clone()
.unwrap_or(vec![]),
pool.attribute_vals
.clone()
.unwrap_or(vec![]),
)
.clone()
.map(|(key, value)| Attribute {
name: key,
value: value.into(),
change: ChangeType::Creation.into(),
})
.collect::<Vec<_>>(),
}],
)))
} else {
Ok(None)
}
@@ -134,6 +156,8 @@ mod tests {
"0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48".to_string(),
"0xdac17f958d2ee523a2206206994597c13d831ec7".to_string(),
],
static_attribute_keys: None,
static_attribute_vals: None,
attribute_keys: Some(vec!["key1".to_string()]),
attribute_vals: Some(vec!["val1".to_string()]),
},