From 4d528ddab3209744039b8745a91cd3bffbbcc076 Mon Sep 17 00:00:00 2001 From: Florian Pellissier <111426680+flopell@users.noreply.github.com> Date: Wed, 31 Jul 2024 11:40:26 +0200 Subject: [PATCH] fix(curve): fix curve tests after SDKv2 update, also add a few missing tests --- .../integration_test.tycho.yaml | 125 +++++--- substreams/ethereum-curve/src/modules.rs | 58 +++- .../ethereum-curve/src/pool_factories.rs | 271 +++++++++++++++--- substreams/ethereum-curve/substreams.yaml | 9 + 4 files changed, 383 insertions(+), 80 deletions(-) diff --git a/substreams/ethereum-curve/integration_test.tycho.yaml b/substreams/ethereum-curve/integration_test.tycho.yaml index 6552c25..fdb4361 100644 --- a/substreams/ethereum-curve/integration_test.tycho.yaml +++ b/substreams/ethereum-curve/integration_test.tycho.yaml @@ -1,9 +1,11 @@ substreams_yaml_path: ./substreams.yaml protocol_type_names: - "curve_pool" -adapter_contract: "CurveSwapAdapter.evm.runtime" -skip_balance_check: false +adapter_contract: "CurveAdapter" +skip_balance_check: true +initialized_accounts: tests: + - name: test_3pool_creation start_block: 10809470 stop_block: 10810226 @@ -16,6 +18,8 @@ tests: - "0x6b175474e89094c44da98b954eedeac495271d0f" static_attributes: creation_tx: "0x20793bbf260912aae189d5d261ff003c9b9166da8191d8f9d63ff1c7722f3ac6" + skip_simulation: false + - name: test_steth_creation start_block: 11592550 stop_block: 11595553 @@ -27,31 +31,46 @@ tests: - "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84" static_attributes: creation_tx: "0xfac67ecbd423a5b915deff06045ec9343568edaec34ae95c43d35f2c018afdaa" + skip_simulation: false + - name: test_crypto_swap_ng_factory_plain_pool_creation - start_block: 19355220 - stop_block: 19356225 + start_block: 18580701 + stop_block: 18614742 + initialized_accounts: + - "0x6a8cbed756804b16e05e741edabd5cb544ae21bf" + - "0x0c0e5f2fF0ff18a3be9b835635039256dC4B4963" # Needed by another component that is created within this block range + - "0xbebc44782c7db0a1a60cb6fe97d0b483032ff1c7" expected_state: protocol_components: - - id: "0xeeda34a377dd0ca676b9511ee1324974fa8d980d" + - id: "0x02950460E2b9529D0E00284A5fA2d7bDF3fA4d72" tokens: - - "0xd9a442856c234a39a81a089c06451ebaa4306a72" - - "0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0" + - "0x4c9EDD5852cd905f086C759E8383e09bff1E68B3" + - "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" static_attributes: - creation_tx: "0x0e2bad5695d4ff8ebbaf668674a24bdcc4843da44933d947f2a454fd731da3c1" + creation_tx: "0x6f4438aa1785589e2170599053a0cdc740d8987746a4b5ad9614b6ab7bb4e550" + skip_simulation: false + - name: test_crypto_swap_ng_factory_meta_pool_creation start_block: 19216042 stop_block: 19217045 + initialized_accounts: + - "0x6a8cbed756804b16e05e741edabd5cb544ae21bf" # Factory, needed for implementations contrats queries + - "0xa5588f7cdf560811710a2d82d3c9c99769db1dcb" # Base pool of this meta pool expected_state: protocol_components: - id: "0xef484de8C07B6e2d732A92B5F78e81B38f99f95E" tokens: - "0x865377367054516e17014CcdED1e7d814EDC9ce4" - - "0xA5588F7cdf560811710A2D82D3C9c99769DB1Dcb" + - "0xa5588f7cdf560811710a2d82d3c9c99769db1dcb" static_attributes: creation_tx: "0x3cfeecae1b43086ee5705f89b803e21eb0492d7d5db06c229586db8fc72f5665" + skip_simulation: true # Reason: this pool use a base pool which is also one of its tokens, therefore our token override doesn't work here and it fails on transfers + - name: test_metapool_factory_metapool_creation - start_block: 18028600 + start_block: 18028604 stop_block: 18029610 + initialized_accounts: + - "0xdcef968d416a41cdac0ed8702fac8128a64241a2" expected_state: protocol_components: - id: "0x61fA2c947e523F9ABfb8d7e2903A5D5218C119a7" @@ -60,6 +79,8 @@ tests: - "0x3175Df0976dFA876431C2E9eE6Bc45b65d3473CC" static_attributes: creation_tx: "0xc9c6b879cbb19f7f26405335c3879c350592d530956878ff172e9efad786c63f" + skip_simulation: true # Reason: this pool calls `totalSupply()` on the LP token during simulation. But this token is overridden and doesn't have anything for totalSupply + - name: test_metapool_factory_plainpool_creation start_block: 18808555 stop_block: 18818577 @@ -71,12 +92,15 @@ tests: - "0x77E06c9eCCf2E797fd462A92B6D7642EF85b0A44" static_attributes: creation_tx: "0xeb34c90d352f18ffcfe78b7e393e155f0314acf06c54d1ac9996e4ee5a9b4742" + skip_simulation: false - id: "0x3f67dc2AdBA4B1beB6A48c30AB3AFb1c1440d35B" tokens: - "0xe9633C52f4c8B7BDeb08c4A7fE8a5c1B84AFCf67" - "0x77E06c9eCCf2E797fd462A92B6D7642EF85b0A44" static_attributes: creation_tx: "0x455559b43afaf429c15c1d807fd7f5dd47be30f6411a854499f719b944f4c024" + skip_simulation: true # Reason: this pool has no liquidity at stop_block + - name: test_cryptopool_factory_creation start_block: 19162590 stop_block: 19163633 @@ -88,15 +112,20 @@ tests: - "0x4591dbff62656e7859afe5e45f6f47d3669fbb28" static_attributes: creation_tx: "0xa89c09a7e0dfd84f3a294b8df4f33cc4a623e6d52deee357457afe2591ea596f" + skip_simulation: false - id: "0x6c9Fe53cC13b125d6476E5Ce2b76983bd5b7A112" tokens: - "0x35fA164735182de50811E8e2E824cFb9B6118ac2" - "0xf951E335afb289353dc249e82926178EaC7DEd78" static_attributes: creation_tx: "0xa5b13d50c56242f7994b8e1339032bb4c6f9ac3af3054d4eae3ce9e32e3c1a50" + skip_simulation: true # Reason: this pool has no liquidity at stop_block + - name: test_tricrypto_factory_creation start_block: 17371455 stop_block: 17374457 + initialized_accounts: + - "0x0c0e5f2ff0ff18a3be9b835635039256dc4b4963" expected_state: protocol_components: - id: "0x7F86Bf177Dd4F3494b841a37e810A34dD56c829B" @@ -106,38 +135,62 @@ tests: - "0x0000000000000000000000000000000000000000" static_attributes: creation_tx: "0x2bd59c19f993b83729fb23498f897a58567c6f0b3ee2f00613ba515a7b19fe23" + skip_simulation: false + - name: test_twocrypto_factory_creation - start_block: 19760009 - stop_block: 19763634 + start_block: 19692166 + stop_block: 19692232 + initialized_accounts: + - "0x98ee851a00abee0d95d08cf4ca2bdce32aeaaf7f" # Factory, needed for implementations contracts queries expected_state: protocol_components: - - id: "0x011e998d2d794424de95935d55a6ca81822ecb2b" + - id: "0x77146B0a1d08B6844376dF6d9da99bA7F1b19e71" tokens: - - "0x6c4a8973e6633da2da7187669479c27830c7b1c4" - - "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" + - "0x55C08ca52497e2f1534B59E2917BF524D4765257" + - "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" static_attributes: - creation_tx: "0x412b745a9467aed14f22d2a4cc30651939872d19cee65053f14dd3eb9d488003" - - id: "0x19d2b5ce188ca60790755204691e38102749297b" + creation_tx: "0x61d563e2627437da172fdd60ab54e5cc955fcb75829fd819486e857bac31cad2" + skip_simulation: false + + - name: test_stableswap_factory_plain_pool_creation + start_block: 17258004 + stop_block: 17260023 + expected_state: + protocol_components: + - id: "0x390f3595bCa2Df7d23783dFd126427CCeb997BF4" tokens: - - "0x6c4a8973e6633da2da7187669479c27830c7b1c4" - - "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" + - "0xf939E0A03FB07F59A73314E73794Be0E57ac1b4E" + - "0xdAC17F958D2ee523a2206206994597C13D831ec7" static_attributes: - creation_tx: "0x61118d9903f8344e5971d1e7c781f76e855996408dac979d3a4971cefafa6587" - - id: "0xb3341ca63b6cecf1e1a0d1a99bf0587f4c305652" + creation_tx: "0x40b25773bf8ea673434277d279af40a85b09072072e7004e9048a2ec0f0dd5a0" + skip_simulation: false + + # - name: test_stableswap_factory_meta_pool_creation + # There was no metapool created from this factory yet. + # TODO: Double check https://etherscan.io/address/0x4F8846Ae9380B90d2E71D5e3D042dff3E7ebb40d#events search events with topic 0x01f31cd2abdeb4e5e10ba500f2db0f937d9e8c735ab04681925441b4ea37eda5. + # Got the topic using: + # from web3 import Web3 + # + # def keccak(event): + # return Web3.keccak(text=event).hex() + # + # plain_pool_deployed = "PlainPoolDeployed(address[4],uint256,uint256,address,address)" + # meta_pool_deployed = "MetaPoolDeployed(address,address,uint256,uint256,address)" + # + # print(keccak(plain_pool_deployed)) + # print(keccak(meta_pool_deployed)) + + - name: test_metapool_factory_old + start_block: 11968730 + stop_block: 12028110 + initialized_accounts: + - "0xbebc44782c7db0a1a60cb6fe97d0b483032ff1c7" # Linked pool of this metapool + expected_state: + protocol_components: + - id: "0xd632f22692FaC7611d2AA1C0D552930D43CAEd3B" tokens: - - "0x6c4a8973e6633da2da7187669479c27830c7b1c4" - - "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" + - "0x853d955aCEf822Db058eb8505911ED77F175b99e" + - "0x6c3F90f043a72FA612cbac8115EE7e52BDe6E490" static_attributes: - creation_tx: "0xc69332294313b3a8f260e0d5b6a50f0d83707f715fbd8016c32ca61a39ce7ad5" - - id: "0x99ca0fbaa278cd62e26f0e9b6d167b07d1f0d51b" - tokens: - - "0x6c4a8973e6633da2da7187669479c27830c7b1c4" - - "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" - static_attributes: - creation_tx: "0xf2b0c697161f08384c642297e01b3a35f7ec00dd3871d4237a16ae4bb8a1ca99" - - id: "0xde73e407efc75edbafc5bcd62ebb1e7a9b38ebcd" - tokens: - - "0x0d86883faf4ffd7aeb116390af37746f45b6f378" - - "0x78da5799cf427fee11e9996982f4150ece7a99a7" - static_attributes: - creation_tx: "0xd4ad7efdcc16d797dd3494ba02b377da4127fd5b1bd25089858b66e5a7e456ab" + creation_tx: "0x1f2a0d4e1c1eca594bd7f27f9952480ccda422c3453e0c5074a63aa46a2ed628" + skip_simulation: true # Reason: this pool calls `totalSupply()` on the LP token during simulation. But this token is overridden and doesn't have anything for totalSupply diff --git a/substreams/ethereum-curve/src/modules.rs b/substreams/ethereum-curve/src/modules.rs index 59f75c9..8c63055 100644 --- a/substreams/ethereum-curve/src/modules.rs +++ b/substreams/ethereum-curve/src/modules.rs @@ -5,12 +5,19 @@ use itertools::Itertools; use substreams::{ pb::substreams::StoreDeltas, scalar::BigInt, - store::{StoreAddBigInt, StoreGet, StoreGetString, StoreNew, StoreSet, StoreSetString}, + store::{ + StoreAddBigInt, StoreGet, StoreGetInt64, StoreGetString, StoreNew, StoreSet, StoreSetInt64, + StoreSetString, + }, }; - use substreams_ethereum::pb::eth; -use crate::{pool_changes::emit_eth_deltas, pool_factories, pools::emit_specific_pools}; +use crate::{ + consts::{CRYPTO_SWAP_NG_FACTORY, TRICRYPTO_FACTORY}, + pool_changes::emit_eth_deltas, + pool_factories, + pools::emit_specific_pools, +}; use tycho_substreams::{ balances::{extract_balance_deltas_from_tx, store_balance_changes}, contract::extract_contract_changes, @@ -99,6 +106,43 @@ pub fn store_component_tokens(map: BlockTransactionProtocolComponents, store: St }); } +/// Stores contracts required by components, for example LP tokens if they are different from the +/// 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 + .iter() + .flat_map(|tx_components| &tx_components.components) + .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 + if component + .static_att + .contains(&Attribute { + name: "pool_type".into(), + value: "crypto_pool".into(), + change: ChangeType::Creation.into(), + }) && + component + .static_att + .contains(&Attribute { + name: "factory_name".into(), + value: "crypto_pool_factory".into(), + change: ChangeType::Creation.into(), + }) + { + let lp_token = component + .static_att + .iter() + .find(|attr| attr.name == "lp_token") + .unwrap() + .value + .clone(); + store.set(0, hex::encode(lp_token), &1); + } + }); +} + /// Since the `PoolBalanceChanged` events administer only deltas, we need to leverage a map and a /// store to be able to tally up final balances for tokens in a pool. #[substreams::handlers::map] @@ -153,6 +197,7 @@ pub fn map_protocol_changes( grouped_components: BlockTransactionProtocolComponents, deltas: BlockBalanceDeltas, components_store: StoreGetString, + non_component_accounts_store: StoreGetInt64, balance_store: StoreDeltas, // Note, this map module is using the `deltas` mode for the store. ) -> Result { // We merge contract changes by transaction (identified by transaction index) making it easy to @@ -242,7 +287,12 @@ pub fn map_protocol_changes( |addr| { components_store .get_last(format!("pool:{0}", hex::encode(addr))) - .is_some() + .is_some() || + non_component_accounts_store + .get_last(hex::encode(addr)) + .is_some() || + addr.eq(&CRYPTO_SWAP_NG_FACTORY) || + addr.eq(&TRICRYPTO_FACTORY) }, &mut transaction_changes, ); diff --git a/substreams/ethereum-curve/src/pool_factories.rs b/substreams/ethereum-curve/src/pool_factories.rs index cf3c658..4418022 100644 --- a/substreams/ethereum-curve/src/pool_factories.rs +++ b/substreams/ethereum-curve/src/pool_factories.rs @@ -1,3 +1,4 @@ +use substreams::hex; use substreams_ethereum::{ pb::eth::v2::{Call, Log, TransactionTrace}, Event, Function, @@ -66,9 +67,9 @@ fn swap_weth_for_eth(tokens: Vec>) -> Vec> { /// The basic flow of this function is as follows: /// - Match the factory address /// - Decode the relevant event from the log -/// - Attempt to decode the cooresponding function call (based on the permutation of the ABI) +/// - Attempt to decode the corresponding function call (based on the permutation of the ABI) /// - Optionally make an RPC call to produce further information (see metapools) -/// - Construct the cooresponding `ProtocolComponent` +/// - Construct the corresponding `ProtocolComponent` pub fn address_map( call_address: &[u8; 20], log: &Log, @@ -84,6 +85,12 @@ pub fn address_map( let component_id = &call.return_data[12..]; + let pool_implementation = abi::crypto_pool_factory::functions::PoolImplementation {} + .call(CRYPTO_POOL_FACTORY.to_vec())?; + + let token_implementation = abi::crypto_pool_factory::functions::TokenImplementation {} + .call(CRYPTO_POOL_FACTORY.to_vec())?; + Some(ProtocolComponent { id: hex::encode(component_id), tx: Some(Transaction { @@ -93,7 +100,7 @@ pub fn address_map( index: tx.index.into(), }), tokens, - contracts: vec![component_id.into()], + contracts: vec![component_id.into(), pool_added.token.clone()], static_att: vec![ Attribute { name: "pool_type".into(), @@ -115,6 +122,21 @@ pub fn address_map( value: address_to_bytes_with_0x(&CRYPTO_POOL_FACTORY), change: ChangeType::Creation.into(), }, + Attribute { + name: "lp_token".into(), + value: pool_added.token, + change: ChangeType::Creation.into(), + }, + Attribute { + name: "stateless_contract_addr_0".into(), + value: address_to_bytes_with_0x(&pool_implementation.try_into().unwrap()), + change: ChangeType::Creation.into(), + }, + Attribute { + name: "stateless_contract_addr_1".into(), + value: address_to_bytes_with_0x(&token_implementation.try_into().unwrap()), + change: ChangeType::Creation.into(), + }, ], change: ChangeType::Creation.into(), protocol_type: Some(ProtocolType { @@ -164,6 +186,17 @@ pub fn address_map( // The return data of several of these calls contain the actual component id let component_id = &call.return_data[12..]; + let tokens: Vec<_> = pool_added + .coins + .into_iter() + .filter(|token| *token != [0; 20]) + .collect(); + + let pool_implementation = abi::meta_pool_factory::functions::PlainImplementations { + arg0: BigInt::from(tokens.len()), + arg1: add_pool.implementation_idx, + } + .call(META_POOL_FACTORY.to_vec())?; Some(ProtocolComponent { id: hex::encode(component_id), @@ -173,11 +206,7 @@ pub fn address_map( hash: tx.hash.clone(), index: tx.index.into(), }), - tokens: pool_added - .coins - .into_iter() - .filter(|token| *token != [0; 20]) - .collect(), + tokens, contracts: vec![component_id.into()], static_att: vec![ Attribute { @@ -200,6 +229,13 @@ pub fn address_map( value: address_to_bytes_with_0x(&META_POOL_FACTORY), change: ChangeType::Creation.into(), }, + Attribute { + name: "stateless_contract_addr_0".into(), + value: address_to_bytes_with_0x( + &pool_implementation.try_into().unwrap(), + ), + change: ChangeType::Creation.into(), + }, ], change: ChangeType::Creation.into(), protocol_type: Some(ProtocolType { @@ -238,6 +274,14 @@ pub fn address_map( abi::meta_registry::functions::GetLpToken1 { pool: add_pool.base_pool.clone() }; let lp_token = get_lp_token.call(META_REGISTRY.to_vec())?; + let pool_implementation = + abi::meta_pool_factory::functions::MetapoolImplementations { + base_pool: add_pool.base_pool.clone(), + } + .call(META_POOL_FACTORY.to_vec())? + [usize::try_from(add_pool.implementation_idx.to_u64()).unwrap()] + .clone(); + Some(ProtocolComponent { id: hex::encode(component_id), tx: Some(Transaction { @@ -247,7 +291,7 @@ pub fn address_map( index: tx.index.into(), }), tokens: vec![pool_added.coin, lp_token], - contracts: vec![component_id.into()], + contracts: vec![component_id.into(), add_pool.base_pool.clone()], static_att: vec![ Attribute { name: "pool_type".into(), @@ -276,6 +320,13 @@ pub fn address_map( ), change: ChangeType::Creation.into(), }, + Attribute { + name: "stateless_contract_addr_0".into(), + value: address_to_bytes_with_0x( + &pool_implementation.try_into().unwrap(), + ), + change: ChangeType::Creation.into(), + }, ], change: ChangeType::Creation.into(), protocol_type: Some(ProtocolType { @@ -309,6 +360,20 @@ pub fn address_map( call, ) })?; + let filtered: Vec<_> = tx + .calls + .iter() + .filter(|call| !call.account_creations.is_empty()) + .collect(); + + let implementation = extract_eip1167_target_from_code( + filtered + .first()? + .code_changes + .first()? + .new_code + .clone(), + ); let component_id = &call.return_data[12..]; let lp_token = get_token_from_pool(&pool_added.base_pool); @@ -351,6 +416,11 @@ pub fn address_map( ), change: ChangeType::Creation.into(), }, + Attribute { + name: "stateless_contract_addr_0".into(), + value: address_to_bytes_with_0x(&implementation.try_into().unwrap()), + change: ChangeType::Creation.into(), + }, ], change: ChangeType::Creation.into(), protocol_type: Some(ProtocolType { @@ -382,7 +452,7 @@ pub fn address_map( index: tx.index.into(), }), tokens: pool_added.coins, - contracts: vec![component_id.into()], + contracts: vec![component_id.into(), CRYPTO_SWAP_NG_FACTORY.into()], static_att: vec![ Attribute { name: "pool_type".into(), @@ -404,6 +474,16 @@ pub fn address_map( value: address_to_bytes_with_0x(&CRYPTO_SWAP_NG_FACTORY), change: ChangeType::Creation.into(), }, + Attribute { + name: "stateless_contract_addr_0".into(), + // Call views_implementation() on CRYPTO_SWAP_NG_FACTORY + value: format!( + "call:{}:views_implementation()", + format!("0x{}", hex::encode(CRYPTO_SWAP_NG_FACTORY)) + ) + .into(), + change: ChangeType::Creation.into(), + }, ], change: ChangeType::Creation.into(), protocol_type: Some(ProtocolType { @@ -430,7 +510,11 @@ pub fn address_map( index: tx.index.into(), }), tokens: vec![pool_added.coin, lp_token], - contracts: vec![component_id.into()], + contracts: vec![ + component_id.into(), + CRYPTO_SWAP_NG_FACTORY.into(), + pool_added.base_pool.clone(), + ], static_att: vec![ Attribute { name: "pool_type".into(), @@ -459,6 +543,26 @@ pub fn address_map( ), change: ChangeType::Creation.into(), }, + Attribute { + name: "stateless_contract_addr_0".into(), + // Call views_implementation() on CRYPTO_SWAP_NG_FACTORY + value: format!( + "call:{}:views_implementation()", + format!("0x{}", hex::encode(CRYPTO_SWAP_NG_FACTORY)) + ) + .into(), + change: ChangeType::Creation.into(), + }, + Attribute { + name: "stateless_contract_addr_1".into(), + // Call math_implementation() on CRYPTO_SWAP_NG_FACTORY + value: format!( + "call:{}:math_implementation()", + format!("0x{}", hex::encode(CRYPTO_SWAP_NG_FACTORY)) + ) + .into(), + change: ChangeType::Creation.into(), + }, ], change: ChangeType::Creation.into(), protocol_type: Some(ProtocolType { @@ -477,6 +581,60 @@ pub fn address_map( abi::tricrypto_factory::events::TricryptoPoolDeployed::match_and_decode(log) { let tokens = swap_weth_for_eth(pool_added.coins.into()); + let mut static_attributes = vec![ + Attribute { + name: "pool_type".into(), + value: "tricrypto".into(), + change: ChangeType::Creation.into(), + }, + Attribute { + name: "name".into(), + value: pool_added.name.into(), + change: ChangeType::Creation.into(), + }, + Attribute { + name: "factory_name".into(), + value: "tricrypto_factory".into(), + change: ChangeType::Creation.into(), + }, + Attribute { + name: "factory".into(), + value: address_to_bytes_with_0x(&TRICRYPTO_FACTORY), + change: ChangeType::Creation.into(), + }, + Attribute { + name: "stateless_contract_addr_0".into(), + // Call views_implementation() on TRICRYPTO_FACTORY + value: format!( + "call:{}:views_implementation()", + format!("0x{}", hex::encode(TRICRYPTO_FACTORY)) + ) + .into(), + change: ChangeType::Creation.into(), + }, + Attribute { + name: "stateless_contract_addr_1".into(), + // Call math_implementation() on TRICRYPTO_FACTORY + value: format!( + "call:{}:math_implementation()", + format!("0x{}", hex::encode(TRICRYPTO_FACTORY)) + ) + .into(), + change: ChangeType::Creation.into(), + }, + ]; + + // This is relevant only if the contract has ETH + if tokens.contains(Ð_ADDRESS.into()) { + static_attributes.push(Attribute { + name: "stateless_contract_addr_2".into(), + // WETH + value: address_to_bytes_with_0x(&hex!( + "c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" + )), + change: ChangeType::Creation.into(), + }) + } Some(ProtocolComponent { id: hex::encode(&pool_added.pool), @@ -487,29 +645,8 @@ pub fn address_map( index: tx.index.into(), }), tokens, - contracts: vec![pool_added.pool], - static_att: vec![ - Attribute { - name: "pool_type".into(), - value: "tricrypto".into(), - change: ChangeType::Creation.into(), - }, - Attribute { - name: "name".into(), - value: pool_added.name.into(), - change: ChangeType::Creation.into(), - }, - Attribute { - name: "factory_name".into(), - value: "tricrypto_factory".into(), - change: ChangeType::Creation.into(), - }, - Attribute { - name: "factory".into(), - value: address_to_bytes_with_0x(&TRICRYPTO_FACTORY), - change: ChangeType::Creation.into(), - }, - ], + contracts: vec![pool_added.pool, TRICRYPTO_FACTORY.into()], + static_att: static_attributes, change: ChangeType::Creation.into(), protocol_type: Some(ProtocolType { name: "curve_pool".into(), @@ -558,6 +695,20 @@ pub fn address_map( return None; }; let component_id = &call.return_data[12..]; + + let tokens: Vec<_> = pool_added + .coins + .into_iter() + .filter(|token| *token != [0; 20]) + .collect(); + + let pool_implementation = + abi::stableswap_factory::functions::PlainImplementations { + arg0: BigInt::from(tokens.len()), + arg1: add_pool.implementation_idx, + } + .call(STABLESWAP_FACTORY.to_vec())?; + Some(ProtocolComponent { id: hex::encode(component_id), tx: Some(Transaction { @@ -566,11 +717,7 @@ pub fn address_map( hash: tx.hash.clone(), index: tx.index.into(), }), - tokens: pool_added - .coins - .into_iter() - .filter(|token| *token != [0; 20]) - .collect(), + tokens, contracts: vec![component_id.into()], static_att: vec![ Attribute { @@ -593,6 +740,13 @@ pub fn address_map( value: address_to_bytes_with_0x(&STABLESWAP_FACTORY), change: ChangeType::Creation.into(), }, + Attribute { + name: "stateless_contract_addr_0".into(), + value: address_to_bytes_with_0x( + &pool_implementation.try_into().unwrap(), + ), + change: ChangeType::Creation.into(), + }, ], change: ChangeType::Creation.into(), protocol_type: Some(ProtocolType { @@ -694,7 +848,7 @@ pub fn address_map( index: tx.index.into(), }), tokens: pool_added.coins.into(), - contracts: vec![pool_added.pool], + contracts: vec![pool_added.pool, TWOCRYPTO_FACTORY.into()], static_att: vec![ Attribute { name: "pool_type".into(), @@ -716,6 +870,26 @@ pub fn address_map( value: address_to_bytes_with_0x(&TWOCRYPTO_FACTORY), change: ChangeType::Creation.into(), }, + Attribute { + name: "stateless_contract_addr_0".into(), + // Call views_implementation() on TWOCRYPTO_FACTORY + value: format!( + "call:{}:views_implementation()", + format!("0x{}", hex::encode(TWOCRYPTO_FACTORY)) + ) + .into(), + change: ChangeType::Creation.into(), + }, + Attribute { + name: "stateless_contract_addr_1".into(), + // Call math_implementation() on TWOCRYPTO_FACTORY + value: format!( + "call:{}:math_implementation()", + format!("0x{}", hex::encode(TWOCRYPTO_FACTORY)) + ) + .into(), + change: ChangeType::Creation.into(), + }, ], change: ChangeType::Creation.into(), protocol_type: Some(ProtocolType { @@ -769,3 +943,20 @@ fn get_token_from_pool(pool: &Vec) -> Vec { }) .unwrap() } + +//TODO: We can most likely replace many RPC calls above using this function. +fn extract_eip1167_target_from_code(code: Vec) -> [u8; 20] { + let mut target = [0u8; 20]; + + // Depending on the Vyper version, they use different implementation of EIP1167. + // We use the first 10 bytes of the code to make a clear distinction. + match code[0..10] { + [54, 61, 61, 55, 61, 61, 61, 54, 61, 115] => target.copy_from_slice(&code[10..30]), + [54, 96, 0, 96, 0, 55, 97, 16, 0, 96] => target.copy_from_slice(&code[15..35]), + _ => { + panic!("unknown implementation") + } + } + + target +} diff --git a/substreams/ethereum-curve/substreams.yaml b/substreams/ethereum-curve/substreams.yaml index dc1ae65..f46d6c6 100644 --- a/substreams/ethereum-curve/substreams.yaml +++ b/substreams/ethereum-curve/substreams.yaml @@ -35,6 +35,14 @@ modules: inputs: - map: map_components + - name: store_non_component_accounts + kind: store + initialBlock: 11968730 + updatePolicy: set + valueType: int64 + inputs: + - map: map_components + - name: map_relative_balances kind: map initialBlock: 9906598 # An arbitrary block that should change based on your requirements @@ -60,6 +68,7 @@ modules: - map: map_components - map: map_relative_balances - store: store_component_tokens + - store: store_non_component_accounts - store: store_balances mode: deltas # This is the key property that simplifies `BalanceChange` handling output: