feat: Add builder pattern and registry for SwapEncoders
Save swap executor addresses in a config file
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
use alloy_primitives::Address;
|
||||
use alloy_sol_types::SolValue;
|
||||
use anyhow::Error;
|
||||
use num_bigint::BigUint;
|
||||
@@ -7,7 +8,7 @@ use std::cmp::min;
|
||||
use crate::encoding::models::{
|
||||
ActionType, EncodingContext, NativeAction, Solution, PROPELLER_ROUTER_ADDRESS,
|
||||
};
|
||||
use crate::encoding::swap_encoder::{get_swap_encoder, get_swap_executor_address};
|
||||
use crate::encoding::swap_encoder::SWAP_ENCODER_REGISTRY;
|
||||
use crate::encoding::utils::{biguint_to_u256, ple_encode};
|
||||
|
||||
pub trait StrategyEncoder {
|
||||
@@ -19,13 +20,12 @@ pub trait StrategyEncoder {
|
||||
fn encode_protocol_header(
|
||||
&self,
|
||||
protocol_data: Vec<u8>,
|
||||
protocol_system: String,
|
||||
executor_address: Address,
|
||||
// Token indices, split, and token inclusion are only used for split swaps
|
||||
token_in: u16,
|
||||
token_out: u16,
|
||||
split: u16, // not sure what should be the type of this :/
|
||||
) -> Vec<u8> {
|
||||
let executor_address = get_swap_executor_address(&protocol_system);
|
||||
let args = (executor_address, token_in, token_out, split, protocol_data);
|
||||
args.abi_encode()
|
||||
}
|
||||
@@ -77,8 +77,10 @@ impl StrategyEncoder for SequentialStrategyEncoder {
|
||||
let mut swaps = vec![];
|
||||
for (index, swap) in solution.swaps.iter().enumerate() {
|
||||
let is_last = index == solution.swaps.len() - 1;
|
||||
let protocol_system = swap.component.protocol_system.clone();
|
||||
let swap_encoder = get_swap_encoder(&protocol_system);
|
||||
let registry = SWAP_ENCODER_REGISTRY.read().unwrap();
|
||||
let swap_encoder = registry
|
||||
.get_encoder(&swap.component.protocol_system)
|
||||
.expect("Swap encoder not found");
|
||||
let router_address = if solution.router_address.is_some() {
|
||||
solution.router_address.clone().unwrap()
|
||||
} else {
|
||||
@@ -96,7 +98,8 @@ impl StrategyEncoder for SequentialStrategyEncoder {
|
||||
address_for_approvals: router_address,
|
||||
};
|
||||
let protocol_data = swap_encoder.encode_swap(swap.clone(), encoding_context)?;
|
||||
let swap_data = self.encode_protocol_header(protocol_data, protocol_system, 0, 0, 0);
|
||||
let executor_address = swap_encoder.executor_address();
|
||||
let swap_data = self.encode_protocol_header(protocol_data, executor_address, 0, 0, 0);
|
||||
swaps.push(swap_data);
|
||||
}
|
||||
|
||||
@@ -165,8 +168,10 @@ impl StrategyEncoder for StraightToPoolStrategyEncoder {
|
||||
));
|
||||
}
|
||||
let swap = solution.swaps.first().unwrap();
|
||||
let protocol_system = swap.component.protocol_system.clone();
|
||||
let swap_encoder = get_swap_encoder(&protocol_system);
|
||||
let registry = SWAP_ENCODER_REGISTRY.read().unwrap();
|
||||
let swap_encoder = registry
|
||||
.get_encoder(&swap.component.protocol_system)
|
||||
.expect("Swap encoder not found");
|
||||
let router_address = solution.router_address.unwrap();
|
||||
|
||||
let encoding_context = EncodingContext {
|
||||
@@ -175,6 +180,7 @@ impl StrategyEncoder for StraightToPoolStrategyEncoder {
|
||||
address_for_approvals: router_address,
|
||||
};
|
||||
let protocol_data = swap_encoder.encode_swap(swap.clone(), encoding_context)?;
|
||||
// TODO: here we need to pass also the address of the executor to be used
|
||||
Ok(protocol_data)
|
||||
}
|
||||
|
||||
|
||||
39
src/encoding/swap_encoder/builder.rs
Normal file
39
src/encoding/swap_encoder/builder.rs
Normal file
@@ -0,0 +1,39 @@
|
||||
use crate::encoding::swap_encoder::swap_encoder::{
|
||||
BalancerV2SwapEncoder, SwapEncoder, UniswapV2SwapEncoder,
|
||||
};
|
||||
use alloy_primitives::Address;
|
||||
use std::str::FromStr;
|
||||
|
||||
pub struct SwapEncoderBuilder {
|
||||
protocol_system: String,
|
||||
executor_address: Option<Address>,
|
||||
}
|
||||
|
||||
impl SwapEncoderBuilder {
|
||||
pub fn new(protocol_system: &str) -> Self {
|
||||
SwapEncoderBuilder {
|
||||
protocol_system: protocol_system.to_string(),
|
||||
executor_address: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn executor_address(mut self, address: &str) -> Self {
|
||||
self.executor_address =
|
||||
Some(Address::from_str(address).expect(&format!("Invalid address: {}", address)));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Result<Box<dyn SwapEncoder>, String> {
|
||||
let executor_address = self.executor_address.ok_or_else(|| {
|
||||
format!(
|
||||
"Executor address must be provided for protocol: {}",
|
||||
self.protocol_system
|
||||
)
|
||||
})?;
|
||||
match self.protocol_system.as_str() {
|
||||
"uniswap_v2" => Ok(Box::new(UniswapV2SwapEncoder::new(executor_address))),
|
||||
"vm:balancer_v2" => Ok(Box::new(BalancerV2SwapEncoder::new(executor_address))),
|
||||
_ => Err(format!("Unknown protocol system: {}", self.protocol_system)),
|
||||
}
|
||||
}
|
||||
}
|
||||
6
src/encoding/swap_encoder/config.json
Normal file
6
src/encoding/swap_encoder/config.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"executors": {
|
||||
"uniswap_v2": "0x5C2F5a71f67c01775180ADc06909288B4C329308",
|
||||
"vm:balancer_v2": "0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"
|
||||
}
|
||||
}
|
||||
14
src/encoding/swap_encoder/mod.rs
Normal file
14
src/encoding/swap_encoder/mod.rs
Normal file
@@ -0,0 +1,14 @@
|
||||
use crate::encoding::swap_encoder::registry::{Config, SwapEncoderRegistry};
|
||||
use lazy_static::lazy_static;
|
||||
use std::sync::RwLock;
|
||||
|
||||
mod builder;
|
||||
mod registry;
|
||||
mod swap_encoder;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref SWAP_ENCODER_REGISTRY: RwLock<SwapEncoderRegistry> = {
|
||||
let config = Config::from_file("config.json").expect("Failed to load configuration file");
|
||||
RwLock::new(SwapEncoderRegistry::new(config))
|
||||
};
|
||||
}
|
||||
43
src/encoding/swap_encoder/registry.rs
Normal file
43
src/encoding/swap_encoder/registry.rs
Normal file
@@ -0,0 +1,43 @@
|
||||
use crate::encoding::swap_encoder::builder::SwapEncoderBuilder;
|
||||
use crate::encoding::swap_encoder::swap_encoder::SwapEncoder;
|
||||
use serde::Deserialize;
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
|
||||
pub struct SwapEncoderRegistry {
|
||||
encoders: HashMap<String, Box<dyn SwapEncoder>>,
|
||||
}
|
||||
|
||||
impl SwapEncoderRegistry {
|
||||
pub fn new(config: Config) -> Self {
|
||||
let mut encoders = HashMap::new();
|
||||
|
||||
for (protocol, executor_address) in config.executors {
|
||||
let builder = SwapEncoderBuilder::new(&protocol).executor_address(&executor_address);
|
||||
let encoder = builder.build().expect(&format!(
|
||||
"Failed to build swap encoder for protocol: {}",
|
||||
protocol
|
||||
));
|
||||
encoders.insert(protocol, encoder);
|
||||
}
|
||||
|
||||
Self { encoders }
|
||||
}
|
||||
|
||||
pub fn get_encoder(&self, protocol_system: &str) -> Option<&Box<dyn SwapEncoder>> {
|
||||
self.encoders.get(protocol_system)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Config {
|
||||
pub executors: HashMap<String, String>, // Protocol -> Executor address mapping
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn from_file(path: &str) -> Result<Self, anyhow::Error> {
|
||||
let config_str = fs::read_to_string(path)?;
|
||||
let config: Config = serde_json::from_str(&config_str)?;
|
||||
Ok(config)
|
||||
}
|
||||
}
|
||||
@@ -8,23 +8,37 @@ use std::str::FromStr;
|
||||
|
||||
pub trait SwapEncoder: Sync + Send {
|
||||
fn encode_swap(&self, swap: Swap, encoding_context: EncodingContext) -> Result<Vec<u8>, Error>;
|
||||
fn executor_address(&self) -> Address;
|
||||
}
|
||||
|
||||
struct UniswapV2SwapEncoder {}
|
||||
pub struct UniswapV2SwapEncoder {
|
||||
executor_address: Address,
|
||||
}
|
||||
|
||||
impl UniswapV2SwapEncoder {
|
||||
pub fn new(executor_address: Address) -> Self {
|
||||
Self { executor_address }
|
||||
}
|
||||
}
|
||||
impl SwapEncoder for UniswapV2SwapEncoder {
|
||||
fn encode_swap(&self, swap: Swap, encoding_context: EncodingContext) -> Result<Vec<u8>, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn executor_address(&self) -> Address {
|
||||
self.executor_address
|
||||
}
|
||||
}
|
||||
|
||||
struct BalancerV2SwapEncoder {
|
||||
pub struct BalancerV2SwapEncoder {
|
||||
executor_address: Address,
|
||||
vault_address: Address,
|
||||
}
|
||||
|
||||
impl BalancerV2SwapEncoder {
|
||||
pub fn new() -> Self {
|
||||
pub fn new(executor_address: Address) -> Self {
|
||||
Self {
|
||||
executor_address,
|
||||
vault_address: Address::from_str("0xba12222222228d8ba445958a75a0704d566bf2c8")
|
||||
.expect("Invalid string for balancer vault address"),
|
||||
}
|
||||
@@ -57,22 +71,8 @@ impl SwapEncoder for BalancerV2SwapEncoder {
|
||||
);
|
||||
Ok(args.abi_encode())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_swap_encoder(protocol_system: &str) -> Box<dyn SwapEncoder> {
|
||||
match protocol_system {
|
||||
"uniswap_v2" => Box::new(UniswapV2SwapEncoder {}),
|
||||
"vm:balancer_v2" => Box::new(BalancerV2SwapEncoder::new()),
|
||||
_ => panic!("Unknown protocol system: {}", protocol_system),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_swap_executor_address(protocol_system: &str) -> Address {
|
||||
match protocol_system {
|
||||
"uniswap_v2" => Address::from_str("0x5C2F5a71f67c01775180ADc06909288B4C329308")
|
||||
.expect("Invalid address"),
|
||||
"vm:balancer_v2" => Address::from_str("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4")
|
||||
.expect("Invalid address"),
|
||||
_ => panic!("Unknown protocol system: {}", protocol_system),
|
||||
fn executor_address(&self) -> Address {
|
||||
self.executor_address
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user