Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Settlement merge flag #2460

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion crates/driver/example.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
[[solver]]
name = "mysolver" # Arbitrary name given to this solver, must be unique
name = "mysolver1" # Arbitrary name given to this solver, must be unique
endpoint = "http://0.0.0.0:7872"
absolute-slippage = "40000000000000000" # Denominated in wei, optional
relative-slippage = "0.1" # Percentage in the [0, 1] range
account = "0x0000000000000000000000000000000000000000000000000000000000000001" # The private key of the solver
#TODO:
skip-merge = true # Whether to merge solutions or not when solver returns multiple solutions

# [[solver]] # And so on, specify as many solvers as needed
# name = "othersolver"
Expand Down
42 changes: 20 additions & 22 deletions crates/driver/src/boundary/settlement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,10 @@ use {
boundary,
domain::{
competition::{
self,
auction,
order,
score,
self, auction, order, score,
solution::settlement::{self, Internalization},
},
eth,
liquidity,
eth, liquidity,
},
infra::Ethereum,
util::conv::u256::U256Ext,
Expand All @@ -20,15 +16,8 @@ use {
app_data::AppDataHash,
interaction::InteractionData,
order::{
BuyTokenDestination,
Interactions,
Order,
OrderClass,
OrderData,
OrderKind,
OrderMetadata,
OrderUid,
SellTokenSource,
BuyTokenDestination, Interactions, Order, OrderClass, OrderData, OrderKind,
OrderMetadata, OrderUid, SellTokenSource,
},
signature::EcdsaSignature,
DomainSeparator,
Expand All @@ -45,9 +34,9 @@ use {
liquidity::{
order_converter::OrderConverter,
slippage::{SlippageCalculator, SlippageContext},
AmmOrderExecution,
LimitOrderExecution,
AmmOrderExecution, LimitOrderExecution,
},
settlement::MergeSkippable,
settlement::Revertable,
settlement_simulation::settle_method_builder,
},
Expand Down Expand Up @@ -241,12 +230,18 @@ impl Settlement {
}

pub fn merge(self, other: Self) -> Result<Self> {
self.inner.merge(other.inner).map(|inner| Self {
inner,
solver: self.solver,
})

match self.inner.encoder.is_merged() {
false => self.inner.merge(other.inner).map(|inner| Self {
inner,
solver: self.solver,
}),
true => Ok(Self {
inner: self.inner,
solver: self.solver,
}),
}
}

pub fn clearing_prices(&self) -> HashMap<eth::TokenAddress, eth::TokenAmount> {
self.inner
.clearing_prices()
Expand All @@ -255,6 +250,9 @@ impl Settlement {
.collect()
}

pub fn merge_skippable(&self) -> bool {
self.inner.merge_skippable() != MergeSkippable::NotSkippable
}
pub fn revertable(&self) -> bool {
self.inner.revertable() != Revertable::NoRisk
}
Expand Down
5 changes: 5 additions & 0 deletions crates/driver/src/infra/config/file/load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ pub async fn load(chain: eth::ChainId, path: &Path) -> infra::Config {
solver::Liquidity::Fetch
},
account,
merging: if config.skip_merge {
solver::Merging::Skip
} else {
solver::Merging::Fetch
},
timeouts: solver::Timeouts {
http_delay: chrono::Duration::from_std(config.timeouts.http_time_buffer)
.unwrap(),
Expand Down
8 changes: 8 additions & 0 deletions crates/driver/src/infra/config/file/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,10 @@ fn default_soft_cancellations_flag() -> bool {
false
}

fn default_skip_merge_flag() -> bool {
false
}

pub fn default_http_time_buffer() -> Duration {
Duration::from_millis(500)
}
Expand Down Expand Up @@ -182,6 +186,10 @@ struct SolverConfig {
/// The account which should be used to sign settlements for this solver.
account: Account,

/// Wheter or not to skip merging the solutions from this solver.
#[serde(default = "default_skip_merge_flag")]
skip_merge: bool,

/// Timeout configuration for the solver.
#[serde(default, flatten)]
timeouts: Timeouts,
Expand Down
19 changes: 17 additions & 2 deletions crates/driver/src/infra/solver/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ use {
auction::{self, Auction},
solution::{self, Solution},
},
eth,
liquidity,
eth, liquidity,
time::Remaining,
},
infra::blockchain::Ethereum,
Expand Down Expand Up @@ -64,6 +63,15 @@ pub enum Liquidity {
Skip,
}

#[derive(Clone, Copy, Debug)]
pub enum Merging {
/// Merged solutions from this solver should be fetched
Fetch,
/// The solver already solves for merged settlements, so merging multiple
/// solutions from this solver can be skipped.
Skip,
}

#[derive(Clone, Copy, Debug)]
pub struct Timeouts {
/// Maximum time allocated for http request/reponse to propagate through
Expand Down Expand Up @@ -93,6 +101,8 @@ pub struct Config {
pub slippage: Slippage,
/// Whether or not liquidity is used by this solver.
pub liquidity: Liquidity,
/// Whether or not to skip merging for this solver.
pub merging: Merging,
/// The private key of this solver, used for settlement submission.
pub account: ethcontract::Account,
/// How much time to spend for each step of the solving and competition.
Expand Down Expand Up @@ -132,6 +142,11 @@ impl Solver {
self.config.liquidity
}

/// The merging configuration of this solver
pub fn merging(&self) -> Merging {
self.config.merging
}

/// The blockchain address of this solver.
pub fn address(&self) -> eth::Address {
self.config.account.address().into()
Expand Down
1 change: 0 additions & 1 deletion crates/driver/src/tests/cases/example_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use crate::tests;
/// Test that the example configuration file is valid by checking that the
/// driver does not crash when started with this file.
#[tokio::test]
#[ignore]
async fn test() {
let example_config_file = std::env::current_dir().unwrap().join("example.toml");
tests::setup()
Expand Down
61 changes: 61 additions & 0 deletions crates/driver/src/tests/cases/merge_flag.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
use crate::tests::{
setup,
setup::{ab_order, ab_pool, ab_solution, cd_order, cd_pool, cd_solution, Solution},
};

// tests that flagging for settlement merge is possible
#[tokio::test]
async fn possible() {
let skipping_config_file = std::env::current_dir().unwrap().join("example.toml");
let ab_order = ab_order();
let cd_order = cd_order();
let test = setup()
.config(skipping_config_file)
.settlement_address("0x9008D19f58AAbD9eD0D60971565AA8510560ab41")
.pool(cd_pool())
.pool(ab_pool())
.order(ab_order.clone())
.order(cd_order.clone())
.solution(cd_solution())
.solution(ab_solution())
.done()
.await;
test.solve().await.ok().orders(&[ab_order, cd_order]);
test.reveal().await.ok().calldata();
test.settle()
.await
// Even though the solver returned two solutions, the executed settlement is a
// combination of the two, meaning the settlements were merged successfully.
.ok()
.await
.ab_order_executed()
.await
.cd_order_executed()
.await;
}


// tests that skipping is not valid when flag is fetching merged settlement
// TODO: config has to be changed to fetch to pass
#[tokio::test]
async fn impossible() {
let fetching_config_file = std::env::current_dir().unwrap().join("example.toml");
let order = ab_order();
let test = setup()
.pool(ab_pool())
.order(order.clone())
.order(order.clone().rename("reduced order").reduce_amount(1000000000000000u128.into()))
.solution(ab_solution())
.solution(Solution {
orders: vec!["reduced order"],
..ab_solution().reduce_score()
})
.done()
.await;

// Only the first A-B order gets settled.

test.solve().await.ok().orders(&[order]);
test.reveal().await.ok().calldata();
test.settle().await.ok().await.ab_order_executed().await;
}
2 changes: 0 additions & 2 deletions crates/driver/src/tests/cases/merge_settlements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use crate::tests::{

/// Test that settlements can be merged.
#[tokio::test]
#[ignore]
async fn possible() {
let ab_order = ab_order();
let cd_order = cd_order();
Expand Down Expand Up @@ -35,7 +34,6 @@ async fn possible() {

/// Test that settlements are not merged if the clearing prices don't permit it.
#[tokio::test]
#[ignore]
async fn impossible() {
let order = ab_order();
let test = setup()
Expand Down
1 change: 1 addition & 0 deletions crates/driver/src/tests/cases/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub mod buy_eth;
pub mod example_config;
pub mod fees;
pub mod internalization;
pub mod merge_flag;
pub mod merge_settlements;
pub mod multiple_drivers;
pub mod multiple_solutions;
Expand Down
2 changes: 0 additions & 2 deletions crates/driver/src/tests/cases/multiple_solutions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use crate::tests::{
/// Test that the best-scoring solution is picked when the /solve endpoint
/// returns multiple valid solutions.
#[tokio::test]
#[ignore]
async fn valid() {
let order = ab_order();
let test = setup()
Expand All @@ -24,7 +23,6 @@ async fn valid() {
/// Test that the invalid solution is discarded when the /solve endpoint
/// returns multiple solutions.
#[tokio::test]
#[ignore]
async fn invalid() {
let order = ab_order();
let test = setup()
Expand Down
2 changes: 1 addition & 1 deletion crates/driver/src/tests/setup/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ async fn create_config_file(
}
}
}

//TODO: skip-merge value
for (solver, addr) in solvers {
write!(
file,
Expand Down
15 changes: 15 additions & 0 deletions crates/solver/src/settlement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,12 @@ pub struct Settlement {
pub score: Score,
}

#[derive(Debug, Eq, PartialEq)]
pub enum MergeSkippable {
Skippable,
NotSkippable,
}

#[derive(Debug, Eq, PartialEq)]
pub enum Revertable {
NoRisk,
Expand Down Expand Up @@ -464,6 +470,15 @@ impl Settlement {
}
}

// Calculates if settlement should merge multiple solutions
pub fn merge_skippable(&self) -> MergeSkippable {
if self.encoder.has_interactions() {
MergeSkippable::NotSkippable
} else {
MergeSkippable::Skippable
}
}

pub fn encode(self, internalization_strategy: InternalizationStrategy) -> EncodedSettlement {
self.encoder.finish(internalization_strategy)
}
Expand Down
10 changes: 10 additions & 0 deletions crates/solver/src/settlement/settlement_encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ pub struct SettlementEncoder {
execution_plan: Vec<MaybeInternalizableInteraction>,
pre_interactions: Vec<InteractionData>,
post_interactions: Vec<InteractionData>,
merges: Vec<InteractionData>,
unwraps: Vec<UnwrapWethInteraction>,
}

Expand Down Expand Up @@ -121,6 +122,7 @@ impl SettlementEncoder {
execution_plan: Vec::new(),
pre_interactions: Vec::new(),
post_interactions: Vec::new(),
merges: Vec::new(),
unwraps: Vec::new(),
}
}
Expand Down Expand Up @@ -151,6 +153,7 @@ impl SettlementEncoder {
.collect(),
pre_interactions: self.pre_interactions.clone(),
post_interactions: self.post_interactions.clone(),
merges: self.merges.clone(),
unwraps: self.unwraps.clone(),
}
}
Expand Down Expand Up @@ -199,6 +202,13 @@ impl SettlementEncoder {
.iter()
.any(|(_, internalizable)| !internalizable)
}
// or has_merges??
pub fn is_merged(&self) -> bool {
self.execution_plan
.iter()
.any(|(_, mergable)| !mergable)

}

/// Adds an order trade using the uniform clearing prices for sell and buy
/// token. Fails if any used token doesn't have a price or if executed
Expand Down
Loading