Skip to content

Commit

Permalink
Merge pull request #25 from propeller-heads/vm/dc/ENG-3757-marginal-p…
Browse files Browse the repository at this point in the history
…rices

feat: Spot prices and overwrites
  • Loading branch information
dianacarvalho1 authored Oct 31, 2024
2 parents 6ea7cde + b6bb110 commit 707f283
Show file tree
Hide file tree
Showing 7 changed files with 497 additions and 228 deletions.
12 changes: 11 additions & 1 deletion src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
//! ERC20Tokens provide instructions on how to handle prices and amounts,
//! while Swap and SwapSequence are usually used as results types.
use std::{convert::TryFrom, str::FromStr};
use std::{
convert::TryFrom,
hash::{Hash, Hasher},
str::FromStr,
};

use ethers::types::{H160, U256};
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -70,6 +74,12 @@ impl PartialEq for ERC20Token {
}
}

impl Hash for ERC20Token {
fn hash<H: Hasher>(&self, state: &mut H) {
self.address.hash(state);
}
}

impl TryFrom<ResponseToken> for ERC20Token {
type Error = std::num::TryFromIntError;

Expand Down
34 changes: 16 additions & 18 deletions src/protocol/vm/adapter_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
use crate::{
evm::account_storage::StateUpdate,
protocol::vm::{
errors::ProtosimError, models::Capability, protosim_contract::ProtosimContract,
erc20_overwrite_factory::Overwrites, errors::ProtosimError, models::Capability,
protosim_contract::ProtosimContract,
},
};
use ethers::{
Expand Down Expand Up @@ -43,9 +44,9 @@ where
pair_id: String,
sell_token: Address,
buy_token: Address,
amounts: Vec<u64>,
amounts: Vec<U256>,
block: u64,
overwrites: Option<HashMap<rAddress, HashMap<U256, U256>>>,
overwrites: Option<HashMap<rAddress, Overwrites>>,
) -> Result<Vec<f64>, ProtosimError> {
let args = vec![
self.hexstring_to_bytes(&pair_id)?,
Expand All @@ -54,7 +55,7 @@ where
Token::Array(
amounts
.into_iter()
.map(|a| Token::Uint(U256::from(a)))
.map(Token::Uint)
.collect(),
),
];
Expand All @@ -63,7 +64,6 @@ where
.call("price", args, block, None, overwrites, None, U256::zero())
.await?
.return_value;
// returning just floats - the python version returns Fractions (not sure why)
let price = self.calculate_price(res[0].clone())?;
Ok(price)
}
Expand Down Expand Up @@ -112,7 +112,7 @@ where
buy_token: Address,
block: u64,
overwrites: Option<HashMap<rAddress, HashMap<U256, U256>>>,
) -> Result<(u64, u64), ProtosimError> {
) -> Result<(U256, U256), ProtosimError> {
let args = vec![
self.hexstring_to_bytes(&pair_id)?,
Token::Address(sell_token),
Expand All @@ -123,18 +123,16 @@ where
.call("getLimits", args, block, None, overwrites, None, U256::zero())
.await?
.return_value;
Ok((
res[0]
.clone()
.into_uint()
.unwrap()
.as_u64(),
res[1]
.clone()
.into_uint()
.unwrap()
.as_u64(),
))

if let Some(Token::Array(inner)) = res.first() {
if let (Some(Token::Uint(value1)), Some(Token::Uint(value2))) =
(inner.first(), inner.get(1))
{
return Ok((*value1, *value2));
}
}

Err(ProtosimError::DecodingError("Unexpected response format".into()))
}

pub async fn get_capabilities(
Expand Down
64 changes: 33 additions & 31 deletions src/protocol/vm/erc20_overwrite_factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
#![allow(dead_code)]
use crate::protocol::vm::{
errors::FileError,
utils::{get_contract_bytecode, get_storage_slot_index_at_key, SlotHash},
utils::{get_contract_bytecode, get_storage_slot_index_at_key, SlotId},
};
use ethers::{addressbook::Address, prelude::U256};
use ethers::{abi::Address, types::U256};
use revm::primitives::Address as rAddress;
use std::{collections::HashMap, path::Path};

pub struct GethOverwrite {
Expand All @@ -14,24 +15,24 @@ pub struct GethOverwrite {
pub code: String,
}

pub type Overwrites = HashMap<SlotHash, U256>;
pub type Overwrites = HashMap<SlotId, U256>;

pub struct ERC20OverwriteFactory {
token_address: Address,
token_address: rAddress,
overwrites: Overwrites,
balance_slot: SlotHash,
allowance_slot: SlotHash,
total_supply_slot: SlotHash,
balance_slot: SlotId,
allowance_slot: SlotId,
total_supply_slot: SlotId,
}

impl ERC20OverwriteFactory {
pub fn new(token_address: Address, token_slots: (SlotHash, SlotHash)) -> Self {
pub fn new(token_address: rAddress, token_slots: (SlotId, SlotId)) -> Self {
ERC20OverwriteFactory {
token_address,
overwrites: HashMap::new(),
balance_slot: token_slots.0,
allowance_slot: token_slots.1,
total_supply_slot: SlotHash::from_low_u64_be(2),
total_supply_slot: SlotId::from(2),
}
}

Expand All @@ -53,21 +54,23 @@ impl ERC20OverwriteFactory {
.insert(self.total_supply_slot, supply);
}

pub fn get_protosim_overwrites(&self) -> HashMap<Address, Overwrites> {
pub fn get_protosim_overwrites(&self) -> HashMap<rAddress, Overwrites> {
let mut result = HashMap::new();
result.insert(self.token_address, self.overwrites.clone());
result
}

pub fn get_geth_overwrites(&self) -> Result<HashMap<Address, GethOverwrite>, FileError> {
pub fn get_geth_overwrites(&self) -> Result<HashMap<rAddress, GethOverwrite>, FileError> {
let mut formatted_overwrites = HashMap::new();

for (key, val) in &self.overwrites {
let hex_key = hex::encode(key.as_bytes());
let mut key_bytes = [0u8; 32];
key.to_big_endian(&mut key_bytes);
let hex_key = hex::encode(key_bytes);

let mut bytes = [0u8; 32];
val.to_big_endian(&mut bytes);
let hex_val = format!("0x{:0>64}", hex::encode(bytes));
let mut value_bytes = [0u8; 32];
val.to_big_endian(&mut value_bytes);
let hex_val = format!("0x{:0>64}", hex::encode(value_bytes));

formatted_overwrites.insert(hex_key, hex_val);
}
Expand All @@ -82,17 +85,12 @@ impl ERC20OverwriteFactory {
.join("assets")
.join("ERC20.abi");

let code = format!(
"0x{}",
hex::encode(
get_contract_bytecode(erc20_abi_path.to_str().ok_or_else(|| {
FileError::FilePath("Failed to convert file path to string.".to_string())
})?)
.map_err(|_err| FileError::MalformedABI(
"Failed to read contract bytecode.".to_string()
))?
)
);
let contract_bytecode =
get_contract_bytecode(erc20_abi_path.to_str().ok_or_else(|| {
FileError::FilePath("Failed to convert file path to string.".to_string())
})?)?;

let code = format!("0x{}", hex::encode(contract_bytecode.bytes()));

let mut result = HashMap::new();
result.insert(self.token_address, GethOverwrite { state_diff: formatted_overwrites, code });
Expand All @@ -104,12 +102,16 @@ impl ERC20OverwriteFactory {
#[cfg(test)]
mod tests {
use super::*;
use crate::protocol::vm::utils::SlotHash;
use crate::protocol::vm::utils::SlotId;

fn setup_factory() -> ERC20OverwriteFactory {
let token_address = Address::random();
let balance_slot = SlotHash::random();
let allowance_slot = SlotHash::random();
let token_address = rAddress::parse_checksummed(
String::from("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"),
None,
)
.expect("Failed to parse address");
let balance_slot = SlotId::from(5);
let allowance_slot = SlotId::from(6);
ERC20OverwriteFactory::new(token_address, (balance_slot, allowance_slot))
}

Expand Down Expand Up @@ -173,7 +175,7 @@ mod tests {
fn test_get_geth_overwrites() {
let mut factory = setup_factory();

let storage_slot = SlotHash::from_low_u64_be(1);
let storage_slot = SlotId::from(1);
let val = U256::from(123456);
factory
.overwrites
Expand Down
16 changes: 14 additions & 2 deletions src/protocol/vm/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ use crate::evm::simulation::SimulationError;
/// - `RPCError`: Indicates an error related to RPC interaction.
/// - `UnsupportedCapability`: Denotes an error when a pool state does not support a necessary
/// capability.
/// - `UninitializedAdapter`: Indicates an error when trying to set capabilities before initializing
/// the adapter.
/// - `UninitializedAdapter`: Indicates an error when trying to use the Adapter before initializing
/// it.
/// - `CapabilityRetrievalFailure`: Indicates an error when trying to retrieve capabilities.
/// - `EngineNotSet`: Indicates an error when trying to use the engine before setting it.
// the adapter.
#[derive(Error, Debug)]
pub enum ProtosimError {
#[error("ABI loading error: {0}")]
Expand All @@ -41,6 +43,8 @@ pub enum ProtosimError {
UnsupportedCapability(String),
#[error("Adapter not initialized: {0}")]
UninitializedAdapter(String),
#[error("Engine not set")]
EngineNotSet(),
}

#[derive(Debug, Error)]
Expand Down Expand Up @@ -89,10 +93,18 @@ pub enum RpcError {
InvalidRequest(String),
#[error("Invalid Response: {0}")]
InvalidResponse(ProviderError),
#[error("Empty Response")]
EmptyResponse(),
}

impl From<RpcError> for ProtosimError {
fn from(err: RpcError) -> Self {
ProtosimError::RpcError(err)
}
}

impl From<ethers::abi::Error> for ProtosimError {
fn from(err: ethers::abi::Error) -> Self {
ProtosimError::DecodingError(err.to_string())
}
}
3 changes: 2 additions & 1 deletion src/protocol/vm/protosim_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use crate::{
evm::simulation::{SimulationEngine, SimulationParameters, SimulationResult},
protocol::vm::{
constants::EXTERNAL_ACCOUNT,
erc20_overwrite_factory::Overwrites,
errors::ProtosimError,
utils::{load_swap_abi, maybe_coerce_error},
},
Expand Down Expand Up @@ -142,7 +143,7 @@ where
args: Vec<Token>,
block_number: u64,
timestamp: Option<u64>,
overrides: Option<HashMap<Address, HashMap<U256, U256>>>,
overrides: Option<HashMap<Address, Overwrites>>,
caller: Option<Address>,
value: U256,
) -> Result<ProtoSimResponse, ProtosimError> {
Expand Down
Loading

0 comments on commit 707f283

Please sign in to comment.