Skip to content

Commit

Permalink
Merge pull request #114 from propeller-heads/dc/load-bytecode
Browse files Browse the repository at this point in the history
fix: Load bytecode from files with include_bytes!
  • Loading branch information
dianacarvalho1 authored Dec 20, 2024
2 parents 3af77b1 + dd39094 commit a9687e3
Show file tree
Hide file tree
Showing 9 changed files with 69 additions and 165 deletions.
12 changes: 6 additions & 6 deletions .github/workflows/tests-and-lints-template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ jobs:

- name: Setup git to use https
run: |
git config --global credential.helper store
echo "https://${{ steps.generate-token.outputs.token }}@github.com" > ~/.git-credentials
git config --global url."https://x-access-token:${{ steps.generate-token.outputs.token }}@github.com".insteadOf ssh://github.com
git config --global credential.helper store
echo "https://${{ steps.generate-token.outputs.token }}@github.com" > ~/.git-credentials
git config --global url."https://x-access-token:${{ steps.generate-token.outputs.token }}@github.com".insteadOf ssh://github.com
- name: Setup toolchain
uses: dtolnay/rust-toolchain@v1
Expand Down Expand Up @@ -92,9 +92,9 @@ jobs:

- name: Setup git to use https
run: |
git config --global credential.helper store
echo "https://${{ steps.generate-token.outputs.token }}@github.com" > ~/.git-credentials
git config --global url."https://x-access-token:${{ steps.generate-token.outputs.token }}@github.com".insteadOf ssh://github.com
git config --global credential.helper store
echo "https://${{ steps.generate-token.outputs.token }}@github.com" > ~/.git-credentials
git config --global url."https://x-access-token:${{ steps.generate-token.outputs.token }}@github.com".insteadOf ssh://github.com
- name: Setup clippy toolchain - stable
uses: dtolnay/rust-toolchain@v1
Expand Down
6 changes: 3 additions & 3 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ Each native protocol should have its own module under `tycho-simulation/src/prot

#### VM protocol:

1. Add the associated adapter runtime file to `tycho-simulations/src/protocol/assets`. Make sure to name the file
according to the protocol name used by tycho in the following format: `<Protocol><Version>Adapter.evm.runtime`.
For example: `vm:balancer_v2` will be `BalancerV2Adapter.evm.runtime`.
1. Add the associated adapter runtime file to `tycho-simulations/src/protocol/assets`. In
`evm/protocol/vm/constants.rs`, load the file as a bytes constant and add a corresponding entry
to `get_adapter_file()`.

### 1\. Adding state & behaviour

Expand Down
15 changes: 15 additions & 0 deletions src/evm/protocol/vm/constants.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,25 @@
use alloy_primitives::{Address, U256};
use lazy_static::lazy_static;

use crate::protocol::errors::SimulationError;

lazy_static! {
pub static ref EXTERNAL_ACCOUNT: Address = Address::from_slice(
&hex::decode("f847a638E44186F3287ee9F8cAF73FF4d4B80784")
.expect("Invalid string for external account address"),
);
pub static ref MAX_BALANCE: U256 = U256::MAX / U256::from(2);
}

pub const ERC20_BYTECODE: &[u8] = include_bytes!("assets/ERC20.bin");
pub const BALANCER_V2: &[u8] = include_bytes!("assets/BalancerV2SwapAdapter.evm.runtime");
pub const CURVE: &[u8] = include_bytes!("assets/CurveSwapAdapter.evm.runtime");
pub fn get_adapter_file(protocol: &str) -> Result<&'static [u8], SimulationError> {
match protocol {
"balancer_v2" => Ok(BALANCER_V2),
"curve" => Ok(CURVE),
_ => {
Err(SimulationError::FatalError(format!("Adapter for protocol {} not found", protocol)))
}
}
}
2 changes: 1 addition & 1 deletion src/evm/protocol/vm/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
mod adapter_contract;
mod constants;
pub mod constants;
mod erc20_token;
mod models;
pub mod state;
Expand Down
8 changes: 2 additions & 6 deletions src/evm/protocol/vm/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use alloy_primitives::{Address, U256};
use itertools::Itertools;
use num_bigint::BigUint;
use revm::DatabaseRef;
use tracing::info;
use tycho_core::{dto::ProtocolStateDelta, Bytes};

use super::{
Expand Down Expand Up @@ -175,7 +174,6 @@ where
&mut self,
tokens: &HashMap<Bytes, Token>,
) -> Result<(), SimulationError> {
info!("Setting spot prices for pool {}", self.id.clone());
self.ensure_capability(Capability::PriceFunction)?;
for [sell_token_address, buy_token_address] in self
.tokens
Expand Down Expand Up @@ -586,7 +584,6 @@ where
mod tests {
use std::{
collections::{HashMap, HashSet},
path::PathBuf,
str::FromStr,
};

Expand All @@ -602,6 +599,7 @@ mod tests {
};
use crate::evm::{
engine_db::{create_engine, SHARED_TYCHO_DB},
protocol::vm::constants::BALANCER_V2,
simulation::SimulationEngine,
tycho_models::AccountUpdate,
};
Expand Down Expand Up @@ -696,9 +694,7 @@ mod tests {

EVMPoolStateBuilder::new(pool_id, tokens, balances, block, adapter_address)
.balance_owner(Address::from_str("0xBA12222222228d8Ba445958a75a0704d566BF2C8").unwrap())
.adapter_contract_path(PathBuf::from(
"src/evm/protocol/vm/assets/BalancerV2SwapAdapter.evm.runtime".to_string(),
))
.adapter_contract_bytecode(Bytecode::new_raw(BALANCER_V2.into()))
.stateless_contracts(stateless_contracts)
.build(SHARED_TYCHO_DB.clone())
.await
Expand Down
39 changes: 15 additions & 24 deletions src/evm/protocol/vm/state_builder.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::{
collections::{HashMap, HashSet},
fmt::Debug,
path::PathBuf,
};

use alloy_primitives::{Address, U256};
Expand All @@ -22,14 +21,14 @@ use super::{
models::Capability,
state::EVMPoolState,
tycho_simulation_contract::TychoSimulationContract,
utils::{get_code_for_contract, load_erc20_bytecode},
utils::get_code_for_contract,
};
use crate::{
evm::{
engine_db::{
create_engine, engine_db_interface::EngineDatabaseInterface, simulation_db::BlockHeader,
},
protocol::utils::bytes_to_address,
protocol::{utils::bytes_to_address, vm::constants::ERC20_BYTECODE},
simulation::{SimulationEngine, SimulationParameters},
ContractCompiler,
},
Expand All @@ -55,10 +54,12 @@ use crate::{
/// use tycho_simulation::evm::engine_db::SHARED_TYCHO_DB;
/// use tycho_simulation::protocol::errors::SimulationError;
/// use tycho_simulation::evm::protocol::vm::state_builder::EVMPoolStateBuilder;
/// use tycho_simulation::evm::protocol::vm::constants::BALANCER_V2;
///
/// #[tokio::main]
/// async fn main() -> Result<(), SimulationError> {
/// let pool_id: String = "0x4626d81b3a1711beb79f4cecff2413886d461677000200000000000000000011".into();
/// use revm::primitives::Bytecode;
/// let pool_id: String = "0x4626d81b3a1711beb79f4cecff2413886d461677000200000000000000000011".into();
///
/// let tokens = vec![
/// Bytes::from("0x6b175474e89094c44da98b954eedeac495271d0f"),
Expand All @@ -77,9 +78,7 @@ use crate::{
/// // Build the EVMPoolState
/// let pool_state = EVMPoolStateBuilder::new(pool_id, tokens, balances, block, Address::random())
/// .balance_owner(Address::random())
/// .adapter_contract_path(PathBuf::from(
/// "src/evm/protocol/vm/assets/BalancerV2SwapAdapter.evm.runtime".to_string(),
/// ))
/// .adapter_contract_bytecode(Bytecode::new_raw(BALANCER_V2.into()))
/// .build(SHARED_TYCHO_DB.clone())
/// .await?;
/// Ok(())
Expand All @@ -104,7 +103,7 @@ where
trace: Option<bool>,
engine: Option<SimulationEngine<D>>,
adapter_contract: Option<TychoSimulationContract<D>>,
adapter_contract_path: Option<PathBuf>,
adapter_contract_bytecode: Option<Bytecode>,
}

impl<D> EVMPoolStateBuilder<D>
Expand Down Expand Up @@ -135,7 +134,7 @@ where
trace: None,
engine: None,
adapter_contract: None,
adapter_contract_path: None,
adapter_contract_bytecode: None,
}
}

Expand Down Expand Up @@ -190,8 +189,8 @@ where
self
}

pub fn adapter_contract_path(mut self, adapter_contract_path: PathBuf) -> Self {
self.adapter_contract_path = Some(adapter_contract_path);
pub fn adapter_contract_bytecode(mut self, adapter_contract_bytecode: Bytecode) -> Self {
self.adapter_contract_bytecode = Some(adapter_contract_bytecode);
self
}

Expand All @@ -207,10 +206,10 @@ where
if self.adapter_contract.is_none() {
self.adapter_contract = Some(TychoSimulationContract::new_swap_adapter(
self.adapter_address,
self.adapter_contract_path
.as_ref()
self.adapter_contract_bytecode
.clone()
.ok_or_else(|| {
SimulationError::FatalError("Adapter contract path not set".to_string())
SimulationError::FatalError("Adapter contract bytecode not set".to_string())
})?,
engine.clone(),
)?)
Expand Down Expand Up @@ -246,20 +245,12 @@ where

async fn get_default_engine(&self, db: D) -> Result<SimulationEngine<D>, SimulationError> {
let engine = create_engine(db, self.trace.unwrap_or(false))?;

// Mock the ERC20 contract at the given token addresses.
let mocked_contract_bytecode: Bytecode = load_erc20_bytecode().map_err(|err| {
SimulationError::FatalError(format!(
"{:?} when loading ERC20 bytecode",
err.to_string()
))
})?;
for token_address in &self.tokens {
let info = AccountInfo {
balance: Default::default(),
nonce: 0,
code_hash: KECCAK_EMPTY,
code: Some(mocked_contract_bytecode.clone()),
code: Some(Bytecode::new_raw(ERC20_BYTECODE.into())),
};
engine
.state
Expand Down Expand Up @@ -486,7 +477,7 @@ mod tests {
assert!(result.is_err());
match result.unwrap_err() {
SimulationError::FatalError(field) => {
assert_eq!(field, "Adapter contract path not set")
assert_eq!(field, "Adapter contract bytecode not set")
}
_ => panic!("Unexpected error type"),
}
Expand Down
36 changes: 10 additions & 26 deletions src/evm/protocol/vm/tycho_decoder.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
use std::{
collections::HashMap,
path::PathBuf,
str::FromStr,
time::{SystemTime, UNIX_EPOCH},
};

use alloy_primitives::{Address, B256, U256};
use tracing::info;
use revm::primitives::Bytecode;
use tycho_client::feed::{synchronizer::ComponentWithState, Header};
use tycho_core::Bytes;

use super::{state::EVMPoolState, state_builder::EVMPoolStateBuilder};
use crate::{
evm::engine_db::{simulation_db::BlockHeader, tycho_db::PreCachedDB, SHARED_TYCHO_DB},
evm::{
engine_db::{simulation_db::BlockHeader, tycho_db::PreCachedDB, SHARED_TYCHO_DB},
protocol::vm::constants::get_adapter_file,
},
models::Token,
protocol::{errors::InvalidSnapshotError, models::TryFromWithBlock},
};
Expand Down Expand Up @@ -125,9 +127,7 @@ impl TryFromWithBlock<ComponentWithState> for EVMPoolState<PreCachedDB> {
.protocol_system
.as_str()
});
let adapter_file_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("src/evm/protocol/vm/assets")
.join(to_adapter_file_name(protocol_name));
let adapter_bytecode = Bytecode::new_raw(get_adapter_file(protocol_name)?.into());
let adapter_contract_address =
Address::from_str(&format!("{:0>40}", hex::encode(protocol_name)))
.expect("Can't convert protocol name to address");
Expand All @@ -139,7 +139,7 @@ impl TryFromWithBlock<ComponentWithState> for EVMPoolState<PreCachedDB> {
block,
adapter_contract_address,
)
.adapter_contract_path(adapter_file_path)
.adapter_contract_bytecode(adapter_bytecode)
.involved_contracts(involved_contracts)
.stateless_contracts(stateless_contracts)
.manual_updates(manual_updates);
Expand All @@ -154,28 +154,11 @@ impl TryFromWithBlock<ComponentWithState> for EVMPoolState<PreCachedDB> {
.map_err(InvalidSnapshotError::VMError)?;

pool_state.set_spot_prices(all_tokens)?;
info!("Finished creating balancer pool with id {}", &id);

Ok(pool_state)
}
}

/// Converts a protocol system name to the name of the adapter file. For example, `balancer_v2`
/// would be converted to `BalancerV2SwapAdapter.evm.runtime`.
fn to_adapter_file_name(protocol_system: &str) -> String {
protocol_system
.split('_')
.map(|word| {
let mut chars = word.chars();
match chars.next() {
Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
None => String::new(),
}
})
.collect::<String>() +
"SwapAdapter.evm.runtime"
}

#[cfg(test)]
mod tests {
use std::{collections::HashSet, fs, path::Path, str::FromStr};
Expand All @@ -193,15 +176,16 @@ mod tests {
use crate::{
evm::{
engine_db::{create_engine, engine_db_interface::EngineDatabaseInterface},
protocol::vm::constants::{get_adapter_file, BALANCER_V2, CURVE},
tycho_models::AccountUpdate,
},
protocol::models::TryFromWithBlock,
};

#[test]
fn test_to_adapter_file_name() {
assert_eq!(to_adapter_file_name("balancer_v2"), "BalancerV2SwapAdapter.evm.runtime");
assert_eq!(to_adapter_file_name("uniswap_v3"), "UniswapV3SwapAdapter.evm.runtime");
assert_eq!(get_adapter_file("balancer_v2").unwrap(), BALANCER_V2);
assert_eq!(get_adapter_file("curve").unwrap(), CURVE);
}

fn vm_component() -> ProtocolComponent {
Expand Down
Loading

0 comments on commit a9687e3

Please sign in to comment.