Sdk implementation: Sfrax adapter and substream (#91)
* feat: initial setup * feat: implemented getCapabilities and getTokens * chore: adjusted getPoolIds * feat: Initial implementation of getLimits() * feat: implemented getLimits, getTokens and internal functions for amounts * feat: implemented price * feat: implemented swap function * fix and test: fixed minor issues on adapter and setup test * debugging price function * fix: debugged price function and fixed getPriceAt function * test: testOneIncreasingPriceFoundFraxV3SFrax * fix: debugging and fixing buy function * fix: fixed getPriceAt * test: testing post trade price * fix: Fixed getPriceAt * fix: Fixed getLimits * fix: Fixed prices and improved readability * fix: Fixed price and transfers in swap * feat: Finished tests * chore: Changed approve to safeIncreaseAllowance * feat: created substream for staked frax * feat: remove useless files * feat: fixed dependencies in cargo.toml * feat: rename folder * feat: updated cargo.lock * feat: changed lib.rs, added modules.rs * feat: update modules.rs with corrects addresses * feat: rename folder in ethereum-sfrax * feat: remove useless comments, change locked asset address, rename * feat: undo changes on mod.rs in ethereum-balancer * feat: rename variable * feat: update substreams/cargo.toml * feat: modify ristfmt.toml * feat: performed code formatting * feat: modify src/abi * feat: performed formatting with nightly * feat: fix addition opeation * feat: adjust code with for i, f * feat: performed fmt inside ethereum-sfrax folder * feat: performed clippy * feat: fix with clippy warning suggests * feat: undo any change in ethereum-balancer * feat: change stakedfrax_contract.rs * fix: stakedfrax_contract.rs * feat: add blank line * feat: add #[allow(clippy::all)] on ethereum-sfrax/src/abi/mod.rs * feat: update comments on pool_factories.rs * feat: update cargo.toml and substreams.yaml * feat: add tycho evm in pb folder * feat: add params to take contracts' addresses * feat: add logic to map rewards_cycle * feat: performed fmt and fix versioning * feat: remove useless functions * feat: add logic to track rewards_to_distribute * feat: passing CI * fix: substreams.yaml * feat: fixed params in manifest Co-authored-by: mrBovo <bovo.ignazio@proton.me> * feat: fixed error in map_relative_balances function * feat: passing CI checks * fix: 🐛 hex-binary address encoding + refactoring vault-> underlying map * style: 💄 fix formatting * feat: Implemented testPoolBehaviour * alignment with propeller main * Update forge-std submodule reference to include ds-test * files update to match propeller/main * creating integration_test fir sfrax * fixed FraxV3SFraxAdapter.sol import paths * updated with correct addresses FraxV3SFraxAdapter manifest.yaml * updated sfrax manifest.yaml * updated to support sdk * integration_test sfrax updated * fix: 🐛 add reward processing * chore: ♻️ minor cleanups * fix: Fixed adapter limits * fix: fix adapter and substream sdk tests * fix: Fixed CI errors * chore: fmt * chore: Removed unused line * fix: Fixed clippy warnings * chore: formatted with rustup * chore: Removed unused line * chore: post-build formatting * chore: Formatting using different toolchain vesion * chore: 💄 format * chore: 💄 format 2 * chore: Using static address for frax * feat: Added second constructor param for sfrax * fix: Fixed limits on frax sell * chore: Fixed merge conflict with sfraxeth * chore: Remove sfraxeth_contract changes * chore: Fixed EOFs * fix: Fixed fmt on stakedfrax contract --------- Co-authored-by: mp-web3 <mp.web3.t@gmail.com> Co-authored-by: gabrir99 <gabri.ruini@gmail.com> Co-authored-by: mrBovo <bovo.ignazio@proton.me> Co-authored-by: Ignazio Bovo <ignazio@jsgenesis.com> Co-authored-by: mrBovo <bovoignazio.dev@gmail.com> Co-authored-by: Mattia <mp.web3@gmail.com>
This commit is contained in:
277
substreams/ethereum-sfrax/src/modules.rs
Normal file
277
substreams/ethereum-sfrax/src/modules.rs
Normal file
@@ -0,0 +1,277 @@
|
||||
use crate::abi;
|
||||
use anyhow::Result;
|
||||
use itertools::Itertools;
|
||||
use std::collections::HashMap;
|
||||
use substreams::{
|
||||
hex,
|
||||
pb::substreams::StoreDeltas,
|
||||
store::{StoreAdd, StoreAddBigInt, StoreAddInt64, StoreGet, StoreGetInt64, StoreNew},
|
||||
};
|
||||
use substreams_ethereum::{
|
||||
pb::eth::{self},
|
||||
Event,
|
||||
};
|
||||
use tycho_substreams::{
|
||||
balances::aggregate_balances_changes, contract::extract_contract_changes, prelude::*,
|
||||
};
|
||||
|
||||
#[substreams::handlers::map]
|
||||
pub fn map_components(
|
||||
params: String,
|
||||
block: eth::v2::Block,
|
||||
) -> Result<BlockTransactionProtocolComponents, anyhow::Error> {
|
||||
let vault_address = hex::decode(params).unwrap();
|
||||
let locked_asset = find_deployed_underlying_address(&vault_address).unwrap();
|
||||
// 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 components = tx
|
||||
.calls()
|
||||
.filter(|call| !call.call.state_reverted)
|
||||
.filter_map(|_| {
|
||||
// address doesn't exist before contract deployment, hence the first tx with
|
||||
// a log.address = vault_address is the deployment tx
|
||||
if is_deployment_tx(tx, &vault_address) {
|
||||
Some(
|
||||
ProtocolComponent::at_contract(&vault_address, &tx.into())
|
||||
.with_tokens(&[
|
||||
locked_asset.as_slice(),
|
||||
vault_address.as_slice(),
|
||||
])
|
||||
.as_swap_type("sfrax_vault", ImplementationType::Vm),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if !components.is_empty() {
|
||||
Some(TransactionProtocolComponents { tx: Some(tx.into()), components })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
})
|
||||
}
|
||||
|
||||
#[substreams::handlers::store]
|
||||
pub fn store_components(map: BlockTransactionProtocolComponents, store: StoreAddInt64) {
|
||||
store.add_many(
|
||||
0,
|
||||
&map.tx_components
|
||||
.iter()
|
||||
.flat_map(|tx_components| &tx_components.components)
|
||||
.map(|component| format!("pool:{0}", component.id))
|
||||
.collect::<Vec<_>>(),
|
||||
1,
|
||||
);
|
||||
}
|
||||
|
||||
#[substreams::handlers::map]
|
||||
pub fn map_relative_balances(
|
||||
block: eth::v2::Block,
|
||||
store: StoreGetInt64,
|
||||
) -> Result<BlockBalanceDeltas, anyhow::Error> {
|
||||
let balance_deltas = block
|
||||
.logs()
|
||||
.flat_map(|vault_log| {
|
||||
let mut deltas = Vec::new();
|
||||
|
||||
if let Some(ev) =
|
||||
abi::stakedfrax_contract::events::Withdraw::match_and_decode(vault_log.log)
|
||||
{
|
||||
let address_bytes_be = vault_log.address();
|
||||
let address_hex = format!("0x{}", hex::encode(address_bytes_be));
|
||||
if store
|
||||
.get_last(format!("pool:{}", address_hex))
|
||||
.is_some()
|
||||
{
|
||||
deltas.extend_from_slice(&[
|
||||
BalanceDelta {
|
||||
ord: vault_log.ordinal(),
|
||||
tx: Some(vault_log.receipt.transaction.into()),
|
||||
token: find_deployed_underlying_address(address_bytes_be)
|
||||
.unwrap()
|
||||
.to_vec(),
|
||||
delta: ev.assets.neg().to_signed_bytes_be(),
|
||||
component_id: address_hex.as_bytes().to_vec(),
|
||||
},
|
||||
BalanceDelta {
|
||||
ord: vault_log.ordinal(),
|
||||
tx: Some(vault_log.receipt.transaction.into()),
|
||||
token: address_bytes_be.to_vec(),
|
||||
delta: ev.shares.neg().to_signed_bytes_be(),
|
||||
component_id: address_hex.as_bytes().to_vec(),
|
||||
},
|
||||
]);
|
||||
substreams::log::debug!(
|
||||
"Withdraw: vault: {}, frax:- {}, sfrax:- {}",
|
||||
address_hex,
|
||||
ev.assets,
|
||||
ev.shares
|
||||
);
|
||||
}
|
||||
} else if let Some(ev) =
|
||||
abi::stakedfrax_contract::events::Deposit::match_and_decode(vault_log.log)
|
||||
{
|
||||
let address_bytes_be = vault_log.address();
|
||||
let address_hex = format!("0x{}", hex::encode(address_bytes_be));
|
||||
|
||||
if store
|
||||
.get_last(format!("pool:{}", address_hex))
|
||||
.is_some()
|
||||
{
|
||||
deltas.extend_from_slice(&[
|
||||
BalanceDelta {
|
||||
ord: vault_log.ordinal(),
|
||||
tx: Some(vault_log.receipt.transaction.into()),
|
||||
token: find_deployed_underlying_address(address_bytes_be)
|
||||
.unwrap()
|
||||
.to_vec(),
|
||||
delta: ev.assets.to_signed_bytes_be(),
|
||||
component_id: address_hex.as_bytes().to_vec(),
|
||||
},
|
||||
BalanceDelta {
|
||||
ord: vault_log.ordinal(),
|
||||
tx: Some(vault_log.receipt.transaction.into()),
|
||||
token: address_bytes_be.to_vec(),
|
||||
delta: ev.shares.to_signed_bytes_be(),
|
||||
component_id: address_hex.as_bytes().to_vec(),
|
||||
},
|
||||
]);
|
||||
substreams::log::debug!(
|
||||
"Deposit: vault: {}, frax:+ {}, sfrax:+ {}",
|
||||
address_hex,
|
||||
ev.assets,
|
||||
ev.shares
|
||||
);
|
||||
}
|
||||
} else if let Some(ev) =
|
||||
abi::stakedfrax_contract::events::DistributeRewards::match_and_decode(vault_log.log)
|
||||
{
|
||||
let address_bytes_be = vault_log.address();
|
||||
let address_hex = format!("0x{}", hex::encode(address_bytes_be));
|
||||
|
||||
if store
|
||||
.get_last(format!("pool:{}", address_hex))
|
||||
.is_some()
|
||||
{
|
||||
deltas.extend_from_slice(&[BalanceDelta {
|
||||
ord: vault_log.ordinal(),
|
||||
tx: Some(vault_log.receipt.transaction.into()),
|
||||
token: address_bytes_be.to_vec(),
|
||||
delta: ev
|
||||
.rewards_to_distribute
|
||||
.to_signed_bytes_be(),
|
||||
component_id: address_hex.as_bytes().to_vec(),
|
||||
}]);
|
||||
// Log token and amount without encoding
|
||||
substreams::log::debug!(
|
||||
"DistributeRewards: vault: {}, frax:+ {}",
|
||||
address_hex,
|
||||
ev.rewards_to_distribute
|
||||
);
|
||||
}
|
||||
}
|
||||
deltas
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Ok(BlockBalanceDeltas { balance_deltas })
|
||||
}
|
||||
|
||||
#[substreams::handlers::store]
|
||||
pub fn store_balances(deltas: BlockBalanceDeltas, store: StoreAddBigInt) {
|
||||
tycho_substreams::balances::store_balance_changes(deltas, store);
|
||||
}
|
||||
|
||||
#[substreams::handlers::map]
|
||||
pub fn map_protocol_changes(
|
||||
block: eth::v2::Block,
|
||||
grouped_components: BlockTransactionProtocolComponents,
|
||||
deltas: BlockBalanceDeltas,
|
||||
components_store: StoreGetInt64,
|
||||
balance_store: StoreDeltas,
|
||||
) -> Result<BlockChanges, anyhow::Error> {
|
||||
let mut transaction_contract: HashMap<u64, TransactionChanges> = HashMap::new();
|
||||
|
||||
grouped_components
|
||||
.tx_components
|
||||
.iter()
|
||||
.for_each(|tx_component| {
|
||||
let tx = tx_component.tx.as_ref().unwrap();
|
||||
transaction_contract
|
||||
.entry(tx.index)
|
||||
.or_insert_with(|| TransactionChanges::new(tx))
|
||||
.component_changes
|
||||
.extend_from_slice(&tx_component.components);
|
||||
});
|
||||
|
||||
aggregate_balances_changes(balance_store, deltas)
|
||||
.into_iter()
|
||||
.for_each(|(_, (tx, balances))| {
|
||||
transaction_contract
|
||||
.entry(tx.index)
|
||||
.or_insert_with(|| TransactionChanges::new(&tx))
|
||||
.balance_changes
|
||||
.extend(balances.into_values());
|
||||
});
|
||||
|
||||
extract_contract_changes(
|
||||
&block,
|
||||
|addr| {
|
||||
components_store
|
||||
.get_last(format!("pool:0x{0}", hex::encode(addr)))
|
||||
.is_some()
|
||||
},
|
||||
&mut transaction_contract,
|
||||
);
|
||||
|
||||
Ok(BlockChanges {
|
||||
block: Some((&block).into()),
|
||||
changes: transaction_contract
|
||||
.drain()
|
||||
.sorted_unstable_by_key(|(index, _)| *index)
|
||||
.filter_map(|(_, change)| {
|
||||
if change.contract_changes.is_empty() &&
|
||||
change.component_changes.is_empty() &&
|
||||
change.balance_changes.is_empty()
|
||||
{
|
||||
None
|
||||
} else {
|
||||
Some(change)
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
})
|
||||
}
|
||||
|
||||
fn is_deployment_tx(tx: ð::v2::TransactionTrace, vault_address: &[u8]) -> bool {
|
||||
let created_accounts = tx
|
||||
.calls
|
||||
.iter()
|
||||
.flat_map(|call| {
|
||||
call.account_creations
|
||||
.iter()
|
||||
.map(|ac| ac.account.to_owned())
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if let Some(deployed_address) = created_accounts.first() {
|
||||
return deployed_address.as_slice() == vault_address;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn find_deployed_underlying_address(vault_address: &[u8]) -> Option<[u8; 20]> {
|
||||
match vault_address {
|
||||
hex!("A663B02CF0a4b149d2aD41910CB81e23e1c41c32") => {
|
||||
Some(hex!("853d955aCEf822Db058eb8505911ED77F175b99e"))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user